1
1
package org .bouncycastle .asn1 .x509 ;
2
2
3
3
import java .io .IOException ;
4
+ import java .util .Collections ;
5
+ import java .util .HashSet ;
4
6
import java .util .Hashtable ;
7
+ import java .util .Set ;
5
8
import java .util .Vector ;
6
9
7
10
import org .bouncycastle .asn1 .ASN1Encodable ;
11
+ import org .bouncycastle .asn1 .ASN1EncodableVector ;
8
12
import org .bouncycastle .asn1 .ASN1Encoding ;
9
13
import org .bouncycastle .asn1 .ASN1ObjectIdentifier ;
14
+ import org .bouncycastle .asn1 .ASN1Sequence ;
10
15
import org .bouncycastle .asn1 .DEROctetString ;
16
+ import org .bouncycastle .asn1 .DERSequence ;
11
17
12
18
/**
13
19
* Generator for X.509 extensions
@@ -16,6 +22,18 @@ public class ExtensionsGenerator
16
22
{
17
23
private Hashtable extensions = new Hashtable ();
18
24
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
+ }
19
37
20
38
/**
21
39
* Reset the generator
@@ -30,14 +48,14 @@ public void reset()
30
48
* Add an extension with the given oid and the passed in value to be included
31
49
* in the OCTET STRING associated with the extension.
32
50
*
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.
36
54
*/
37
55
public void addExtension (
38
56
ASN1ObjectIdentifier oid ,
39
- boolean critical ,
40
- ASN1Encodable value )
57
+ boolean critical ,
58
+ ASN1Encodable value )
41
59
throws IOException
42
60
{
43
61
this .addExtension (oid , critical , value .toASN1Primitive ().getEncoded (ASN1Encoding .DER ));
@@ -47,22 +65,52 @@ public void addExtension(
47
65
* Add an extension with the given oid and the passed in byte array to be wrapped in the
48
66
* OCTET STRING associated with the extension.
49
67
*
50
- * @param oid OID for the extension.
68
+ * @param oid OID for the extension.
51
69
* @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.
53
71
*/
54
72
public void addExtension (
55
73
ASN1ObjectIdentifier oid ,
56
- boolean critical ,
57
- byte [] value )
74
+ boolean critical ,
75
+ byte [] value )
58
76
{
77
+
59
78
if (extensions .containsKey (oid ))
60
79
{
61
- throw new IllegalArgumentException ( "extension " + oid + " already added" );
62
- }
80
+ if ( dupsAllowed . contains ( oid ))
81
+ {
63
82
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
+ }
66
114
}
67
115
68
116
/**
@@ -86,14 +134,14 @@ public void addExtension(
86
134
* Replace an extension with the given oid and the passed in value to be included
87
135
* in the OCTET STRING associated with the extension.
88
136
*
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.
92
140
*/
93
141
public void replaceExtension (
94
142
ASN1ObjectIdentifier oid ,
95
- boolean critical ,
96
- ASN1Encodable value )
143
+ boolean critical ,
144
+ ASN1Encodable value )
97
145
throws IOException
98
146
{
99
147
this .replaceExtension (oid , critical , value .toASN1Primitive ().getEncoded (ASN1Encoding .DER ));
@@ -103,14 +151,14 @@ public void replaceExtension(
103
151
* Replace an extension with the given oid and the passed in byte array to be wrapped in the
104
152
* OCTET STRING associated with the extension.
105
153
*
106
- * @param oid OID for the extension.
154
+ * @param oid OID for the extension.
107
155
* @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.
109
157
*/
110
158
public void replaceExtension (
111
159
ASN1ObjectIdentifier oid ,
112
- boolean critical ,
113
- byte [] value )
160
+ boolean critical ,
161
+ byte [] value )
114
162
{
115
163
this .replaceExtension (new Extension (oid , critical , value ));
116
164
}
@@ -156,7 +204,7 @@ public void removeExtension(
156
204
*/
157
205
public boolean hasExtension (ASN1ObjectIdentifier oid )
158
206
{
159
- return extensions .containsKey (oid );
207
+ return extensions .containsKey (oid );
160
208
}
161
209
162
210
/**
@@ -167,7 +215,7 @@ public boolean hasExtension(ASN1ObjectIdentifier oid)
167
215
*/
168
216
public Extension getExtension (ASN1ObjectIdentifier oid )
169
217
{
170
- return (Extension )extensions .get (oid );
218
+ return (Extension )extensions .get (oid );
171
219
}
172
220
173
221
/**
@@ -183,7 +231,7 @@ public boolean isEmpty()
183
231
/**
184
232
* Generate an Extensions object based on the current state of the generator.
185
233
*
186
- * @return an X09Extensions object.
234
+ * @return an X09Extensions object.
187
235
*/
188
236
public Extensions generate ()
189
237
{
@@ -196,4 +244,13 @@ public Extensions generate()
196
244
197
245
return new Extensions (exts );
198
246
}
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
+ }
199
256
}
0 commit comments