Skip to content

Commit 092e85d

Browse files
committed
Refactor delta cert code
1 parent ae332c0 commit 092e85d

File tree

5 files changed

+293
-260
lines changed

5 files changed

+293
-260
lines changed

core/src/main/java/org/bouncycastle/asn1/x509/Certificate.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package org.bouncycastle.asn1.x509;
22

33
import org.bouncycastle.asn1.ASN1BitString;
4+
import org.bouncycastle.asn1.ASN1EncodableVector;
45
import org.bouncycastle.asn1.ASN1Integer;
56
import org.bouncycastle.asn1.ASN1Object;
67
import org.bouncycastle.asn1.ASN1Primitive;
78
import org.bouncycastle.asn1.ASN1Sequence;
89
import org.bouncycastle.asn1.ASN1TaggedObject;
10+
import org.bouncycastle.asn1.DERSequence;
911
import org.bouncycastle.asn1.x500.X500Name;
1012

1113
/**
@@ -69,6 +71,32 @@ private Certificate(
6971
}
7072
}
7173

74+
public Certificate(TBSCertificate tbsCertificate, AlgorithmIdentifier signatureAlgorithm, ASN1BitString signature)
75+
{
76+
if (tbsCertificate == null)
77+
{
78+
throw new NullPointerException("'tbsCertificate' cannot be null");
79+
}
80+
if (signatureAlgorithm == null)
81+
{
82+
throw new NullPointerException("'signatureAlgorithm' cannot be null");
83+
}
84+
if (signature == null)
85+
{
86+
throw new NullPointerException("'signature' cannot be null");
87+
}
88+
89+
this.tbsCert = tbsCertificate;
90+
this.sigAlgId = signatureAlgorithm;
91+
this.sig = signature;
92+
93+
ASN1EncodableVector v = new ASN1EncodableVector(3);
94+
v.add(tbsCertificate);
95+
v.add(signatureAlgorithm);
96+
v.add(signature);
97+
this.seq = new DERSequence(v);
98+
}
99+
72100
public TBSCertificate getTBSCertificate()
73101
{
74102
return tbsCert;
@@ -119,6 +147,21 @@ public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
119147
return tbsCert.getSubjectPublicKeyInfo();
120148
}
121149

150+
public ASN1BitString getIssuerUniqueID()
151+
{
152+
return tbsCert.getIssuerUniqueId();
153+
}
154+
155+
public ASN1BitString getSubjectUniqueID()
156+
{
157+
return tbsCert.getSubjectUniqueId();
158+
}
159+
160+
public Extensions getExtensions()
161+
{
162+
return tbsCert.getExtensions();
163+
}
164+
122165
public AlgorithmIdentifier getSignatureAlgorithm()
123166
{
124167
return sigAlgId;

core/src/main/java/org/bouncycastle/asn1/x509/DeltaCertificateDescriptor.java

Lines changed: 128 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -17,32 +17,28 @@
1717

1818
/**
1919
* <pre>
20-
* DeltaCertificateDescriptor ::= SEQUENCE {
21-
* serialNumber CertificateSerialNumber,
22-
* signature [0] IMPLICIT AlgorithmIdentifier
23-
* {SIGNATURE_ALGORITHM, {...}} OPTIONAL,
24-
* issuer [1] IMPLICIT Name OPTIONAL,
25-
* validity [2] IMPLICIT Validity OPTIONAL,
26-
* subject [3] IMPLICIT Name OPTIONAL,
27-
* subjectPublicKeyInfo SubjectPublicKeyInfo,
28-
* extensions [4] IMPLICIT Extensions{CertExtensions}
29-
* OPTIONAL,
30-
* signatureValue BIT STRING
31-
* }
32-
* </pre>
20+
* DeltaCertificateDescriptor ::= SEQUENCE {
21+
* serialNumber CertificateSerialNumber,
22+
* signature [0] EXPLICIT AlgorithmIdentifier {SIGNATURE_ALGORITHM, {...}} OPTIONAL,
23+
* issuer [1] EXPLICIT Name OPTIONAL,
24+
* validity [2] EXPLICIT Validity OPTIONAL,
25+
* subject [3] EXPLICIT Name OPTIONAL,
26+
* subjectPublicKeyInfo SubjectPublicKeyInfo,
27+
* extensions [4] EXPLICIT Extensions{CertExtensions} OPTIONAL,
28+
* signatureValue BIT STRING
29+
* }
30+
* </pre>
3331
*/
3432
public class DeltaCertificateDescriptor
3533
extends ASN1Object
3634
{
3735
private final ASN1Integer serialNumber;
38-
39-
private AlgorithmIdentifier signature;
40-
private X500Name issuer;
41-
private ASN1Sequence validity;
42-
private X500Name subject;
43-
private SubjectPublicKeyInfo subjectPublicKeyInfo;
44-
private Extensions extensions;
45-
36+
private final AlgorithmIdentifier signature;
37+
private final X500Name issuer;
38+
private final Validity validity;
39+
private final X500Name subject;
40+
private final SubjectPublicKeyInfo subjectPublicKeyInfo;
41+
private final Extensions extensions;
4642
private final ASN1BitString signatureValue;
4743

4844
public static DeltaCertificateDescriptor getInstance(
@@ -73,10 +69,15 @@ public static DeltaCertificateDescriptor fromExtensions(Extensions extensions)
7369

7470
private DeltaCertificateDescriptor(ASN1Sequence seq)
7571
{
76-
this.serialNumber = ASN1Integer.getInstance(seq.getObjectAt(0));
72+
ASN1Integer serialNumber = ASN1Integer.getInstance(seq.getObjectAt(0));
7773

7874
int idx = 1;
7975
ASN1Encodable next = seq.getObjectAt(idx++);
76+
77+
AlgorithmIdentifier signature = null;
78+
X500Name issuer = null;
79+
Validity validity = null;
80+
X500Name subject = null;
8081
while (next instanceof ASN1TaggedObject)
8182
{
8283
ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(next);
@@ -89,7 +90,7 @@ private DeltaCertificateDescriptor(ASN1Sequence seq)
8990
issuer = X500Name.getInstance(tagged, true); // issuer
9091
break;
9192
case 2:
92-
validity = ASN1Sequence.getInstance(tagged, true);
93+
validity = Validity.getInstance(tagged, true);
9394
break;
9495
case 3:
9596
subject = X500Name.getInstance(tagged, true); // subject
@@ -98,9 +99,11 @@ private DeltaCertificateDescriptor(ASN1Sequence seq)
9899
next = seq.getObjectAt(idx++);
99100
}
100101

101-
subjectPublicKeyInfo = subjectPublicKeyInfo.getInstance(next);
102+
SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(next);
102103

103104
next = seq.getObjectAt(idx);
105+
106+
Extensions extensions = null;
104107
while (next instanceof ASN1TaggedObject)
105108
{
106109
ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(next);
@@ -113,7 +116,43 @@ private DeltaCertificateDescriptor(ASN1Sequence seq)
113116
next = seq.getObjectAt(idx++);
114117
}
115118

116-
signatureValue = ASN1BitString.getInstance(next);
119+
ASN1BitString signatureValue = ASN1BitString.getInstance(next);
120+
121+
this.serialNumber = serialNumber;
122+
this.signature = signature;
123+
this.issuer = issuer;
124+
this.validity = validity;
125+
this.subject = subject;
126+
this.subjectPublicKeyInfo = subjectPublicKeyInfo;
127+
this.extensions = extensions;
128+
this.signatureValue = signatureValue;
129+
}
130+
131+
public DeltaCertificateDescriptor(ASN1Integer serialNumber, AlgorithmIdentifier signature, X500Name issuer,
132+
Validity validity, X500Name subject, SubjectPublicKeyInfo subjectPublicKeyInfo, Extensions extensions,
133+
ASN1BitString signatureValue)
134+
{
135+
if (serialNumber == null)
136+
{
137+
throw new NullPointerException("'serialNumber' cannot be null");
138+
}
139+
if (subjectPublicKeyInfo == null)
140+
{
141+
throw new NullPointerException("'subjectPublicKeyInfo' cannot be null");
142+
}
143+
if (signatureValue == null)
144+
{
145+
throw new NullPointerException("'signatureValue' cannot be null");
146+
}
147+
148+
this.serialNumber = serialNumber;
149+
this.signature = signature;
150+
this.issuer = issuer;
151+
this.validity = validity;
152+
this.subject = subject;
153+
this.subjectPublicKeyInfo = subjectPublicKeyInfo;
154+
this.extensions = extensions;
155+
this.signatureValue = signatureValue;
117156
}
118157

119158
public ASN1Integer getSerialNumber()
@@ -131,7 +170,13 @@ public X500Name getIssuer()
131170
return issuer;
132171
}
133172

173+
/** @deprecated Use getValidityObject instead. */
134174
public ASN1Sequence getValidity()
175+
{
176+
return (ASN1Sequence)validity.toASN1Primitive();
177+
}
178+
179+
public Validity getValidityObject()
135180
{
136181
return validity;
137182
}
@@ -156,96 +201,83 @@ public ASN1BitString getSignatureValue()
156201
return signatureValue;
157202
}
158203

