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.net.InetAddress; 041import java.util.Iterator; 042import java.util.List; 043 044import com.unboundid.ldap.sdk.DN; 045import com.unboundid.asn1.ASN1Element; 046import com.unboundid.util.Debug; 047import com.unboundid.util.NotExtensible; 048import com.unboundid.util.ObjectPair; 049import com.unboundid.util.OID; 050import com.unboundid.util.StaticUtils; 051import com.unboundid.util.ThreadSafety; 052import com.unboundid.util.ThreadSafetyLevel; 053 054import static com.unboundid.util.ssl.cert.CertMessages.*; 055 056 057 058/** 059 * This class provides support for decoding the values of the 060 * {@link SubjectAlternativeNameExtension} and 061 * {@link IssuerAlternativeNameExtension} extensions as described in 062 * <A HREF="https://www.ietf.org/rfc/rfc5280.txt">RFC 5280</A> sections 4.2.1.6 063 * and 4.2.1.7. 064 * <BR><BR> 065 * Note that this implementation only provides complete decoding for the RFC 822 066 * names (email addresses), DNS names, directory names, uniform resource 067 * identifiers, and IP addresses elements. The other elements will be left in 068 * their raw forms. 069 * <BR><BR> 070 * The value has the following encoding: 071 * <PRE> 072 * SubjectAltName ::= GeneralNames 073 * 074 * IssuerAltName ::= GeneralNames 075 * 076 * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 077 * 078 * GeneralName ::= CHOICE { 079 * otherName [0] OtherName, 080 * rfc822Name [1] IA5String, 081 * dNSName [2] IA5String, 082 * x400Address [3] ORAddress, 083 * directoryName [4] Name, 084 * ediPartyName [5] EDIPartyName, 085 * uniformResourceIdentifier [6] IA5String, 086 * iPAddress [7] OCTET STRING, 087 * registeredID [8] OBJECT IDENTIFIER } 088 * 089 * OtherName ::= SEQUENCE { 090 * type-id OBJECT IDENTIFIER, 091 * value [0] EXPLICIT ANY DEFINED BY type-id } 092 * 093 * EDIPartyName ::= SEQUENCE { 094 * nameAssigner [0] DirectoryString OPTIONAL, 095 * partyName [1] DirectoryString } 096 * </PRE> 097 */ 098@NotExtensible() 099@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 100public abstract class GeneralAlternativeNameExtension 101 extends X509CertificateExtension 102{ 103 /** 104 * The serial version UID for this serializable class. 105 */ 106 private static final long serialVersionUID = -1076071031835517176L; 107 108 109 110 // The general names for inclusion in this extension. 111 private final GeneralNames generalNames; 112 113 114 115 /** 116 * Creates a new general alternative name extension with the provided 117 * information. 118 * 119 * @param oid The OID for this extension. 120 * @param isCritical Indicates whether this extension should be 121 * considered critical. 122 * @param generalNames The general names for inclusion in this extension. 123 * 124 * @throws CertException If a problem is encountered while encoding the 125 * value for this extension. 126 */ 127 protected GeneralAlternativeNameExtension(final OID oid, 128 final boolean isCritical, 129 final GeneralNames generalNames) 130 throws CertException 131 { 132 super(oid, isCritical, generalNames.encode().encode()); 133 134 this.generalNames = generalNames; 135 } 136 137 138 139 /** 140 * Creates a new general alternative name extension from the provided generic 141 * extension. 142 * 143 * @param extension The extension to decode as a general alternative name 144 * extension. 145 * 146 * @throws CertException If the provided extension cannot be decoded as a 147 * general alternative name extension. 148 */ 149 protected GeneralAlternativeNameExtension( 150 final X509CertificateExtension extension) 151 throws CertException 152 { 153 super(extension); 154 155 try 156 { 157 generalNames = new GeneralNames(ASN1Element.decode(extension.getValue())); 158 } 159 catch (final Exception e) 160 { 161 Debug.debugException(e); 162 163 final String name; 164 if (extension.getOID().equals(SubjectAlternativeNameExtension. 165 SUBJECT_ALTERNATIVE_NAME_OID)) 166 { 167 name = INFO_SUBJECT_ALT_NAME_EXTENSION_NAME.get(); 168 } 169 else if (extension.getOID().equals(IssuerAlternativeNameExtension. 170 ISSUER_ALTERNATIVE_NAME_OID)) 171 { 172 name = INFO_ISSUER_ALT_NAME_EXTENSION_NAME.get(); 173 } 174 else 175 { 176 name = extension.getOID().toString(); 177 } 178 179 throw new CertException( 180 ERR_GENERAL_ALT_NAME_EXTENSION_CANNOT_PARSE.get( 181 String.valueOf(extension), name, 182 StaticUtils.getExceptionMessage(e)), 183 e); 184 } 185 } 186 187 188 189 /** 190 * Retrieves the {@code GeneralNames} object for this alternative name 191 * extension. 192 * 193 * @return The {@code GeneralNames} object for this alternative name 194 * extension. 195 */ 196 public final GeneralNames getGeneralNames() 197 { 198 return generalNames; 199 } 200 201 202 203 /** 204 * Retrieves the otherName elements from the extension. 205 * 206 * @return The otherName elements from the extension. 207 */ 208 public final List<ObjectPair<OID,ASN1Element>> getOtherNames() 209 { 210 return generalNames.getOtherNames(); 211 } 212 213 214 215 /** 216 * Retrieves the RFC 822 names (email addresses) from the extension. 217 * 218 * @return The RFC 822 names from the extension. 219 */ 220 public final List<String> getRFC822Names() 221 { 222 return generalNames.getRFC822Names(); 223 } 224 225 226 227 /** 228 * Retrieves the DNS names from the extension. 229 * 230 * @return The DNS names from the extension. 231 */ 232 public final List<String> getDNSNames() 233 { 234 return generalNames.getDNSNames(); 235 } 236 237 238 239 /** 240 * Retrieves the x400Address elements from the extension. 241 * 242 * @return The x400Address elements from the extension. 243 */ 244 public final List<ASN1Element> getX400Addresses() 245 { 246 return generalNames.getX400Addresses(); 247 } 248 249 250 251 /** 252 * Retrieves the directory names from the extension. 253 * 254 * @return The directory names from the extension. 255 */ 256 public final List<DN> getDirectoryNames() 257 { 258 return generalNames.getDirectoryNames(); 259 } 260 261 262 263 /** 264 * Retrieves the ediPartyName elements from the extensions. 265 * 266 * @return The ediPartyName elements from the extension. 267 */ 268 public final List<ASN1Element> getEDIPartyNames() 269 { 270 return generalNames.getEDIPartyNames(); 271 } 272 273 274 275 /** 276 * Retrieves the uniform resource identifiers (URIs) from the extension. 277 * 278 * @return The URIs from the extension. 279 */ 280 public final List<String> getUniformResourceIdentifiers() 281 { 282 return generalNames.getUniformResourceIdentifiers(); 283 } 284 285 286 287 /** 288 * Retrieves the IP addresses from the extension. 289 * 290 * @return The IP addresses from the extension. 291 */ 292 public final List<InetAddress> getIPAddresses() 293 { 294 return generalNames.getIPAddresses(); 295 } 296 297 298 299 /** 300 * Retrieves the registeredID elements from the extension. 301 * 302 * @return The registeredID elements from the extension. 303 */ 304 public final List<OID> getRegisteredIDs() 305 { 306 return generalNames.getRegisteredIDs(); 307 } 308 309 310 311 /** 312 * Appends a string representation of this extension to the provided buffer. 313 * 314 * @param extensionName The name to use for this extension. 315 * @param buffer The buffer to which the information should be 316 * appended. 317 */ 318 protected void toString(final String extensionName, 319 final StringBuilder buffer) 320 { 321 buffer.append(extensionName); 322 buffer.append("(oid='"); 323 buffer.append(getOID()); 324 buffer.append("', isCritical="); 325 buffer.append(isCritical()); 326 327 if (! getDNSNames().isEmpty()) 328 { 329 buffer.append(", dnsNames={"); 330 331 final Iterator<String> iterator = getDNSNames().iterator(); 332 while (iterator.hasNext()) 333 { 334 buffer.append('\''); 335 buffer.append(iterator.next()); 336 buffer.append('\''); 337 338 if (iterator.hasNext()) 339 { 340 buffer.append(','); 341 } 342 } 343 344 buffer.append('}'); 345 } 346 347 if (! getIPAddresses().isEmpty()) 348 { 349 buffer.append(", ipAddresses={"); 350 351 final Iterator<InetAddress> iterator = getIPAddresses().iterator(); 352 while (iterator.hasNext()) 353 { 354 buffer.append('\''); 355 buffer.append(iterator.next().getHostAddress()); 356 buffer.append('\''); 357 358 if (iterator.hasNext()) 359 { 360 buffer.append(','); 361 } 362 } 363 364 buffer.append('}'); 365 } 366 367 if (! getRFC822Names().isEmpty()) 368 { 369 buffer.append(", rfc822Names={"); 370 371 final Iterator<String> iterator = getRFC822Names().iterator(); 372 while (iterator.hasNext()) 373 { 374 buffer.append('\''); 375 buffer.append(iterator.next()); 376 buffer.append('\''); 377 378 if (iterator.hasNext()) 379 { 380 buffer.append(','); 381 } 382 } 383 384 buffer.append('}'); 385 } 386 387 if (! getDirectoryNames().isEmpty()) 388 { 389 buffer.append(", directoryNames={"); 390 391 final Iterator<DN> iterator = getDirectoryNames().iterator(); 392 while (iterator.hasNext()) 393 { 394 buffer.append('\''); 395 buffer.append(iterator.next()); 396 buffer.append('\''); 397 398 if (iterator.hasNext()) 399 { 400 buffer.append(','); 401 } 402 } 403 404 buffer.append('}'); 405 } 406 407 if (! getUniformResourceIdentifiers().isEmpty()) 408 { 409 buffer.append(", uniformResourceIdentifiers={"); 410 411 final Iterator<String> iterator = 412 getUniformResourceIdentifiers().iterator(); 413 while (iterator.hasNext()) 414 { 415 buffer.append('\''); 416 buffer.append(iterator.next()); 417 buffer.append('\''); 418 419 if (iterator.hasNext()) 420 { 421 buffer.append(','); 422 } 423 } 424 425 buffer.append('}'); 426 } 427 428 if (! getRegisteredIDs().isEmpty()) 429 { 430 buffer.append(", registeredIDs={"); 431 432 final Iterator<OID> iterator = getRegisteredIDs().iterator(); 433 while (iterator.hasNext()) 434 { 435 buffer.append('\''); 436 buffer.append(iterator.next()); 437 buffer.append('\''); 438 439 if (iterator.hasNext()) 440 { 441 buffer.append(','); 442 } 443 } 444 445 buffer.append('}'); 446 } 447 448 if (! getOtherNames().isEmpty()) 449 { 450 buffer.append(", otherNameCount="); 451 buffer.append(getOtherNames().size()); 452 } 453 454 if (! getX400Addresses().isEmpty()) 455 { 456 buffer.append(", x400AddressCount="); 457 buffer.append(getX400Addresses().size()); 458 } 459 460 if (! getEDIPartyNames().isEmpty()) 461 { 462 buffer.append(", ediPartyNameCount="); 463 buffer.append(getEDIPartyNames().size()); 464 } 465 466 buffer.append(')'); 467 } 468}