Skip to content

Commit 5beab0c

Browse files
authored
Feat: Add MessageParser and MessageBuilder for ByteArrays
2 parents 7b9ef52 + c59d1b5 commit 5beab0c

File tree

4 files changed

+547
-0
lines changed

4 files changed

+547
-0
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*-
2+
* ---license-start
3+
* EU Digital Green Certificate Gateway Service / dgc-lib
4+
* ---
5+
* Copyright (C) 2021 T-Systems International GmbH and all other contributors
6+
* ---
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* ---license-end
19+
*/
20+
21+
package eu.europa.ec.dgc.signing;
22+
23+
import lombok.NoArgsConstructor;
24+
import lombok.extern.slf4j.Slf4j;
25+
26+
/**
27+
* Utility to build a CMS signed message containing a Byte Array (e.g. a File).
28+
*/
29+
@Slf4j
30+
@NoArgsConstructor
31+
public class SignedByteArrayMessageBuilder extends SignedMessageBuilder<byte[], SignedByteArrayMessageBuilder> {
32+
33+
@Override
34+
byte[] convertToBytes(byte[] payload) {
35+
return payload;
36+
}
37+
38+
@Override
39+
SignedByteArrayMessageBuilder getThis() {
40+
return this;
41+
}
42+
43+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*-
2+
* ---license-start
3+
* EU Digital Green Certificate Gateway Service / dgc-lib
4+
* ---
5+
* Copyright (C) 2021 T-Systems International GmbH and all other contributors
6+
* ---
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* ---license-end
19+
*/
20+
21+
package eu.europa.ec.dgc.signing;
22+
23+
import lombok.NonNull;
24+
import lombok.extern.slf4j.Slf4j;
25+
26+
/**
27+
* Utility to parse a CMS signed message containing a Byte Array (e.g. a File).
28+
*/
29+
@Slf4j
30+
public class SignedByteArrayMessageParser extends SignedMessageParser<byte[]> {
31+
32+
@Override
33+
byte[] convertFromBytes(byte[] bytes) {
34+
return bytes;
35+
}
36+
37+
/**
38+
* Create a new instance of {@link SignedByteArrayMessageParser} and starts the parsing process.
39+
* The result of parsing process will be immediately available.
40+
*
41+
* @param cmsMessage base64 encoded CMS message bytes.
42+
*/
43+
public SignedByteArrayMessageParser(@NonNull byte[] cmsMessage) {
44+
super(cmsMessage);
45+
}
46+
47+
/**
48+
* Create a new instance of {@link SignedByteArrayMessageParser} and starts the parsing process.
49+
* The result of parsing process will be immediately available.
50+
*
51+
* @param cmsSignature base64 encoded detached CMS signature bytes.
52+
* @param cmsPayload base64 encoded CMS message payload.
53+
*/
54+
public SignedByteArrayMessageParser(@NonNull byte[] cmsSignature, @NonNull byte[] cmsPayload) {
55+
super(cmsSignature, cmsPayload);
56+
}
57+
58+
/**
59+
* Create a new instance of {@link SignedByteArrayMessageParser} and starts the parsing process.
60+
* The result of parsing process will be immediately available.
61+
*
62+
* @param cmsMessage base64 encoded CMS message string.
63+
*/
64+
public SignedByteArrayMessageParser(@NonNull String cmsMessage) {
65+
super(cmsMessage);
66+
}
67+
68+
/**
69+
* Create a new instance of {@link SignedByteArrayMessageParser} and starts the parsing process.
70+
* The result of parsing process will be immediately available.
71+
*
72+
* @param cmsSignature base64 encoded detached CMS signature string.
73+
* @param cmsPayload base64 encoded CMS message payload string.
74+
*/
75+
public SignedByteArrayMessageParser(@NonNull String cmsSignature, @NonNull String cmsPayload) {
76+
super(cmsSignature, cmsPayload);
77+
}
78+
79+
/**
80+
* Create a new instance of {@link SignedByteArrayMessageParser} and starts the parsing process.
81+
* The result of parsing process will be immediately available.
82+
*
83+
* @param cmsSignature base64 encoded detached CMS signature bytes.
84+
* @param cmsPayload base64 encoded CMS message payload string.
85+
*/
86+
public SignedByteArrayMessageParser(@NonNull byte[] cmsSignature, @NonNull String cmsPayload) {
87+
super(cmsSignature, cmsPayload);
88+
}
89+
90+
/**
91+
* Create a new instance of {@link SignedByteArrayMessageParser} and starts the parsing process.
92+
* The result of parsing process will be immediately available.
93+
*
94+
* @param cmsSignature base64 encoded detached CMS signature string.
95+
* @param cmsPayload base64 encoded CMS message payload bytes.
96+
*/
97+
public SignedByteArrayMessageParser(@NonNull String cmsSignature, @NonNull byte[] cmsPayload) {
98+
super(cmsSignature, cmsPayload);
99+
}
100+
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*-
2+
* ---license-start
3+
* EU Digital Green Certificate Gateway Service / dgc-lib
4+
* ---
5+
* Copyright (C) 2021 T-Systems International GmbH and all other contributors
6+
* ---
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* ---license-end
19+
*/
20+
21+
package eu.europa.ec.dgc.signing;
22+
23+
import eu.europa.ec.dgc.testdata.CertificateTestUtils;
24+
import java.security.KeyPair;
25+
import java.security.KeyPairGenerator;
26+
import java.security.cert.X509Certificate;
27+
import java.util.Base64;
28+
import java.util.Collection;
29+
import java.util.Random;
30+
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
31+
import org.bouncycastle.cert.X509CertificateHolder;
32+
import org.bouncycastle.cms.CMSProcessableByteArray;
33+
import org.bouncycastle.cms.CMSSignedData;
34+
import org.bouncycastle.cms.SignerInformation;
35+
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
36+
import org.junit.jupiter.api.Assertions;
37+
import org.junit.jupiter.api.BeforeEach;
38+
import org.junit.jupiter.api.Test;
39+
40+
class SignedByteArrayMessageBuilderTest {
41+
42+
KeyPair signingKeyPair;
43+
X509Certificate signingCertificate;
44+
byte[] payload;
45+
46+
SignedByteArrayMessageBuilder builder;
47+
48+
@BeforeEach
49+
void setupTestData() throws Exception {
50+
payload = new byte[100];
51+
new Random().nextBytes(payload);
52+
53+
signingKeyPair = KeyPairGenerator.getInstance("ec").generateKeyPair();
54+
signingCertificate = CertificateTestUtils.generateCertificate(signingKeyPair, "DE", "SigningCertificate");
55+
56+
builder = new SignedByteArrayMessageBuilder()
57+
.withPayload(payload)
58+
.withSigningCertificate(new X509CertificateHolder(signingCertificate.getEncoded()), signingKeyPair.getPrivate());
59+
}
60+
61+
@Test
62+
void testUnreadyBuilder() {
63+
builder = new SignedByteArrayMessageBuilder();
64+
Assertions.assertThrows(RuntimeException.class, builder::buildAsString);
65+
}
66+
67+
@Test
68+
void testSignedMessage() throws Exception {
69+
CMSSignedData cmsSignedData = new CMSSignedData(builder.build());
70+
71+
Assertions.assertEquals(CMSObjectIdentifiers.data, cmsSignedData.getSignedContent().getContentType());
72+
Assertions.assertArrayEquals(payload, (byte[]) cmsSignedData.getSignedContent().getContent());
73+
74+
Collection<X509CertificateHolder> certificateHolderCollection = cmsSignedData.getCertificates().getMatches(null);
75+
Assertions.assertEquals(1, certificateHolderCollection.size());
76+
X509CertificateHolder readSigningCertificate = certificateHolderCollection.iterator().next();
77+
Assertions.assertNotNull(readSigningCertificate);
78+
79+
Assertions.assertEquals(1, cmsSignedData.getSignerInfos().size());
80+
SignerInformation signerInformation = cmsSignedData.getSignerInfos().iterator().next();
81+
82+
Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(signingCertificate)));
83+
Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(readSigningCertificate)));
84+
}
85+
86+
@Test
87+
void testSignedMessageDetached() throws Exception {
88+
CMSSignedData cmsSignedData = new CMSSignedData(builder.build(true));
89+
90+
Assertions.assertNull(cmsSignedData.getSignedContent());
91+
92+
Collection<X509CertificateHolder> certificateHolderCollection = cmsSignedData.getCertificates().getMatches(null);
93+
Assertions.assertEquals(1, certificateHolderCollection.size());
94+
X509CertificateHolder readSigningCertificate = certificateHolderCollection.iterator().next();
95+
Assertions.assertNotNull(readSigningCertificate);
96+
97+
cmsSignedData = new CMSSignedData(new CMSProcessableByteArray(payload), builder.build(true));
98+
99+
Assertions.assertEquals(1, cmsSignedData.getSignerInfos().size());
100+
SignerInformation signerInformation = cmsSignedData.getSignerInfos().iterator().next();
101+
102+
Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(signingCertificate)));
103+
Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(readSigningCertificate)));
104+
}
105+
106+
@Test
107+
void testSignedMessageBase64() throws Exception {
108+
CMSSignedData cmsSignedData = new CMSSignedData(Base64.getDecoder().decode(builder.buildAsString()));
109+
110+
Assertions.assertEquals(CMSObjectIdentifiers.data, cmsSignedData.getSignedContent().getContentType());
111+
Assertions.assertArrayEquals(payload, (byte[]) cmsSignedData.getSignedContent().getContent());
112+
113+
Collection<X509CertificateHolder> certificateHolderCollection = cmsSignedData.getCertificates().getMatches(null);
114+
Assertions.assertEquals(1, certificateHolderCollection.size());
115+
X509CertificateHolder readSigningCertificate = certificateHolderCollection.iterator().next();
116+
Assertions.assertNotNull(readSigningCertificate);
117+
118+
Assertions.assertEquals(1, cmsSignedData.getSignerInfos().size());
119+
SignerInformation signerInformation = cmsSignedData.getSignerInfos().iterator().next();
120+
121+
Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(signingCertificate)));
122+
Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(readSigningCertificate)));
123+
}
124+
125+
@Test
126+
void testSignedMessageDetachedBase64() throws Exception {
127+
CMSSignedData cmsSignedData = new CMSSignedData(Base64.getDecoder().decode(builder.buildAsString(true)));
128+
129+
Assertions.assertNull(cmsSignedData.getSignedContent());
130+
131+
Collection<X509CertificateHolder> certificateHolderCollection = cmsSignedData.getCertificates().getMatches(null);
132+
Assertions.assertEquals(1, certificateHolderCollection.size());
133+
X509CertificateHolder readSigningCertificate = certificateHolderCollection.iterator().next();
134+
Assertions.assertNotNull(readSigningCertificate);
135+
136+
cmsSignedData = new CMSSignedData(new CMSProcessableByteArray(payload), Base64.getDecoder().decode(builder.buildAsString(true)));
137+
138+
Assertions.assertEquals(1, cmsSignedData.getSignerInfos().size());
139+
SignerInformation signerInformation = cmsSignedData.getSignerInfos().iterator().next();
140+
141+
Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(signingCertificate)));
142+
Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(readSigningCertificate)));
143+
}
144+
}

0 commit comments

Comments
 (0)