Skip to content

Commit 57494e1

Browse files
committed
Added new constructor to ASN1EncodableVector that takes array of ASN1Encodables. Updated ExtensionGenerator to match C# equivalent. Added method to extract extensions from PKCS10CertificationRequest Added tests
1 parent 2d7814a commit 57494e1

File tree

5 files changed

+358
-91
lines changed

5 files changed

+358
-91
lines changed

core/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ public ASN1EncodableVector(int initialCapacity)
3030
this.copyOnWrite = false;
3131
}
3232

33+
public ASN1EncodableVector(ASN1Encodable[] items)
34+
{
35+
this();
36+
for (ASN1Encodable enc : items)
37+
{
38+
add(enc);
39+
}
40+
}
41+
3342
public void add(ASN1Encodable element)
3443
{
3544
if (null == element)

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

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

33
import java.io.IOException;
4+
import java.util.Collections;
5+
import java.util.HashSet;
46
import java.util.Hashtable;
7+
import java.util.Set;
58
import java.util.Vector;
69

710
import org.bouncycastle.asn1.ASN1Encodable;
11+
import org.bouncycastle.asn1.ASN1EncodableVector;
812
import org.bouncycastle.asn1.ASN1Encoding;
913
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
14+
import org.bouncycastle.asn1.ASN1Sequence;
1015
import org.bouncycastle.asn1.DEROctetString;
16+
import org.bouncycastle.asn1.DERSequence;
1117

1218
/**
1319
* Generator for X.509 extensions
@@ -16,6 +22,18 @@ public class ExtensionsGenerator
1622
{
1723
private Hashtable extensions = new Hashtable();
1824
private Vector extOrdering = new Vector();
25+
private static final Set dupsAllowed;
26+
27+
28+
static
29+
{
30+
Set dups = new HashSet();
31+
dups.add(Extension.subjectAlternativeName);
32+
dups.add(Extension.issuerAlternativeName);
33+
dups.add(Extension.subjectDirectoryAttributes);
34+
dups.add(Extension.certificateIssuer);
35+
dupsAllowed = Collections.unmodifiableSet(dups);
36+
}
1937

2038
/**
2139
* Reset the generator
@@ -30,14 +48,14 @@ public void reset()
3048
* Add an extension with the given oid and the passed in value to be included
3149
* in the OCTET STRING associated with the extension.
3250
*
33-
* @param oid OID for the extension.
34-
* @param critical true if critical, false otherwise.
35-
* @param value the ASN.1 object to be included in the extension.
51+
* @param oid OID for the extension.
52+
* @param critical true if critical, false otherwise.
53+
* @param value the ASN.1 object to be included in the extension.
3654
*/
3755
public void addExtension(
3856
ASN1ObjectIdentifier oid,
39-
boolean critical,
40-
ASN1Encodable value)
57+
boolean critical,
58+
ASN1Encodable value)
4159
throws IOException
4260
{
4361
this.addExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER));
@@ -47,22 +65,52 @@ public void addExtension(
4765
* Add an extension with the given oid and the passed in byte array to be wrapped in the
4866
* OCTET STRING associated with the extension.
4967
*
50-
* @param oid OID for the extension.
68+
* @param oid OID for the extension.
5169
* @param critical true if critical, false otherwise.
52-
* @param value the byte array to be wrapped.
70+
* @param value the byte array to be wrapped.
5371
*/
5472
public void addExtension(
5573
ASN1ObjectIdentifier oid,
56-
boolean critical,
57-
byte[] value)
74+
boolean critical,
75+
byte[] value)
5876
{
77+
5978
if (extensions.containsKey(oid))
6079
{
61-
throw new IllegalArgumentException("extension " + oid + " already added");
62-
}
80+
if (dupsAllowed.contains(oid))
81+
{
6382

64-
extOrdering.addElement(oid);
65-
extensions.put(oid, new Extension(oid, critical, new DEROctetString(value)));
83+
Extension existingExtension = (Extension)extensions.get(oid);
84+
ASN1Sequence seq1 = ASN1Sequence.getInstance(DEROctetString.getInstance(existingExtension.getExtnValue()).getOctets());
85+
ASN1EncodableVector items = new ASN1EncodableVector();
86+
for (ASN1Encodable enc : seq1)
87+
{
88+
items.add(enc);
89+
}
90+
ASN1Sequence seq2 = ASN1Sequence.getInstance(value);
91+
for (ASN1Encodable enc : seq2)
92+
{
93+
items.add(enc);
94+
}
95+
try
96+
{
97+
extensions.put(oid, new Extension(oid, critical, new DERSequence(items).getEncoded()));
98+
}
99+
catch (IOException e)
100+
{
101+
throw new RuntimeException(e.getMessage(), e);
102+
}
103+
}
104+
else
105+
{
106+
throw new IllegalArgumentException("extension " + oid + " already added");
107+
}
108+
}
109+
else
110+
{
111+
extOrdering.addElement(oid);
112+
extensions.put(oid, new Extension(oid, critical, new DEROctetString(value)));
113+
}
66114
}
67115

