001/* 002 * Copyright 2017-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2017-2019 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.util.ssl.cert; 022 023 024 025import java.io.Serializable; 026import java.net.InetAddress; 027import java.util.ArrayList; 028import java.util.Collections; 029import java.util.Iterator; 030import java.util.List; 031 032import com.unboundid.asn1.ASN1Element; 033import com.unboundid.asn1.ASN1IA5String; 034import com.unboundid.asn1.ASN1ObjectIdentifier; 035import com.unboundid.asn1.ASN1OctetString; 036import com.unboundid.asn1.ASN1Sequence; 037import com.unboundid.ldap.sdk.DN; 038import com.unboundid.util.Debug; 039import com.unboundid.util.NotMutable; 040import com.unboundid.util.OID; 041import com.unboundid.util.ObjectPair; 042import com.unboundid.util.StaticUtils; 043import com.unboundid.util.ThreadSafety; 044import com.unboundid.util.ThreadSafetyLevel; 045 046import static com.unboundid.util.ssl.cert.CertMessages.*; 047 048 049 050/** 051 * This class provides a data structure that represents a {@code GeneralNames} 052 * element that may appear in a number of X.509 certificate extensions, 053 * including {@link SubjectAlternativeNameExtension}, 054 * {@link IssuerAlternativeNameExtension}, 055 * {@link AuthorityKeyIdentifierExtension}, and 056 * {@link CRLDistributionPointsExtension}. The {@code GeneralNames} element has 057 * the following encoding (as described in 058 * <A HREF="https://www.ietf.org/rfc/rfc5280.txt">RFC 5280</A> section 4.2.1.6): 059 * <PRE> 060 * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 061 * 062 * GeneralName ::= CHOICE { 063 * otherName [0] OtherName, 064 * rfc822Name [1] IA5String, 065 * dNSName [2] IA5String, 066 * x400Address [3] ORAddress, 067 * directoryName [4] Name, 068 * ediPartyName [5] EDIPartyName, 069 * uniformResourceIdentifier [6] IA5String, 070 * iPAddress [7] OCTET STRING, 071 * registeredID [8] OBJECT IDENTIFIER } 072 * 073 * OtherName ::= SEQUENCE { 074 * type-id OBJECT IDENTIFIER, 075 * value [0] EXPLICIT ANY DEFINED BY type-id } 076 * 077 * EDIPartyName ::= SEQUENCE { 078 * nameAssigner [0] DirectoryString OPTIONAL, 079 * partyName [1] DirectoryString } 080 * </PRE> 081 */ 082@NotMutable() 083@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 084public final class GeneralNames 085 implements Serializable 086{ 087 /** 088 * The DER type for otherName elements. 089 */ 090 private static final byte NAME_TYPE_OTHER_NAME = (byte) 0xA0; 091 092 093 094 /** 095 * The DER type for rfc822Name elements. 096 */ 097 private static final byte NAME_TYPE_RFC_822_NAME = (byte) 0x81; 098 099 100 101 /** 102 * The DER type for dNSName elements. 103 */ 104 private static final byte NAME_TYPE_DNS_NAME = (byte) 0x82; 105 106 107 108 /** 109 * The DER type for x400Address elements. 110 */ 111 private static final byte NAME_TYPE_X400_ADDRESS = (byte) 0xA3; 112 113 114 115 /** 116 * The DER type for directoryName elements. 117 */ 118 private static final byte NAME_TYPE_DIRECTORY_NAME = (byte) 0xA4; 119 120 121 122 /** 123 * The DER type for ediPartyName elements. 124 */ 125 private static final byte NAME_TYPE_EDI_PARTY_NAME = (byte) 0xA5; 126 127 128 129 /** 130 * The DER type for uniformResourceIdentifier elements. 131 */ 132 private static final byte NAME_TYPE_UNIFORM_RESOURCE_IDENTIFIER = (byte) 0x86; 133 134 135 136 /** 137 * The DER type for ipAddress elements. 138 */ 139 private static final byte NAME_TYPE_IP_ADDRESS = (byte) 0x87; 140 141 142 143 /** 144 * The DER type for registeredID elements. 145 */ 146 private static final byte NAME_TYPE_REGISTERED_ID = (byte) 0x88; 147 148 149 150 /** 151 * The DER type for the value element in an otherName element. 152 */ 153 private static final byte NAME_TYPE_OTHER_NAME_VALUE = (byte) 0xA0; 154 155 156 157 /** 158 * The serial version UID for this serializable class. 159 */ 160 private static final long serialVersionUID = -8789437423467093314L; 161 162 163 164 // The EDI party names included in the extension. 165 private final List<ASN1Element> ediPartyNames; 166 167 // The X.400 names included in the extension. 168 private final List<ASN1Element> x400Addresses; 169 170 // The directory names included in the extension. 171 private final List<DN> directoryNames; 172 173 // The IP addresses included in the extension. 174 private final List<InetAddress> ipAddresses; 175 176 // The other names included in the extension. 177 private final List<ObjectPair<OID,ASN1Element>> otherNames; 178 179 // The registered IDs included in the extension. 180 private final List<OID> registeredIDs; 181 182 // The DNS names included in the extension. 183 private final List<String> dnsNames; 184 185 // The RFC 822 names (email addresses) in the extension. 186 private final List<String> rfc822Names; 187 188 // The uniform resource identifiers in the extension. 189 private final List<String> uniformResourceIdentifiers; 190 191 192 193 /** 194 * Creates a new general names object from the provided information. 195 * 196 * @param otherNames The list of other names to include in 197 * the object. This must not be 198 * {@code null} but may be empty. 199 * @param rfc822Names The list of RFC 822 names (email 200 * addresses) to include in the object. 201 * This must not be {@code null} but may 202 * be empty. 203 * @param dnsNames The list of DNS name values to include 204 * in the object. This must not be 205 * {@code null} but may be empty. 206 * @param x400Addresses The list of X.400 address values to 207 * include in the object. This must not 208 * be {@code null} but may be empty. 209 * @param directoryNames The list of directory name values to 210 * include in the object. This must not 211 * be {@code null} but may be empty. 212 * @param ediPartyNames The list of EDI party name values to 213 * include in the object. This must not 214 * be {@code null} but may be empty. 215 * @param uniformResourceIdentifiers The list of uniform resource 216 * identifier values to include in the 217 * object. This must not be {@code null} 218 * but may be empty. 219 * @param ipAddresses The list of IP address values to 220 * include in the object. This must not 221 * be {@code null} but may be empty. 222 * @param registeredIDs The list of registered ID values to 223 * include in the object. This must not 224 * be {@code null} but may be empty. 225 */ 226 GeneralNames(final List<ObjectPair<OID,ASN1Element>> otherNames, 227 final List<String> rfc822Names, final List<String> dnsNames, 228 final List<ASN1Element> x400Addresses, 229 final List<DN> directoryNames, 230 final List<ASN1Element> ediPartyNames, 231 final List<String> uniformResourceIdentifiers, 232 final List<InetAddress> ipAddresses, 233 final List<OID> registeredIDs) 234 { 235 this.otherNames = otherNames; 236 this.rfc822Names = rfc822Names; 237 this.dnsNames = dnsNames; 238 this.x400Addresses = x400Addresses; 239 this.directoryNames = directoryNames; 240 this.ediPartyNames = ediPartyNames; 241 this.uniformResourceIdentifiers = uniformResourceIdentifiers; 242 this.ipAddresses = ipAddresses; 243 this.registeredIDs = registeredIDs; 244 } 245 246 247 248 /** 249 * Creates a new general names object that is decoded from the provided ASN.1 250 * element. 251 * 252 * @param element The ASN.1 element to decode as a general names object. 253 * 254 * @throws CertException If the provided element cannot be decoded as a 255 * general names element. 256 */ 257 GeneralNames(final ASN1Element element) 258 throws CertException 259 { 260 try 261 { 262 final ASN1Element[] elements = element.decodeAsSequence().elements(); 263 final ArrayList<ASN1Element> ediPartyList = 264 new ArrayList<>(elements.length); 265 final ArrayList<ASN1Element> x400AddressList = 266 new ArrayList<>(elements.length); 267 final ArrayList<DN> directoryNameList = new ArrayList<>(elements.length); 268 final ArrayList<InetAddress> ipAddressList = 269 new ArrayList<>(elements.length); 270 final ArrayList<ObjectPair<OID,ASN1Element>> otherNameList = 271 new ArrayList<>(elements.length); 272 final ArrayList<OID> registeredIDList = 273 new ArrayList<>(elements.length); 274 final ArrayList<String> dnsNameList = new ArrayList<>(elements.length); 275 final ArrayList<String> rfc822NameList = new ArrayList<>(elements.length); 276 final ArrayList<String> uriList = new ArrayList<>(elements.length); 277 278 for (final ASN1Element e : elements) 279 { 280 switch (e.getType()) 281 { 282 case NAME_TYPE_OTHER_NAME: 283 final ASN1Element[] otherNameElements = 284 ASN1Sequence.decodeAsSequence(e).elements(); 285 final OID otherNameOID = 286 ASN1ObjectIdentifier.decodeAsObjectIdentifier( 287 otherNameElements[0]).getOID(); 288 final ASN1Element otherNameValue = 289 ASN1Element.decode(otherNameElements[1].getValue()); 290 otherNameList.add(new ObjectPair<>(otherNameOID, otherNameValue)); 291 break; 292 case NAME_TYPE_RFC_822_NAME: 293 rfc822NameList.add( 294 ASN1IA5String.decodeAsIA5String(e).stringValue()); 295 break; 296 case NAME_TYPE_DNS_NAME: 297 dnsNameList.add(ASN1IA5String.decodeAsIA5String(e).stringValue()); 298 break; 299 case NAME_TYPE_X400_ADDRESS: 300 x400AddressList.add(e); 301 break; 302 case NAME_TYPE_DIRECTORY_NAME: 303 directoryNameList.add(X509Certificate.decodeName(e)); 304 break; 305 case NAME_TYPE_EDI_PARTY_NAME: 306 ediPartyList.add(e); 307 break; 308 case NAME_TYPE_UNIFORM_RESOURCE_IDENTIFIER: 309 uriList.add(ASN1IA5String.decodeAsIA5String(e).stringValue()); 310 break; 311 case NAME_TYPE_IP_ADDRESS: 312 ipAddressList.add(InetAddress.getByAddress(e.getValue())); 313 break; 314 case NAME_TYPE_REGISTERED_ID: 315 registeredIDList.add( 316 ASN1ObjectIdentifier.decodeAsObjectIdentifier(e).getOID()); 317 break; 318 } 319 } 320 321 ediPartyNames = Collections.unmodifiableList(ediPartyList); 322 otherNames = Collections.unmodifiableList(otherNameList); 323 registeredIDs = Collections.unmodifiableList(registeredIDList); 324 x400Addresses = Collections.unmodifiableList(x400AddressList); 325 directoryNames = Collections.unmodifiableList(directoryNameList); 326 ipAddresses = Collections.unmodifiableList(ipAddressList); 327 dnsNames = Collections.unmodifiableList(dnsNameList); 328 rfc822Names = Collections.unmodifiableList(rfc822NameList); 329 uniformResourceIdentifiers = Collections.unmodifiableList(uriList); 330 } 331 catch (final Exception e) 332 { 333 Debug.debugException(e); 334 throw new CertException( 335 ERR_GENERAL_NAMES_CANNOT_PARSE.get( 336 StaticUtils.getExceptionMessage(e)), 337 e); 338 } 339 } 340 341 342 343 /** 344 * Encodes this general names object to an ASN.1 element for use in a 345 * certificate extension. 346 * 347 * @return The encoded general names object. 348 * 349 * @throws CertException If a problem is encountered while encoding the 350 * set of general name values. 351 */ 352 ASN1Element encode() 353 throws CertException 354 { 355 try 356 { 357 final ArrayList<ASN1Element> elements = new ArrayList<>(10); 358 for (final ObjectPair<OID,ASN1Element> otherName : otherNames) 359 { 360 elements.add(new ASN1Sequence(NAME_TYPE_OTHER_NAME, 361 new ASN1ObjectIdentifier(otherName.getFirst()), 362 new ASN1Element(NAME_TYPE_OTHER_NAME_VALUE, 363 otherName.getSecond().encode()))); 364 } 365 366 for (final String rfc822Name : rfc822Names) 367 { 368 elements.add(new ASN1IA5String(NAME_TYPE_RFC_822_NAME, rfc822Name)); 369 } 370 371 for (final String dnsName : dnsNames) 372 { 373 elements.add(new ASN1IA5String(NAME_TYPE_DNS_NAME, dnsName)); 374 } 375 376 for (final ASN1Element x400Address : x400Addresses) 377 { 378 elements.add(new ASN1Element(NAME_TYPE_X400_ADDRESS, 379 x400Address.getValue())); 380 } 381 382 for (final DN directoryName : directoryNames) 383 { 384 elements.add(new ASN1Element(NAME_TYPE_DIRECTORY_NAME, 385 X509Certificate.encodeName(directoryName).getValue())); 386 } 387 388 for (final ASN1Element ediPartyName : ediPartyNames) 389 { 390 elements.add(new ASN1Element(NAME_TYPE_EDI_PARTY_NAME, 391 ediPartyName.getValue())); 392 } 393 394 for (final String uri : uniformResourceIdentifiers) 395 { 396 elements.add(new ASN1IA5String(NAME_TYPE_UNIFORM_RESOURCE_IDENTIFIER, 397 uri)); 398 } 399 400 for (final InetAddress ipAddress : ipAddresses) 401 { 402 elements.add(new ASN1OctetString(NAME_TYPE_IP_ADDRESS, 403 ipAddress.getAddress())); 404 } 405 406 for (final OID registeredID : registeredIDs) 407 { 408 elements.add(new ASN1ObjectIdentifier(NAME_TYPE_REGISTERED_ID, 409 registeredID)); 410 } 411 412 return new ASN1Sequence(elements); 413 } 414 catch (final Exception e) 415 { 416 Debug.debugException(e); 417 throw new CertException( 418 ERR_GENERAL_NAMES_CANNOT_ENCODE.get(toString(), 419 StaticUtils.getExceptionMessage(e)), 420 e); 421 } 422 } 423 424 425 426 /** 427 * Retrieves the otherName elements from the extension. 428 * 429 * @return The otherName elements from the extension. 430 */ 431 public List<ObjectPair<OID,ASN1Element>> getOtherNames() 432 { 433 return otherNames; 434 } 435 436 437 438 /** 439 * Retrieves the RFC 822 names (email addresses) from the extension. 440 * 441 * @return The RFC 822 names from the extension. 442 */ 443 public List<String> getRFC822Names() 444 { 445 return rfc822Names; 446 } 447 448 449 450 /** 451 * Retrieves the DNS names from the extension. 452 * 453 * @return The DNS names from the extension. 454 */ 455 public List<String> getDNSNames() 456 { 457 return dnsNames; 458 } 459 460 461 462 /** 463 * Retrieves the x400Address elements from the extension. 464 * 465 * @return The x400Address elements from the extension. 466 */ 467 public List<ASN1Element> getX400Addresses() 468 { 469 return x400Addresses; 470 } 471 472 473 474 /** 475 * Retrieves the directory names from the extension. 476 * 477 * @return The directory names from the extension. 478 */ 479 public List<DN> getDirectoryNames() 480 { 481 return directoryNames; 482 } 483 484 485 486 /** 487 * Retrieves the ediPartyName elements from the extensions. 488 * 489 * @return The ediPartyName elements from the extension. 490 */ 491 public List<ASN1Element> getEDIPartyNames() 492 { 493 return ediPartyNames; 494 } 495 496 497 498 /** 499 * Retrieves the uniform resource identifiers (URIs) from the extension. 500 * 501 * @return The URIs from the extension. 502 */ 503 public List<String> getUniformResourceIdentifiers() 504 { 505 return uniformResourceIdentifiers; 506 } 507 508 509 510 /** 511 * Retrieves the IP addresses from the extension. 512 * 513 * @return The IP addresses from the extension. 514 */ 515 public List<InetAddress> getIPAddresses() 516 { 517 return ipAddresses; 518 } 519 520 521 522 /** 523 * Retrieves the registeredID elements from the extension. 524 * 525 * @return The registeredID elements from the extension. 526 */ 527 public List<OID> getRegisteredIDs() 528 { 529 return registeredIDs; 530 } 531 532 533 534 /** 535 * Retrieves a string representation of this general names element. 536 * 537 * @return A string representation of this general names element. 538 */ 539 @Override() 540 public String toString() 541 { 542 final StringBuilder buffer = new StringBuilder(); 543 toString(buffer); 544 return buffer.toString(); 545 } 546 547 548 549 /** 550 * Appends a string representation of this general names element to the 551 * provided buffer. 552 * 553 * @param buffer The buffer to which the information should be appended. 554 */ 555 public void toString(final StringBuilder buffer) 556 { 557 buffer.append("GeneralNames("); 558 559 boolean appended = false; 560 if (! dnsNames.isEmpty()) 561 { 562 buffer.append("dnsNames={"); 563 564 final Iterator<String> iterator = dnsNames.iterator(); 565 while (iterator.hasNext()) 566 { 567 buffer.append('\''); 568 buffer.append(iterator.next()); 569 buffer.append('\''); 570 571 if (iterator.hasNext()) 572 { 573 buffer.append(','); 574 } 575 } 576 577 buffer.append('}'); 578 appended = true; 579 } 580 581 if (! ipAddresses.isEmpty()) 582 { 583 if (appended) 584 { 585 buffer.append(", "); 586 } 587 588 buffer.append("ipAddresses={"); 589 590 final Iterator<InetAddress> iterator = ipAddresses.iterator(); 591 while (iterator.hasNext()) 592 { 593 buffer.append('\''); 594 buffer.append(iterator.next().getHostAddress()); 595 buffer.append('\''); 596 597 if (iterator.hasNext()) 598 { 599 buffer.append(','); 600 } 601 } 602 603 buffer.append('}'); 604 appended = true; 605 } 606 607 if (! rfc822Names.isEmpty()) 608 { 609 if (appended) 610 { 611 buffer.append(", "); 612 } 613 614 buffer.append("rfc822Names={"); 615 616 final Iterator<String> iterator = rfc822Names.iterator(); 617 while (iterator.hasNext()) 618 { 619 buffer.append('\''); 620 buffer.append(iterator.next()); 621 buffer.append('\''); 622 623 if (iterator.hasNext()) 624 { 625 buffer.append(','); 626 } 627 } 628 629 buffer.append('}'); 630 appended = true; 631 } 632 633 if (! directoryNames.isEmpty()) 634 { 635 if (appended) 636 { 637 buffer.append(", "); 638 } 639 640 buffer.append("directoryNames={"); 641 642 final Iterator<DN> iterator = directoryNames.iterator(); 643 while (iterator.hasNext()) 644 { 645 buffer.append('\''); 646 buffer.append(iterator.next()); 647 buffer.append('\''); 648 649 if (iterator.hasNext()) 650 { 651 buffer.append(','); 652 } 653 } 654 655 buffer.append('}'); 656 appended = true; 657 } 658 659 if (! uniformResourceIdentifiers.isEmpty()) 660 { 661 if (appended) 662 { 663 buffer.append(", "); 664 } 665 666 buffer.append("uniformResourceIdentifiers={"); 667 668 final Iterator<String> iterator = uniformResourceIdentifiers.iterator(); 669 while (iterator.hasNext()) 670 { 671 buffer.append('\''); 672 buffer.append(iterator.next()); 673 buffer.append('\''); 674 675 if (iterator.hasNext()) 676 { 677 buffer.append(','); 678 } 679 } 680 681 buffer.append('}'); 682 appended = true; 683 } 684 685 if (! registeredIDs.isEmpty()) 686 { 687 if (appended) 688 { 689 buffer.append(", "); 690 } 691 692 buffer.append("registeredIDs={"); 693 694 final Iterator<OID> iterator = registeredIDs.iterator(); 695 while (iterator.hasNext()) 696 { 697 buffer.append('\''); 698 buffer.append(iterator.next()); 699 buffer.append('\''); 700 701 if (iterator.hasNext()) 702 { 703 buffer.append(','); 704 } 705 } 706 707 buffer.append('}'); 708 appended = true; 709 } 710 711 if (! otherNames.isEmpty()) 712 { 713 if (appended) 714 { 715 buffer.append(", "); 716 } 717 718 buffer.append("otherNameCount="); 719 buffer.append(otherNames.size()); 720 } 721 722 if (! x400Addresses.isEmpty()) 723 { 724 if (appended) 725 { 726 buffer.append(", "); 727 } 728 729 buffer.append("x400AddressCount="); 730 buffer.append(x400Addresses.size()); 731 } 732 733 if (! ediPartyNames.isEmpty()) 734 { 735 if (appended) 736 { 737 buffer.append(", "); 738 } 739 740 buffer.append("ediPartyNameCount="); 741 buffer.append(ediPartyNames.size()); 742 } 743 744 buffer.append(')'); 745 } 746}