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