1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50:
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67:
68: import ;
69:
70:
89: public class X509CertSelector implements CertSelector, Cloneable
90: {
91:
92:
93:
94:
95: private static final String AUTH_KEY_ID = "2.5.29.35";
96: private static final String SUBJECT_KEY_ID = "2.5.29.14";
97: private static final String NAME_CONSTRAINTS_ID = "2.5.29.30";
98:
99: private static boolean checkOid(int[] oid)
100: {
101: return (oid != null && oid.length > 2 &&
102: (oid[0] >= 0 && oid[0] <= 2) && (oid[1] >= 0 && oid[1] <= 39));
103: }
104:
105: private static GeneralName makeName(int id, String name) throws IOException
106: {
107: byte[] nameBytes = null;
108: GeneralName.Kind kind = GeneralName.Kind.forTag(id);
109: switch (Kind.forTag(id))
110: {
111: case dNSName:
112: case rfc822Name:
113: case uniformResourceIdentifier:
114: nameBytes = name.getBytes("ASCII");
115: break;
116:
117: case iPAddress:
118: InetAddress addr = InetAddress.getByName(name);
119: nameBytes = addr.getAddress();
120: break;
121:
122: case registeredId:
123: OID oid = new OID(name);
124: nameBytes = oid.getDER();
125: break;
126:
127: case directoryName:
128: X500Principal xname = new X500Principal(name);
129: nameBytes = xname.getEncoded();
130: break;
131:
132: case ediPartyName:
133: case x400Address:
134: case otherName:
135: throw new IOException("cannot decode string representation of "
136: + kind);
137: }
138: return new GeneralName(kind, nameBytes);
139: }
140:
141: private int basicConstraints;
142: private X509Certificate cert;
143: private BigInteger serialNo;
144: private X500Principal issuer;
145: private X500Principal subject;
146: private byte[] subjectKeyId;
147: private byte[] authKeyId;
148: private boolean[] keyUsage;
149: private Date certValid;
150: private OID sigId;
151: private PublicKey subjectKey;
152: private X509EncodedKeySpec subjectKeySpec;
153: private Set<String> keyPurposeSet;
154: private List<GeneralName> altNames;
155: private boolean matchAllNames;
156: private byte[] nameConstraints;
157: private Set<OID> policy;
158: private List<GeneralName> pathToNames;
159:
160:
165: public X509CertSelector()
166: {
167: basicConstraints = -1;
168: }
169:
170:
181: public void addPathToName(int id, byte[] name) throws IOException
182: {
183: GeneralName generalName = new GeneralName(GeneralName.Kind.forTag(id), name);
184: if (pathToNames == null)
185: pathToNames = new LinkedList<GeneralName>();
186: pathToNames.add(generalName);
187: }
188:
189:
199: public void addPathToName(int id, String name) throws IOException
200: {
201: GeneralName generalName = makeName(id, name);
202: if (pathToNames == null)
203: pathToNames = new LinkedList<GeneralName>();
204: pathToNames.add(generalName);
205: }
206:
207:
230: public void addSubjectAlternativeName(int id, byte[] name)
231: throws IOException
232: {
233: GeneralName generalName = new GeneralName(GeneralName.Kind.forTag(id), name);
234: if (altNames == null)
235: altNames = new LinkedList<GeneralName>();
236: altNames.add(generalName);
237: }
238:
239:
252: public void addSubjectAlternativeName(int id, String name)
253: throws IOException
254: {
255: GeneralName generalName = makeName(id, name);
256: if (altNames == null)
257: altNames = new LinkedList<GeneralName>();
258: altNames.add(generalName);
259: }
260:
261: public Object clone()
262: {
263: try
264: {
265: return super.clone();
266: }
267: catch (CloneNotSupportedException shouldNotHappen)
268: {
269: throw new Error(shouldNotHappen);
270: }
271: }
272:
273:
280: public byte[] getAuthorityKeyIdentifier()
281: {
282: if (authKeyId != null)
283: return (byte[]) authKeyId.clone();
284: else
285: return null;
286: }
287:
288:
293: public int getBasicConstraints()
294: {
295: return basicConstraints;
296: }
297:
298:
304: public X509Certificate getCertificate()
305: {
306: return cert;
307: }
308:
309:
315: public Date getCertificateValid()
316: {
317: if (certValid != null)
318: return (Date) certValid.clone();
319: else
320: return null;
321: }
322:
323:
330: public Set<String> getExtendedKeyUsage()
331: {
332: if (keyPurposeSet != null)
333: return Collections.unmodifiableSet(keyPurposeSet);
334: else
335: return null;
336: }
337:
338:
344: public byte[] getIssuerAsBytes() throws IOException
345: {
346: if (issuer != null)
347: return issuer.getEncoded();
348: else
349: return null;
350: }
351:
352:
358: public String getIssuerAsString()
359: {
360: if (issuer != null)
361: return issuer.getName();
362: else
363: return null;
364: }
365:
366:
372: public boolean[] getKeyUsage()
373: {
374: if (keyUsage != null)
375: return (boolean[]) keyUsage.clone();
376: else
377: return null;
378: }
379:
380:
387: public boolean getMatchAllSubjectAltNames()
388: {
389: return matchAllNames;
390: }
391:
392:
399: public byte[] getNameConstraints()
400: {
401: if (nameConstraints != null)
402: return (byte[]) nameConstraints.clone();
403: else
404: return null;
405: }
406:
407: public Collection<List<?>> getPathToNames()
408: {
409: if (pathToNames != null)
410: {
411: List<List<?>> names = new ArrayList<List<?>>(pathToNames.size());
412: for (GeneralName name : pathToNames)
413: {
414: List<Object> n = new ArrayList<Object>(2);
415: n.add(name.kind().tag());
416: n.add(name.name());
417: names.add(n);
418: }
419:
420: return names;
421: }
422: return null;
423: }
424:
425:
431: public Set<String> getPolicy()
432: {
433: Set<OID> p = this.policy;
434: if (p != null)
435: {
436: Set<String> strings = new HashSet<String>(p.size());
437: for (OID o : p)
438: {
439: strings.add(o.toString());
440: }
441: return strings;
442: }
443: return null;
444: }
445:
446:
458: public Date getPrivateKeyValid()
459: {
460: return null;
461: }
462:
463:
469: public BigInteger getSerialNumber()
470: {
471: return serialNo;
472: }
473:
474:
483: public Collection<List<?>> getSubjectAlternativeNames()
484: {
485: if (altNames != null)
486: {
487: List<List<?>> names = new ArrayList<List<?>>(altNames.size());
488: for (GeneralName name : altNames)
489: {
490: List<Object> n = new ArrayList<Object>(2);
491: n.add(name.kind().tag());
492: n.add(name.name());
493: names.add(n);
494: }
495: return names;
496: }
497: return null;
498: }
499:
500:
506: public byte[] getSubjectAsBytes() throws IOException
507: {
508: if (subject != null)
509: return subject.getEncoded();
510: else
511: return null;
512: }
513:
514:
520: public String getSubjectAsString()
521: {
522: if (subject != null)
523: return subject.getName();
524: else
525: return null;
526: }
527:
528:
535: public byte[] getSubjectKeyIdentifier()
536: {
537: if (subjectKeyId != null)
538: return (byte[]) subjectKeyId.clone();
539: else
540: return null;
541: }
542:
543:
549: public PublicKey getSubjectPublicKey()
550: {
551: return subjectKey;
552: }
553:
554:
560: public String getSubjectPublicKeyAlgID()
561: {
562: return String.valueOf(sigId);
563: }
564:
565:
573: public boolean match(Certificate certificate)
574: {
575: if (!(certificate instanceof X509Certificate))
576: return false;
577: X509Certificate cert = (X509Certificate) certificate;
578: if (this.cert != null)
579: {
580: try
581: {
582: byte[] e1 = this.cert.getEncoded();
583: byte[] e2 = cert.getEncoded();
584: if (!Arrays.equals(e1, e2))
585: return false;
586: }
587: catch (CertificateEncodingException cee)
588: {
589: return false;
590: }
591: }
592: if (serialNo != null)
593: {
594: if (!serialNo.equals(cert.getSerialNumber()))
595: return false;
596: }
597: if (certValid != null)
598: {
599: try
600: {
601: cert.checkValidity(certValid);
602: }
603: catch (CertificateException ce)
604: {
605: return false;
606: }
607: }
608: if (issuer != null)
609: {
610: if (!issuer.equals(cert.getIssuerX500Principal()))
611: return false;
612: }
613: if (subject != null)
614: {
615: if (!subject.equals(cert.getSubjectX500Principal()))
616: return false;
617: }
618: if (sigId != null)
619: {
620: if (!sigId.toString().equals(cert.getSigAlgOID()))
621: return false;
622: }
623: if (subjectKeyId != null)
624: {
625: byte[] b = cert.getExtensionValue(SUBJECT_KEY_ID);
626: if (!Arrays.equals(b, subjectKeyId))
627: return false;
628: }
629: if (authKeyId != null)
630: {
631: byte[] b = cert.getExtensionValue(AUTH_KEY_ID);
632: if (!Arrays.equals(b, authKeyId))
633: return false;
634: }
635: if (keyUsage != null)
636: {
637: boolean[] b = cert.getKeyUsage();
638: if (!Arrays.equals(b, keyUsage))
639: return false;
640: }
641: if (basicConstraints >= 0)
642: {
643: if (cert.getBasicConstraints() != basicConstraints)
644: return false;
645: }
646: if (keyPurposeSet != null)
647: {
648: List kp = null;
649: try
650: {
651: kp = cert.getExtendedKeyUsage();
652: }
653: catch (CertificateParsingException cpe)
654: {
655: return false;
656: }
657: if (kp == null)
658: return false;
659: for (Iterator it = keyPurposeSet.iterator(); it.hasNext(); )
660: {
661: if (!kp.contains(it.next()))
662: return false;
663: }
664: }
665: if (altNames != null)
666: {
667: Collection<List<?>> an = null;
668: try
669: {
670: an = cert.getSubjectAlternativeNames();
671: }
672: catch (CertificateParsingException cpe)
673: {
674: return false;
675: }
676: if (an == null)
677: return false;
678: int match = 0;
679: for (GeneralName name : altNames)
680: {
681: for (List<?> list : an)
682: {
683: try
684: {
685: Integer id = (Integer) list.get(0);
686: Object val = list.get(1);
687: GeneralName n = null;
688: if (val instanceof String)
689: n = makeName(id, (String) val);
690: else if (val instanceof byte[])
691: {
692: n = new GeneralName(GeneralName.Kind.forTag(id),
693: (byte[]) val);
694: }
695: else
696: continue;
697: if (name.equals(n))
698: match++;
699: }
700: catch (Exception e)
701: {
702: continue;
703: }
704: }
705: if (match == 0 || (matchAllNames && match < altNames.size()))
706: return false;
707: }
708: }
709: if (nameConstraints != null)
710: {
711: byte[] nc = cert.getExtensionValue(NAME_CONSTRAINTS_ID);
712: if (!Arrays.equals(nameConstraints, nc))
713: return false;
714: }
715:
716: if (policy != null)
717: {
718: CertificatePolicies policies = null;
719: if (cert instanceof GnuPKIExtension)
720: {
721: policies = (CertificatePolicies)
722: ((GnuPKIExtension) cert).getExtension(CertificatePolicies.ID).getValue();
723: }
724: else
725: {
726: byte[] policiesDer =
727: cert.getExtensionValue(CertificatePolicies.ID.toString());
728: try
729: {
730: policies = new CertificatePolicies(policiesDer);
731: }
732: catch (IOException ioe)
733: {
734:
735: }
736: }
737:
738: if (policies == null)
739: return false;
740: if (!policies.getPolicies().containsAll(policy))
741: return false;
742: }
743:
744: if (pathToNames != null)
745: {
746: NameConstraints nc = null;
747: if (cert instanceof GnuPKIExtension)
748: {
749: Extension e =
750: ((GnuPKIExtension) cert).getExtension(NameConstraints.ID);
751: if (e != null)
752: nc = (NameConstraints) e.getValue();
753: }
754: else
755: {
756: byte[] b = cert.getExtensionValue(NameConstraints.ID.toString());
757: if (b != null)
758: {
759: try
760: {
761: nc = new NameConstraints(b);
762: }
763: catch (IOException ioe)
764: {
765: }
766: }
767: }
768:
769: if (nc == null)
770: return false;
771:
772: int match = 0;
773: for (GeneralName name : pathToNames)
774: {
775: for (GeneralSubtree subtree : nc.permittedSubtrees())
776: {
777: if (name.equals(subtree.base()))
778: match++;
779: }
780: }
781: if (match == 0 || (matchAllNames && match < pathToNames.size()))
782: return false;
783: }
784:
785: return true;
786: }
787:
788:
794: public void setAuthorityKeyIdentifier(byte[] authKeyId)
795: {
796: this.authKeyId = authKeyId != null ? (byte[]) authKeyId.clone() : null;
797: }
798:
799:
804: public void setBasicConstraints(int basicConstraints)
805: {
806: if (basicConstraints < -1)
807: basicConstraints = -1;
808: this.basicConstraints = basicConstraints;
809: }
810:
811:
817: public void setCertificate(X509Certificate cert)
818: {
819: this.cert = cert;
820: }
821:
822:
828: public void setCertificateValid(Date certValid)
829: {
830: this.certValid = certValid != null ? (Date) certValid.clone() : null;
831: }
832:
833:
840: public void setExtendedKeyUsage(Set<String> keyPurposeSet) throws IOException
841: {
842: if (keyPurposeSet == null)
843: {
844: this.keyPurposeSet = null;
845: return;
846: }
847: Set<String> s = new HashSet<String>();
848: for (Iterator it = keyPurposeSet.iterator(); it.hasNext(); )
849: {
850: Object o = it.next();
851: if (!(o instanceof String))
852: throw new IOException("not a string: " + o);
853: try
854: {
855: OID oid = new OID((String) o);
856: int[] comp = oid.getIDs();
857: if (!checkOid(comp))
858: throw new IOException("malformed OID: " + o);
859: }
860: catch (IllegalArgumentException iae)
861: {
862: IOException ioe = new IOException("malformed OID: " + o);
863: ioe.initCause(iae);
864: throw ioe;
865: }
866: }
867: this.keyPurposeSet = s;
868: }
869:
870:
878: public void setIssuer(byte[] name) throws IOException
879: {
880: if (name != null)
881: {
882: try
883: {
884: issuer = new X500Principal(name);
885: }
886: catch (IllegalArgumentException iae)
887: {
888: throw new IOException(iae.getMessage());
889: }
890: }
891: