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: import ;
51:
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: import ;
68:
69: import ;
70:
71:
90: public class X509CertSelector implements CertSelector, Cloneable
91: {
92:
93:
94:
95:
96: private static final String AUTH_KEY_ID = "2.5.29.35";
97: private static final String SUBJECT_KEY_ID = "2.5.29.14";
98: private static final String NAME_CONSTRAINTS_ID = "2.5.29.30";
99:
100: private static boolean checkOid(int[] oid)
101: {
102: return (oid != null && oid.length > 2 &&
103: (oid[0] >= 0 && oid[0] <= 2) && (oid[1] >= 0 && oid[1] <= 39));
104: }
105:
106: private static GeneralName makeName(int id, String name) throws IOException
107: {
108: byte[] nameBytes = null;
109: GeneralName.Kind kind = GeneralName.Kind.forTag(id);
110: switch (Kind.forTag(id))
111: {
112: case dNSName:
113: case rfc822Name:
114: case uniformResourceIdentifier:
115: nameBytes = name.getBytes("ASCII");
116: break;
117:
118: case iPAddress:
119: InetAddress addr = InetAddress.getByName(name);
120: nameBytes = addr.getAddress();
121: break;
122:
123: case registeredId:
124: OID oid = new OID(name);
125: nameBytes = oid.getDER();
126: break;
127:
128: case directoryName:
129: X500Principal xname = new X500Principal(name);
130: nameBytes = xname.getEncoded();
131: break;
132:
133: case ediPartyName:
134: case x400Address:
135: case otherName:
136: throw new IOException("cannot decode string representation of "
137: + kind);
138: }
139: return new GeneralName(kind, nameBytes);
140: }
141:
142: private int basicConstraints;
143: private X509Certificate cert;
144: private BigInteger serialNo;
145: private X500Principal issuer;
146: private X500Principal subject;
147: private byte[] subjectKeyId;
148: private byte[] authKeyId;
149: private boolean[] keyUsage;
150: private Date certValid;
151: private OID sigId;
152: private PublicKey subjectKey;
153: private X509EncodedKeySpec subjectKeySpec;
154: private Set<String> keyPurposeSet;
155: private List<GeneralName> altNames;
156: private boolean matchAllNames;
157: private byte[] nameConstraints;
158: private Set<OID> policy;
159: private List<GeneralName> pathToNames;
160:
161:
166: public X509CertSelector()
167: {
168: basicConstraints = -1;
169: }
170:
171:
182: public void addPathToName(int id, byte[] name) throws IOException
183: {
184: GeneralName generalName = new GeneralName(GeneralName.Kind.forTag(id), name);
185: if (pathToNames == null)
186: pathToNames = new LinkedList<GeneralName>();
187: pathToNames.add(generalName);
188: }
189:
190:
200: public void addPathToName(int id, String name) throws IOException
201: {
202: GeneralName generalName = makeName(id, name);
203: if (pathToNames == null)
204: pathToNames = new LinkedList<GeneralName>();
205: pathToNames.add(generalName);
206: }
207:
208:
231: public void addSubjectAlternativeName(int id, byte[] name)
232: throws IOException
233: {
234: GeneralName generalName = new GeneralName(GeneralName.Kind.forTag(id), name);
235: if (altNames == null)
236: altNames = new LinkedList<GeneralName>();
237: altNames.add(generalName);
238: }
239:
240:
253: public void addSubjectAlternativeName(int id, String name)
254: throws IOException
255: {
256: GeneralName generalName = makeName(id, name);
257: if (altNames == null)
258: altNames = new LinkedList<GeneralName>();
259: altNames.add(generalName);
260: }
261:
262: public Object clone()
263: {
264: try
265: {
266: return super.clone();
267: }
268: catch (CloneNotSupportedException shouldNotHappen)
269: {
270: throw new Error(shouldNotHappen);
271: }
272: }
273:
274:
281: public byte[] getAuthorityKeyIdentifier()
282: {
283: if (authKeyId != null)
284: return (byte[]) authKeyId.clone();
285: else
286: return null;
287: }
288:
289:
294: public int getBasicConstraints()
295: {
296: return basicConstraints;
297: }
298:
299:
305: public X509Certificate getCertificate()
306: {
307: return cert;
308: }
309:
310:
316: public Date getCertificateValid()
317: {
318: if (certValid != null)
319: return (Date) certValid.clone();
320: else
321: return null;
322: }
323:
324:
331: public Set<String> getExtendedKeyUsage()
332: {
333: if (keyPurposeSet != null)
334: return Collections.unmodifiableSet(keyPurposeSet);
335: else
336: return null;
337: }
338:
339:
345: public byte[] getIssuerAsBytes() throws IOException
346: {
347: if (issuer != null)
348: return issuer.getEncoded();
349: else
350: return null;
351: }
352:
353:
359: public String getIssuerAsString()
360: {
361: if (issuer != null)
362: return issuer.getName();
363: else
364: return null;
365: }
366:
367:
373: public boolean[] getKeyUsage()
374: {
375: if (keyUsage != null)
376: return (boolean[]) keyUsage.clone();
377: else
378: return null;
379: }
380:
381:
388: public boolean getMatchAllSubjectAltNames()
389: {
390: return matchAllNames;
391: }
392:
393:
400: public byte[] getNameConstraints()
401: {
402: if (nameConstraints != null)
403: return (byte[]) nameConstraints.clone();
404: else
405: return null;
406: }
407:
408: public Collection<List<?>> getPathToNames()
409: {
410: if (pathToNames != null)
411: {
412: List<List<?>> names = new ArrayList<List<?>>(pathToNames.size());
413: for (GeneralName name : pathToNames)
414: {
415: List<Object> n = new ArrayList<Object>(2);
416: n.add(name.kind().tag());
417: n.add(name.name());
418: names.add(n);
419: }
420:
421: return names;
422: }
423: return null;
424: }
425:
426:
432: public Set<String> getPolicy()
433: {
434: Set<OID> p = this.policy;
435: if (p != null)
436: {
437: Set<String> strings = new HashSet<String>(p.size());
438: for (OID o : p)
439: {
440: strings.add(o.toString());
441: }
442: return strings;
443: }
444: return null;
445: }
446:
447:
459: public Date getPrivateKeyValid()
460: {
461: return null;
462: }
463:
464:
470: public BigInteger getSerialNumber()
471: {
472: return serialNo;
473: }
474:
475:
484: public Collection<List<?>> getSubjectAlternativeNames()
485: {
486: if (altNames != null)
487: {
488: List<List<?>> names = new ArrayList<List<?>>(altNames.size());
489: for (GeneralName name : altNames)
490: {
491: List<Object> n = new ArrayList<Object>(2);
492: n.add(name.kind().tag());
493: n.add(name.name());
494: names.add(n);
495: }
496: return names;
497: }
498: return null;
499: }
500:
501:
507: public byte[] getSubjectAsBytes() throws IOException
508: {
509: if (subject != null)
510: return subject.getEncoded();
511: else
512: return null;
513: }
514:
515:
521: public String getSubjectAsString()
522: {
523: if (subject != null)
524: return subject.getName();
525: else
526: return null;
527: }
528:
529:
536: public byte[] getSubjectKeyIdentifier()
537: {
538: if (subjectKeyId != null)
539: return (byte[]) subjectKeyId.clone();
540: else
541: return null;
542: }
543:
544:
550: public PublicKey getSubjectPublicKey()
551: {
552: return subjectKey;
553: }
554:
555:
561: public String getSubjectPublicKeyAlgID()
562: {
563: return String.valueOf(sigId);
564: }
565:
566:
574: public boolean match(Certificate certificate)
575: {
576: if (!(certificate instanceof X509Certificate))
577: return false;
578: X509Certificate cert = (X509Certificate) certificate;
579: if (this.cert != null)
580: {
581: try
582: {
583: byte[] e1 = this.cert.getEncoded();
584: byte[] e2 = cert.getEncoded();
585: if (!Arrays.equals(e1, e2))
586: return false;
587: }
588: catch (CertificateEncodingException cee)
589: {
590: return false;
591: }
592: }
593: if (serialNo != null)
594: {
595: if (!serialNo.equals(cert.getSerialNumber()))
596: return false;
597: }
598: if (certValid != null)
599: {
600: try
601: {
602: cert.checkValidity(certValid);
603: }
604: catch (CertificateException ce)
605: {
606: return false;
607: }
608: }
609: if (issuer != null)
610: {
611: if (!issuer.equals(cert.getIssuerX500Principal()))
612: return false;
613: }
614: if (subject != null)
615: {
616: if (!subject.equals(cert.getSubjectX500Principal()))
617: return false;
618: }
619: if (sigId != null)
620: {
621: if (!sigId.toString().equals(cert.getSigAlgOID()))
622: return false;
623: }
624: if (subjectKeyId != null)
625: {
626: byte[] b = cert.getExtensionValue(SUBJECT_KEY_ID);
627: if (!Arrays.equals(b, subjectKeyId))
628: return false;
629: }
630: if (authKeyId != null)
631: {
632: byte[] b = cert.getExtensionValue(AUTH_KEY_ID);
633: if (!Arrays.equals(b, authKeyId))
634: return false;
635: }
636: if (keyUsage != null)
637: {
638: boolean[] b = cert.getKeyUsage();
639: if (!Arrays.equals(b, keyUsage))
640: return false;
641: }
642: if (basicConstraints >= 0)
643: {
644: if (cert.getBasicConstraints() != basicConstraints)
645: return false;
646: }
647: if (keyPurposeSet != null)
648: {
649: List kp = null;
650: try
651: {
652: kp = cert.getExtendedKeyUsage();
653: }
654: catch (CertificateParsingException cpe)
655: {
656: return false;
657: }
658: if (kp == null)
659: return false;
660: for (Iterator it = keyPurposeSet.iterator(); it.hasNext(); )
661: {
662: if (!kp.contains(it.next()))
663: return false;
664: }
665: }
666: if (altNames != null)
667: {
668: Collection<List<?>> an = null;
669: try
670: {
671: an = cert.getSubjectAlternativeNames();
672: }
673: catch (CertificateParsingException cpe)
674: {
675: return false;
676: }
677: if (an == null)
678: return false;
679: int match = 0;
680: for (GeneralName name : altNames)
681: {
682: for (List<?> list : an)
683: {
684: try
685: {
686: Integer id = (Integer) list.get(0);
687: Object val = list.get(1);
688: GeneralName n = null;
689: if (val instanceof String)
690: n = makeName(id, (String) val);
691: else if (val instanceof byte[])
692: {
693: n = new GeneralName(GeneralName.Kind.forTag(id),
694: (byte[]) val);
695: }
696: else
697: continue;
698: if (name.equals(n))
699: match++;
700: }
701: catch (Exception e)
702: {
703: continue;
704: }
705: }
706: if (match == 0 || (matchAllNames && match < altNames.size()))
707: return false;
708: }
709: }
710: if (nameConstraints != null)
711: {
712: byte[] nc = cert.getExtensionValue(NAME_CONSTRAINTS_ID);
713: if (!Arrays.equals(nameConstraints, nc))
714: return false;
715: }
716:
717: if (policy != null)
718: {
719: CertificatePolicies policies = null;
720: if (cert instanceof GnuPKIExtension)
721: {
722: policies = (CertificatePolicies)
723: ((GnuPKIExtension) cert).getExtension(CertificatePolicies.ID).getValue();
724: }
725: else
726: {
727: byte[] policiesDer =
728: cert.getExtensionValue(CertificatePolicies.ID.toString());
729: try
730: {
731: policies = new CertificatePolicies(policiesDer);
732: }
733: catch (IOException ioe)
734: {
735:
736: }
737: }
738:
739: if (policies == null)
740: return false;
741: if (!policies.getPolicies().containsAll(policy))
742: return false;
743: }
744:
745: if (pathToNames != null)
746: {
747: NameConstraints nc = null;
748: if (cert instanceof GnuPKIExtension)
749: {
750: Extension e =
751: ((GnuPKIExtension) cert).getExtension(NameConstraints.ID);
752: if (e != null)
753: nc = (NameConstraints) e.getValue();
754: }
755: else
756: {
757: byte[] b = cert.getExtensionValue(NameConstraints.ID.toString());
758: if (b != null)
759: {
760: try
761: {
762: nc = new NameConstraints(b);
763: }
764: catch (IOException ioe)
765: {
766: }
767: }
768: }
769:
770: if (nc == null)
771: return false;
772:
773: int match = 0;
774: for (GeneralName name : pathToNames)
775: {
776: for (GeneralSubtree subtree : nc.permittedSubtrees())
777: {
778: if (name.equals(subtree.base()))
779: match++;
780: }
781: }
782: if (match == 0 || (matchAllNames && match < pathToNames.size()))
783: return false;
784: }
785:
786: return true;
787: }
788:
789:
795: public void setAuthorityKeyIdentifier(byte[] authKeyId)
796: {
797: this.authKeyId = authKeyId != null ? (byte[]) authKeyId.clone() : null;
798: }
799:
800:
805: public void setBasicConstraints(int basicConstraints)
806: {
807: if (basicConstraints < -1)
808: basicConstraints = -1;
809: this.basicConstraints = basicConstraints;
810: }
811:
812:
818: public void setCertificate(X509Certificate cert)
819: {
820: this.cert = cert;
821: }
822:
823:
829: public void setCertificateValid(Date certValid)
830: {
831: this.certValid = certValid != null ? (Date) certValid.clone() : null;
832: }
833:
834:
841: public void setExtendedKeyUsage(Set<String> keyPurposeSet) throws IOException
842: {
843: if (keyPurposeSet == null)
844: {
845: this.keyPurposeSet = null;
846: return;
847: }
848: Set<String> s = new HashSet<String>();
849: for (Iterator it = keyPurposeSet.iterator(); it.hasNext(); )
850: {
851: Object o = it.next();
852: if (!(o instanceof String))
853: throw new IOException("not a string: " + o);
854: try
855: {
856: OID oid = new OID((String) o);
857: int[] comp = oid.getIDs();
858: if (!checkOid(comp))
859: throw new IOException("malformed OID: " + o);
860: }
861: catch (IllegalArgumentException iae)
862: {
863: IOException ioe = new IOException("malformed OID: " + o);
864: ioe.initCause(iae);
865: throw ioe;
866: }
867: }
868: this.keyPurposeSet = s;
869: }
870:
871:
879: public void setIssuer(byte[] name) throws IOException
880: {
881: if (name != null)
882: {
883: try
884: {
885: issuer = new X500Principal(name);
886: }
887: catch (IllegalArgumentException iae)
888: {
889: throw new IOException(iae.getMessage());
890: }
891: }
892: else
893: issuer = null;
894: }
895:
896:
904: public void setIssuer(String name) throws IOException
905: {
906: if (name != null)
907: {
908: try
909: {
910: issuer = new X500Principal(name);
911: }
912: catch (IllegalArgumentException iae)
913: {
914: throw new IOException(iae.getMessage());
915: }
916: }
917: else
918: issuer = null;
919: }
920:
921:
927: public void setKeyUsage(boolean[] keyUsage)
928: {
929: this.keyUsage = keyUsage != null ? (boolean[]) keyUsage.clone() : null;
930: }
931:
932:
940: public void setMatchAllSubjectAltNames(boolean matchAllNames)
941: {
942: this.matchAllNames = matchAllNames;
943: }
944:
945:
954: public void setNameConstraints(byte[] nameConstraints)
955: throws IOException
956: {
957:
958: new NameConstraints(nameConstraints);
959:
960:
961: this.nameConstraints = nameConstraints != null
962: ? (byte[]) nameConstraints.clone() : null;
963: }
964:
965:
977: public void setPathToNames(Collection<List<?>> names) throws IOException
978: {
979: if (names == null || names.size() == 0)
980: {
981: pathToNames = null;
982: }
983: else
984: {
985: pathToNames = new ArrayList<GeneralName>(names.size());
986: for (List<?> name : names)
987: {
988: Integer id = (Integer) name.get(0);
989: Object name2 = name.get(1);
990: if (name2 instanceof String)
991: addPathToName(id, (String) name2);
992: else if (name2 instanceof byte[])
993: addPathToName(id, (byte[]) name2);
994: else
995: throw new IOException("invalid name type: "
996: + name2.getClass().getName());
997: }
998: }
999: }
1000:
1001:
1010: public void setPolicy(Set<String> policy) throws IOException
1011: {
1012: if (policy != null)
1013: {
1014: HashSet<OID> p = new HashSet<OID>(policy.size());
1015: for (String s : policy)
1016: {
1017: try
1018: {
1019: OID oid = new OID(s);
1020: int[] i = oid.getIDs();
1021: if (!checkOid(i))
1022: throw new IOException("invalid OID");
1023: p.add(oid);
1024: }
1025: catch (IOException ioe)
1026: {
1027: throw ioe;
1028: }
1029: catch (Exception x)
1030: {
1031: IOException ioe = new IOException("invalid OID");
1032: ioe.initCause(x);
1033: throw ioe;
1034: }
1035: }
1036: this.policy = p;
1037: }
1038: else
1039: this.policy = null;
1040: }
1041:
1042:
1053: public void setPrivateKeyValid(Date UNUSED)
1054: {
1055: }
1056:
1057:
1063: public void setSerialNumber(BigInteger serialNo)
1064: {
1065: this.serialNo = serialNo;
1066: }
1067:
1068:
1076: public void setSubject(byte[] name) throws IOException
1077: {
1078: if (name != null)
1079: {
1080: try
1081: {
1082: subject = new X500Principal(name);
1083: }
1084: catch (IllegalArgumentException iae)
1085: {
1086: throw new IOException(iae.getMessage());
1087: }
1088: }
1089: else
1090: subject = null;
1091: }
1092:
1093:
1101: public void setSubject(String name) throws IOException
1102: {
1103: if (name != null)
1104: {
1105: try
1106: {
1107: subject = new X500Principal(name);
1108: }
1109: catch (IllegalArgumentException iae)
1110: {
1111: throw new IOException(iae.getMessage());
1112: }
1113: }
1114: else
1115: subject = null;
1116: }
1117:
1118:
1128: public void setSubjectAlternativeNames(Collection<List<?>> altNames)
1129: throws IOException
1130: {
1131: if (altNames == null || altNames.isEmpty())
1132: {
1133: this.altNames = null;
1134: return;
1135: }
1136: List<GeneralName> l = new ArrayList<GeneralName>(altNames.size());
1137: for (List<?> list : altNames)
1138: {
1139: Integer id = (Integer) list.get(0);
1140: Object value = list.get(1);
1141: GeneralName name = null;
1142: if (value instanceof String)
1143: name = makeName(id, (String) value);
1144: else if (value instanceof byte[])
1145: name = new GeneralName(GeneralName.Kind.forTag(id), (byte[]) value);
1146: else
1147: throw new IOException("invalid name type: " + value.getClass().getName());
1148: l.add(name);
1149: }
1150: this.altNames = l;
1151: }
1152:
1153:
1159: public void setSubjectKeyIdentifier(byte[] subjectKeyId)
1160: {
1161: this.subjectKeyId = subjectKeyId != null ? (byte[]) subjectKeyId.clone() :
1162: null;
1163: }
1164:
1165:
1172: public void setSubjectPublicKey(byte[] key) throws IOException
1173: {
1174: if (key == null)
1175: {
1176: subjectKey = null;
1177: subjectKeySpec = null;
1178: return;
1179: }
1180: try
1181: {
1182: subjectKeySpec = new X509EncodedKeySpec(key);
1183: KeyFactory enc = KeyFactory.getInstance("X.509");
1184: subjectKey = enc.generatePublic(subjectKeySpec);
1185: }
1186: catch (Exception x)
1187: {
1188: subjectKey = null;
1189: subjectKeySpec = null;
1190: IOException ioe = new IOException(x.getMessage());
1191: ioe.initCause(x);
1192: throw ioe;
1193: }
1194: }
1195:
1196:
1202: public void setSubjectPublicKey(PublicKey key)
1203: {
1204: this.subjectKey = key;
1205: if (key == null)
1206: {
1207: subjectKeySpec = null;
1208: return;
1209: }
1210: try
1211: {
1212: KeyFactory enc = KeyFactory.getInstance("X.509");
1213: subjectKeySpec = (X509EncodedKeySpec)
1214: enc.getKeySpec(key, X509EncodedKeySpec.class);
1215: }
1216: catch (Exception x)
1217: {
1218: subjectKey = null;
1219: subjectKeySpec = null;
1220: }
1221: }
1222:
1223:
1230: public void setSubjectPublicKeyAlgID(String sigId) throws IOException
1231: {
1232: if (sigId != null)
1233: {
1234: try
1235: {
1236: OID oid = new OID(sigId);
1237: int[] comp = oid.getIDs();
1238: if (!checkOid(comp))
1239: throw new IOException("malformed OID: " + sigId);
1240: this.sigId = oid;
1241: }
1242: catch (IllegalArgumentException iae)
1243: {
1244: IOException ioe = new IOException("malformed OID: " + sigId);
1245: ioe.initCause(iae);
1246: throw ioe;
1247: }
1248: }
1249: else
1250: this.sigId = null;
1251: }
1252:
1253: public String toString()
1254: {
1255: CPStringBuilder str = new CPStringBuilder(X509CertSelector.class.getName());
1256: String nl = SystemProperties.getProperty("line.separator");
1257: String eol = ";" + nl;
1258: str.append(" {").append(nl);
1259: if (cert != null)
1260: str.append(" certificate = ").append(cert).append(eol);
1261: if (basicConstraints >= 0)
1262: str.append(" basic constraints = ").append(basicConstraints).append(eol);
1263: if (serialNo != null)
1264: str.append(" serial number = ").append(serialNo).append(eol);
1265: if (certValid != null)
1266: str.append(" valid date = ").append(certValid).append(eol);
1267: if (issuer != null)
1268: str.append(" issuer = ").append(issuer).append(eol);
1269: if (subject != null)
1270: str.append(" subject = ").append(subject).append(eol);
1271: if (sigId != null)
1272: str.append(" signature OID = ").append(sigId).append(eol);
1273: if (subjectKey != null)
1274: str.append(" subject public key = ").append(subjectKey).append(eol);
1275: if (subjectKeyId != null)
1276: {
1277: str.append(" subject key ID = ");
1278: for (int i = 0; i < subjectKeyId.length; i++)
1279: {
1280: str.append(Character.forDigit((subjectKeyId[i] & 0xF0) >>> 8, 16));
1281: str.append(Character.forDigit((subjectKeyId[i] & 0x0F), 16));
1282: if (i < subjectKeyId.length - 1)
1283: str.append(':');
1284: }
1285: str.append(eol);
1286: }
1287: if (authKeyId != null)
1288: {
1289: str.append(" authority key ID = ");
1290: for (int i = 0; i < authKeyId.length; i++)
1291: {
1292: str.append(Character.forDigit((authKeyId[i] & 0xF0) >>> 8, 16));
1293: str.append(Character.forDigit((authKeyId[i] & 0x0F), 16));
1294: if (i < authKeyId.length - 1)
1295: str.append(':');
1296: }
1297: str.append(eol);
1298: }
1299: if (keyUsage != null)
1300: {
1301: str.append(" key usage = ");
1302: for (int i = 0; i < keyUsage.length; i++)
1303: str.append(keyUsage[i] ? '1' : '0');
1304: str.append(eol);
1305: }
1306: if (keyPurposeSet != null)
1307: str.append(" key purpose = ").append(keyPurposeSet).append(eol);
1308: if (altNames != null)
1309: str.append(" alternative names = ").append(altNames).append(eol);
1310: if (nameConstraints != null)
1311: str.append(" name constraints = <blob of data>").append(eol);
1312: if (policy != null)
1313: str.append(" policy = ").append(policy).append(eol);
1314: if (pathToNames != null)
1315: str.append(" pathToNames = ").append(pathToNames).append(eol);
1316: str.append("}").append(nl);
1317: return str.toString();
1318: }
1319: }