001 /* X509CertSelector.java -- selects X.509 certificates by criteria.
002 Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package java.security.cert;
040
041 import gnu.classpath.SystemProperties;
042 import gnu.java.lang.CPStringBuilder;
043 import gnu.java.security.OID;
044 import gnu.java.security.x509.GnuPKIExtension;
045 import gnu.java.security.x509.ext.CertificatePolicies;
046 import gnu.java.security.x509.ext.Extension;
047 import gnu.java.security.x509.ext.GeneralName;
048 import gnu.java.security.x509.ext.GeneralSubtree;
049 import gnu.java.security.x509.ext.NameConstraints;
050 import gnu.java.security.x509.ext.GeneralName.Kind;
051
052 import java.io.IOException;
053 import java.math.BigInteger;
054 import java.net.InetAddress;
055 import java.security.KeyFactory;
056 import java.security.PublicKey;
057 import java.security.spec.X509EncodedKeySpec;
058 import java.util.ArrayList;
059 import java.util.Arrays;
060 import java.util.Collection;
061 import java.util.Collections;
062 import java.util.Date;
063 import java.util.HashSet;
064 import java.util.Iterator;
065 import java.util.LinkedList;
066 import java.util.List;
067 import java.util.Set;
068
069 import javax.security.auth.x500.X500Principal;
070
071 /**
072 * A concrete implementation of {@link CertSelector} for X.509 certificates,
073 * which allows a number of criteria to be set when accepting certificates,
074 * from validity dates, to issuer and subject distinguished names, to some
075 * of the various X.509 extensions.
076 *
077 * <p>Use of this class requires extensive knowledge of the Internet
078 * Engineering Task Force's Public Key Infrastructure (X.509). The primary
079 * document describing this standard is <a
080 * href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509
081 * Public Key Infrastructure Certificate and Certificate Revocation List
082 * (CRL) Profile</a>.
083 *
084 * <p>Note that this class is not thread-safe. If multiple threads will
085 * use or modify this class then they need to synchronize on the object.
086 *
087 * @author Casey Marshall (csm@gnu.org)
088 * @since 1.4
089 */
090 public class X509CertSelector implements CertSelector, Cloneable
091 {
092
093 // Constants and fields.
094 // -------------------------------------------------------------------------
095
096 private static final String AUTH_KEY_ID = "2.5.29.35";
097 private static final String SUBJECT_KEY_ID = "2.5.29.14";
098 private static final String NAME_CONSTRAINTS_ID = "2.5.29.30";
099
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 /**
162 * Creates a new X.509 certificate selector. The new selector will be
163 * empty, and will accept any certificate (provided that it is an
164 * {@link X509Certificate}).
165 */
166 public X509CertSelector()
167 {
168 basicConstraints = -1;
169 }
170
171 /**
172 * Add a name to match in the NameConstraints extension. The argument is
173 * the DER-encoded bytes of a GeneralName structure.
174 *
175 * See the method {@link #addSubjectAlternativeName(int, byte[])} for the
176 * format of the GeneralName structure.
177 *
178 * @param id The name identifier. Must be between 0 and 8.
179 * @param name The DER-encoded bytes of the name to match.
180 * @throws IOException If the name DER is malformed.
181 */
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 /**
191 * Add a name to match in the NameConstraints extension. This method will
192 * only recognize certain types of name that have convenient string
193 * encodings. For robustness, you should use the {@link
194 * #addPathToName(int, byte[])} method whenever possible.
195 *
196 * @param id The name identifier. Must be between 0 and 8.
197 * @param name The name.
198 * @throws IOException If the name cannot be decoded.
199 */
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 /**
209 * Add a name, as DER-encoded bytes, to the subject alternative names
210 * criterion.
211 *
212 * The name is a GeneralName structure, which has the ASN.1 format:
213 *
214 * <pre>
215 GeneralName ::= CHOICE {
216 otherName [0] OtherName,
217 rfc822Name [1] IA5String,
218 dNSName [2] IA5String,
219 x400Address [3] ORAddress,
220 directoryName [4] Name,
221 ediPartyName [5] EDIPartyName,
222 uniformResourceIdentifier [6] IA5String,
223 iPAddress [7] OCTET STRING,
224 registeredID [8] OBJECT IDENTIFIER }
225 </pre>
226 *
227 * @param id The type of name this is.
228 * @param name The DER-encoded name.
229 * @throws IOException If the name is not a valid DER sequence.
230 */
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 /**
241 * Add a name to the subject alternative names criterion. This method will
242 * only recognize certain types of name that have convenient string
243 * encodings. For robustness, you should use the {@link
244 * #addSubjectAlternativeName(int, byte[])} method whenever possible.
245 *
246 * This method can only decode certain name kinds of names as strings.
247 *
248 * @param id The type of name this is. Must be in the range [0,8].
249 * @param name The name.
250 * @throws IOException If the id is out of range, or if the name
251 * is null.
252 */
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 /**
275 * Returns the authority key identifier criterion, or <code>null</code> if
276 * this value was not set. Note that the byte array is cloned to prevent
277 * modification.
278 *
279 * @return The authority key identifier.
280 */
281 public byte[] getAuthorityKeyIdentifier()
282 {
283 if (authKeyId != null)
284 return (byte[]) authKeyId.clone();
285 else
286 return null;
287 }
288
289 /**
290 * Returns the basic constraints criterion, or -1 if this value is not set.
291 *
292 * @return The basic constraints.
293 */
294 public int getBasicConstraints()
295 {
296 return basicConstraints;
297 }
298
299 /**
300 * Returns the certificate criterion, or <code>null</code> if this value
301 * was not set.
302 *
303 * @return The certificate.
304 */
305 public X509Certificate getCertificate()
306 {
307 return cert;
308 }
309
310 /**
311 * Returns the date at which certificates must be valid, or <code>null</code>
312 * if this criterion was not set.
313 *
314 * @return The target certificate valitity date.
315 */
316 public Date getCertificateValid()
317 {
318 if (certValid != null)
319 return (Date) certValid.clone();
320 else
321 return null;
322 }
323
324 /**
325 * Returns the set of extended key purpose IDs, as an unmodifiable set
326 * of OID strings. Returns <code>null</code> if this criterion is not
327 * set.
328 *
329 * @return The set of key purpose OIDs (strings).
330 */
331 public Set<String> getExtendedKeyUsage()
332 {
333 if (keyPurposeSet != null)
334 return Collections.unmodifiableSet(keyPurposeSet);
335 else
336 return null;
337 }
338
339 /**
340 * Returns the issuer criterion as a sequence of DER bytes, or
341 * <code>null</code> if this value was not set.
342 *
343 * @return The issuer.
344 */
345 public byte[] getIssuerAsBytes() throws IOException
346 {
347 if (issuer != null)
348 return issuer.getEncoded();
349 else
350 return null;
351 }
352
353 /**
354 * Returns the issuer criterion as a string, or <code>null</code> if this
355 * value was not set.
356 *
357 * @return The issuer.
358 */
359 public String getIssuerAsString()
360 {
361 if (issuer != null)
362 return issuer.getName();
363 else
364 return null;
365 }
366
367 /**
368 * Returns the public key usage criterion, or <code>null</code> if this
369 * value is not set. Note that the array is cloned to prevent modification.
370 *
371 * @return The public key usage.
372 */
373 public boolean[] getKeyUsage()
374 {
375 if (keyUsage != null)
376 return (boolean[]) keyUsage.clone();
377 else
378 return null;
379 }
380
381 /**
382 * Returns whether or not all specified alternative names must match.
383 * If false, a certificate is considered a match if <em>one</em> of the
384 * specified alternative names matches.
385 *
386 * @return true if all names must match.
387 */
388 public boolean getMatchAllSubjectAltNames()
389 {
390 return matchAllNames;
391 }
392
393 /**
394 * Returns the name constraints criterion, or <code>null</code> if this
395 * value is not set. Note that the byte array is cloned to prevent
396 * modification.
397 *
398 * @return The name constraints.
399 */
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 /**
427 * Returns the certificate policy extension that will be matched by this
428 * selector, or null if the certificate policy will not be matched.
429 *
430 * @return The policy to be matched, or null.
431 */
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 /**
448 * This method, and its related X.509 certificate extension — the
449 * private key usage period — is not supported under the Internet
450 * PKI for X.509 certificates (PKIX), described in RFC 3280. As such, this
451 * method is not supported either.
452 *
453 * <p>Do not use this method. It is not deprecated, as it is not deprecated
454 * in the Java standard, but it is basically a no-operation and simply
455 * returns <code>null</code>.
456 *
457 * @return Null.
458 */
459 public Date getPrivateKeyValid()
460 {
461 return null;
462 }
463
464 /**
465 * Returns the serial number criterion, or <code>null</code> if this
466 * value was not set.
467 *
468 * @return The serial number.
469 */
470 public BigInteger getSerialNumber()
471 {
472 return serialNo;
473 }
474
475 /**
476 * Get the subject alternative names criterion. The collection returned
477 * is a collection of pairs: the first element is an {@link Integer}
478 * containing the name type, and the second is a byte array containing
479 * the DER-encoded name bytes.
480 *
481 * @return The subject alternative names criterion. Returns null if this
482 * criterion is not set.
483 */
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 /**
502 * Returns the subject criterion as a sequence of DER bytes, or
503 * <code>null</code> if this value is not set.
504 *
505 * @return The subject.
506 */
507 public byte[] getSubjectAsBytes() throws IOException
508 {
509 if (subject != null)
510 return subject.getEncoded();
511 else
512 return null;
513 }
514
515 /**
516 * Returns the subject criterion as a string, of <code>null</code> if
517 * this value was not set.
518 *
519 * @return The subject.
520 */
521 public String getSubjectAsString()
522 {
523 if (subject != null)
524 return subject.getName();
525 else
526 return null;
527 }
528
529 /**
530 * Returns the subject key identifier criterion, or <code>null</code> if
531 * this value was not set. Note that the byte array is cloned to prevent
532 * modification.
533 *
534 * @return The subject key identifier.
535 */
536 public byte[] getSubjectKeyIdentifier()
537 {
538 if (subjectKeyId != null)
539 return (byte[]) subjectKeyId.clone();
540 else
541 return null;
542 }
543
544 /**
545 * Returns the subject public key criterion, or <code>null</code> if this
546 * value is not set.
547 *
548 * @return The subject public key.
549 */
550 public PublicKey getSubjectPublicKey()
551 {
552 return subjectKey;
553 }
554
555 /**
556 * Returns the public key algorithm ID that matching certificates must have,
557 * or <code>null</code> if this criterion was not set.
558 *
559 * @return The public key algorithm ID.
560 */
561 public String getSubjectPublicKeyAlgID()
562 {
563 return String.valueOf(sigId);
564 }
565
566 /**
567 * Match a certificate. This method will check the given certificate
568 * against all the enabled criteria of this selector, and will return
569 * <code>true</code> if the given certificate matches.
570 *
571 * @param certificate The certificate to check.
572 * @return true if the certificate matches all criteria.
573 */
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 // ignored
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 /**
790 * Sets the authority key identifier criterion, or <code>null</code> to clear
791 * this criterion. Note that the byte array is cloned to prevent modification.
792 *
793 * @param authKeyId The authority key identifier.
794 */
795 public void setAuthorityKeyIdentifier(byte[] authKeyId)
796 {
797 this.authKeyId = authKeyId != null ? (byte[]) authKeyId.clone() : null;
798 }
799
800 /**
801 * Sets the basic constraints criterion. Specify -1 to clear this parameter.
802 *
803 * @param basicConstraints The new basic constraints value.
804 */
805 public void setBasicConstraints(int basicConstraints)
806 {
807 if (basicConstraints < -1)
808 basicConstraints = -1;
809 this.basicConstraints = basicConstraints;
810 }
811
812 /**
813 * Sets the certificate criterion. If set, only certificates that are
814 * equal to the certificate passed here will be accepted.
815 *
816 * @param cert The certificate.
817 */
818 public void setCertificate(X509Certificate cert)
819 {
820 this.cert = cert;
821 }
822
823 /**
824 * Sets the date at which certificates must be valid. Specify
825 * <code>null</code> to clear this criterion.
826 *
827 * @param certValid The certificate validity date.
828 */
829 public void setCertificateValid(Date certValid)
830 {
831 this.certValid = certValid != null ? (Date) certValid.clone() : null;
832 }
833
834 /**
835 * Sets the extended key usage criterion, as a set of OID strings. Specify
836 * <code>null</code> to clear this value.
837 *
838 * @param keyPurposeSet The set of key purpose OIDs.
839 * @throws IOException If any element of the set is not a valid OID string.
840 */
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 /**
872 * Sets the issuer, specified as the DER encoding of the issuer's
873 * distinguished name. Only certificates issued by this issuer will
874 * be accepted.
875 *
876 * @param name The DER encoding of the issuer's distinguished name.
877 * @throws IOException If the given name is incorrectly formatted.
878 */
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 /**
897 * Sets the issuer, specified as a string representation of the issuer's
898 * distinguished name. Only certificates issued by this issuer will
899 * be accepted.
900 *
901 * @param name The string representation of the issuer's distinguished name.
902 * @throws IOException If the given name is incorrectly formatted.
903 */
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 /**
922 * Sets the public key usage criterion. Specify <code>null</code> to clear
923 * this value.
924 *
925 * @param keyUsage The public key usage.
926 */
927 public void setKeyUsage(boolean[] keyUsage)
928 {
929 this.keyUsage = keyUsage != null ? (boolean[]) keyUsage.clone() : null;
930 }
931
932 /**
933 * Sets whether or not all subject alternative names must be matched.
934 * If false, then a certificate will be considered a match if one
935 * alternative name matches.
936 *
937 * @param matchAllNames Whether or not all alternative names must be
938 * matched.
939 */
940 public void setMatchAllSubjectAltNames(boolean matchAllNames)
941 {
942 this.matchAllNames = matchAllNames;
943 }
944
945 /**
946 * Sets the name constraints criterion; specify <code>null</code> to
947 * clear this criterion. Note that if non-null, the argument will be
948 * cloned to prevent modification.
949 *
950 * @param nameConstraints The new name constraints.
951 * @throws IOException If the argument is not a valid DER-encoded
952 * name constraints.
953 */
954 public void setNameConstraints(byte[] nameConstraints)
955 throws IOException
956 {
957 // Check if the input is well-formed...
958 new NameConstraints(nameConstraints);
959
960 // But we just compare raw byte arrays.
961 this.nameConstraints = nameConstraints != null
962 ? (byte[]) nameConstraints.clone() : null;
963 }
964
965 /**
966 * Sets the pathToNames criterion. The argument is a collection of
967 * pairs, the first element of which is an {@link Integer} giving
968 * the ID of the name, and the second element is either a {@link String}
969 * or a byte array.
970 *
971 * See {@link #addPathToName(int, byte[])} and {@link #addPathToName(int, String)}
972 * for how these arguments are handled.
973 *
974 * @param names The names.
975 * @throws IOException If any argument is malformed.
976 */
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 /**
1002 * Sets the certificate policy to match, or null if this criterion should
1003 * not be checked. Each element if the set must be a dotted-decimal form
1004 * of certificate policy object identifier.
1005 *
1006 * @param policy The policy to match.
1007 * @throws IOException If some element of the policy is not a valid
1008 * policy extenison OID.
1009 */
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 /**
1043 * This method, and its related X.509 certificate extension — the
1044 * private key usage period — is not supported under the Internet
1045 * PKI for X.509 certificates (PKIX), described in RFC 3280. As such, this
1046 * method is not supported either.
1047 *
1048 * <p>Do not use this method. It is not deprecated, as it is not deprecated
1049 * in the Java standard, but it is basically a no-operation.
1050 *
1051 * @param UNUSED Is silently ignored.
1052 */
1053 public void setPrivateKeyValid(Date UNUSED)
1054 {
1055 }
1056
1057 /**
1058 * Sets the serial number of the desired certificate. Only certificates that
1059 * contain this serial number are accepted.
1060 *
1061 * @param serialNo The serial number.
1062 */
1063 public void setSerialNumber(BigInteger serialNo)
1064 {
1065 this.serialNo = serialNo;
1066 }
1067
1068 /**
1069 * Sets the subject, specified as the DER encoding of the subject's
1070 * distinguished name. Only certificates with the given subject will
1071 * be accepted.
1072 *
1073 * @param name The DER encoding of the subject's distinguished name.
1074 * @throws IOException If the given name is incorrectly formatted.
1075 */
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 /**
1094 * Sets the subject, specified as a string representation of the
1095 * subject's distinguished name. Only certificates with the given
1096 * subject will be accepted.
1097 *
1098 * @param name The string representation of the subject's distinguished name.
1099 * @throws IOException If the given name is incorrectly formatted.
1100 */
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 /**
1119 * Sets the subject alternative names critertion. Each element of the
1120 * argument must be a {@link java.util.List} that contains exactly two
1121 * elements: the first an {@link Integer}, representing the type of
1122 * name, and the second either a {@link String} or a byte array,
1123 * representing the name itself.
1124 *
1125 * @param altNames The alternative names.
1126 * @throws IOException If any element of the argument is invalid.
1127 */
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 /**
1154 * Sets the subject key identifier criterion, or <code>null</code> to clear
1155 * this criterion. Note that the byte array is cloned to prevent modification.
1156 *
1157 * @param subjectKeyId The subject key identifier.
1158 */
1159 public void setSubjectKeyIdentifier(byte[] subjectKeyId)
1160 {
1161 this.subjectKeyId = subjectKeyId != null ? (byte[]) subjectKeyId.clone() :
1162 null;
1163 }
1164
1165 /**
1166 * Sets the subject public key criterion as a DER-encoded key. Specify
1167 * <code>null</code> to clear this value.
1168 *
1169 * @param key The DER-encoded key bytes.
1170 * @throws IOException If the argument is not a valid DER-encoded key.
1171 */
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 /**
1197 * Sets the subject public key criterion as an opaque representation.
1198 * Specify <code>null</code> to clear this criterion.
1199 *
1200 * @param key The public key.
1201 */
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 /**
1224 * Sets the public key algorithm ID that matching certificates must have.
1225 * Specify <code>null</code> to clear this criterion.
1226 *
1227 * @param sigId The public key ID.
1228 * @throws IOException If the specified ID is not a valid object identifier.
1229 */
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 }