Skip to content

Commit f8cd3f3

Browse files
committed
Refactor around Extension (reduce array copies)
1 parent 092e85d commit f8cd3f3

File tree

7 files changed

+91
-68
lines changed

7 files changed

+91
-68
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ public static Extension create(
266266
ASN1Encodable value)
267267
throws IOException
268268
{
269-
return new Extension(extnId, critical, value.toASN1Primitive().getEncoded());
269+
return new Extension(extnId, critical, new DEROctetString(value.toASN1Primitive().getEncoded()));
270270
}
271271

272272
private Extension(ASN1Sequence seq)

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

Lines changed: 71 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import org.bouncycastle.asn1.ASN1Sequence;
1717
import org.bouncycastle.asn1.DEROctetString;
1818
import org.bouncycastle.asn1.DERSequence;
19-
import org.bouncycastle.util.Arrays;
2019

2120
/**
2221
* Generator for X.509 extensions
@@ -55,13 +54,17 @@ public void reset()
5554
* @param critical true if critical, false otherwise.
5655
* @param value the ASN.1 object to be included in the extension.
5756
*/
58-
public void addExtension(
59-
ASN1ObjectIdentifier oid,
60-
boolean critical,
61-
ASN1Encodable value)
62-
throws IOException
57+
public void addExtension(ASN1ObjectIdentifier oid, boolean critical, ASN1Encodable value) throws IOException
6358
{
64-
this.addExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER));
59+
Extension existingExtension = (Extension)extensions.get(oid);
60+
if (existingExtension != null)
61+
{
62+
implAddExtensionDup(existingExtension, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER));
63+
}
64+
else
65+
{
66+
implAddExtension(new Extension(oid, critical, new DEROctetString(value)));
67+
}
6568
}
6669

6770
/**
@@ -72,47 +75,16 @@ public void addExtension(
7275
* @param critical true if critical, false otherwise.
7376
* @param value the byte array to be wrapped.
7477
*/
75-
public void addExtension(
76-
ASN1ObjectIdentifier oid,
77-
boolean critical,
78-
byte[] value)
78+
public void addExtension(ASN1ObjectIdentifier oid, boolean critical, byte[] value)
7979
{
80-
if (extensions.containsKey(oid))
80+
Extension existingExtension = (Extension)extensions.get(oid);
81+
if (existingExtension != null)
8182
{
82-
if (dupsAllowed.contains(oid))
83-
{
84-
Extension existingExtension = (Extension)extensions.get(oid);
85-
ASN1Sequence seq1 = ASN1Sequence.getInstance(DEROctetString.getInstance(existingExtension.getExtnValue()).getOctets());
86-
ASN1Sequence seq2 = ASN1Sequence.getInstance(value);
87-
88-
ASN1EncodableVector items = new ASN1EncodableVector(seq1.size() + seq2.size());
89-
for (Enumeration en = seq1.getObjects(); en.hasMoreElements();)
90-
{
91-
items.add((ASN1Encodable)en.nextElement());
92-
}
93-
for (Enumeration en = seq2.getObjects(); en.hasMoreElements();)
94-
{
95-
items.add((ASN1Encodable)en.nextElement());
96-
}
97-
98-
try
99-
{
100-
extensions.put(oid, new Extension(oid, critical, new DERSequence(items).getEncoded()));
101-
}
102-
catch (IOException e)
103-
{
104-
throw new ASN1ParsingException(e.getMessage(), e);
105-
}
106-
}
107-
else
108-
{
109-
throw new IllegalArgumentException("extension " + oid + " already added");
110-
}
83+
implAddExtensionDup(existingExtension, critical, value);
11184
}
11285
else
11386
{
114-
extOrdering.addElement(oid);
115-
extensions.put(oid, new Extension(oid, critical, new DEROctetString(Arrays.clone(value))));
87+
implAddExtension(new Extension(oid, critical, value));
11688
}
11789
}
11890