204+
/** @deprecated Use DeltaCertificateTool#trimDeltaCertificateDescriptor instead. */
159205
public DeltaCertificateDescriptor trimTo(TBSCertificate baseTbsCertificate, Extensions tbsExtensions)
160206
{
161-
AlgorithmIdentifier signature = baseTbsCertificate.signature;
162-
X500Name issuer = baseTbsCertificate.issuer;
163-
ASN1Sequence validity = new DERSequence(new ASN1Encodable[]
207+
return trimDeltaCertificateDescriptor(this, baseTbsCertificate, tbsExtensions);
208+
}
209+
210+
// NB: This can replace DeltaCertificateTool#trimDeltaCertificateDescriptor once 'trimTo' is removed
211+
private static DeltaCertificateDescriptor trimDeltaCertificateDescriptor(DeltaCertificateDescriptor descriptor,
212+
TBSCertificate tbsCertificate, Extensions tbsExtensions)
213+
{
214+
ASN1Integer serialNumber = descriptor.getSerialNumber();
215+
216+
AlgorithmIdentifier signature = descriptor.getSignature();
217+
if (signature != null && signature.equals(tbsCertificate.getSignature()))
164218
{
165-
baseTbsCertificate.startDate, baseTbsCertificate.endDate
166-
});
167-
X500Name subject = baseTbsCertificate.subject;
168-
ASN1Sequence s = ASN1Sequence.getInstance(toASN1Primitive());
169-
ASN1EncodableVector v = new ASN1EncodableVector();
219+
signature = null;
220+
}
170221

