Skip to content

Commit d619a8c

Browse files
committed
added Kyber/Dilithium CRMF/CMP test, simplified use of CMP API for encrypted certificate processing, minor enhancements
1 parent a9dcbfc commit d619a8c

16 files changed

+808
-4
lines changed

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import org.bouncycastle.asn1.cmp.CertConfirmContent;
44
import org.bouncycastle.asn1.cmp.CertStatus;
5+
import org.bouncycastle.asn1.cmp.PKIBody;
6+
import org.bouncycastle.asn1.crmf.CertReqMessages;
7+
import org.bouncycastle.cert.crmf.CertificateReqMessages;
58
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
69
import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder;
710

@@ -21,6 +24,32 @@ public CertificateConfirmationContent(CertConfirmContent content, DigestAlgorith
2124
this.content = content;
2225
}
2326

27+
public static CertificateConfirmationContent fromPKIBody(PKIBody pkiBody)
28+
{
29+
return fromPKIBody(pkiBody, new DefaultDigestAlgorithmIdentifierFinder());
30+
}
31+
32+
public static CertificateConfirmationContent fromPKIBody(PKIBody pkiBody, DigestAlgorithmIdentifierFinder digestAlgFinder)
33+
{
34+
if (!isCertificateConfirmationContent(pkiBody.getType()))
35+
{
36+
throw new IllegalArgumentException("content of PKIBody wrong type: " + pkiBody.getType());
37+
}
38+
39+
return new CertificateConfirmationContent(CertConfirmContent.getInstance(pkiBody.getContent()), digestAlgFinder);
40+
}
41+
42+
public static boolean isCertificateConfirmationContent(int bodyType)
43+
{
44+
switch (bodyType)
45+
{
46+
case PKIBody.TYPE_CERT_CONFIRM:
47+
return true;
48+
default:
49+
return false;
50+
}
51+
}
52+
2453
public CertConfirmContent toASN1Structure()
2554
{
2655
return content;

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

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,24 @@
55

66
import org.bouncycastle.asn1.ASN1EncodableVector;
77
import org.bouncycastle.asn1.ASN1Encoding;
8+
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
89
import org.bouncycastle.asn1.DERSequence;
910
import org.bouncycastle.asn1.cmp.CMPCertificate;
1011
import org.bouncycastle.asn1.cmp.CMPObjectIdentifiers;
1112
import org.bouncycastle.asn1.cmp.PKIBody;
1213
import org.bouncycastle.asn1.cmp.PKIHeader;
1314
import org.bouncycastle.asn1.cmp.PKIMessage;
15+
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
16+
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
17+
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
18+
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
1419
import org.bouncycastle.cert.X509CertificateHolder;
1520
import org.bouncycastle.operator.ContentVerifier;
1621
import org.bouncycastle.operator.ContentVerifierProvider;
1722
import org.bouncycastle.operator.MacCalculator;
1823
import org.bouncycastle.operator.PBEMacCalculatorProvider;
1924
import org.bouncycastle.util.Arrays;
25+
import sun.security.x509.AlgorithmId;
2026

2127
/**
2228
* Wrapper for a PKIMessage with protection attached to it.
@@ -81,14 +87,25 @@ public PKIMessage toASN1Structure()
8187
}
8288

8389
/**
84-
* Determine whether the message is protected by a password based MAC. Use verify(PKMACBuilder, char[])
90+
* Determine whether the message is protected by a the CMP password based MAC. Use verify(PBEMacCalculatorProvider, char[])
8591
* to verify the message if this method returns true.
8692
*
8793
* @return true if protection MAC PBE based, false otherwise.
8894
*/
8995
public boolean hasPasswordBasedMacProtection()
9096
{
91-
return pkiMessage.getHeader().getProtectionAlg().getAlgorithm().equals(CMPObjectIdentifiers.passwordBasedMac);
97+
ASN1ObjectIdentifier procAlg = pkiMessage.getHeader().getProtectionAlg().getAlgorithm();
98+
return procAlg.equals(CMPObjectIdentifiers.passwordBasedMac);
99+
}
100+
101+
/**
102+
* Return the message's protection algorithm.
103+
*
104+
* @return the algorithm ID for the message's protection algorithm.
105+
*/
106+
public AlgorithmIdentifier getProtectionAlgorithm()
107+
{
108+
return pkiMessage.getHeader().getProtectionAlg();
92109
}
93110

94111
/**

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
2222
import org.bouncycastle.asn1.x509.GeneralName;
2323
import org.bouncycastle.cert.X509CertificateHolder;
24+
import org.bouncycastle.cert.crmf.CertificateRepMessage;
25+
import org.bouncycastle.cert.crmf.CertificateReqMessages;
26+
import org.bouncycastle.cert.crmf.CertificateResponse;
2427
import org.bouncycastle.operator.ContentSigner;
2528
import org.bouncycastle.operator.MacCalculator;
2629

@@ -174,6 +177,42 @@ public ProtectedPKIMessageBuilder setBody(PKIBody body)
174177
return this;
175178
}
176179

180+
public ProtectedPKIMessageBuilder setBody(int bodyType, CertificateReqMessages certificateReqMessages)
181+
{
182+
if (!CertificateReqMessages.isCertificateRequestMessages(bodyType))
183+
{
184+
throw new IllegalArgumentException("body type " + bodyType + " does not match CMP type CertReqMessages");
185+
}
186+
187+
this.body = new PKIBody(bodyType, certificateReqMessages.toASN1Structure());
188+
189+
return this;
190+
}
191+
192+
public ProtectedPKIMessageBuilder setBody(int bodyType, CertificateRepMessage certificateRepMessage)
193+
{
194+
if (!CertificateRepMessage.isCertificateRepMessage(bodyType))
195+
{
196+
throw new IllegalArgumentException("body type " + bodyType + " does not match CMP type CertReqMessages");
197+
}
198+
199+
this.body = new PKIBody(bodyType, certificateRepMessage.toASN1Structure());
200+
201+
return this;
202+
}
203+
204+
public ProtectedPKIMessageBuilder setBody(int bodyType, CertificateConfirmationContent certificateConfirmationContent)
205+
{
206+
if (!CertificateConfirmationContent.isCertificateConfirmationContent(bodyType))
207+
{
208+
throw new IllegalArgumentException("body type " + bodyType + " does not match CMP type CertConfirmContent");
209+
}
210+
211+
this.body = new PKIBody(bodyType, certificateConfirmationContent.toASN1Structure());
212+
213+
return this;
214+
}
215+
177216
/**
178217
* Add an "extra certificate" to the message.
179218
*
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package org.bouncycastle.cert.crmf;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import org.bouncycastle.asn1.ASN1Encodable;
7+
import org.bouncycastle.asn1.cmp.CMPCertificate;
8+
import org.bouncycastle.asn1.cmp.CertRepMessage;
9+
import org.bouncycastle.asn1.cmp.CertResponse;
10+
import org.bouncycastle.asn1.cmp.PKIBody;
11+
import org.bouncycastle.cert.X509CertificateHolder;
12+
13+
public class CertificateRepMessage
14+
{
15+
private final CertResponse[] resps;
16+
private final CMPCertificate[] caCerts;
17+
18+
public CertificateRepMessage(CertRepMessage repMessage)
19+
{
20+
resps = repMessage.getResponse();
21+
caCerts = repMessage.getCaPubs();
22+
}
23+
24+
public static CertificateRepMessage fromPKIBody(PKIBody pkiBody)
25+
{
26+
if (!isCertificateRepMessage(pkiBody.getType()))
27+
{
28+
throw new IllegalArgumentException("content of PKIBody wrong type: " + pkiBody.getType());
29+
}
30+
31+
return new CertificateRepMessage(CertRepMessage.getInstance(pkiBody.getContent()));
32+
}
33+
34+
public static boolean isCertificateRepMessage(int bodyType)
35+
{
36+
switch (bodyType)
37+
{
38+
case PKIBody.TYPE_INIT_REP:
39+
case PKIBody.TYPE_CERT_REP:
40+
case PKIBody.TYPE_KEY_UPDATE_REP:
41+
case PKIBody.TYPE_CROSS_CERT_REP:
42+
return true;
43+
default:
44+
return false;
45+
}
46+
}
47+
48+
public CertificateResponse[] getResponses()
49+
{
50+
CertificateResponse[] responses = new CertificateResponse[resps.length];
51+
for (int i = 0; i != responses.length; i++)
52+
{
53+
responses[i] = new CertificateResponse(resps[i]);
54+
}
55+
56+
return responses;
57+
}
58+
59+
public X509CertificateHolder[] getX509Certificates()
60+
{
61+
List<X509CertificateHolder> certs = new ArrayList<X509CertificateHolder>();
62+
63+
for (int i = 0; i != caCerts.length; i++)
64+
{
65+
if (caCerts[i].isX509v3PKCert())
66+
{
67+
certs.add(new X509CertificateHolder(caCerts[i].getX509v3PKCert()));
68+
}
69+
}
70+
71+
return certs.toArray(new X509CertificateHolder[0]);
72+
}
73+
74+
/**
75+
* Return true if the message only contains X.509 public key certificates.
76+
*
77+
* @return true if only X.509 PK, false otherwise.
78+
*/
79+
public boolean isOnlyX509PKCertificates()
80+
{
81+
boolean isOnlyX509 = true;
82+
83+
for (int i = 0; i != caCerts.length; i++)
84+
{
85+
isOnlyX509 &= caCerts[i].isX509v3PKCert();
86+
}
87+
88+
return isOnlyX509;
89+
}
90+
91+
/**
92+
* Return the actual CMP certificates - useful if the array also contains non-X509 PK certificates.
93+
*
94+
* @return CMPCertificate array
95+
*/
96+
public CMPCertificate[] getCMPCertificates()
97+
{
98+
CMPCertificate[] certs = new CMPCertificate[caCerts.length];
99+
100+
System.arraycopy(caCerts, 0, certs, 0, certs.length);
101+
102+
return certs;
103+
}
104+
105+
public ASN1Encodable toASN1Structure()
106+
{
107+
return new CertRepMessage(caCerts, resps);
108+
}
109+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package org.bouncycastle.cert.crmf;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import org.bouncycastle.asn1.cmp.CMPCertificate;
7+
import org.bouncycastle.asn1.cmp.CertRepMessage;
8+
import org.bouncycastle.asn1.cmp.CertResponse;
9+
import org.bouncycastle.cert.X509CertificateHolder;
10+
11+
/**
12+
* Builder for a CertRepMessage.
13+
*/
14+
public class CertificateRepMessageBuilder
15+
{
16+
private final List<CertResponse> responses = new ArrayList<CertResponse>();
17+
private final CMPCertificate[] caCerts;
18+
19+
/**
20+
* Base constructor which can accept 0 or more certificates representing the CA plus its chain.
21+
*
22+
* @param caCerts the CA public key and it's support certificates (optional)
23+
*/
24+
public CertificateRepMessageBuilder(X509CertificateHolder... caCerts)
25+
{
26+
this.caCerts = new CMPCertificate[caCerts.length];
27+
28+
for (int i = 0; i != caCerts.length; i++)
29+
{
30+
this.caCerts[i] = new CMPCertificate(caCerts[i].toASN1Structure());
31+
}
32+
}
33+
public CertificateRepMessageBuilder addCertificateResponse(CertificateResponse response)
34+
{
35+
responses.add(response.toASN1Structure());
36+
37+
return this;
38+
}
39+
40+
public CertificateRepMessage build()
41+
{
42+
CertRepMessage repMessage;
43+
if (caCerts.length != 0)
44+
{
45+
repMessage = new CertRepMessage(caCerts, (CertResponse[])responses.toArray(new CertResponse[0]));
46+
}
47+
else
48+
{
49+
// older versions of CertRepMessage need null if no caCerts.
50+
repMessage = new CertRepMessage(null, (CertResponse[])responses.toArray(new CertResponse[0]));
51+
}
52+
53+
responses.clear();
54+
55+
return new CertificateRepMessage(repMessage);
56+
}
57+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package org.bouncycastle.cert.crmf;
2+
3+
import org.bouncycastle.asn1.cmp.PKIBody;
4+
import org.bouncycastle.asn1.crmf.CertReqMessages;
5+
import org.bouncycastle.asn1.crmf.CertReqMsg;
6+
7+
public class CertificateReqMessages
8+
{
9+
private final CertReqMsg[] reqs;
10+
11+
public CertificateReqMessages(CertReqMessages certReqMessages)
12+
{
13+
reqs = certReqMessages.toCertReqMsgArray();
14+
}
15+
16+
public static CertificateReqMessages fromPKIBody(PKIBody pkiBody)
17+
{
18+
if (!isCertificateRequestMessages(pkiBody.getType()))
19+
{
20+
throw new IllegalArgumentException("content of PKIBody wrong type: " + pkiBody.getType());
21+
}
22+
23+
return new CertificateReqMessages(CertReqMessages.getInstance(pkiBody.getContent()));
24+
}
25+
26+
public static boolean isCertificateRequestMessages(int bodyType)
27+
{
28+
switch (bodyType)
29+
{
30+
case PKIBody.TYPE_INIT_REQ:
31+
case PKIBody.TYPE_CERT_REQ:
32+
case PKIBody.TYPE_KEY_UPDATE_REQ:
33+
case PKIBody.TYPE_KEY_RECOVERY_REQ:
34+
case PKIBody.TYPE_CROSS_CERT_REQ:
35+
return true;
36+
default:
37+
return false;
38+
}
39+
}
40+
41+
public CertificateRequestMessage[] getRequests()
42+
{
43+
CertificateRequestMessage[] requestMessages = new CertificateRequestMessage[reqs.length];
44+
for (int i = 0; i != requestMessages.length; i++)
45+
{
46+
requestMessages[i] = new CertificateRequestMessage(reqs[i]);
47+
}
48+
49+
return requestMessages;
50+
}
51+
52+
public CertReqMessages toASN1Structure()
53+
{
54+
return new CertReqMessages(reqs);
55+
}
56+
}

0 commit comments

Comments
 (0)