@@ -124,15 +96,31 @@ public void addExtension(
12496
public void addExtension(
12597
Extension extension)
12698
{
127-
if (extensions.containsKey(extension.getExtnId()))
99+
if (hasExtension(extension.getExtnId()))
128100
{
129101
throw new IllegalArgumentException("extension " + extension.getExtnId() + " already added");
130102
}
131103

132-
extOrdering.addElement(extension.getExtnId());
133-
extensions.put(extension.getExtnId(), extension);
104+
implAddExtension(extension);
134105
}
135106

107+
/** @deprecated Use addExtensions instead. */
108+
public void addExtension(Extensions extensions)
109+
{
110+
addExtensions(extensions);
111+
}
112+
113+
public void addExtensions(Extensions extensions)
114+
{
115+
ASN1ObjectIdentifier[] oids = extensions.getExtensionOIDs();
116+
for (int i = 0; i != oids.length; i++)
117+
{
118+
ASN1ObjectIdentifier ident = oids[i];
119+
Extension ext = extensions.getExtension(ident);
120+
addExtension(ASN1ObjectIdentifier.getInstance(ident), ext.isCritical(), ext.getExtnValue().getOctets());
121+
}
122+
}
123+
136124
/**
137125
* Replace an extension with the given oid and the passed in value to be included
138126
* in the OCTET STRING associated with the extension.
@@ -147,7 +135,7 @@ public void replaceExtension(
147135
ASN1Encodable value)
148136
throws IOException
149137
{
150-
this.replaceExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER));
138+
replaceExtension(new Extension(oid, critical, new DEROctetString(value)));
151139
}
152140

153141
/**
@@ -163,7 +151,7 @@ public void replaceExtension(
163151
boolean critical,
164152
byte[] value)
165153
{
166-
this.replaceExtension(new Extension(oid, critical, value));
154+
replaceExtension(new Extension(oid, critical, value));
167155
}
168156

169157
/**
@@ -174,7 +162,7 @@ public void replaceExtension(
174162
public void replaceExtension(
175163
Extension extension)
176164
{
177-
if (!extensions.containsKey(extension.getExtnId()))
165+
if (!hasExtension(extension.getExtnId()))
178166
{
179167
throw new IllegalArgumentException("extension " + extension.getExtnId() + " not present");
180168
}
@@ -190,7 +178,7 @@ public void replaceExtension(
190178
public void removeExtension(
191179
ASN1ObjectIdentifier oid)
192180
{
193-
if (!extensions.containsKey(oid))
181+
if (!hasExtension(oid))
194182
{
195183
throw new IllegalArgumentException("extension " + oid + " not present");
196184
}
@@ -248,14 +236,41 @@ public Extensions generate()
248236
return new Extensions(exts);
249237
}
250238

251-
public void addExtension(Extensions extensions)
239+
private void implAddExtension(Extension extension)
252240
{
253-
ASN1ObjectIdentifier[] oids = extensions.getExtensionOIDs();
254-
for (int i = 0; i != oids.length; i++)
241+
extOrdering.addElement(extension.getExtnId());
242+
extensions.put(extension.getExtnId(), extension);
243+
}
244+
245+
private void implAddExtensionDup(Extension existingExtension, boolean critical, byte[] value)
246+
{
247+
ASN1ObjectIdentifier oid = existingExtension.getExtnId();
248+
if (!dupsAllowed.contains(oid))
255249
{
256-
ASN1ObjectIdentifier ident = oids[i];
257-
Extension ext = extensions.getExtension(ident);
258-
addExtension(ASN1ObjectIdentifier.getInstance(ident), ext.isCritical(), ext.getExtnValue().getOctets());
250+
throw new IllegalArgumentException("extension " + oid + " already added");
251+
}
252+
253+
ASN1Sequence seq1 = ASN1Sequence.getInstance(
254+
DEROctetString.getInstance(existingExtension.getExtnValue()).getOctets());
255+
ASN1Sequence seq2 = ASN1Sequence.getInstance(value);
256+
257+
ASN1EncodableVector items = new ASN1EncodableVector(seq1.size() + seq2.size());
258+
for (Enumeration en = seq1.getObjects(); en.hasMoreElements();)
259+
{
260+
items.add((ASN1Encodable)en.nextElement());
261+
}
262+
for (Enumeration en = seq2.getObjects(); en.hasMoreElements();)
263+
{
264+
items.add((ASN1Encodable)en.nextElement());
265+
}
266+
267+
try
268+
{
269+
extensions.put(oid, new Extension(oid, critical, new DEROctetString(new DERSequence(items))));
270+
}
271+
catch (IOException e)
272+
{
273+
throw new ASN1ParsingException(e.getMessage(), e);
259274
}
260275
}
261276
}

core/src/test/java/org/bouncycastle/asn1/test/GenerationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ public void testDuplicateExtensions()
412412
//
413413

414414
ExtensionsGenerator genX = new ExtensionsGenerator();
415-
genX.addExtension(ext);
415+
genX.addExtensions(ext);
416416

417417
ext = Extensions.getInstance(ASN1Sequence.getInstance(genX.generate().getEncoded()));
418418
returnedExtension = ext.getExtension(Extension.subjectAlternativeName);

pkix/src/main/java/org/bouncycastle/cert/X509v2AttributeCertificateBuilder.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
import java.util.Locale;
88

99
import org.bouncycastle.asn1.ASN1Encodable;
10-
import org.bouncycastle.asn1.ASN1Encoding;
1110
import org.bouncycastle.asn1.ASN1GeneralizedTime;
1211
import org.bouncycastle.asn1.ASN1Integer;
1312
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
13+
import org.bouncycastle.asn1.DEROctetString;
1414
import org.bouncycastle.asn1.DERSet;
1515
import org.bouncycastle.asn1.x509.AttCertIssuer;
1616
import org.bouncycastle.asn1.x509.Attribute;
@@ -249,7 +249,8 @@ public X509v2AttributeCertificateBuilder replaceExtension(
249249
{
250250
try
251251
{
252-
extGenerator = CertUtils.doReplaceExtension(extGenerator, new Extension(oid, isCritical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER)));
252+
extGenerator = CertUtils.doReplaceExtension(extGenerator,
253+
new Extension(oid, isCritical, new DEROctetString(value)));
253254
}
254255
catch (IOException e)
255256
{

pkix/src/main/java/org/bouncycastle/cert/X509v2CRLBuilder.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
1717
import org.bouncycastle.asn1.ASN1Sequence;
1818
import org.bouncycastle.asn1.DERBitString;
19+
import org.bouncycastle.asn1.DEROctetString;
1920
import org.bouncycastle.asn1.DERSequence;
2021
import org.bouncycastle.asn1.x500.X500Name;
2122
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
@@ -384,7 +385,8 @@ public X509v2CRLBuilder replaceExtension(
384385
{
385386
try
386387
{
387-
extGenerator = CertUtils.doReplaceExtension(extGenerator, new Extension(oid, isCritical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER)));
388+
extGenerator = CertUtils.doReplaceExtension(extGenerator,
389+
new Extension(oid, isCritical, new DEROctetString(value)));
388390
}
389391
catch (IOException e)
390392
{

pkix/src/main/java/org/bouncycastle/cert/X509v3CertificateBuilder.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
1616
import org.bouncycastle.asn1.DERBitString;
1717
import org.bouncycastle.asn1.DERNull;
18+
import org.bouncycastle.asn1.DEROctetString;
1819
import org.bouncycastle.asn1.DERSequence;
1920
import org.bouncycastle.asn1.x500.X500Name;
2021
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
@@ -274,7 +275,8 @@ public X509v3CertificateBuilder replaceExtension(
274275
{
275276
try
276277
{
277-
extGenerator = CertUtils.doReplaceExtension(extGenerator, new Extension(oid, isCritical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER)));
278+
extGenerator = CertUtils.doReplaceExtension(extGenerator,
279+
new Extension(oid, isCritical, new DEROctetString(value)));
278280
}
279281
catch (IOException e)
280282
{
@@ -452,7 +454,7 @@ public X509CertificateHolder build(
452454
// the altSignatureValue is not present yet, but it must be in the deltaCertificate and
453455
// it must be different (by definition!). We add a dummy one to trigger inclusion.
454456
ExtensionsGenerator tmpExtGen = new ExtensionsGenerator();
455-
tmpExtGen.addExtension(extGenerator.generate());
457+
tmpExtGen.addExtensions(extGenerator.generate());
456458
tmpExtGen.addExtension(Extension.altSignatureValue, false, DERNull.INSTANCE);
457459

458460
DeltaCertificateDescriptor descriptor = DeltaCertificateTool.trimDeltaCertificateDescriptor(

prov/src/main/java/org/bouncycastle/jce/provider/OcspCache.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
2525
import org.bouncycastle.asn1.ASN1OctetString;
2626
import org.bouncycastle.asn1.ASN1Sequence;
27+
import org.bouncycastle.asn1.DEROctetString;
2728
import org.bouncycastle.asn1.DERSequence;
2829
import org.bouncycastle.asn1.ocsp.BasicOCSPResponse;
2930
import org.bouncycastle.asn1.ocsp.CertID;
@@ -39,6 +40,7 @@
3940
import org.bouncycastle.asn1.x509.Extensions;
4041
import org.bouncycastle.jcajce.PKIXCertRevocationCheckerParameters;
4142
import org.bouncycastle.jcajce.util.JcaJceHelper;
43+
import org.bouncycastle.util.Arrays;
4244
import org.bouncycastle.util.io.Streams;
4345

4446
class OcspCache
@@ -108,15 +110,16 @@ static OCSPResponse getOcspResponse(
108110
for (int i = 0; i != exts.size(); i++)
109111
{
110112
Extension ext = (Extension)exts.get(i);
111-
byte[] value = ext.getValue();
112113

113-
if (OCSPObjectIdentifiers.id_pkix_ocsp_nonce.getId().equals(ext.getId()))
114+
ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(ext.getId());
115+
ASN1OctetString value = new DEROctetString(ext.getValue());
116+
117+
if (OCSPObjectIdentifiers.id_pkix_ocsp_nonce.equals(oid))
114118
{
115-
nonce = value;
119+
nonce = Arrays.clone(value.getOctets());
116120
}
117121

118-
requestExtensions.add(new org.bouncycastle.asn1.x509.Extension(
119-
new ASN1ObjectIdentifier(ext.getId()), ext.isCritical(), value));
122+
requestExtensions.add(new org.bouncycastle.asn1.x509.Extension(oid, ext.isCritical(), value));
120123
}
121124

122125
// TODO: configure originator

0 commit comments

Comments
 (0)