001/*
002 * Copyright 2017-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2017-2018 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}