68116
/**
@@ -86,14 +134,14 @@ public void addExtension(
86134
* Replace an extension with the given oid and the passed in value to be included
87135
* in the OCTET STRING associated with the extension.
88136
*
89-
* @param oid OID for the extension.
90-
* @param critical true if critical, false otherwise.
91-
* @param value the ASN.1 object to be included in the extension.
137+
* @param oid OID for the extension.
138+
* @param critical true if critical, false otherwise.
139+
* @param value the ASN.1 object to be included in the extension.
92140
*/
93141
public void replaceExtension(
94142
ASN1ObjectIdentifier oid,
95-
boolean critical,
96-
ASN1Encodable value)
143+
boolean critical,
144+
ASN1Encodable value)
97145
throws IOException
98146
{
99147
this.replaceExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER));
@@ -103,14 +151,14 @@ public void replaceExtension(
103151
* Replace an extension with the given oid and the passed in byte array to be wrapped in the
104152
* OCTET STRING associated with the extension.
105153
*
106-
* @param oid OID for the extension.
154+
* @param oid OID for the extension.
107155
* @param critical true if critical, false otherwise.
108-
* @param value the byte array to be wrapped.
156+
* @param value the byte array to be wrapped.
109157
*/
110158
public void replaceExtension(
111159
ASN1ObjectIdentifier oid,
112-
boolean critical,
113-
byte[] value)
160+
boolean critical,
161+
byte[] value)
114162
{
115163
this.replaceExtension(new Extension(oid, critical, value));
116164
}
@@ -156,7 +204,7 @@ public void removeExtension(
156204
*/
157205
public boolean hasExtension(ASN1ObjectIdentifier oid)
158206
{
159-
return extensions.containsKey(oid);
207+
return extensions.containsKey(oid);
160208
}
161209

162210
/**
@@ -167,7 +215,7 @@ public boolean hasExtension(ASN1ObjectIdentifier oid)
167215
*/
168216
public Extension getExtension(ASN1ObjectIdentifier oid)
169217
{
170-
return (Extension)extensions.get(oid);
218+
return (Extension)extensions.get(oid);
171219
}
172220

173221
/**
@@ -183,7 +231,7 @@ public boolean isEmpty()
183231
/**
184232
* Generate an Extensions object based on the current state of the generator.
185233
*
186-
* @return an X09Extensions object.
234+
* @return an X09Extensions object.
187235
*/
188236
public Extensions generate()
189237
{
@@ -196,4 +244,13 @@ public Extensions generate()
196244

197245
return new Extensions(exts);
198246
}
247+
248+
public void addExtension(Extensions extensions)
249+
{
250+
for (ASN1ObjectIdentifier _ident : extensions.getExtensionOIDs())
251+
{
252+
Extension ext = extensions.getExtension(_ident);
253+
addExtension(ASN1ObjectIdentifier.getInstance(_ident), ext.isCritical(), ext.getExtnValue().getOctets());
254+
}
255+
}
199256
}

0 commit comments

Comments
 (0)