001: package org.bouncycastle.asn1.test;
002:
003: import org.bouncycastle.asn1.ASN1EncodableVector;
004: import org.bouncycastle.asn1.ASN1InputStream;
005: import org.bouncycastle.asn1.ASN1OutputStream;
006: import org.bouncycastle.asn1.ASN1Sequence;
007: import org.bouncycastle.asn1.ASN1Set;
008: import org.bouncycastle.asn1.DEREncodable;
009: import org.bouncycastle.asn1.DERGeneralizedTime;
010: import org.bouncycastle.asn1.DERIA5String;
011: import org.bouncycastle.asn1.DERObjectIdentifier;
012: import org.bouncycastle.asn1.DERPrintableString;
013: import org.bouncycastle.asn1.DERSequence;
014: import org.bouncycastle.asn1.DERSet;
015: import org.bouncycastle.asn1.DERUTF8String;
016: import org.bouncycastle.asn1.x509.X509DefaultEntryConverter;
017: import org.bouncycastle.asn1.x509.X509Name;
018: import org.bouncycastle.util.Arrays;
019: import org.bouncycastle.util.encoders.Hex;
020: import org.bouncycastle.util.test.SimpleTest;
021:
022: import java.io.ByteArrayInputStream;
023: import java.io.ByteArrayOutputStream;
024: import java.io.IOException;
025: import java.util.Hashtable;
026: import java.util.Vector;
027:
028: public class X509NameTest extends SimpleTest {
029: String[] subjects = {
030: "C=AU,ST=Victoria,L=South Melbourne,O=Connect 4 Pty Ltd,OU=Webserver Team,CN=www2.connect4.com.au,E=webmaster@connect4.com.au",
031: "C=AU,ST=Victoria,L=South Melbourne,O=Connect 4 Pty Ltd,OU=Certificate Authority,CN=Connect 4 CA,E=webmaster@connect4.com.au",
032: "C=AU,ST=QLD,CN=SSLeay/rsa test cert",
033: "C=US,O=National Aeronautics and Space Administration,SERIALNUMBER=16+CN=Steve Schoch",
034: "E=cooke@issl.atl.hp.com,C=US,OU=Hewlett Packard Company (ISSL),CN=Paul A. Cooke",
035: "O=Sun Microsystems Inc,CN=store.sun.com",
036: "unstructuredAddress=192.168.1.33,unstructuredName=pixfirewall.ciscopix.com,CN=pixfirewall.ciscopix.com" };
037:
038: public String getName() {
039: return "X509Name";
040: }
041:
042: private static X509Name fromBytes(byte[] bytes) throws IOException {
043: return X509Name.getInstance(new ASN1InputStream(
044: new ByteArrayInputStream(bytes)).readObject());
045: }
046:
047: private DEREncodable createEntryValue(DERObjectIdentifier oid,
048: String value) {
049: Hashtable attrs = new Hashtable();
050:
051: attrs.put(oid, value);
052:
053: X509Name name = new X509Name(attrs);
054:
055: ASN1Sequence seq = (ASN1Sequence) name.getDERObject();
056: ASN1Set set = (ASN1Set) seq.getObjectAt(0);
057: seq = (ASN1Sequence) set.getObjectAt(0);
058:
059: return seq.getObjectAt(1);
060: }
061:
062: private DEREncodable createEntryValueFromString(
063: DERObjectIdentifier oid, String value) {
064: Hashtable attrs = new Hashtable();
065:
066: attrs.put(oid, value);
067:
068: X509Name name = new X509Name(new X509Name(attrs).toString());
069:
070: ASN1Sequence seq = (ASN1Sequence) name.getDERObject();
071: ASN1Set set = (ASN1Set) seq.getObjectAt(0);
072: seq = (ASN1Sequence) set.getObjectAt(0);
073:
074: return seq.getObjectAt(1);
075: }
076:
077: private void testEncodingPrintableString(DERObjectIdentifier oid,
078: String value) {
079: DEREncodable converted = createEntryValue(oid, value);
080: if (!(converted instanceof DERPrintableString)) {
081: fail("encoding for " + oid + " not printable string");
082: }
083: }
084:
085: private void testEncodingIA5String(DERObjectIdentifier oid,
086: String value) {
087: DEREncodable converted = createEntryValue(oid, value);
088: if (!(converted instanceof DERIA5String)) {
089: fail("encoding for " + oid + " not IA5String");
090: }
091: }
092:
093: private void testEncodingGeneralizedTime(DERObjectIdentifier oid,
094: String value) {
095: DEREncodable converted = createEntryValue(oid, value);
096: if (!(converted instanceof DERGeneralizedTime)) {
097: fail("encoding for " + oid + " not GeneralizedTime");
098: }
099: converted = createEntryValueFromString(oid, value);
100: if (!(converted instanceof DERGeneralizedTime)) {
101: fail("encoding for " + oid + " not GeneralizedTime");
102: }
103: }
104:
105: public void performTest() throws Exception {
106: testEncodingPrintableString(X509Name.C, "AU");
107: testEncodingPrintableString(X509Name.SERIALNUMBER, "123456");
108: testEncodingPrintableString(X509Name.DN_QUALIFIER, "123456");
109: testEncodingIA5String(X509Name.EmailAddress, "test@test.com");
110: testEncodingIA5String(X509Name.DC, "test");
111: // correct encoding
112: testEncodingGeneralizedTime(X509Name.DATE_OF_BIRTH,
113: "#180F32303032303132323132323232305A");
114: // compatability encoding
115: testEncodingGeneralizedTime(X509Name.DATE_OF_BIRTH,
116: "20020122122220Z");
117:
118: //
119: // composite
120: //
121: Hashtable attrs = new Hashtable();
122:
123: attrs.put(X509Name.C, "AU");
124: attrs.put(X509Name.O, "The Legion of the Bouncy Castle");
125: attrs.put(X509Name.L, "Melbourne");
126: attrs.put(X509Name.ST, "Victoria");
127: attrs.put(X509Name.E, "feedback-crypto@bouncycastle.org");
128:
129: X509Name name1 = new X509Name(attrs);
130:
131: if (!name1.equals(name1)) {
132: fail("Failed same object test");
133: }
134:
135: if (!name1.equals(name1, true)) {
136: fail("Failed same object test - in Order");
137: }
138:
139: X509Name name2 = new X509Name(attrs);
140:
141: if (!name1.equals(name2)) {
142: fail("Failed same name test");
143: }
144:
145: if (!name1.equals(name2, true)) {
146: fail("Failed same name test - in Order");
147: }
148:
149: if (name1.hashCode() != name2.hashCode()) {
150: fail("Failed same name test - in Order");
151: }
152:
153: Vector ord1 = new Vector();
154:
155: ord1.addElement(X509Name.C);
156: ord1.addElement(X509Name.O);
157: ord1.addElement(X509Name.L);
158: ord1.addElement(X509Name.ST);
159: ord1.addElement(X509Name.E);
160:
161: Vector ord2 = new Vector();
162:
163: ord2.addElement(X509Name.E);
164: ord2.addElement(X509Name.ST);
165: ord2.addElement(X509Name.L);
166: ord2.addElement(X509Name.O);
167: ord2.addElement(X509Name.C);
168:
169: name1 = new X509Name(ord1, attrs);
170: name2 = new X509Name(ord2, attrs);
171:
172: if (!name1.equals(name2)) {
173: fail("Failed reverse name test");
174: }
175:
176: if (name1.equals(name2, true)) {
177: fail("Failed reverse name test - in Order");
178: }
179:
180: if (!name1.equals(name2, false)) {
181: fail("Failed reverse name test - in Order false");
182: }
183:
184: Vector oids = name1.getOIDs();
185: if (!compareVectors(oids, ord1)) {
186: fail("oid comparison test");
187: }
188:
189: Vector val1 = new Vector();
190:
191: val1.addElement("AU");
192: val1.addElement("The Legion of the Bouncy Castle");
193: val1.addElement("Melbourne");
194: val1.addElement("Victoria");
195: val1.addElement("feedback-crypto@bouncycastle.org");
196:
197: name1 = new X509Name(ord1, val1);
198:
199: Vector values = name1.getValues();
200: if (!compareVectors(values, val1)) {
201: fail("value comparison test");
202: }
203:
204: ord2 = new Vector();
205:
206: ord2.addElement(X509Name.ST);
207: ord2.addElement(X509Name.ST);
208: ord2.addElement(X509Name.L);
209: ord2.addElement(X509Name.O);
210: ord2.addElement(X509Name.C);
211:
212: name1 = new X509Name(ord1, attrs);
213: name2 = new X509Name(ord2, attrs);
214:
215: if (name1.equals(name2)) {
216: fail("Failed different name test");
217: }
218:
219: ord2 = new Vector();
220:
221: ord2.addElement(X509Name.ST);
222: ord2.addElement(X509Name.L);
223: ord2.addElement(X509Name.O);
224: ord2.addElement(X509Name.C);
225:
226: name1 = new X509Name(ord1, attrs);
227: name2 = new X509Name(ord2, attrs);
228:
229: if (name1.equals(name2)) {
230: fail("Failed subset name test");
231: }
232:
233: compositeTest();
234:
235: ByteArrayOutputStream bOut;
236: ASN1OutputStream aOut;
237: ASN1InputStream aIn;
238:
239: //
240: // getValues test
241: //
242: Vector v1 = name1.getValues(X509Name.O);
243:
244: if (v1.size() != 1
245: || !v1.elementAt(0).equals(
246: "The Legion of the Bouncy Castle")) {
247: fail("O test failed");
248: }
249:
250: Vector v2 = name1.getValues(X509Name.L);
251:
252: if (v2.size() != 1 || !v2.elementAt(0).equals("Melbourne")) {
253: fail("L test failed");
254: }
255:
256: //
257: // general subjects test
258: //
259: for (int i = 0; i != subjects.length; i++) {
260: X509Name name = new X509Name(subjects[i]);
261:
262: bOut = new ByteArrayOutputStream();
263: aOut = new ASN1OutputStream(bOut);
264:
265: aOut.writeObject(name);
266:
267: aIn = new ASN1InputStream(new ByteArrayInputStream(bOut
268: .toByteArray()));
269:
270: name = X509Name.getInstance(aIn.readObject());
271:
272: if (!name.toString().equals(subjects[i])) {
273: fail("failed regeneration test " + i);
274: }
275: }
276:
277: //
278: // sort test
279: //
280: X509Name unsorted = new X509Name("SERIALNUMBER=BBB + CN=AA");
281:
282: if (!fromBytes(unsorted.getEncoded()).toString().equals(
283: "CN=AA+SERIALNUMBER=BBB")) {
284: fail("failed sort test 1");
285: }
286:
287: unsorted = new X509Name("CN=AA + SERIALNUMBER=BBB");
288:
289: if (!fromBytes(unsorted.getEncoded()).toString().equals(
290: "CN=AA+SERIALNUMBER=BBB")) {
291: fail("failed sort test 2");
292: }
293:
294: unsorted = new X509Name("SERIALNUMBER=B + CN=AA");
295:
296: if (!fromBytes(unsorted.getEncoded()).toString().equals(
297: "SERIALNUMBER=B+CN=AA")) {
298: fail("failed sort test 3");
299: }
300:
301: unsorted = new X509Name("CN=AA + SERIALNUMBER=B");
302:
303: if (!fromBytes(unsorted.getEncoded()).toString().equals(
304: "SERIALNUMBER=B+CN=AA")) {
305: fail("failed sort test 4");
306: }
307:
308: //
309: // equality tests
310: //
311: equalityTest(new X509Name("CN=The Legion"), new X509Name(
312: "CN=The Legion"));
313: equalityTest(new X509Name("CN= The Legion"), new X509Name(
314: "CN=The Legion"));
315: equalityTest(new X509Name("CN=The Legion "), new X509Name(
316: "CN=The Legion"));
317: equalityTest(new X509Name("CN= The Legion "),
318: new X509Name("CN=The Legion"));
319: equalityTest(new X509Name("CN= the legion "),
320: new X509Name("CN=The Legion"));
321:
322: //
323: // inequality to sequences
324: //
325: name1 = new X509Name("CN=The Legion");
326:
327: if (name1.equals(new DERSequence())) {
328: fail("inequality test with sequence");
329: }
330:
331: if (name1.equals(new DERSequence(new DERSet()))) {
332: fail("inequality test with sequence and set");
333: }
334:
335: ASN1EncodableVector v = new ASN1EncodableVector();
336:
337: v.add(new DERObjectIdentifier("1.1"));
338: v.add(new DERObjectIdentifier("1.1"));
339: if (name1.equals(new DERSequence(new DERSet(new DERSet(v))))) {
340: fail("inequality test with sequence and bad set");
341: }
342:
343: if (name1.equals(new DERSequence(new DERSet(new DERSet(v))),
344: true)) {
345: fail("inequality test with sequence and bad set");
346: }
347:
348: if (name1
349: .equals(new DERSequence(new DERSet(new DERSequence())))) {
350: fail("inequality test with sequence and short sequence");
351: }
352:
353: if (name1.equals(
354: new DERSequence(new DERSet(new DERSequence())), true)) {
355: fail("inequality test with sequence and short sequence");
356: }
357:
358: v = new ASN1EncodableVector();
359:
360: v.add(new DERObjectIdentifier("1.1"));
361: v.add(new DERSequence());
362:
363: if (name1
364: .equals(new DERSequence(new DERSet(new DERSequence(v))))) {
365: fail("inequality test with sequence and bad sequence");
366: }
367:
368: if (name1.equals(null)) {
369: fail("inequality test with null");
370: }
371:
372: if (name1.equals(null, true)) {
373: fail("inequality test with null");
374: }
375:
376: //
377: // this is contrived but it checks sorting of sets with equal elements
378: //
379: unsorted = new X509Name("CN=AA + CN=AA + CN=AA");
380:
381: //
382: // tagging test - only works if CHOICE implemented
383: //
384: /*
385: ASN1TaggedObject tag = new DERTaggedObject(false, 1, new X509Name("CN=AA"));
386:
387: if (!tag.isExplicit())
388: {
389: fail("failed to explicitly tag CHOICE object");
390: }
391:
392: X509Name name = X509Name.getInstance(tag, false);
393:
394: if (!name.equals(new X509Name("CN=AA")))
395: {
396: fail("failed to recover tagged name");
397: }
398: */
399:
400: DERUTF8String testString = new DERUTF8String(
401: "The Legion of the Bouncy Castle");
402: byte[] encodedBytes = testString.getEncoded();
403: byte[] hexEncodedBytes = Hex.encode(encodedBytes);
404: String hexEncodedString = "#" + new String(hexEncodedBytes);
405:
406: DERUTF8String converted = (DERUTF8String) new X509DefaultEntryConverter()
407: .getConvertedValue(X509Name.L, hexEncodedString);
408:
409: if (!converted.equals(testString)) {
410: fail("failed X509DefaultEntryConverter test");
411: }
412:
413: //
414: // try a weird value
415: //
416:
417: }
418:
419: private boolean compareVectors(Vector a, Vector b) // for compatibility with early JDKs
420: {
421: if (a.size() != b.size()) {
422: return false;
423: }
424:
425: for (int i = 0; i != a.size(); i++) {
426: if (!a.elementAt(i).equals(b.elementAt(i))) {
427: return false;
428: }
429: }
430:
431: return true;
432: }
433:
434: private void compositeTest() throws IOException {
435: //
436: // composite test
437: //
438: byte[] enc = Hex
439: .decode("305e310b300906035504061302415531283026060355040a0c1f546865204c6567696f6e206f662074686520426f756e637920436173746c653125301006035504070c094d656c626f75726e653011060355040b0c0a4173636f742056616c65");
440: ASN1InputStream aIn = new ASN1InputStream(
441: new ByteArrayInputStream(enc));
442:
443: X509Name n = X509Name.getInstance(aIn.readObject());
444:
445: if (!n
446: .toString()
447: .equals(
448: "C=AU,O=The Legion of the Bouncy Castle,L=Melbourne+OU=Ascot Vale")) {
449: fail("Failed composite to string test got: " + n.toString());
450: }
451:
452: if (!n
453: .toString(true, X509Name.DefaultSymbols)
454: .equals(
455: "L=Melbourne+OU=Ascot Vale,O=The Legion of the Bouncy Castle,C=AU")) {
456: fail("Failed composite to string test got: "
457: + n.toString(true, X509Name.DefaultSymbols));
458: }
459:
460: n = new X509Name(true,
461: "L=Melbourne+OU=Ascot Vale,O=The Legion of the Bouncy Castle,C=AU");
462: if (!n
463: .toString()
464: .equals(
465: "C=AU,O=The Legion of the Bouncy Castle,L=Melbourne+OU=Ascot Vale")) {
466: fail("Failed composite to string reversal test got: "
467: + n.toString());
468: }
469:
470: n = new X509Name(
471: "C=AU, O=The Legion of the Bouncy Castle, L=Melbourne + OU=Ascot Vale");
472:
473: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
474: ASN1OutputStream aOut = new ASN1OutputStream(bOut);
475:
476: aOut.writeObject(n);
477:
478: byte[] enc2 = bOut.toByteArray();
479:
480: if (!Arrays.areEqual(enc, enc2)) {
481: fail("Failed composite string to encoding test");
482: }
483: }
484:
485: private void equalityTest(X509Name x509Name, X509Name x509Name1) {
486: if (!x509Name.equals(x509Name1)) {
487: fail("equality test failed for " + x509Name + " : "
488: + x509Name1);
489: }
490:
491: if (!x509Name.equals(x509Name1, true)) {
492: fail("equality test failed for " + x509Name + " : "
493: + x509Name1);
494: }
495: }
496:
497: public static void main(String[] args) {
498: runTest(new X509NameTest());
499: }
500: }
|