171-
Enumeration en = s.getObjects();
172-
v.add((ASN1Encodable)en.nextElement());
222+
X500Name issuer = descriptor.getIssuer();
223+
if (issuer != null && issuer.equals(tbsCertificate.getIssuer()))
224+
{
225+
issuer = null;
226+
}
173227

174-
ASN1Encodable next = (ASN1Encodable)en.nextElement();
175-
while (next instanceof ASN1TaggedObject)
228+
Validity validity = descriptor.getValidityObject();
229+
if (validity != null && validity.equals(tbsCertificate.getValidity()))
176230
{
177-
ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(next);
178-
switch (tagged.getTagNo())
179-
{
180-
case 0:
181-
AlgorithmIdentifier sig = AlgorithmIdentifier.getInstance(tagged, true);
182-
if (!sig.equals(signature))
183-
{
184-
v.add(next);
185-
}
186-
break;
187-
case 1:
188-
X500Name iss = X500Name.getInstance(tagged, true); // issuer
189-
if (!iss.equals(issuer))
190-
{
191-
v.add(next);
192-
}
193-
break;
194-
case 2:
195-
ASN1Sequence val = ASN1Sequence.getInstance(tagged, true);
196-
if (!val.equals(validity))
197-
{
198-
v.add(next);
199-
}
200-
break;
201-
case 3:
202-
X500Name sub = X500Name.getInstance(tagged, true); // subject
203-
if (!sub.equals(subject))
204-
{
205-
v.add(next);
206-
}
207-
break;
208-
}
209-
next = (ASN1Encodable)en.nextElement();
231+
validity = null;
210232
}
211233

