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