1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package io.earcam.utilitarian.security;
20
21 import java.io.IOException;
22 import java.security.GeneralSecurityException;
23 import java.security.cert.Certificate;
24 import java.security.cert.X509Certificate;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.List;
29
30 import org.bouncycastle.cert.X509CertificateHolder;
31 import org.bouncycastle.cert.jcajce.JcaCertStore;
32 import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
33 import org.bouncycastle.cms.CMSException;
34 import org.bouncycastle.cms.CMSProcessableByteArray;
35 import org.bouncycastle.cms.CMSSignedData;
36 import org.bouncycastle.cms.CMSSignedDataGenerator;
37 import org.bouncycastle.cms.CMSSignedDataParser;
38 import org.bouncycastle.cms.CMSTypedData;
39 import org.bouncycastle.cms.SignerInfoGenerator;
40 import org.bouncycastle.cms.SignerInformation;
41 import org.bouncycastle.cms.SignerInformationStore;
42 import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
43 import org.bouncycastle.jce.provider.BouncyCastleProvider;
44 import org.bouncycastle.operator.ContentSigner;
45 import org.bouncycastle.operator.DigestCalculatorProvider;
46 import org.bouncycastle.operator.OperatorCreationException;
47 import org.bouncycastle.operator.OperatorException;
48 import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
49 import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
50 import org.bouncycastle.util.Store;
51
52 import io.earcam.unexceptional.Exceptional;
53 import io.earcam.unexceptional.UncheckedSecurityException;
54
55 public final class Signatures {
56
57 private static final BouncyCastleProvider PROVIDER = new BouncyCastleProvider();
58
59
60 private Signatures()
61 {}
62
63
64 public static byte[] sign(byte[] contents, OpenedKeyStore keyStore, String signatureAlgorithm)
65 {
66 try {
67 CMSSignedDataGenerator gen = createSignedDataGenerator(keyStore, signatureAlgorithm);
68
69 CMSTypedData cmsData = new CMSProcessableByteArray(contents);
70 CMSSignedData signedData = gen.generate(cmsData);
71 return signedData.getEncoded();
72 } catch(CMSException | OperatorException | IllegalArgumentException | IOException | GeneralSecurityException e) {
73 throw new UncheckedSecurityException(new GeneralSecurityException(e));
74 }
75 }
76
77
78 private static CMSSignedDataGenerator createSignedDataGenerator(OpenedKeyStore openedKeyStore, String signatureAlgorithm)
79 throws GeneralSecurityException, OperatorException, CMSException
80 {
81 List<Certificate> certChain = Arrays.asList(openedKeyStore.getCertificateChain());
82 JcaCertStore certStore = new JcaCertStore(certChain);
83 Certificate cert = openedKeyStore.getCertificate();
84 ContentSigner signer = new JcaContentSignerBuilder(signatureAlgorithm).setProvider(PROVIDER).build(openedKeyStore.privateKey());
85 CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
86 DigestCalculatorProvider dcp = new JcaDigestCalculatorProviderBuilder().setProvider(PROVIDER).build();
87 SignerInfoGenerator sig = new JcaSignerInfoGeneratorBuilder(dcp).build(signer, (X509Certificate) cert);
88 generator.addSignerInfoGenerator(sig);
89 generator.addCertificates(certStore);
90 return generator;
91 }
92
93
94 public static List<X509Certificate> certificatesFromSignature(byte[] encapSigData)
95 {
96 try {
97 CMSSignedDataParser parser = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(PROVIDER).build(), encapSigData);
98
99 @SuppressWarnings("unchecked")
100 Store<X509CertificateHolder> certStore = parser.getCertificates();
101 SignerInformationStore signers = parser.getSignerInfos();
102
103 List<X509Certificate> certificates = new ArrayList<>();
104
105 JcaX509CertificateConverter converter = new JcaX509CertificateConverter().setProvider(PROVIDER);
106
107 for(SignerInformation signer : signers.getSigners()) {
108 @SuppressWarnings("unchecked")
109 Collection<X509CertificateHolder> holders = certStore.getMatches(signer.getSID());
110
111 for(X509CertificateHolder holder : holders) {
112 X509Certificate certificate = Exceptional.apply(converter::getCertificate, holder);
113 certificates.add(certificate);
114 }
115 }
116 return certificates;
117 } catch(CMSException | OperatorCreationException e) {
118 throw new UncheckedSecurityException(new GeneralSecurityException(e));
119 }
120 }
121
122 }