212-
v.add(next);
234+
X500Name subject = descriptor.getSubject();
235+
if (subject != null && subject.equals(tbsCertificate.getSubject()))
236+
{
237+
subject = null;
238+
}
213239

214-
next = (ASN1Encodable)en.nextElement();
215-
while (next instanceof ASN1TaggedObject)
240+
SubjectPublicKeyInfo subjectPublicKeyInfo = descriptor.getSubjectPublicKeyInfo();
241+
242+
Extensions extensions = descriptor.getExtensions();
243+
if (extensions != null)
216244
{
217-
ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(next);
218-
switch (tagged.getTagNo())
245+
/*
246+
* draft-bonnell-lamps-chameleon-certs-05 4.1:
247+
*
248+
* [The extensions] field MUST NOT contain any extension:
249+
* - which has the same criticality and DER-encoded value as encoded in the Base Certificate,
250+
* - whose type does not appear in the Base Certificate, or
251+
* - which is of the DCD extension type (recursive Delta Certificates are not permitted).
252+
*
253+
* [...] The ordering of extensions in [the extensions] field MUST be relative to the ordering of the
254+
* extensions as they are encoded in the Delta [recte Base] Certificate.
255+
*/
256+
257+
ExtensionsGenerator generator = new ExtensionsGenerator();
258+
259+
for (Enumeration extEn = tbsExtensions.oids(); extEn.hasMoreElements();)
219260
{
220-
case 4:
221-
Extensions deltaExts = Extensions.getInstance(tagged, true);
222-
ExtensionsGenerator deltaExtGen = new ExtensionsGenerator();
223-
for (Enumeration extEn = deltaExts.oids(); extEn.hasMoreElements(); )
261+
ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)extEn.nextElement();
262+
if (Extension.deltaCertificateDescriptor.equals(oid))
224263
{
225-
Extension deltaExt = deltaExts.getExtension((ASN1ObjectIdentifier)extEn.nextElement());
226-
Extension primaryExt = tbsExtensions.getExtension(deltaExt.getExtnId());
227-
228-
if (primaryExt != null)
229-
{
230-
if (!deltaExt.equals(primaryExt))
231-
{
232-
deltaExtGen.addExtension(deltaExt);
233-
}
234-
}
264+
continue;
235265
}
236266

237-
DeltaCertificateDescriptor trimmedDeltaCertDesc;
238-
if (!deltaExtGen.isEmpty())
267+
Extension deltaExtension = extensions.getExtension(oid);
268+
if (deltaExtension != null && !deltaExtension.equals(tbsExtensions.getExtension(oid)))
239269
{
240-
v.add(new DERTaggedObject(true, 4, deltaExtGen.generate()));
270+
generator.addExtension(deltaExtension);
241271
}
242272
}
243-
next = (ASN1Encodable)en.nextElement();
273+
274+
extensions = generator.isEmpty() ? null : generator.generate();
244275
}
245276

246-
v.add(next);
277+
ASN1BitString signatureValue = descriptor.getSignatureValue();
247278

248-
return new DeltaCertificateDescriptor(new DERSequence(v));
279+
return new DeltaCertificateDescriptor(serialNumber, signature, issuer, validity, subject,
280+
subjectPublicKeyInfo, extensions, signatureValue);
249281
}
250282

251283
private void addOptional(ASN1EncodableVector v, int tag, boolean explicit, ASN1Object obj)
@@ -258,7 +290,7 @@ private void addOptional(ASN1EncodableVector v, int tag, boolean explicit, ASN1O
258290

259291
public ASN1Primitive toASN1Primitive()
260292
{
261-
ASN1EncodableVector v = new ASN1EncodableVector(7);
293+
ASN1EncodableVector v = new ASN1EncodableVector(8);
262294

263295
v.add(serialNumber);
264296
addOptional(v, 0, true, signature);

0 commit comments

Comments
 (0)