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