Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Camel 20759 allow client compression before signing #14110

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,10 @@ public HttpCoreContext send(
signedCompressed(httpContext, applicationEntity, request);
break;
}
case COMPRESSED_SIGNED: {
compressedSigned(httpContext, applicationEntity, request);
break;
}
case ENCRYPTED_COMPRESSED: {
encryptedCompressed(httpContext, applicationEntity, request);
break;
Expand All @@ -296,6 +300,10 @@ public HttpCoreContext send(
encryptedCompressedSigned(httpContext, applicationEntity, request);
break;
}
case ENCRYPTED_SIGNED_COMPRESSED: {
encryptedSignedCompressed(httpContext, applicationEntity, request);
break;
}
default:
throw new HttpException("Unknown AS2 Message Structure");
}
Expand Down Expand Up @@ -324,13 +332,44 @@ private HttpResponse sendRequest(HttpCoreContext httpContext, BasicClassicHttpRe
return response;
}

// payload is compressed before being signed and encrypted
private void encryptedCompressedSigned(
HttpCoreContext httpContext, ApplicationEntity applicationEntity, BasicClassicHttpRequest request)
throws HttpException {

// Create Compressed Entity containing the EDI Entity
CMSCompressedDataGenerator compressedDataGenerator = createCompressorGenerator();
OutputCompressor compressor = createCompressor(httpContext);
ApplicationPkcs7MimeCompressedDataEntity pkcs7MimeCompressedDataEntity
= new ApplicationPkcs7MimeCompressedDataEntity(
applicationEntity, compressedDataGenerator, compressor, AS2TransferEncoding.BASE64, false);

// Create Multipart Signed Entity containing the Compressed Entity
AS2SignedDataGenerator signingGenerator = createSigningGenerator(httpContext);
MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(
pkcs7MimeCompressedDataEntity, signingGenerator,
StandardCharsets.US_ASCII.name(), AS2TransferEncoding.BASE64, false, null);

// Create Enveloped Entity containing th Signed Entity
CMSEnvelopedDataGenerator envelopedDataGenerator = createEncryptingGenerator(httpContext);
OutputEncryptor encryptor = createEncryptor(httpContext);
ApplicationPkcs7MimeEnvelopedDataEntity pkcs7MimeEnvelopedDataEntity
= new ApplicationPkcs7MimeEnvelopedDataEntity(
multipartSignedEntity, envelopedDataGenerator, encryptor, AS2TransferEncoding.BASE64,
true);

// Add Enveloped Entity to main body of request
EntityUtils.setMessageEntity(request, pkcs7MimeEnvelopedDataEntity);
}

