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: else
892: issuer = null;
893: }
894:
895:
903: public void setIssuer(String name) throws IOException
904: {
905: if (name != null)
906: {
907: try
908: {
909: issuer = new X500Principal(name);
910: }
911: catch (IllegalArgumentException iae)
912: {
913: throw new IOException(iae.getMessage());
914: }
915: }
916: else
917: issuer = null;
918: }
919:
920:
926: public void setKeyUsage(boolean[] keyUsage)
927: {
928: this.keyUsage = keyUsage != null ? (boolean[]) keyUsage.clone() : null;
929: }
930:
931:
939: public void setMatchAllSubjectAltNames(boolean matchAllNames)
940: {
941: this.matchAllNames = matchAllNames;
942: }
943:
944:
953: public void setNameConstraints(byte[] nameConstraints)
954: throws IOException
955: {
956:
957: new NameConstraints(nameConstraints);
958:
959:
960: this.nameConstraints = nameConstraints != null
961: ? (byte[]) nameConstraints.clone() : null;
962: }
963:
964:
976: public void setPathToNames(Collection<List<?>> names) throws IOException
977: {
978: if (names == null || names.size() == 0)
979: {
980: pathToNames = null;
981: }
982: else
983: {
984: pathToNames = new ArrayList<GeneralName>(names.size());
985: for (List<?> name : names)
986: {
987: Integer id = (Integer) name.get(0);
988: Object name2 = name.get(1);
989: if (name2 instanceof String)
990: addPathToName(id, (String) name2);
991: else if (name2 instanceof byte[])
992: addPathToName(id, (byte[]) name2);
993: else
994: throw new IOException("invalid name type: "
995: + name2.getClass().getName());
996: }
997: }
998: }
999:
1000:
1009: public void setPolicy(Set<String> policy) throws IOException
1010: {
1011: if (policy != null)
1012: {
1013: HashSet<OID> p = new HashSet<OID>(policy.size());
1014: for (String s : policy)
1015: {
1016: try
1017: {
1018: OID oid = new OID(s);
1019: int[] i = oid.getIDs();
1020: if (!checkOid(i))
1021: throw new IOException("invalid OID");
1022: p.add(oid);
1023: }
1024: catch (IOException ioe)
1025: {
1026: throw ioe;
1027: }
1028: catch (Exception x)
1029: {
1030: IOException ioe = new IOException("invalid OID");
1031: ioe.initCause(x);
1032: throw ioe;
1033: }
1034: }
1035: this.policy = p;
1036: }
1037: else
1038: this.policy = null;
1039: }
1040:
1041:
1052: public void setPrivateKeyValid(Date UNUSED)
1053: {
1054: }
1055:
1056:
1062: public void setSerialNumber(BigInteger serialNo)
1063: {
1064: this.serialNo = serialNo;
1065: }
1066:
1067:
1075: public void setSubject(byte[] name) throws IOException
1076: {
1077: if (name != null)
1078: {
1079: try
1080: {
1081: subject = new X500Principal(name);
1082: }
1083: catch (IllegalArgumentException iae)
1084: {
1085: throw new IOException(iae.getMessage());
1086: }
1087: }
1088: else
1089: subject = null;
1090: }
1091:
1092:
1100: public void setSubject(String name) throws IOException
1101: {
1102: if (name != null)
1103: {
1104: try
1105: {
1106: subject = new X500Principal(name);
1107: }
1108: catch (IllegalArgumentException iae)
1109: {
1110: throw new IOException(iae.getMessage());
1111: }
1112: }
1113: else
1114: subject = null;
1115: }
1116:
1117:
1127: public void setSubjectAlternativeNames(Collection<List<?>> altNames)
1128: throws IOException
1129: {
1130: if (altNames == null || altNames.isEmpty())
1131: {
1132: this.altNames = null;
1133: return;
1134: }
1135: List<GeneralName> l = new ArrayList<GeneralName>(altNames.size());
1136: for (List<?> list : altNames)
1137: {
1138: Integer id = (Integer) list.get(0);
1139: Object value = list.get(1);
1140: GeneralName name = null;
1141: if (value instanceof String)
1142: name = makeName(id, (String) value);
1143: else if (value instanceof byte[])
1144: name = new GeneralName(GeneralName.Kind.forTag(id), (byte[]) value);
1145: else
1146: throw new IOException("invalid name type: " + value.getClass().getName());
1147: l.add(name);
1148: }
1149: this.altNames = l;
1150: }
1151:
1152:
1158: public void setSubjectKeyIdentifier(byte[] subjectKeyId)
1159: {
1160: this.subjectKeyId = subjectKeyId != null ? (byte[]) subjectKeyId.clone() :
1161: null;
1162: }
1163:
1164:
1171: public void setSubjectPublicKey(byte[] key) throws IOException
1172: {
1173: if (key == null)
1174: {
1175: subjectKey = null;
1176: subjectKeySpec = null;
1177: return;
1178: }
1179: try
1180: {
1181: subjectKeySpec = new X509EncodedKeySpec(key);
1182: KeyFactory enc = KeyFactory.getInstance("X.509");
1183: subjectKey = enc.generatePublic(subjectKeySpec);
1184: }
1185: catch (Exception x)
1186: {
1187: subjectKey = null;
1188: subjectKeySpec = null;
1189: IOException ioe = new IOException(x.getMessage());
1190: ioe.initCause(x);
1191: throw ioe;
1192: }
1193: }
1194:
1195:
1201: public void setSubjectPublicKey(PublicKey key)
1202: {
1203: this.subjectKey = key;
1204: if (key == null)
1205: {
1206: subjectKeySpec = null;
1207: return;
1208: }
1209: try
1210: {
1211: KeyFactory enc = KeyFactory.getInstance("X.509");
1212: subjectKeySpec = (X509EncodedKeySpec)
1213: enc.getKeySpec(key, X509EncodedKeySpec.class);
1214: }
1215: catch (Exception x)
1216: {
1217: subjectKey = null;
1218: subjectKeySpec = null;
1219: }
1220: }
1221:
1222:
1229: public void setSubjectPublicKeyAlgID(String sigId) throws IOException
1230: {
1231: if (sigId != null)
1232: {
1233: try
1234: {
1235: OID oid = new OID(sigId);
1236: int[] comp = oid.getIDs();
1237: if (!checkOid(comp))
1238: throw new IOException("malformed OID: " + sigId);
1239: this.sigId = oid;
1240: }
1241: catch (IllegalArgumentException iae)
1242: {
1243: IOException ioe = new IOException("malformed OID: " + sigId);
1244: ioe.initCause(iae);
1245: throw ioe;
1246: }
1247: }
1248: else
1249: this.sigId = null;
1250: }
1251:
1252: public String toString()
1253: {
1254: StringBuffer str = new StringBuffer(X509CertSelector.class.getName());
1255: String nl = SystemProperties.getProperty("line.separator");
1256: String eol = ";" + nl;
1257: str.append(" {").append(nl);
1258: if (cert != null)
1259: str.append(" certificate = ").append(cert).append(eol);
1260: if (basicConstraints >= 0)
1261: str.append(" basic constraints = ").append(basicConstraints).append(eol);
1262: if (serialNo != null)
1263: str.append(" serial number = ").append(serialNo).append(eol);
1264: if (certValid != null)
1265: str.append(" valid date = ").append(certValid).append(eol);
1266: if (issuer != null)
1267: str.append(" issuer = ").append(issuer).append(eol);
1268: if (subject != null)
1269: str.append(" subject = ").append(subject).append(eol);
1270: if (sigId != null)
1271: str.append(" signature OID = ").append(sigId).append(eol);
1272: if (subjectKey != null)
1273: str.append(" subject public key = ").append(subjectKey).append(eol);
1274: if (subjectKeyId != null)
1275: {
1276: str.append(" subject key ID = ");
1277: for (int i = 0; i < subjectKeyId.length; i++)
1278: {
1279: str.append(Character.forDigit((subjectKeyId[i] & 0xF0) >>> 8, 16));
1280: str.append(Character.forDigit((subjectKeyId[i] & 0x0F), 16));
1281: if (i < subjectKeyId.length - 1)
1282: str.append(':');
1283: }
1284: str.append(eol);
1285: }
1286: if (authKeyId != null)
1287: {
1288: str.append(" authority key ID = ");
1289: for (int i = 0; i < authKeyId.length; i++)
1290: {
1291: str.append(Character.forDigit((authKeyId[i] & 0xF0) >>> 8, 16));
1292: str.append(Character.forDigit((authKeyId[i] & 0x0F), 16));
1293: if (i < authKeyId.length - 1)
1294: str.append(':');
1295: }
1296: str.append(eol);
1297: }
1298: if (keyUsage != null)
1299: {
1300: str.append(" key usage = ");
1301: for (int i = 0; i < keyUsage.length; i++)
1302: str.append(keyUsage[i] ? '1' : '0');
1303: str.append(eol);
1304: }
1305: if (keyPurposeSet != null)
1306: str.append(" key purpose = ").append(keyPurposeSet).append(eol);
1307: if (altNames != null)
1308: str.append(" alternative names = ").append(altNames).append(eol);
1309: if (nameConstraints != null)
1310: str.append(" name constraints = <blob of data>").append(eol);
1311: if (policy != null)
1312: str.append(" policy = ").append(policy).append(eol);
1313: if (pathToNames != null)
1314: str.append(" pathToNames = ").append(pathToNames).append(eol);
1315: str.append("}").append(nl);
1316: return str.toString();
1317: }
1318: }