1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43:
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59:
60: import ;
61:
62:
80: public class X509CertSelector implements CertSelector, Cloneable
81: {
82:
83:
84:
85:
86: private static final String AUTH_KEY_ID = "2.5.29.35";
87: private static final String SUBJECT_KEY_ID = "2.5.29.14";
88: private static final String NAME_CONSTRAINTS_ID = "2.5.29.30";
89:
90: private int basicConstraints;
91: private X509Certificate cert;
92: private BigInteger serialNo;
93: private X500Principal issuer;
94: private X500Principal subject;
95: private byte[] subjectKeyId;
96: private byte[] authKeyId;
97: private boolean[] keyUsage;
98: private Date certValid;
99: private OID sigId;
100: private PublicKey subjectKey;
101: private X509EncodedKeySpec subjectKeySpec;
102: private Set keyPurposeSet;
103: private List altNames;
104: private boolean matchAllNames;
105: private byte[] nameConstraints;
106: private Set policy;
107:
108:
109:
110:
111:
116: public X509CertSelector()
117: {
118: basicConstraints = -1;
119: }
120:
121:
122:
123:
124:
130: public X509Certificate getCertificate()
131: {
132: return cert;
133: }
134:
135:
141: public void setCertificate(X509Certificate cert)
142: {
143: this.cert = cert;
144: }
145:
146:
152: public BigInteger getSerialNumber()
153: {
154: return serialNo;
155: }
156:
157:
163: public void setSerialNumber(BigInteger serialNo)
164: {
165: this.serialNo = serialNo;
166: }
167:
168:
174: public String getIssuerAsString()
175: {
176: if (issuer != null)
177: return issuer.getName();
178: else
179: return null;
180: }
181:
182:
188: public byte[] getIssuerAsBytes() throws IOException
189: {
190: if (issuer != null)
191: return issuer.getEncoded();
192: else
193: return null;
194: }
195:
196:
204: public void setIssuer(String name) throws IOException
205: {
206: if (name != null)
207: {
208: try
209: {
210: issuer = new X500Principal(name);
211: }
212: catch (IllegalArgumentException iae)
213: {
214: throw new IOException(iae.getMessage());
215: }
216: }
217: else
218: issuer = null;
219: }
220:
221:
229: public void setIssuer(byte[] name) throws IOException
230: {
231: if (name != null)
232: {
233: try
234: {
235: issuer = new X500Principal(name);
236: }
237: catch (IllegalArgumentException iae)
238: {
239: throw new IOException(iae.getMessage());
240: }
241: }
242: else
243: issuer = null;
244: }
245:
246:
252: public String getSubjectAsString()
253: {
254: if (subject != null)
255: return subject.getName();
256: else
257: return null;
258: }
259:
260:
266: public byte[] getSubjectAsBytes() throws IOException
267: {
268: if (subject != null)
269: return subject.getEncoded();
270: else
271: return null;
272: }
273:
274:
282: public void setSubject(String name) throws IOException
283: {
284: if (name != null)
285: {
286: try
287: {
288: subject = new X500Principal(name);
289: }
290: catch (IllegalArgumentException iae)
291: {
292: throw new IOException(iae.getMessage());
293: }
294: }
295: else
296: subject = null;
297: }
298:
299:
307: public void setSubject(byte[] name) throws IOException
308: {
309: if (name != null)
310: {
311: try
312: {
313: subject = new X500Principal(name);
314: }
315: catch (IllegalArgumentException iae)
316: {
317: throw new IOException(iae.getMessage());
318: }
319: }
320: else
321: subject = null;
322: }
323:
324:
331: public byte[] getSubjectKeyIdentifier()
332: {
333: if (subjectKeyId != null)
334: return (byte[]) subjectKeyId.clone();
335: else
336: return null;
337: }
338:
339:
345: public void setSubjectKeyIdentifier(byte[] subjectKeyId)
346: {
347: this.subjectKeyId = subjectKeyId != null ? (byte[]) subjectKeyId.clone() :
348: null;
349: }
350:
351:
358: public byte[] getAuthorityKeyIdentifier()
359: {
360: if (authKeyId != null)
361: return (byte[]) authKeyId.clone();
362: else
363: return null;
364: }
365:
366:
372: public void setAuthorityKeyIdentifier(byte[] authKeyId)
373: {
374: this.authKeyId = authKeyId != null ? (byte[]) authKeyId.clone() : null;
375: }
376:
377:
383: public Date getCertificateValid()
384: {
385: if (certValid != null)
386: return (Date) certValid.clone();
387: else
388: return null;
389: }
390:
391:
397: public void setCertificateValid(Date certValid)
398: {
399: this.certValid = certValid != null ? (Date) certValid.clone() : null;
400: }
401:
402:
414: public Date getPrivateKeyValid()
415: {
416: return null;
417: }
418:
419:
430: public void setPrivateKeyValid(Date UNUSED)
431: {
432: }
433:
434:
440: public String getSubjectPublicKeyAlgID()
441: {
442: return String.valueOf(sigId);
443: }
444:
445:
452: public void setSubjectPublicKeyAlgID(String sigId) throws IOException
453: {
454: if (sigId != null)
455: {
456: try
457: {
458: OID oid = new OID(sigId);
459: int[] comp = oid.getIDs();
460: if (!checkOid(comp))
461: throw new IOException("malformed OID: " + sigId);
462: this.sigId = oid;
463: }
464: catch (IllegalArgumentException iae)
465: {
466: IOException ioe = new IOException("malformed OID: " + sigId);
467: ioe.initCause(iae);
468: throw ioe;
469: }
470: }
471: else
472: this.sigId = null;
473: }
474:
475:
481: public PublicKey getSubjectPublicKey()
482: {
483: return subjectKey;
484: }
485:
486:
492: public void setSubjectPublicKey(PublicKey key)
493: {
494: this.subjectKey = key;
495: if (key == null)
496: {
497: subjectKeySpec = null;
498: return;
499: }
500: try
501: {
502: KeyFactory enc = KeyFactory.getInstance("X.509");
503: subjectKeySpec = (X509EncodedKeySpec)
504: enc.getKeySpec(key, X509EncodedKeySpec.class);
505: }
506: catch (Exception x)
507: {
508: subjectKey = null;
509: subjectKeySpec = null;
510: }
511: }
512:
513:
520: public void setSubjectPublicKey(byte[] key) throws IOException
521: {
522: if (key == null)
523: {
524: subjectKey = null;
525: subjectKeySpec = null;
526: return;
527: }
528: try
529: {
530: subjectKeySpec = new X509EncodedKeySpec(key);
531: KeyFactory enc = KeyFactory.getInstance("X.509");
532: subjectKey = enc.generatePublic(subjectKeySpec);
533: }
534: catch (Exception x)
535: {
536: subjectKey = null;
537: subjectKeySpec = null;
538: IOException ioe = new IOException(x.getMessage());
539: ioe.initCause(x);
540: throw ioe;
541: }
542: }
543:
544:
550: public boolean[] getKeyUsage()
551: {
552: if (keyUsage != null)
553: return (boolean[]) keyUsage.clone();
554: else
555: return null;
556: }
557:
558:
564: public void setKeyUsage(boolean[] keyUsage)
565: {
566: this.keyUsage = keyUsage != null ? (boolean[]) keyUsage.clone() : null;
567: }
568:
569:
576: public Set getExtendedKeyUsage()
577: {
578: if (keyPurposeSet != null)
579: return Collections.unmodifiableSet(keyPurposeSet);
580: else
581: return null;
582: }
583:
584:
591: public void setExtendedKeyUsage(Set keyPurposeSet) throws IOException
592: {
593: if (keyPurposeSet == null)
594: {
595: this.keyPurposeSet = null;
596: return;
597: }
598: Set s = new HashSet();
599: for (Iterator it = keyPurposeSet.iterator(); it.hasNext(); )
600: {
601: Object o = it.next();
602: if (!(o instanceof String))
603: throw new IOException("not a string: " + o);
604: try
605: {
606: OID oid = new OID((String) o);
607: int[] comp = oid.getIDs();
608: if (!checkOid(comp))
609: throw new IOException("malformed OID: " + o);
610: }
611: catch (IllegalArgumentException iae)
612: {
613: IOException ioe = new IOException("malformed OID: " + o);
614: ioe.initCause(iae);
615: throw ioe;
616: }
617: }
618: this.keyPurposeSet = s;
619: }
620:
621:
628: public boolean getMatchAllSubjectAltNames()
629: {
630: return matchAllNames;
631: }
632:
633:
641: public void setMatchAllSubjectAltNames(boolean matchAllNames)
642: {
643: this.matchAllNames = matchAllNames;
644: }
645:
646:
656: public void setSubjectAlternativeNames(Collection altNames)
657: throws IOException
658: {
659: if (altNames == null)
660: {
661: this.altNames = null;
662: return;
663: }
664: List l = new ArrayList(altNames.size());
665: for (Iterator it = altNames.iterator(); it.hasNext(); )
666: {
667: Object o = it.next();
668: if (!(o instanceof List) || ((List) o).size() != 2 ||
669: !(((List) o).get(0) instanceof Integer) ||
670: !(((List) o).get(1) instanceof String) ||
671: !(((List) o).get(1) instanceof byte[]))
672: throw new IOException("illegal alternative name: " + o);
673: Integer i = (Integer) ((List) o).get(0);
674: if (i.intValue() < 0 || i.intValue() > 8)
675: throw new IOException("illegal alternative name: " + o +
676: ", bad id: " + i);
677: l.add(new ArrayList((List) o));
678: }
679: this.altNames = l;
680: }
681:
682:
690: public void addSubjectAlternativeName(int id, String name)
691: throws IOException
692: {
693: if (id < 0 || id > 8 || name == null)
694: throw new IOException("illegal alternative name");
695: if (altNames == null)
696: altNames = new LinkedList();
697: ArrayList l = new ArrayList(2);
698: l.add(new Integer(id));
699: l.add(name);
700: altNames.add(l);
701: }
702:
703:
709: public void addSubjectAlternativeName(int id, byte[] name)
710: throws IOException
711: {
712: if (id < 0 || id > 8 || name == null)
713: throw new IOException("illegal alternative name");
714: if (altNames == null)
715: altNames = new LinkedList();
716: ArrayList l = new ArrayList(2);
717: l.add(new Integer(id));
718: l.add(name);
719: altNames.add(l);
720: }
721:
722:
729: public byte[] getNameConstraints()
730: {
731: if (nameConstraints != null)
732: return (byte[]) nameConstraints.clone();
733: else
734: return null;
735: }
736:
737:
746: public void setNameConstraints(byte[] nameConstraints)
747: throws IOException
748: {
749:
750: this.nameConstraints = nameConstraints != null
751: ? (byte[]) nameConstraints.clone() : null;
752: }
753:
754:
759: public int getBasicConstraints()
760: {
761: return basicConstraints;
762: }
763:
764:
769: public void setBasicConstraints(int basicConstraints)
770: {
771: if (basicConstraints < -1)
772: basicConstraints = -1;
773: this.basicConstraints = basicConstraints;
774: }
775:
776:
777:
778:
779:
780:
781:
782:
783:
784:
785:
786:
787:
788:
789:
790:
791:
792:
793:
794:
795:
796:
797:
798:
799:
800:
801:
802:
803:
804:
805:
806:
807:
808:
809:
810:
811:
812:
813:
814:
815:
816:
817:
818:
819:
820:
821:
822:
823:
824:
825:
826:
827:
828:
829:
830:
831:
832:
833:
834:
835:
836:
837:
838:
839:
840:
841:
842:
843:
844:
845:
846:
847:
848:
849:
850:
851:
852:
853:
854:
855:
856:
857:
858:
859:
860:
861:
862:
863:
871: public boolean match(Certificate certificate)
872: {
873: if (!(certificate instanceof X509Certificate))
874: return false;
875: X509Certificate cert = (X509Certificate) certificate;
876: if (this.cert != null)
877: {
878: try
879: {
880: byte[] e1 = this.cert.getEncoded();
881: byte[] e2 = cert.getEncoded();
882: if (!Arrays.equals(e1, e2))
883: return false;
884: }
885: catch (CertificateEncodingException cee)
886: {
887: return false;
888: }
889: }
890: if (serialNo != null)
891: {
892: if (!serialNo.equals(cert.getSerialNumber()))
893: return false;
894: }
895: if (certValid != null)
896: {
897: try
898: {
899: cert.checkValidity(certValid);
900: }
901: catch (CertificateException ce)
902: {
903: return false;
904: }
905: }
906: if (issuer != null)
907: {
908: if (!issuer.equals(cert.getIssuerX500Principal()))
909: return false;
910: }
911: if (subject != null)
912: {
913: if (!subject.equals(cert.getSubjectX500Principal()))
914: return false;
915: }
916: if (sigId != null)
917: {
918: if (!sigId.toString().equals(cert.getSigAlgOID()))
919: return false;
920: }
921: if (subjectKeyId != null)
922: {
923: byte[] b = cert.getExtensionValue(SUBJECT_KEY_ID);
924: if (!Arrays.equals(b, subjectKeyId))
925: return false;
926: }
927: if (authKeyId != null)
928: {
929: byte[] b = cert.getExtensionValue(AUTH_KEY_ID);
930: if (!Arrays.equals(b, authKeyId))
931: return false;
932: }
933: if (keyUsage != null)
934: {
935: boolean[] b = cert.getKeyUsage();
936: if (!Arrays.equals(b, keyUsage))
937: return false;
938: }
939: if (basicConstraints >= 0)
940: {
941: if (cert.getBasicConstraints() != basicConstraints)
942: return false;
943: }
944: if (keyPurposeSet != null)
945: {
946: List kp = null;
947: try
948: {
949: kp = cert.getExtendedKeyUsage();
950: }
951: catch (CertificateParsingException cpe)
952: {
953: return false;
954: }
955: if (kp == null)
956: return false;
957: for (Iterator it = keyPurposeSet.iterator(); it.hasNext(); )
958: {
959: if (!kp.contains(it.next()))
960: return false;
961: }
962: }
963: if (altNames != null)
964: {
965: Collection an = null;
966: try
967: {
968: an = cert.getSubjectAlternativeNames();
969: }
970: catch (CertificateParsingException cpe)
971: {
972: return false;
973: }
974: if (an == null)
975: return false;
976: int match = 0;
977: for (Iterator it = altNames.iterator(); it.hasNext(); )
978: {
979: List l = (List) it.next();
980: Integer id = (Integer) l.get(0);
981: String s = null;
982: byte[] b = null;
983: if (l.get(1) instanceof String)
984: s = (String) l.get(1);
985: else if (l.get(1) instanceof byte[])
986: b = (byte[]) l.get(1);
987: else
988: return false;
989: for (Iterator it2 = an.iterator(); it2.hasNext(); )
990: {
991: Object o = it2.next();
992: if (!(o instanceof List))
993: continue;
994: List l2 = (List) o;
995: if (l2.size() != 2)
996: continue;
997: if (!id.equals(l2.get(0)))
998: continue;
999: if (s != null && (l2.get(1) instanceof String) &&
1000: s.equals(l2.get(1)))
1001: match++;
1002: else if (b != null && (l2.get(1) instanceof byte[]) &&
1003: Arrays.equals(b, (byte[]) l2.get(1)))
1004: match++;
1005: }
1006: if (match == 0 || (matchAllNames && match != altNames.size()))
1007: return false;
1008: }
1009: }
1010: if (nameConstraints != null)
1011: {
1012: byte[] nc = cert.getExtensionValue(NAME_CONSTRAINTS_ID);
1013: if (!Arrays.equals(nameConstraints, nc))
1014: return false;
1015: }
1016:
1017:
1018:
1019:
1020: return true;
1021: }
1022:
1023: public String toString()
1024: {
1025: StringBuffer str = new StringBuffer(X509CertSelector.class.getName());
1026: String nl = SystemProperties.getProperty("line.separator");
1027: String eol = ";" + nl;
1028: str.append(" {").append(nl);
1029: if (cert != null)
1030: str.append(" certificate = ").append(cert).append(eol);
1031: if (basicConstraints >= 0)
1032: str.append(" basic constraints = ").append(basicConstraints).append(eol);
1033: if (serialNo != null)
1034: str.append(" serial number = ").append(serialNo).append(eol);
1035: if (certValid != null)
1036: str.append(" valid date = ").append(certValid).append(eol);
1037: if (issuer != null)
1038: str.append(" issuer = ").append(issuer).append(eol);
1039: if (subject != null)
1040: str.append(" subject = ").append(subject).append(eol);
1041: if (sigId != null)
1042: str.append(" signature OID = ").append(sigId).append(eol);
1043: if (subjectKey != null)
1044: str.append(" subject public key = ").append(subjectKey).append(eol);
1045: if (subjectKeyId != null)
1046: {
1047: str.append(" subject key ID = ");
1048: for (int i = 0; i < subjectKeyId.length; i++)
1049: {
1050: str.append(Character.forDigit((subjectKeyId[i] & 0xF0) >>> 8, 16));
1051: str.append(Character.forDigit((subjectKeyId[i] & 0x0F), 16));
1052: if (i < subjectKeyId.length - 1)
1053: str.append(':');
1054: }
1055: str.append(eol);
1056: }
1057: if (authKeyId != null)
1058: {
1059: str.append(" authority key ID = ");
1060: for (int i = 0; i < authKeyId.length; i++)
1061: {
1062: str.append(Character.forDigit((authKeyId[i] & 0xF0) >>> 8, 16));
1063: str.append(Character.forDigit((authKeyId[i] & 0x0F), 16));
1064: if (i < authKeyId.length - 1)
1065: str.append(':');
1066: }
1067: str.append(eol);
1068: }
1069: if (keyUsage != null)
1070: {
1071: str.append(" key usage = ");
1072: for (int i = 0; i < keyUsage.length; i++)
1073: str.append(keyUsage[i] ? '1' : '0');
1074: str.append(eol);
1075: }
1076: if (keyPurposeSet != null)
1077: str.append(" key purpose = ").append(keyPurposeSet).append(eol);
1078: if (altNames != null)
1079: str.append(" alternative names = ").append(altNames).append(eol);
1080: if (nameConstraints != null)
1081: str.append(" name constraints = <blob of data>").append(eol);
1082: str.append("}").append(nl);
1083: return str.toString();
1084: }
1085:
1086: public Object clone()
1087: {
1088: try
1089: {
1090: return super.clone();
1091: }
1092: catch (CloneNotSupportedException shouldNotHappen)
1093: {
1094: throw new Error(shouldNotHappen);
1095: }
1096: }
1097:
1098:
1099:
1100:
1101: private static boolean checkOid(int[] oid)
1102: {
1103: return (oid != null && oid.length > 2 &&
1104: (oid[0] >= 0 && oid[0] <= 2) && (oid[1] >= 0 && oid[1] <= 39));
1105: }
1106: }