Skip to content

Commit f5f41d3

Browse files
committed
refactoring around encrypted certificate transport.
1 parent 5f58375 commit f5f41d3

File tree

11 files changed

+245
-39
lines changed

11 files changed

+245
-39
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*/*.iml
1111

1212
bin/
13+
build/
1314
*/build/
1415
out/
1516
*/out/
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package org.bouncycastle.cert.cmp;
2+
3+
import java.io.IOException;
4+
import java.io.OutputStream;
5+
6+
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
7+
import org.bouncycastle.asn1.cmp.CMPCertificate;
8+
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
9+
import org.bouncycastle.cert.X509CertificateHolder;
10+
import org.bouncycastle.cms.CMSException;
11+
import org.bouncycastle.cms.CMSTypedData;
12+
13+
/**
14+
* Carrier class for a CMPCertificate over CMS.
15+
*/
16+
public class CMSProcessableCMPCertificate
17+
implements CMSTypedData
18+
{
19+
private final CMPCertificate cmpCert;
20+
21+
public CMSProcessableCMPCertificate(X509CertificateHolder certificateHolder)
22+
{
23+
this(new CMPCertificate(certificateHolder.toASN1Structure()));
24+
}
25+
26+
public CMSProcessableCMPCertificate(CMPCertificate cmpCertificate)
27+
{
28+
this.cmpCert = cmpCertificate;
29+
}
30+
31+
@Override
32+
public void write(OutputStream out)
33+
throws IOException, CMSException
34+
{
35+
out.write(cmpCert.getEncoded());
36+
}
37+
38+
@Override
39+
public Object getContent()
40+
{
41+
return cmpCert;
42+
}
43+
44+
@Override
45+
public ASN1ObjectIdentifier getContentType()
46+
{
47+
return PKCSObjectIdentifiers.data;
48+
}
49+
}

pkix/src/main/java/org/bouncycastle/cert/cmp/CertificateConfirmationContent.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
77
import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder;
88

9+
/**
10+
* Carrier class for a {@link CertConfirmContent} message.
11+
*/
912
public class CertificateConfirmationContent
1013
{
1114
private DigestAlgorithmIdentifierFinder digestAlgFinder;

pkix/src/main/java/org/bouncycastle/cert/cmp/CertificateConfirmationContentBuilder.java

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import java.util.List;
66

77
import org.bouncycastle.asn1.ASN1EncodableVector;
8+
import org.bouncycastle.asn1.ASN1Integer;
89
import org.bouncycastle.asn1.DERSequence;
10+
import org.bouncycastle.asn1.cmp.CMPCertificate;
911
import org.bouncycastle.asn1.cmp.CertConfirmContent;
1012
import org.bouncycastle.asn1.cmp.CertStatus;
1113
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
@@ -16,11 +18,15 @@
1618
import org.bouncycastle.operator.DigestCalculatorProvider;
1719
import org.bouncycastle.operator.OperatorCreationException;
1820

21+
/**
22+
* Builder class for a {@link CertConfirmContent} message.
23+
*/
1924
public class CertificateConfirmationContentBuilder
2025
{
2126
private DigestAlgorithmIdentifierFinder digestAlgFinder;
22-
private List acceptedCerts = new ArrayList();
23-
private List acceptedReqIds = new ArrayList();
27+
private List<CMPCertificate> acceptedCerts = new ArrayList<CMPCertificate>();
28+
private List<AlgorithmIdentifier> acceptedSignatureAlgorithms = new ArrayList<AlgorithmIdentifier>();
29+
private List<ASN1Integer> acceptedReqIds = new ArrayList<ASN1Integer>();
2430

2531
public CertificateConfirmationContentBuilder()
2632
{
@@ -34,7 +40,18 @@ public CertificateConfirmationContentBuilder(DigestAlgorithmIdentifierFinder dig
3440

3541
public CertificateConfirmationContentBuilder addAcceptedCertificate(X509CertificateHolder certHolder, BigInteger certReqID)
3642
{
37-
acceptedCerts.add(certHolder);
43+
return addAcceptedCertificate(certHolder, new ASN1Integer(certReqID));
44+
}
45+
46+
public CertificateConfirmationContentBuilder addAcceptedCertificate(X509CertificateHolder certHolder, ASN1Integer certReqID)
47+
{
48+
return addAcceptedCertificate(new CMPCertificate(certHolder.toASN1Structure()), certHolder.getSignatureAlgorithm(), certReqID);
49+
}
50+
51+
public CertificateConfirmationContentBuilder addAcceptedCertificate(CMPCertificate cmpCertificate, AlgorithmIdentifier sigAlg, ASN1Integer certReqID)
52+
{
53+
acceptedCerts.add(cmpCertificate);
54+
acceptedSignatureAlgorithms.add(sigAlg);
3855
acceptedReqIds.add(certReqID);
3956

4057
return this;
@@ -47,10 +64,10 @@ public CertificateConfirmationContent build(DigestCalculatorProvider digesterPro
4764

4865
for (int i = 0; i != acceptedCerts.size(); i++)
4966
{
50-
X509CertificateHolder certHolder = (X509CertificateHolder)acceptedCerts.get(i);
51-
BigInteger reqID = (BigInteger)acceptedReqIds.get(i);
67+
CMPCertificate certHolder = (CMPCertificate)acceptedCerts.get(i);
68+
ASN1Integer reqID = (ASN1Integer)acceptedReqIds.get(i);
5269

53-
AlgorithmIdentifier digAlg = digestAlgFinder.find(certHolder.toASN1Structure().getSignatureAlgorithm());
70+
AlgorithmIdentifier digAlg = digestAlgFinder.find((AlgorithmIdentifier)acceptedSignatureAlgorithms.get(i));
5471
if (digAlg == null)
5572
{
5673
throw new CMPException("cannot find algorithm for digest from signature");
@@ -67,7 +84,7 @@ public CertificateConfirmationContent build(DigestCalculatorProvider digesterPro
6784
throw new CMPException("unable to create digest: " + e.getMessage(), e);
6885
}
6986

70-
CMPUtil.derEncodeToStream(certHolder.toASN1Structure(), digester.getOutputStream());
87+
CMPUtil.derEncodeToStream(certHolder, digester.getOutputStream());
7188

7289
v.add(new CertStatus(digester.getDigest(), reqID));
7390
}

pkix/src/main/java/org/bouncycastle/cert/cmp/CertificateStatus.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
import java.math.BigInteger;
44

5+
import org.bouncycastle.asn1.cmp.CMPCertificate;
56
import org.bouncycastle.asn1.cmp.CertStatus;
67
import org.bouncycastle.asn1.cmp.PKIStatusInfo;
78
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
89
import org.bouncycastle.cert.X509CertificateHolder;
10+
import org.bouncycastle.jcajce.BCFKSLoadStoreParameter;
911
import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder;
1012
import org.bouncycastle.operator.DigestCalculator;
1113
import org.bouncycastle.operator.DigestCalculatorProvider;
@@ -36,7 +38,13 @@ public BigInteger getCertRequestID()
3638
public boolean isVerified(X509CertificateHolder certHolder, DigestCalculatorProvider digesterProvider)
3739
throws CMPException
3840
{
39-
AlgorithmIdentifier digAlg = digestAlgFinder.find(certHolder.toASN1Structure().getSignatureAlgorithm());
41+
return isVerified(new CMPCertificate(certHolder.toASN1Structure()), certHolder.getSignatureAlgorithm(), digesterProvider);
42+
}
43+
44+
public boolean isVerified(CMPCertificate cmpCert, AlgorithmIdentifier signatureAlgorithm, DigestCalculatorProvider digesterProvider)
45+
throws CMPException
46+
{
47+
AlgorithmIdentifier digAlg = digestAlgFinder.find(signatureAlgorithm);
4048
if (digAlg == null)
4149
{
4250
throw new CMPException("cannot find algorithm for digest from signature");
@@ -53,7 +61,7 @@ public boolean isVerified(X509CertificateHolder certHolder, DigestCalculatorProv
5361
throw new CMPException("unable to create digester: " + e.getMessage(), e);
5462
}
5563

56-
CMPUtil.derEncodeToStream(certHolder.toASN1Structure(), digester.getOutputStream());
64+
CMPUtil.derEncodeToStream(cmpCert, digester.getOutputStream());
5765

5866
return Arrays.areEqual(certStatus.getCertHash().getOctets(), digester.getDigest());
5967
}

pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateRequestMessageBuilder.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
import org.bouncycastle.cert.CertIOException;
3333
import org.bouncycastle.operator.ContentSigner;
3434

35+
/**
36+
* Builder for high-level objects built on {@link org.bouncycastle.asn1.crmf.CertReqMsg}.
37+
*/
3538
public class CertificateRequestMessageBuilder
3639
{
3740
private final BigInteger certReqId;

pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateResponse.java

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
package org.bouncycastle.cert.crmf;
22

3+
import java.util.Collection;
4+
import java.util.Iterator;
5+
6+
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
37
import org.bouncycastle.asn1.cmp.CMPCertificate;
48
import org.bouncycastle.asn1.cmp.CertResponse;
59
import org.bouncycastle.asn1.cmp.CertifiedKeyPair;
610
import org.bouncycastle.asn1.cms.ContentInfo;
711
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
812
import org.bouncycastle.cms.CMSEnvelopedData;
913
import org.bouncycastle.cms.CMSException;
14+
import org.bouncycastle.cms.Recipient;
15+
import org.bouncycastle.cms.RecipientInformation;
16+
import org.bouncycastle.cms.RecipientInformationStore;
17+
import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
1018

19+
/**
20+
* High level wrapper for the CertResponse CRMF structure.
21+
*/
1122
public class CertificateResponse
1223
{
1324
private final CertResponse certResponse;
@@ -18,26 +29,85 @@ public CertificateResponse(CertResponse certResponse)
1829
this.certResponse = certResponse;
1930
}
2031

32+
/**
33+
* Return true if the response contains an encrypted certificate.
34+
*
35+
* @return true if certificate in response encrypted, false otherwise.
36+
*/
2137
public boolean hasEncryptecCertificate()
2238
{
2339
return certResponse.getCertifiedKeyPair().getCertOrEncCert().hasEncryptedCertificate();
2440
}
2541

42+
/**
43+
* Return a CMSEnvelopedData representing the encrypted certificate contained in the response.
44+
*
45+
* @return a CMEEnvelopedData if an encrypted certificate is present.
46+
* @throws IllegalStateException if no encrypted certificate is present, or there is an issue with the enveloped data.
47+
*/
2648
public CMSEnvelopedData getEncryptedCertificate()
2749
throws CMSException
2850
{
51+
if (!hasEncryptecCertificate())
52+
{
53+
throw new IllegalStateException("encrypted certificate asked for, none found");
54+
}
55+
2956
CertifiedKeyPair receivedKeyPair = certResponse.getCertifiedKeyPair();
3057

31-
return new CMSEnvelopedData(
58+
CMSEnvelopedData envelopedData = new CMSEnvelopedData(
3259
new ContentInfo(PKCSObjectIdentifiers.envelopedData, receivedKeyPair.getCertOrEncCert().getEncryptedCert().getValue()));
60+
61+
if (envelopedData.getRecipientInfos().size() != 1)
62+
{
63+
throw new IllegalStateException("data encrypted for more than one recipient");
64+
}
65+
66+
return envelopedData;
3367
}
3468

69+
/**
70+
* Return the CMPCertificate representing the plaintext certificate in the response.
71+
*
72+
* @return a CMPCertificate if a plaintext certificate is present.
73+
* @throws IllegalStateException if no plaintext certificate is present.
74+
*/
75+
public CMPCertificate getCertificate(Recipient recipient)
76+
throws CMSException
77+
{
78+
CMSEnvelopedData encryptedCert = getEncryptedCertificate();
79+
80+
RecipientInformationStore recipients = encryptedCert.getRecipientInfos();
81+
82+
Collection c = recipients.getRecipients();
83+
84+
RecipientInformation recInfo = (RecipientInformation)c.iterator().next();
85+
86+
return CMPCertificate.getInstance(recInfo.getContent(recipient));
87+
}
88+
89+
/**
90+
* Return the CMPCertificate representing the plaintext certificate in the response.
91+
*
92+
* @return a CMPCertificate if a plaintext certificate is present.
93+
* @throws IllegalStateException if no plaintext certificate is present.
94+
*/
3595
public CMPCertificate getCertificate()
3696
throws CMSException
3797
{
98+
if (hasEncryptecCertificate())
99+
{
100+
throw new IllegalStateException("plaintext certificate asked for, none found");
101+
}
102+
38103
return certResponse.getCertifiedKeyPair().getCertOrEncCert().getCertificate();
39104
}
40105

106+
/**
107+
* Return this object's underlying ASN.1 structure.
108+
*
109+
* @return a CertResponse
110+
*/
41111
public CertResponse toASN1Structure()
42112
{
43113
return certResponse;

0 commit comments

Comments
 (0)