From e31d78a5f2682147a8a9fcbc769212a509261395 Mon Sep 17 00:00:00 2001 From: Felix Dittrich Date: Fri, 25 Mar 2022 15:35:57 +0100 Subject: [PATCH 1/2] Add ability to get repacked detached and embedded signature from CMS Parser --- .../ec/dgc/signing/SignedMessageParser.java | 39 ++++++++++++++----- .../SignedByteArrayMessageParserTest.java | 28 ++++++++++--- .../SignedCertificateMessageParserTest.java | 28 ++++++++++--- .../SignedStringMessageParserTest.java | 29 +++++++++++--- 4 files changed, 100 insertions(+), 24 deletions(-) diff --git a/src/main/java/eu/europa/ec/dgc/signing/SignedMessageParser.java b/src/main/java/eu/europa/ec/dgc/signing/SignedMessageParser.java index 5429b13..102122a 100644 --- a/src/main/java/eu/europa/ec/dgc/signing/SignedMessageParser.java +++ b/src/main/java/eu/europa/ec/dgc/signing/SignedMessageParser.java @@ -81,13 +81,31 @@ public abstract class SignedMessageParser { private boolean signatureVerified = false; /** - *

Base64 encoded signature of the cms message.

+ *

Base64 encoded signature of the cms message. + * Deprecated: Use getDetachedSignature() or getEmbeddedSignature() instead.

* *

This string contains only the signature which signs the message.

*/ @Getter + @Deprecated private String signature; + /** + *

Base64 encoded detached signature of the cms message.

+ * + *

This string contains only the signature which signs the message and not the payload.

+ */ + @Getter + private String detachedSignature; + + /** + *

Base64 encoded embedded signature of the cms message.

+ * + *

This string contains both the signature which signs the message and the corresponding payload.

+ */ + @Getter + private String embeddedSignature; + /** * Method to convert the encoded bytes to the actual Class instance. * @@ -229,12 +247,14 @@ private void afterPropertiesSet() { } signingCertificate = certificateHolderCollection.iterator().next(); - // Try to extract detached CMS Signature + // Try to repack CMS try { - signature = Base64.getEncoder().encodeToString(repackToDetachedCms(cmsSignedData).getEncoded()); + detachedSignature = Base64.getEncoder().encodeToString(repack(cmsSignedData, true).getEncoded()); + embeddedSignature = Base64.getEncoder().encodeToString(repack(cmsSignedData, false).getEncoded()); + signature = detachedSignature; // for compatibility reasons } catch (IOException | CMSException e) { signature = null; - log.error("Failed to repack CMS to get detached signature."); + log.error("Failed to repack CMS."); } // Get signer information and verify signature @@ -256,20 +276,21 @@ private void afterPropertiesSet() { } /** - * Recreates a CMS without encapsulated Data. + * Recreates a CMS w/o encapsulated Data. * - * @param input input CMS Message - * @return CMS message without encapsulated data. + * @param input input CMS Message + * @param detached whether it should be a detached signature or not + * @return CMS message. * @throws CMSException if repacking fails. */ - private CMSSignedData repackToDetachedCms(CMSSignedData input) throws CMSException { + private CMSSignedData repack(CMSSignedData input, boolean detached) throws CMSException { CMSSignedDataGenerator cmsGenerator = new CMSSignedDataGenerator(); cmsGenerator.addCertificates(input.getCertificates()); cmsGenerator.addSigners(input.getSignerInfos()); cmsGenerator.addAttributeCertificates(input.getAttributeCertificates()); cmsGenerator.addCRLs(input.getCRLs()); - return cmsGenerator.generate(input.getSignedContent(), false); + return cmsGenerator.generate(input.getSignedContent(), !detached); } public enum ParserState { diff --git a/src/test/java/eu/europa/ec/dgc/signing/SignedByteArrayMessageParserTest.java b/src/test/java/eu/europa/ec/dgc/signing/SignedByteArrayMessageParserTest.java index 0147cbe..4940810 100644 --- a/src/test/java/eu/europa/ec/dgc/signing/SignedByteArrayMessageParserTest.java +++ b/src/test/java/eu/europa/ec/dgc/signing/SignedByteArrayMessageParserTest.java @@ -77,7 +77,9 @@ void parserShouldParseByteArray() throws IOException, CertificateEncodingExcepti Assertions.assertArrayEquals(payload, parser.getPayload()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); - checkSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getDetachedSignature()); + checkEmbeddedSignatureFromParser(parser.getEmbeddedSignature()); } @Test @@ -107,7 +109,9 @@ void parserShouldParseByteArrayWithDetachedPayloadAsString() throws IOException, Assertions.assertArrayEquals(payload, parser.getPayload()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); - checkSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getDetachedSignature()); + checkEmbeddedSignatureFromParser(parser.getEmbeddedSignature()); } @Test @@ -119,7 +123,9 @@ void parserShouldParseString() throws IOException, CertificateEncodingException Assertions.assertArrayEquals(payload, parser.getPayload()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); - checkSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getDetachedSignature()); + checkEmbeddedSignatureFromParser(parser.getEmbeddedSignature()); } @Test @@ -132,7 +138,9 @@ void parserShouldParseStringWithDetachedPayload() throws IOException, Certificat Assertions.assertArrayEquals(payload, parser.getPayload()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); - checkSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getDetachedSignature()); + checkEmbeddedSignatureFromParser(parser.getEmbeddedSignature()); } @Test @@ -246,7 +254,7 @@ void parserShouldDetectInvalidSignerInfoAmount() throws Exception { Assertions.assertFalse(parser.isSignatureVerified()); } - private void checkSignatureFromParser(String signature) throws CertificateEncodingException, IOException { + private void checkDetachedSignatureFromParser(String signature) throws CertificateEncodingException, IOException { SignedByteArrayMessageParser parser = new SignedByteArrayMessageParser( signature, Base64.getEncoder().encodeToString(payload)); @@ -256,5 +264,15 @@ private void checkSignatureFromParser(String signature) throws CertificateEncodi Assertions.assertTrue(parser.isSignatureVerified()); Assertions.assertEquals(signature, parser.getSignature()); } + + private void checkEmbeddedSignatureFromParser(String signature) throws CertificateEncodingException, IOException { + SignedByteArrayMessageParser parser = new SignedByteArrayMessageParser(signature); + + Assertions.assertEquals(SignedStringMessageParser.ParserState.SUCCESS, parser.getParserState()); + Assertions.assertArrayEquals(payload, parser.getPayload()); + Assertions.assertEquals(new X509CertificateHolder(signingCertificate.getEncoded()), parser.getSigningCertificate()); + Assertions.assertTrue(parser.isSignatureVerified()); + Assertions.assertEquals(signature, parser.getEmbeddedSignature()); + } } diff --git a/src/test/java/eu/europa/ec/dgc/signing/SignedCertificateMessageParserTest.java b/src/test/java/eu/europa/ec/dgc/signing/SignedCertificateMessageParserTest.java index 9454638..c89a53c 100644 --- a/src/test/java/eu/europa/ec/dgc/signing/SignedCertificateMessageParserTest.java +++ b/src/test/java/eu/europa/ec/dgc/signing/SignedCertificateMessageParserTest.java @@ -75,7 +75,9 @@ void parserShouldParseByteArray() throws IOException, CertificateEncodingExcepti Assertions.assertArrayEquals(payloadCertificate.getEncoded(), parser.getPayload().getEncoded()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); - checkSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getDetachedSignature()); + checkEmbeddedSignatureFromParser(parser.getEmbeddedSignature()); } @Test @@ -105,7 +107,9 @@ void parserShouldParseByteArrayWithDetachedPayloadAsString() throws IOException, Assertions.assertArrayEquals(payloadCertificate.getEncoded(), parser.getPayload().getEncoded()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); - checkSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getDetachedSignature()); + checkEmbeddedSignatureFromParser(parser.getEmbeddedSignature()); } @Test @@ -117,7 +121,9 @@ void parserShouldParseString() throws IOException, CertificateEncodingException Assertions.assertArrayEquals(payloadCertificate.getEncoded(), parser.getPayload().getEncoded()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); - checkSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getDetachedSignature()); + checkEmbeddedSignatureFromParser(parser.getEmbeddedSignature()); } @Test @@ -130,7 +136,9 @@ void parserShouldParseStringWithDetachedPayload() throws IOException, Certificat Assertions.assertArrayEquals(payloadCertificate.getEncoded(), parser.getPayload().getEncoded()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); - checkSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getDetachedSignature()); + checkEmbeddedSignatureFromParser(parser.getEmbeddedSignature()); } @Test @@ -275,7 +283,7 @@ void parserShouldDetectInvalidSignerInfoAmount() throws Exception { Assertions.assertFalse(parser.isSignatureVerified()); } - private void checkSignatureFromParser(String signature) throws CertificateEncodingException, IOException { + private void checkDetachedSignatureFromParser(String signature) throws CertificateEncodingException, IOException { SignedCertificateMessageParser parser = new SignedCertificateMessageParser( signature, Base64.getEncoder().encodeToString(payloadCertificate.getEncoded())); @@ -285,5 +293,15 @@ private void checkSignatureFromParser(String signature) throws CertificateEncodi Assertions.assertTrue(parser.isSignatureVerified()); Assertions.assertEquals(signature, parser.getSignature()); } + + private void checkEmbeddedSignatureFromParser(String signature) throws CertificateEncodingException, IOException { + SignedCertificateMessageParser parser = new SignedCertificateMessageParser(signature); + + Assertions.assertEquals(SignedStringMessageParser.ParserState.SUCCESS, parser.getParserState()); + Assertions.assertEquals(new X509CertificateHolder(payloadCertificate.getEncoded()), parser.getPayload()); + Assertions.assertEquals(new X509CertificateHolder(signingCertificate.getEncoded()), parser.getSigningCertificate()); + Assertions.assertTrue(parser.isSignatureVerified()); + Assertions.assertEquals(signature, parser.getEmbeddedSignature()); + } } diff --git a/src/test/java/eu/europa/ec/dgc/signing/SignedStringMessageParserTest.java b/src/test/java/eu/europa/ec/dgc/signing/SignedStringMessageParserTest.java index 7d34c8f..b8f44ba 100644 --- a/src/test/java/eu/europa/ec/dgc/signing/SignedStringMessageParserTest.java +++ b/src/test/java/eu/europa/ec/dgc/signing/SignedStringMessageParserTest.java @@ -73,7 +73,9 @@ void parserShouldParseByteArray() throws IOException, CertificateEncodingExcepti Assertions.assertEquals(payloadString, parser.getPayload()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); - checkSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getDetachedSignature()); + checkEmbeddedSignatureFromParser(parser.getEmbeddedSignature()); } @Test @@ -103,7 +105,9 @@ void parserShouldParseByteArrayWithDetachedPayloadAsString() throws IOException, Assertions.assertEquals(payloadString, parser.getPayload()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); - checkSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getDetachedSignature()); + checkEmbeddedSignatureFromParser(parser.getEmbeddedSignature()); } @Test @@ -115,7 +119,9 @@ void parserShouldParseString() throws IOException, CertificateEncodingException Assertions.assertEquals(payloadString, parser.getPayload()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); - checkSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getDetachedSignature()); + checkEmbeddedSignatureFromParser(parser.getEmbeddedSignature()); } @Test @@ -128,7 +134,9 @@ void parserShouldParseStringWithDetachedPayload() throws IOException, Certificat Assertions.assertEquals(payloadString, parser.getPayload()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); - checkSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getSignature()); + checkDetachedSignatureFromParser(parser.getDetachedSignature()); + checkEmbeddedSignatureFromParser(parser.getEmbeddedSignature()); } @Test @@ -242,7 +250,7 @@ void parserShouldDetectInvalidSignerInfoAmount() throws Exception { Assertions.assertFalse(parser.isSignatureVerified()); } - private void checkSignatureFromParser(String signature) throws CertificateEncodingException, IOException { + private void checkDetachedSignatureFromParser(String signature) throws CertificateEncodingException, IOException { SignedStringMessageParser parser = new SignedStringMessageParser( signature, Base64.getEncoder().encodeToString(payloadString.getBytes(StandardCharsets.UTF_8))); @@ -251,6 +259,17 @@ private void checkSignatureFromParser(String signature) throws CertificateEncodi Assertions.assertEquals(new X509CertificateHolder(signingCertificate.getEncoded()), parser.getSigningCertificate()); Assertions.assertTrue(parser.isSignatureVerified()); Assertions.assertEquals(signature, parser.getSignature()); + Assertions.assertEquals(signature, parser.getDetachedSignature()); + } + + private void checkEmbeddedSignatureFromParser(String signature) throws CertificateEncodingException, IOException { + SignedStringMessageParser parser = new SignedStringMessageParser(signature); + + Assertions.assertEquals(SignedStringMessageParser.ParserState.SUCCESS, parser.getParserState()); + Assertions.assertEquals(payloadString, parser.getPayload()); + Assertions.assertEquals(new X509CertificateHolder(signingCertificate.getEncoded()), parser.getSigningCertificate()); + Assertions.assertTrue(parser.isSignatureVerified()); + Assertions.assertEquals(signature, parser.getEmbeddedSignature()); } } From 491867a744cebf07f25051464acc218502bd4bb2 Mon Sep 17 00:00:00 2001 From: Felix Dittrich Date: Fri, 25 Mar 2022 15:48:02 +0100 Subject: [PATCH 2/2] Fix Javadoc --- .../java/eu/europa/ec/dgc/signing/SignedMessageParser.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/eu/europa/ec/dgc/signing/SignedMessageParser.java b/src/main/java/eu/europa/ec/dgc/signing/SignedMessageParser.java index 102122a..bd4947e 100644 --- a/src/main/java/eu/europa/ec/dgc/signing/SignedMessageParser.java +++ b/src/main/java/eu/europa/ec/dgc/signing/SignedMessageParser.java @@ -81,10 +81,10 @@ public abstract class SignedMessageParser { private boolean signatureVerified = false; /** - *

Base64 encoded signature of the cms message. - * Deprecated: Use getDetachedSignature() or getEmbeddedSignature() instead.

+ *

Base64 encoded signature of the cms message.

* *

This string contains only the signature which signs the message.

+ * @deprecated Use getDetachedSignature() or getEmbeddedSignature() instead. */ @Getter @Deprecated