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