Skip to content

Commit

Permalink
Add Parser and Builder for SignedByteArrayMessages
Browse files Browse the repository at this point in the history
  • Loading branch information
f11h committed Mar 15, 2022
1 parent 299e51f commit c59d1b5
Show file tree
Hide file tree
Showing 4 changed files with 547 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*-
* ---license-start
* EU Digital Green Certificate Gateway Service / dgc-lib
* ---
* Copyright (C) 2021 T-Systems International GmbH and all other contributors
* ---
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ---license-end
*/

package eu.europa.ec.dgc.signing;

import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
* Utility to build a CMS signed message containing a Byte Array (e.g. a File).
*/
@Slf4j
@NoArgsConstructor
public class SignedByteArrayMessageBuilder extends SignedMessageBuilder<byte[], SignedByteArrayMessageBuilder> {

@Override
byte[] convertToBytes(byte[] payload) {
return payload;
}

@Override
SignedByteArrayMessageBuilder getThis() {
return this;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*-
* ---license-start
* EU Digital Green Certificate Gateway Service / dgc-lib
* ---
* Copyright (C) 2021 T-Systems International GmbH and all other contributors
* ---
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ---license-end
*/

package eu.europa.ec.dgc.signing;

import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;

/**
* Utility to parse a CMS signed message containing a Byte Array (e.g. a File).
*/
@Slf4j
public class SignedByteArrayMessageParser extends SignedMessageParser<byte[]> {

@Override
byte[] convertFromBytes(byte[] bytes) {
return bytes;
}

/**
* Create a new instance of {@link SignedByteArrayMessageParser} and starts the parsing process.
* The result of parsing process will be immediately available.
*
* @param cmsMessage base64 encoded CMS message bytes.
*/
public SignedByteArrayMessageParser(@NonNull byte[] cmsMessage) {
super(cmsMessage);
}

/**
* Create a new instance of {@link SignedByteArrayMessageParser} and starts the parsing process.
* The result of parsing process will be immediately available.
*
* @param cmsSignature base64 encoded detached CMS signature bytes.
* @param cmsPayload base64 encoded CMS message payload.
*/
public SignedByteArrayMessageParser(@NonNull byte[] cmsSignature, @NonNull byte[] cmsPayload) {
super(cmsSignature, cmsPayload);
}

/**
* Create a new instance of {@link SignedByteArrayMessageParser} and starts the parsing process.
* The result of parsing process will be immediately available.
*
* @param cmsMessage base64 encoded CMS message string.
*/
public SignedByteArrayMessageParser(@NonNull String cmsMessage) {
super(cmsMessage);
}

/**
* Create a new instance of {@link SignedByteArrayMessageParser} and starts the parsing process.
* The result of parsing process will be immediately available.
*
* @param cmsSignature base64 encoded detached CMS signature string.
* @param cmsPayload base64 encoded CMS message payload string.
*/
public SignedByteArrayMessageParser(@NonNull String cmsSignature, @NonNull String cmsPayload) {
super(cmsSignature, cmsPayload);
}

/**
* Create a new instance of {@link SignedByteArrayMessageParser} and starts the parsing process.
* The result of parsing process will be immediately available.
*
* @param cmsSignature base64 encoded detached CMS signature bytes.
* @param cmsPayload base64 encoded CMS message payload string.
*/
public SignedByteArrayMessageParser(@NonNull byte[] cmsSignature, @NonNull String cmsPayload) {
super(cmsSignature, cmsPayload);
}

/**
* Create a new instance of {@link SignedByteArrayMessageParser} and starts the parsing process.
* The result of parsing process will be immediately available.
*
* @param cmsSignature base64 encoded detached CMS signature string.
* @param cmsPayload base64 encoded CMS message payload bytes.
*/
public SignedByteArrayMessageParser(@NonNull String cmsSignature, @NonNull byte[] cmsPayload) {
super(cmsSignature, cmsPayload);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*-
* ---license-start
* EU Digital Green Certificate Gateway Service / dgc-lib
* ---
* Copyright (C) 2021 T-Systems International GmbH and all other contributors
* ---
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ---license-end
*/

package eu.europa.ec.dgc.signing;

import eu.europa.ec.dgc.testdata.CertificateTestUtils;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.Collection;
import java.util.Random;
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class SignedByteArrayMessageBuilderTest {

KeyPair signingKeyPair;
X509Certificate signingCertificate;
byte[] payload;

SignedByteArrayMessageBuilder builder;

@BeforeEach
void setupTestData() throws Exception {
payload = new byte[100];
new Random().nextBytes(payload);

signingKeyPair = KeyPairGenerator.getInstance("ec").generateKeyPair();
signingCertificate = CertificateTestUtils.generateCertificate(signingKeyPair, "DE", "SigningCertificate");

builder = new SignedByteArrayMessageBuilder()
.withPayload(payload)
.withSigningCertificate(new X509CertificateHolder(signingCertificate.getEncoded()), signingKeyPair.getPrivate());
}

@Test
void testUnreadyBuilder() {
builder = new SignedByteArrayMessageBuilder();
Assertions.assertThrows(RuntimeException.class, builder::buildAsString);
}

@Test
void testSignedMessage() throws Exception {
CMSSignedData cmsSignedData = new CMSSignedData(builder.build());

Assertions.assertEquals(CMSObjectIdentifiers.data, cmsSignedData.getSignedContent().getContentType());
Assertions.assertArrayEquals(payload, (byte[]) cmsSignedData.getSignedContent().getContent());

Collection<X509CertificateHolder> certificateHolderCollection = cmsSignedData.getCertificates().getMatches(null);
Assertions.assertEquals(1, certificateHolderCollection.size());
X509CertificateHolder readSigningCertificate = certificateHolderCollection.iterator().next();
Assertions.assertNotNull(readSigningCertificate);

Assertions.assertEquals(1, cmsSignedData.getSignerInfos().size());
SignerInformation signerInformation = cmsSignedData.getSignerInfos().iterator().next();

Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(signingCertificate)));
Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(readSigningCertificate)));
}

@Test
void testSignedMessageDetached() throws Exception {
CMSSignedData cmsSignedData = new CMSSignedData(builder.build(true));

Assertions.assertNull(cmsSignedData.getSignedContent());

Collection<X509CertificateHolder> certificateHolderCollection = cmsSignedData.getCertificates().getMatches(null);
Assertions.assertEquals(1, certificateHolderCollection.size());
X509CertificateHolder readSigningCertificate = certificateHolderCollection.iterator().next();
Assertions.assertNotNull(readSigningCertificate);

cmsSignedData = new CMSSignedData(new CMSProcessableByteArray(payload), builder.build(true));

Assertions.assertEquals(1, cmsSignedData.getSignerInfos().size());
SignerInformation signerInformation = cmsSignedData.getSignerInfos().iterator().next();

Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(signingCertificate)));
Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(readSigningCertificate)));
}