// payload is signed before being compressed and encrypted.
private void encryptedSignedCompressed(
HttpCoreContext httpContext, ApplicationEntity applicationEntity, BasicClassicHttpRequest request)
throws HttpException {
// Create Multipart Signed Entity containing EDI Entity
AS2SignedDataGenerator signingGenrator = createSigningGenerator(httpContext);
AS2SignedDataGenerator signingGenerator = createSigningGenerator(httpContext);
MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(
applicationEntity, signingGenrator,
applicationEntity, signingGenerator,
StandardCharsets.US_ASCII.name(), AS2TransferEncoding.BASE64, false, null);

// Create Compressed Entity containing Multipart Signed Entity
Expand Down Expand Up @@ -374,14 +413,35 @@ private void encryptedCompressed(
EntityUtils.setMessageEntity(request, pkcs7MimeEnvelopedDataEntity);
}

private void compressedSigned(
HttpCoreContext httpContext, ApplicationEntity applicationEntity, BasicClassicHttpRequest request)
throws HttpException {

// Create Compressed Entity containing the EDI Entity
CMSCompressedDataGenerator compressedDataGenerator = createCompressorGenerator();
OutputCompressor compressor = createCompressor(httpContext);
ApplicationPkcs7MimeCompressedDataEntity pkcs7MimeCompressedDataEntity
= new ApplicationPkcs7MimeCompressedDataEntity(
applicationEntity, compressedDataGenerator, compressor, AS2TransferEncoding.BASE64, false);

// Create Multipart Signed Entity containing the Compressed Entity
AS2SignedDataGenerator signingGenerator = createSigningGenerator(httpContext);
MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(
pkcs7MimeCompressedDataEntity,
signingGenerator, StandardCharsets.US_ASCII.name(), AS2TransferEncoding.BASE64, true, null);

// Add Compressed Entity to main body of request.
EntityUtils.setMessageEntity(request, multipartSignedEntity);
}

private void signedCompressed(
HttpCoreContext httpContext, ApplicationEntity applicationEntity, BasicClassicHttpRequest request)
throws HttpException {
// Create Multipart Signed Entity containing EDI Entity
AS2SignedDataGenerator signingGenrator = createSigningGenerator(httpContext);
AS2SignedDataGenerator signingGenerator = createSigningGenerator(httpContext);
MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(
applicationEntity,
signingGenrator, StandardCharsets.US_ASCII.name(), AS2TransferEncoding.BASE64, false, null);
signingGenerator, StandardCharsets.US_ASCII.name(), AS2TransferEncoding.BASE64, false, null);

// Create Compressed Entity containing Multipart Signed Entity
CMSCompressedDataGenerator compressedDataGenerator = createCompressorGenerator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ public enum AS2MessageStructure {
ENCRYPTED(false, true, false),
SIGNED_ENCRYPTED(true, true, false),
PLAIN_COMPRESSED(false, false, true),
COMPRESSED_SIGNED(true, false, true),
SIGNED_COMPRESSED(true, false, true),
ENCRYPTED_COMPRESSED(false, true, true),
ENCRYPTED_COMPRESSED_SIGNED(true, true, true);
ENCRYPTED_COMPRESSED_SIGNED(true, true, true),
ENCRYPTED_SIGNED_COMPRESSED(true, true, true);

private final boolean isSigned;
private final boolean isEncrypted;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.KeyPair;
Expand Down Expand Up @@ -836,7 +837,7 @@ public void compressedMessageTest() throws Exception {
}

@Test
public void compressedAndSignedMessageTest() throws Exception {
public void signedAndCompressedMessageTest() throws Exception {
AS2ClientManager clientManager = createDefaultClientManager();

LOG.info("Key Algorithm: {}", signingKP.getPrivate().getAlgorithm());
Expand Down Expand Up @@ -960,14 +961,75 @@ public void envelopedAndCompressedMessageTest() throws Exception {
"Unexpected content for enveloped mime part");
}

// Verify that the payload is compressed before being signed.
@Test
public void compressedAndSignedMessageTest() throws Exception {
AS2ClientManager clientManager = createDefaultClientManager();
HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
AS2MessageStructure.COMPRESSED_SIGNED,
ContentType.create(AS2MediaType.APPLICATION_EDIFACT, StandardCharsets.US_ASCII), "base64",
AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(),
AS2CompressionAlgorithm.ZLIB,
DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null,
null, "file.txt", null);

HttpRequest request = httpContext.getRequest();
verifyRequest(request);

assertTrue(request.getFirstHeader(AS2Header.CONTENT_TYPE).getValue().startsWith(AS2MimeType.MULTIPART_SIGNED),
"Unexpected content type for message");
assertTrue(request instanceof ClassicHttpRequest, "Request does not contain entity");
HttpEntity entity = ((ClassicHttpRequest) request).getEntity();
assertNotNull(entity, "Request does not contain entity");
assertTrue(entity instanceof MultipartSignedEntity, "Unexpected request entity type");
MultipartSignedEntity multipartSignedEntity = (MultipartSignedEntity) entity;
assertTrue(multipartSignedEntity.isMainBody(), "Entity not set as main body of request");

verifyCompressedSignedEntity(multipartSignedEntity);
}

// Verify that the payload is compressed before being signed and encrypted.
@Test
public void envelopedSignedAndCompressedMessageTest() throws Exception {
AS2ClientManager clientManager = createDefaultClientManager();
HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
AS2MessageStructure.ENCRYPTED_COMPRESSED_SIGNED,
ContentType.create(AS2MediaType.APPLICATION_EDIFACT, StandardCharsets.US_ASCII), null,
AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(),
AS2CompressionAlgorithm.ZLIB, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS,
AS2EncryptionAlgorithm.AES128_CBC, certList.toArray(new Certificate[0]), "file.txt", null);

HttpRequest request = httpContext.getRequest();
verifyRequest(request);

assertTrue(request.getFirstHeader(AS2Header.CONTENT_TYPE).getValue().startsWith(AS2MimeType.APPLICATION_PKCS7_MIME),
"Unexpected content type for message");
assertTrue(request instanceof ClassicHttpRequest, "Request does not contain entity");
HttpEntity entity = ((ClassicHttpRequest) request).getEntity();
assertNotNull(entity, "Request does not contain entity");
assertTrue(entity instanceof ApplicationPkcs7MimeEnvelopedDataEntity, "Unexpected request entity type");
ApplicationPkcs7MimeEnvelopedDataEntity envelopedEntity = (ApplicationPkcs7MimeEnvelopedDataEntity) entity;
assertTrue(envelopedEntity.isMainBody(), "Entity not set as main body of request");

// Validated enveloped part.
MimeEntity decryptedEntity = envelopedEntity.getEncryptedEntity(signingKP.getPrivate());
assertTrue(decryptedEntity instanceof MultipartSignedEntity, "Enveloped mime part incorrect type ");
MultipartSignedEntity multipartSignedEntity = (MultipartSignedEntity) decryptedEntity;
assertTrue(multipartSignedEntity.getContentType().startsWith(AS2MimeType.MULTIPART_SIGNED),
"Unexpected content type for compressed mime part");
assertFalse(multipartSignedEntity.isMainBody(), "Enveloped mime type set as main body of request");

verifyCompressedSignedEntity(multipartSignedEntity);
}

@Test
public void envelopedCompressedAndSignedMessageTest() throws Exception {
AS2ClientManager clientManager = createDefaultClientManager();

LOG.info("Key Algorithm: {}", signingKP.getPrivate().getAlgorithm());

HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
AS2MessageStructure.ENCRYPTED_COMPRESSED_SIGNED,
AS2MessageStructure.ENCRYPTED_SIGNED_COMPRESSED,
ContentType.create(AS2MediaType.APPLICATION_EDIFACT, StandardCharsets.US_ASCII), null,
AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(),
AS2CompressionAlgorithm.ZLIB, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS,
Expand Down Expand Up @@ -1076,6 +1138,59 @@ void compressionSignatureOrderTest(boolean encrypt, boolean compressBeforeSign)
assertEquals(EDI_MESSAGE, ediEntity.getEdiMessage().replaceAll("\r", ""));
}

private void verifyRequest(HttpRequest request) throws URISyntaxException {
assertEquals(METHOD, request.getMethod(), "Unexpected method value");
assertEquals(REQUEST_URI, request.getUri().getPath(), "Unexpected request URI value");
assertEquals(HttpVersion.HTTP_1_1, request.getVersion(), "Unexpected HTTP version value");

assertEquals(SUBJECT, request.getFirstHeader(AS2Header.SUBJECT).getValue(), "Unexpected subject value");
assertEquals(FROM, request.getFirstHeader(AS2Header.FROM).getValue(), "Unexpected from value");
assertEquals(AS2_VERSION, request.getFirstHeader(AS2Header.AS2_VERSION).getValue(), "Unexpected AS2 version value");
assertEquals(AS2_NAME, request.getFirstHeader(AS2Header.AS2_FROM).getValue(), "Unexpected AS2 from value");
assertEquals(AS2_NAME, request.getFirstHeader(AS2Header.AS2_TO).getValue(), "Unexpected AS2 to value");
assertTrue(request.getFirstHeader(AS2Header.MESSAGE_ID).getValue().endsWith(CLIENT_FQDN + ">"),
"Unexpected message id value");
assertEquals(TARGET_HOST + ":" + TARGET_PORT, request.getFirstHeader(AS2Header.TARGET_HOST).getValue(),
"Unexpected target host value");
assertEquals(USER_AGENT, request.getFirstHeader(AS2Header.USER_AGENT).getValue(), "Unexpected user agent value");
assertNotNull(request.getFirstHeader(AS2Header.DATE), "Date value missing");
assertNotNull(request.getFirstHeader(AS2Header.CONTENT_LENGTH), "Content length value missing");
}

private void verifyCompressedSignedEntity(MultipartSignedEntity multipartSignedEntity) throws HttpException {
assertEquals(2, multipartSignedEntity.getPartCount(), "Request contains invalid number of mime parts");

// Verify first mime part.
assertTrue(multipartSignedEntity.getPart(0) instanceof ApplicationPkcs7MimeCompressedDataEntity,
"First mime part incorrect type ");
ApplicationPkcs7MimeCompressedDataEntity compressedDataEntity
= (ApplicationPkcs7MimeCompressedDataEntity) multipartSignedEntity.getPart(0);
assertTrue(compressedDataEntity.getContentType().startsWith(AS2MediaType.APPLICATION_PKCS7_MIME_COMPRESSED),
"Unexpected content type for first mime part");
assertFalse(compressedDataEntity.isMainBody(), "First mime type set as main body of request");

// Verify compressed entity.
verifyEdiFactEntity(compressedDataEntity.getCompressedEntity(new ZlibExpanderProvider()));

// Verify second mime part.
assertTrue(multipartSignedEntity.getPart(1) instanceof ApplicationPkcs7SignatureEntity,
"Second mime part incorrect type ");
ApplicationPkcs7SignatureEntity signatureEntity = (ApplicationPkcs7SignatureEntity) multipartSignedEntity.getPart(1);
assertTrue(signatureEntity.getContentType().startsWith(AS2MediaType.APPLICATION_PKCS7_SIGNATURE),
"Unexpected content type for second mime part");
assertFalse(signatureEntity.isMainBody(), "First mime type set as main body of request");

// Verify Signature
assertTrue(SigningUtils.isValid(multipartSignedEntity, new Certificate[] { signingCert }), "Signature must be invalid");
}

private void verifyEdiFactEntity(MimeEntity entity) {
assertTrue(entity instanceof ApplicationEDIFACTEntity, "Enveloped mime part incorrect type ");
ApplicationEDIFACTEntity ediEntity = (ApplicationEDIFACTEntity) entity;
assertTrue(ediEntity.getContentType().startsWith(AS2MediaType.APPLICATION_EDIFACT),
"Unexpected content type for compressed entity");
}

private AS2ClientManager createDefaultClientManager() throws IOException {
AS2ClientConnection clientConnection = new AS2ClientConnection(
AS2_VERSION, USER_AGENT, CLIENT_FQDN,
Expand Down
Loading
Loading