1 /*
2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.security.x509;
27 
28 import java.io.IOException;
29 import java.io.OutputStream;
30 
31 import java.security.cert.*;
32 import java.util.*;
33 
34 import sun.security.util.*;
35 import sun.security.util.HexDumpEncoder;
36 
37 
38 /**
39  * The X509CertInfo class represents X.509 certificate information.
40  *
41  * <P>X.509 certificates have several base data elements, including:
42  *
43  * <UL>
44  * <LI>The <em>Subject Name</em>, an X.500 Distinguished Name for
45  *      the entity (subject) for which the certificate was issued.
46  *
47  * <LI>The <em>Subject Public Key</em>, the public key of the subject.
48  *      This is one of the most important parts of the certificate.
49  *
50  * <LI>The <em>Validity Period</em>, a time period (e.g. six months)
51  *      within which the certificate is valid (unless revoked).
52  *
53  * <LI>The <em>Issuer Name</em>, an X.500 Distinguished Name for the
54  *      Certificate Authority (CA) which issued the certificate.
55  *
56  * <LI>A <em>Serial Number</em> assigned by the CA, for use in
57  *      certificate revocation and other applications.
58  * </UL>
59  *
60  * @author Amit Kapoor
61  * @author Hemma Prafullchandra
62  * @see CertAttrSet
63  * @see X509CertImpl
64  */
65 public class X509CertInfo implements CertAttrSet<String> {
66     /**
67      * Identifier for this attribute, to be used with the
68      * get, set, delete methods of Certificate, x509 type.
69      */
70     public static final String IDENT = "x509.info";
71     // Certificate attribute names
72     public static final String NAME = "info";
73     public static final String DN_NAME = "dname";
74     public static final String VERSION = CertificateVersion.NAME;
75     public static final String SERIAL_NUMBER = CertificateSerialNumber.NAME;
76     public static final String ALGORITHM_ID = CertificateAlgorithmId.NAME;
77     public static final String ISSUER = "issuer";
78     public static final String SUBJECT = "subject";
79     public static final String VALIDITY = CertificateValidity.NAME;
80     public static final String KEY = CertificateX509Key.NAME;
81     public static final String ISSUER_ID = "issuerID";
82     public static final String SUBJECT_ID = "subjectID";
83     public static final String EXTENSIONS = CertificateExtensions.NAME;
84 
85     // X509.v1 data
86     protected CertificateVersion version = new CertificateVersion();
87     protected CertificateSerialNumber   serialNum = null;
88     protected CertificateAlgorithmId    algId = null;
89     protected X500Name                  issuer = null;
90     protected X500Name                  subject = null;
91     protected CertificateValidity       interval = null;
92     protected CertificateX509Key        pubKey = null;
93 
94     // X509.v2 & v3 extensions
95     protected UniqueIdentity   issuerUniqueId = null;
96     protected UniqueIdentity  subjectUniqueId = null;
97 
98     // X509.v3 extensions
99     protected CertificateExtensions     extensions = null;
100 
101     // Attribute numbers for internal manipulation
102     private static final int ATTR_VERSION = 1;
103     private static final int ATTR_SERIAL = 2;
104     private static final int ATTR_ALGORITHM = 3;
105     private static final int ATTR_ISSUER = 4;
106     private static final int ATTR_VALIDITY = 5;
107     private static final int ATTR_SUBJECT = 6;
108     private static final int ATTR_KEY = 7;
109     private static final int ATTR_ISSUER_ID = 8;
110     private static final int ATTR_SUBJECT_ID = 9;
111     private static final int ATTR_EXTENSIONS = 10;
112 
113     // DER encoded CertificateInfo data
114     private byte[]      rawCertInfo = null;
115 
116     // The certificate attribute name to integer mapping stored here
117     private static final Map<String,Integer> map = new HashMap<String,Integer>();
118     static {
map.put(VERSION, Integer.valueOf(ATTR_VERSION))119         map.put(VERSION, Integer.valueOf(ATTR_VERSION));
map.put(SERIAL_NUMBER, Integer.valueOf(ATTR_SERIAL))120         map.put(SERIAL_NUMBER, Integer.valueOf(ATTR_SERIAL));
map.put(ALGORITHM_ID, Integer.valueOf(ATTR_ALGORITHM))121         map.put(ALGORITHM_ID, Integer.valueOf(ATTR_ALGORITHM));
map.put(ISSUER, Integer.valueOf(ATTR_ISSUER))122         map.put(ISSUER, Integer.valueOf(ATTR_ISSUER));
map.put(VALIDITY, Integer.valueOf(ATTR_VALIDITY))123         map.put(VALIDITY, Integer.valueOf(ATTR_VALIDITY));
map.put(SUBJECT, Integer.valueOf(ATTR_SUBJECT))124         map.put(SUBJECT, Integer.valueOf(ATTR_SUBJECT));
map.put(KEY, Integer.valueOf(ATTR_KEY))125         map.put(KEY, Integer.valueOf(ATTR_KEY));
map.put(ISSUER_ID, Integer.valueOf(ATTR_ISSUER_ID))126         map.put(ISSUER_ID, Integer.valueOf(ATTR_ISSUER_ID));
map.put(SUBJECT_ID, Integer.valueOf(ATTR_SUBJECT_ID))127         map.put(SUBJECT_ID, Integer.valueOf(ATTR_SUBJECT_ID));
map.put(EXTENSIONS, Integer.valueOf(ATTR_EXTENSIONS))128         map.put(EXTENSIONS, Integer.valueOf(ATTR_EXTENSIONS));
129     }
130 
131     /**
132      * Construct an uninitialized X509CertInfo on which <a href="#decode">
133      * decode</a> must later be called (or which may be deserialized).
134      */
X509CertInfo()135     public X509CertInfo() { }
136 
137     /**
138      * Unmarshals a certificate from its encoded form, parsing the
139      * encoded bytes.  This form of constructor is used by agents which
140      * need to examine and use certificate contents.  That is, this is
141      * one of the more commonly used constructors.  Note that the buffer
142      * must include only a certificate, and no "garbage" may be left at
143      * the end.  If you need to ignore data at the end of a certificate,
144      * use another constructor.
145      *
146      * @param cert the encoded bytes, with no trailing data.
147      * @exception CertificateParsingException on parsing errors.
148      */
X509CertInfo(byte[] cert)149     public X509CertInfo(byte[] cert) throws CertificateParsingException {
150         try {
151             DerValue    in = new DerValue(cert);
152 
153             parse(in);
154         } catch (IOException e) {
155             throw new CertificateParsingException(e);
156         }
157     }
158 
159     /**
160      * Unmarshal a certificate from its encoded form, parsing a DER value.
161      * This form of constructor is used by agents which need to examine
162      * and use certificate contents.
163      *
164      * @param derVal the der value containing the encoded cert.
165      * @exception CertificateParsingException on parsing errors.
166      */
X509CertInfo(DerValue derVal)167     public X509CertInfo(DerValue derVal) throws CertificateParsingException {
168         try {
169             parse(derVal);
170         } catch (IOException e) {
171             throw new CertificateParsingException(e);
172         }
173     }
174 
175     /**
176      * Appends the certificate to an output stream.
177      *
178      * @param out an output stream to which the certificate is appended.
179      * @exception CertificateException on encoding errors.
180      * @exception IOException on other errors.
181      */
encode(OutputStream out)182     public void encode(OutputStream out)
183     throws CertificateException, IOException {
184         if (rawCertInfo == null) {
185             DerOutputStream tmp = new DerOutputStream();
186             emit(tmp);
187             rawCertInfo = tmp.toByteArray();
188         }
189         out.write(rawCertInfo.clone());
190     }
191 
192     /**
193      * Return an enumeration of names of attributes existing within this
194      * attribute.
195      */
getElements()196     public Enumeration<String> getElements() {
197         AttributeNameEnumeration elements = new AttributeNameEnumeration();
198         elements.addElement(VERSION);
199         elements.addElement(SERIAL_NUMBER);
200         elements.addElement(ALGORITHM_ID);
201         elements.addElement(ISSUER);
202         elements.addElement(VALIDITY);
203         elements.addElement(SUBJECT);
204         elements.addElement(KEY);
205         elements.addElement(ISSUER_ID);
206         elements.addElement(SUBJECT_ID);
207         elements.addElement(EXTENSIONS);
208 
209         return elements.elements();
210     }
211 
212     /**
213      * Return the name of this attribute.
214      */
getName()215     public String getName() {
216         return(NAME);
217     }
218 
219     /**
220      * Returns the encoded certificate info.
221      *
222      * @exception CertificateEncodingException on encoding information errors.
223      */
getEncodedInfo()224     public byte[] getEncodedInfo() throws CertificateEncodingException {
225         try {
226             if (rawCertInfo == null) {
227                 DerOutputStream tmp = new DerOutputStream();
228                 emit(tmp);
229                 rawCertInfo = tmp.toByteArray();
230             }
231             return rawCertInfo.clone();
232         } catch (IOException e) {
233             throw new CertificateEncodingException(e.toString());
234         } catch (CertificateException e) {
235             throw new CertificateEncodingException(e.toString());
236         }
237     }
238 
239     /**
240      * Compares two X509CertInfo objects.  This is false if the
241      * certificates are not both X.509 certs, otherwise it
242      * compares them as binary data.
243      *
244      * @param other the object being compared with this one
245      * @return true iff the certificates are equivalent
246      */
equals(Object other)247     public boolean equals(Object other) {
248         if (other instanceof X509CertInfo) {
249             return equals((X509CertInfo) other);
250         } else {
251             return false;
252         }
253     }
254 
255     /**
256      * Compares two certificates, returning false if any data
257      * differs between the two.
258      *
259      * @param other the object being compared with this one
260      * @return true iff the certificates are equivalent
261      */
equals(X509CertInfo other)262     public boolean equals(X509CertInfo other) {
263         if (this == other) {
264             return(true);
265         } else if (rawCertInfo == null || other.rawCertInfo == null) {
266             return(false);
267         } else if (rawCertInfo.length != other.rawCertInfo.length) {
268             return(false);
269         }
270         for (int i = 0; i < rawCertInfo.length; i++) {
271             if (rawCertInfo[i] != other.rawCertInfo[i]) {
272                 return(false);
273             }
274         }
275         return(true);
276     }
277 
278     /**
279      * Calculates a hash code value for the object.  Objects
280      * which are equal will also have the same hashcode.
281      */
hashCode()282     public int hashCode() {
283         int     retval = 0;
284 
285         for (int i = 1; i < rawCertInfo.length; i++) {
286             retval += rawCertInfo[i] * i;
287         }
288         return(retval);
289     }
290 
291     /**
292      * Returns a printable representation of the certificate.
293      */
toString()294     public String toString() {
295 
296         if (subject == null || pubKey == null || interval == null
297             || issuer == null || algId == null || serialNum == null) {
298                 throw new NullPointerException("X.509 cert is incomplete");
299         }
300         StringBuilder sb = new StringBuilder();
301 
302         sb.append("[\n")
303             .append("  ").append(version).append('\n')
304             .append("  Subject: ").append(subject).append('\n')
305             .append("  Signature Algorithm: ").append(algId).append('\n')
306             .append("  Key:  ").append(pubKey).append('\n')
307             .append("  ").append(interval).append('\n')
308             .append("  Issuer: ").append(issuer).append('\n')
309             .append("  ").append(serialNum).append('\n');
310 
311         // optional v2, v3 extras
312         if (issuerUniqueId != null) {
313             sb.append("  Issuer Id:\n").append(issuerUniqueId).append('\n');
314         }
315         if (subjectUniqueId != null) {
316             sb.append("  Subject Id:\n").append(subjectUniqueId).append('\n');
317         }
318         if (extensions != null) {
319             Collection<Extension> allExts = extensions.getAllExtensions();
320             Extension[] exts = allExts.toArray(new Extension[0]);
321             sb.append("\nCertificate Extensions: ").append(exts.length);
322             for (int i = 0; i < exts.length; i++) {
323                 sb.append("\n[").append(i+1).append("]: ");
324                 Extension ext = exts[i];
325                 try {
326                     if (OIDMap.getClass(ext.getExtensionId()) == null) {
327                         sb.append(ext);
328                         byte[] extValue = ext.getExtensionValue();
329                         if (extValue != null) {
330                             DerOutputStream out = new DerOutputStream();
331                             out.putOctetString(extValue);
332                             extValue = out.toByteArray();
333                             HexDumpEncoder enc = new HexDumpEncoder();
334                             sb.append("Extension unknown: ")
335                                 .append("DER encoded OCTET string =\n")
336                                 .append(enc.encodeBuffer(extValue))
337                                 .append('\n');
338                         }
339                     } else {
340                         sb.append(ext); //sub-class exists
341                     }
342                 } catch (Exception e) {
343                     sb.append(", Error parsing this extension");
344                 }
345             }
346             Map<String,Extension> invalid = extensions.getUnparseableExtensions();
347             if (invalid.isEmpty() == false) {
348                 sb.append("\nUnparseable certificate extensions: ")
349                     .append(invalid.size());
350                 int i = 1;
351                 for (Extension ext : invalid.values()) {
352                     sb.append("\n[")
353                         .append(i++)
354                         .append("]: ")
355                         .append(ext);
356                 }
357             }
358         }
359         sb.append("\n]");
360         return sb.toString();
361     }
362 
363     /**
364      * Set the certificate attribute.
365      *
366      * @param name the name of the Certificate attribute.
367      * @param val the value of the Certificate attribute.
368      * @exception CertificateException on invalid attributes.
369      * @exception IOException on other errors.
370      */
set(String name, Object val)371     public void set(String name, Object val)
372     throws CertificateException, IOException {
373         X509AttributeName attrName = new X509AttributeName(name);
374 
375         int attr = attributeMap(attrName.getPrefix());
376         if (attr == 0) {
377             throw new CertificateException("Attribute name not recognized: "
378                                            + name);
379         }
380         // set rawCertInfo to null, so that we are forced to re-encode
381         rawCertInfo = null;
382         String suffix = attrName.getSuffix();
383 
384         switch (attr) {
385         case ATTR_VERSION:
386             if (suffix == null) {
387                 setVersion(val);
388             } else {
389                 version.set(suffix, val);
390             }
391             break;
392 
393         case ATTR_SERIAL:
394             if (suffix == null) {
395                 setSerialNumber(val);
396             } else {
397                 serialNum.set(suffix, val);
398             }
399             break;
400 
401         case ATTR_ALGORITHM:
402             if (suffix == null) {
403                 setAlgorithmId(val);
404             } else {
405                 algId.set(suffix, val);
406             }
407             break;
408 
409         case ATTR_ISSUER:
410             setIssuer(val);
411             break;
412 
413         case ATTR_VALIDITY:
414             if (suffix == null) {
415                 setValidity(val);
416             } else {
417                 interval.set(suffix, val);
418             }
419             break;
420 
421         case ATTR_SUBJECT:
422             setSubject(val);
423             break;
424 
425         case ATTR_KEY:
426             if (suffix == null) {
427                 setKey(val);
428             } else {
429                 pubKey.set(suffix, val);
430             }
431             break;
432 
433         case ATTR_ISSUER_ID:
434             setIssuerUniqueId(val);
435             break;
436 
437         case ATTR_SUBJECT_ID:
438             setSubjectUniqueId(val);
439             break;
440 
441         case ATTR_EXTENSIONS:
442             if (suffix == null) {
443                 setExtensions(val);
444             } else {
445                 if (extensions == null)
446                     extensions = new CertificateExtensions();
447                 extensions.set(suffix, val);
448             }
449             break;
450         }
451     }
452 
453     /**
454      * Delete the certificate attribute.
455      *
456      * @param name the name of the Certificate attribute.
457      * @exception CertificateException on invalid attributes.
458      * @exception IOException on other errors.
459      */
delete(String name)460     public void delete(String name)
461     throws CertificateException, IOException {
462         X509AttributeName attrName = new X509AttributeName(name);
463 
464         int attr = attributeMap(attrName.getPrefix());
465         if (attr == 0) {
466             throw new CertificateException("Attribute name not recognized: "
467                                            + name);
468         }
469         // set rawCertInfo to null, so that we are forced to re-encode
470         rawCertInfo = null;
471         String suffix = attrName.getSuffix();
472 
473         switch (attr) {
474         case ATTR_VERSION:
475             if (suffix == null) {
476                 version = null;
477             } else {
478                 version.delete(suffix);
479             }
480             break;
481         case (ATTR_SERIAL):
482             if (suffix == null) {
483                 serialNum = null;
484             } else {
485                 serialNum.delete(suffix);
486             }
487             break;
488         case (ATTR_ALGORITHM):
489             if (suffix == null) {
490                 algId = null;
491             } else {
492                 algId.delete(suffix);
493             }
494             break;
495         case (ATTR_ISSUER):
496             issuer = null;
497             break;
498         case (ATTR_VALIDITY):
499             if (suffix == null) {
500                 interval = null;
501             } else {
502                 interval.delete(suffix);
503             }
504             break;
505         case (ATTR_SUBJECT):
506             subject = null;
507             break;
508         case (ATTR_KEY):
509             if (suffix == null) {
510                 pubKey = null;
511             } else {
512                 pubKey.delete(suffix);
513             }
514             break;
515         case (ATTR_ISSUER_ID):
516             issuerUniqueId = null;
517             break;
518         case (ATTR_SUBJECT_ID):
519             subjectUniqueId = null;
520             break;
521         case (ATTR_EXTENSIONS):
522             if (suffix == null) {
523                 extensions = null;
524             } else {
525                 if (extensions != null)
526                    extensions.delete(suffix);
527             }
528             break;
529         }
530     }
531 
532     /**
533      * Get the certificate attribute.
534      *
535      * @param name the name of the Certificate attribute.
536      *
537      * @exception CertificateException on invalid attributes.
538      * @exception IOException on other errors.
539      */
get(String name)540     public Object get(String name)
541     throws CertificateException, IOException {
542         X509AttributeName attrName = new X509AttributeName(name);
543 
544         int attr = attributeMap(attrName.getPrefix());
545         if (attr == 0) {
546             throw new CertificateParsingException(
547                           "Attribute name not recognized: " + name);
548         }
549         String suffix = attrName.getSuffix();
550 
551         switch (attr) { // frequently used attributes first
552         case (ATTR_EXTENSIONS):
553             if (suffix == null) {
554                 return(extensions);
555             } else {
556                 if (extensions == null) {
557                     return null;
558                 } else {
559                     return(extensions.get(suffix));
560                 }
561             }
562         case (ATTR_SUBJECT):
563             if (suffix == null) {
564                 return(subject);
565             } else {
566                 return(getX500Name(suffix, false));
567             }
568         case (ATTR_ISSUER):
569             if (suffix == null) {
570                 return(issuer);
571             } else {
572                 return(getX500Name(suffix, true));
573             }
574         case (ATTR_KEY):
575             if (suffix == null) {
576                 return(pubKey);
577             } else {
578                 return(pubKey.get(suffix));
579             }
580         case (ATTR_ALGORITHM):
581             if (suffix == null) {
582                 return(algId);
583             } else {
584                 return(algId.get(suffix));
585             }
586         case (ATTR_VALIDITY):
587             if (suffix == null) {
588                 return(interval);
589             } else {
590                 return(interval.get(suffix));
591             }
592         case (ATTR_VERSION):
593             if (suffix == null) {
594                 return(version);
595             } else {
596                 return(version.get(suffix));
597             }
598         case (ATTR_SERIAL):
599             if (suffix == null) {
600                 return(serialNum);
601             } else {
602                 return(serialNum.get(suffix));
603             }
604         case (ATTR_ISSUER_ID):
605             return(issuerUniqueId);
606         case (ATTR_SUBJECT_ID):
607             return(subjectUniqueId);
608         }
609         return null;
610     }
611 
612     /*
613      * Get the Issuer or Subject name
614      */
getX500Name(String name, boolean getIssuer)615     private Object getX500Name(String name, boolean getIssuer)
616         throws IOException {
617         if (name.equalsIgnoreCase(X509CertInfo.DN_NAME)) {
618             return getIssuer ? issuer : subject;
619         } else if (name.equalsIgnoreCase("x500principal")) {
620             return getIssuer ? issuer.asX500Principal()
621                              : subject.asX500Principal();
622         } else {
623             throw new IOException("Attribute name not recognized.");
624         }
625     }
626 
627     /*
628      * This routine unmarshals the certificate information.
629      */
parse(DerValue val)630     private void parse(DerValue val)
631     throws CertificateParsingException, IOException {
632         DerInputStream  in;
633         DerValue        tmp;
634 
635         if (val.tag != DerValue.tag_Sequence) {
636             throw new CertificateParsingException("signed fields invalid");
637         }
638         rawCertInfo = val.toByteArray();
639 
640         in = val.data;
641 
642         // Version
643         tmp = in.getDerValue();
644         if (tmp.isContextSpecific((byte)0)) {
645             version = new CertificateVersion(tmp);
646             tmp = in.getDerValue();
647         }
648 
649         // Serial number ... an integer
650         serialNum = new CertificateSerialNumber(tmp);
651 
652         // Algorithm Identifier
653         algId = new CertificateAlgorithmId(in);
654 
655         // Issuer name
656         issuer = new X500Name(in);
657         if (issuer.isEmpty()) {
658             throw new CertificateParsingException(
659                 "Empty issuer DN not allowed in X509Certificates");
660         }
661 
662         // validity:  SEQUENCE { start date, end date }
663         interval = new CertificateValidity(in);
664 
665         // subject name
666         subject = new X500Name(in);
667         if ((version.compare(CertificateVersion.V1) == 0) &&
668                 subject.isEmpty()) {
669             throw new CertificateParsingException(
670                       "Empty subject DN not allowed in v1 certificate");
671         }
672 
673         // public key
674         pubKey = new CertificateX509Key(in);
675 
676         // If more data available, make sure version is not v1.
677         if (in.available() != 0) {
678             if (version.compare(CertificateVersion.V1) == 0) {
679                 throw new CertificateParsingException(
680                           "no more data allowed for version 1 certificate");
681             }
682         } else {
683             return;
684         }
685 
686         // Get the issuerUniqueId if present
687         tmp = in.getDerValue();
688         if (tmp.isContextSpecific((byte)1)) {
689             issuerUniqueId = new UniqueIdentity(tmp);
690             if (in.available() == 0)
691                 return;
692             tmp = in.getDerValue();
693         }
694 
695         // Get the subjectUniqueId if present.
696         if (tmp.isContextSpecific((byte)2)) {
697             subjectUniqueId = new UniqueIdentity(tmp);
698             if (in.available() == 0)
699                 return;
700             tmp = in.getDerValue();
701         }
702 
703         // Get the extensions.
704         if (version.compare(CertificateVersion.V3) != 0) {
705             throw new CertificateParsingException(
706                       "Extensions not allowed in v2 certificate");
707         }
708         if (tmp.isConstructed() && tmp.isContextSpecific((byte)3)) {
709             extensions = new CertificateExtensions(tmp.data);
710         }
711 
712         // verify X.509 V3 Certificate
713         verifyCert(subject, extensions);
714 
715     }
716 
717     /*
718      * Verify if X.509 V3 Certificate is compliant with RFC 5280.
719      */
verifyCert(X500Name subject, CertificateExtensions extensions)720     private void verifyCert(X500Name subject,
721         CertificateExtensions extensions)
722         throws CertificateParsingException, IOException {
723 
724         // if SubjectName is empty, check for SubjectAlternativeNameExtension
725         if (subject.isEmpty()) {
726             if (extensions == null) {
727                 throw new CertificateParsingException("X.509 Certificate is " +
728                         "incomplete: subject field is empty, and certificate " +
729                         "has no extensions");
730             }
731             SubjectAlternativeNameExtension subjectAltNameExt = null;
732             SubjectAlternativeNameExtension extValue = null;
733             GeneralNames names = null;
734             try {
735                 subjectAltNameExt = (SubjectAlternativeNameExtension)
736                         extensions.get(SubjectAlternativeNameExtension.NAME);
737                 names = subjectAltNameExt.get(
738                         SubjectAlternativeNameExtension.SUBJECT_NAME);
739             } catch (IOException e) {
740                 throw new CertificateParsingException("X.509 Certificate is " +
741                         "incomplete: subject field is empty, and " +
742                         "SubjectAlternativeName extension is absent");
743             }
744 
745             // SubjectAlternativeName extension is empty or not marked critical
746             if (names == null || names.isEmpty()) {
747                 throw new CertificateParsingException("X.509 Certificate is " +
748                         "incomplete: subject field is empty, and " +
749                         "SubjectAlternativeName extension is empty");
750             } else if (subjectAltNameExt.isCritical() == false) {
751                 throw new CertificateParsingException("X.509 Certificate is " +
752                         "incomplete: SubjectAlternativeName extension MUST " +
753                         "be marked critical when subject field is empty");
754             }
755         }
756     }
757 
758     /*
759      * Marshal the contents of a "raw" certificate into a DER sequence.
760      */
emit(DerOutputStream out)761     private void emit(DerOutputStream out)
762     throws CertificateException, IOException {
763         DerOutputStream tmp = new DerOutputStream();
764 
765         // version number, iff not V1
766         version.encode(tmp);
767 
768         // Encode serial number, issuer signing algorithm, issuer name
769         // and validity
770         serialNum.encode(tmp);
771         algId.encode(tmp);
772 
773         if ((version.compare(CertificateVersion.V1) == 0) &&
774             (issuer.toString() == null))
775             throw new CertificateParsingException(
776                       "Null issuer DN not allowed in v1 certificate");
777 
778         issuer.encode(tmp);
779         interval.encode(tmp);
780 
781         // Encode subject (principal) and associated key
782         if ((version.compare(CertificateVersion.V1) == 0) &&
783             (subject.toString() == null))
784             throw new CertificateParsingException(
785                       "Null subject DN not allowed in v1 certificate");
786         subject.encode(tmp);
787         pubKey.encode(tmp);
788 
789         // Encode issuerUniqueId & subjectUniqueId.
790         if (issuerUniqueId != null) {
791             issuerUniqueId.encode(tmp, DerValue.createTag(DerValue.TAG_CONTEXT,
792                                                           false,(byte)1));
793         }
794         if (subjectUniqueId != null) {
795             subjectUniqueId.encode(tmp, DerValue.createTag(DerValue.TAG_CONTEXT,
796                                                            false,(byte)2));
797         }
798 
799         // Write all the extensions.
800         if (extensions != null) {
801             extensions.encode(tmp);
802         }
803 
804         // Wrap the data; encoding of the "raw" cert is now complete.
805         out.write(DerValue.tag_Sequence, tmp);
806     }
807 
808     /**
809      * Returns the integer attribute number for the passed attribute name.
810      */
attributeMap(String name)811     private int attributeMap(String name) {
812         Integer num = map.get(name);
813         if (num == null) {
814             return 0;
815         }
816         return num.intValue();
817     }
818 
819     /**
820      * Set the version number of the certificate.
821      *
822      * @param val the Object class value for the Extensions
823      * @exception CertificateException on invalid data.
824      */
setVersion(Object val)825     private void setVersion(Object val) throws CertificateException {
826         if (!(val instanceof CertificateVersion)) {
827             throw new CertificateException("Version class type invalid.");
828         }
829         version = (CertificateVersion)val;
830     }
831 
832     /**
833      * Set the serial number of the certificate.
834      *
835      * @param val the Object class value for the CertificateSerialNumber
836      * @exception CertificateException on invalid data.
837      */
setSerialNumber(Object val)838     private void setSerialNumber(Object val) throws CertificateException {
839         if (!(val instanceof CertificateSerialNumber)) {
840             throw new CertificateException("SerialNumber class type invalid.");
841         }
842         serialNum = (CertificateSerialNumber)val;
843     }
844 
845     /**
846      * Set the algorithm id of the certificate.
847      *
848      * @param val the Object class value for the AlgorithmId
849      * @exception CertificateException on invalid data.
850      */
setAlgorithmId(Object val)851     private void setAlgorithmId(Object val) throws CertificateException {
852         if (!(val instanceof CertificateAlgorithmId)) {
853             throw new CertificateException(
854                              "AlgorithmId class type invalid.");
855         }
856         algId = (CertificateAlgorithmId)val;
857     }
858 
859     /**
860      * Set the issuer name of the certificate.
861      *
862      * @param val the Object class value for the issuer
863      * @exception CertificateException on invalid data.
864      */
setIssuer(Object val)865     private void setIssuer(Object val) throws CertificateException {
866         if (!(val instanceof X500Name)) {
867             throw new CertificateException(
868                              "Issuer class type invalid.");
869         }
870         issuer = (X500Name)val;
871     }
872 
873     /**
874      * Set the validity interval of the certificate.
875      *
876      * @param val the Object class value for the CertificateValidity
877      * @exception CertificateException on invalid data.
878      */
setValidity(Object val)879     private void setValidity(Object val) throws CertificateException {
880         if (!(val instanceof CertificateValidity)) {
881             throw new CertificateException(
882                              "CertificateValidity class type invalid.");
883         }
884         interval = (CertificateValidity)val;
885     }
886 
887     /**
888      * Set the subject name of the certificate.
889      *
890      * @param val the Object class value for the Subject
891      * @exception CertificateException on invalid data.
892      */
setSubject(Object val)893     private void setSubject(Object val) throws CertificateException {
894         if (!(val instanceof X500Name)) {
895             throw new CertificateException(
896                              "Subject class type invalid.");
897         }
898         subject = (X500Name)val;
899     }
900 
901     /**
902      * Set the public key in the certificate.
903      *
904      * @param val the Object class value for the PublicKey
905      * @exception CertificateException on invalid data.
906      */
setKey(Object val)907     private void setKey(Object val) throws CertificateException {
908         if (!(val instanceof CertificateX509Key)) {
909             throw new CertificateException(
910                              "Key class type invalid.");
911         }
912         pubKey = (CertificateX509Key)val;
913     }
914 
915     /**
916      * Set the Issuer Unique Identity in the certificate.
917      *
918      * @param val the Object class value for the IssuerUniqueId
919      * @exception CertificateException
920      */
setIssuerUniqueId(Object val)921     private void setIssuerUniqueId(Object val) throws CertificateException {
922         if (version.compare(CertificateVersion.V2) < 0) {
923             throw new CertificateException("Invalid version");
924         }
925         if (!(val instanceof UniqueIdentity)) {
926             throw new CertificateException(
927                              "IssuerUniqueId class type invalid.");
928         }
929         issuerUniqueId = (UniqueIdentity)val;
930     }
931 
932     /**
933      * Set the Subject Unique Identity in the certificate.
934      *
935      * @param val the Object class value for the SubjectUniqueId
936      * @exception CertificateException
937      */
setSubjectUniqueId(Object val)938     private void setSubjectUniqueId(Object val) throws CertificateException {
939         if (version.compare(CertificateVersion.V2) < 0) {
940             throw new CertificateException("Invalid version");
941         }
942         if (!(val instanceof UniqueIdentity)) {
943             throw new CertificateException(
944                              "SubjectUniqueId class type invalid.");
945         }
946         subjectUniqueId = (UniqueIdentity)val;
947     }
948 
949     /**
950      * Set the extensions in the certificate.
951      *
952      * @param val the Object class value for the Extensions
953      * @exception CertificateException
954      */
setExtensions(Object val)955     private void setExtensions(Object val) throws CertificateException {
956         if (version.compare(CertificateVersion.V3) < 0) {
957             throw new CertificateException("Invalid version");
958         }
959         if (!(val instanceof CertificateExtensions)) {
960           throw new CertificateException(
961                              "Extensions class type invalid.");
962         }
963         extensions = (CertificateExtensions)val;
964     }
965 }
966