@Test
void testSignedMessageBase64() throws Exception {
CMSSignedData cmsSignedData = new CMSSignedData(Base64.getDecoder().decode(builder.buildAsString()));

Assertions.assertEquals(CMSObjectIdentifiers.data, cmsSignedData.getSignedContent().getContentType());
Assertions.assertArrayEquals(payload, (byte[]) cmsSignedData.getSignedContent().getContent());

Collection<X509CertificateHolder> certificateHolderCollection = cmsSignedData.getCertificates().getMatches(null);
Assertions.assertEquals(1, certificateHolderCollection.size());
X509CertificateHolder readSigningCertificate = certificateHolderCollection.iterator().next();
Assertions.assertNotNull(readSigningCertificate);

Assertions.assertEquals(1, cmsSignedData.getSignerInfos().size());
SignerInformation signerInformation = cmsSignedData.getSignerInfos().iterator().next();

Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(signingCertificate)));
Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(readSigningCertificate)));
}

@Test
void testSignedMessageDetachedBase64() throws Exception {
CMSSignedData cmsSignedData = new CMSSignedData(Base64.getDecoder().decode(builder.buildAsString(true)));

Assertions.assertNull(cmsSignedData.getSignedContent());

Collection<X509CertificateHolder> certificateHolderCollection = cmsSignedData.getCertificates().getMatches(null);
Assertions.assertEquals(1, certificateHolderCollection.size());
X509CertificateHolder readSigningCertificate = certificateHolderCollection.iterator().next();
Assertions.assertNotNull(readSigningCertificate);

cmsSignedData = new CMSSignedData(new CMSProcessableByteArray(payload), Base64.getDecoder().decode(builder.buildAsString(true)));

Assertions.assertEquals(1, cmsSignedData.getSignerInfos().size());
SignerInformation signerInformation = cmsSignedData.getSignerInfos().iterator().next();

Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(signingCertificate)));
Assertions.assertTrue(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(readSigningCertificate)));
}
}
Loading

0 comments on commit c59d1b5

Please sign in to comment.