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.math.BigInteger; 026import java.util.ArrayList; 027 028import com.unboundid.asn1.ASN1BigInteger; 029import com.unboundid.asn1.ASN1Element; 030import com.unboundid.asn1.ASN1OctetString; 031import com.unboundid.asn1.ASN1Sequence; 032import com.unboundid.util.Debug; 033import com.unboundid.util.NotMutable; 034import com.unboundid.util.OID; 035import com.unboundid.util.StaticUtils; 036import com.unboundid.util.ThreadSafety; 037import com.unboundid.util.ThreadSafetyLevel; 038 039import static com.unboundid.util.ssl.cert.CertMessages.*; 040 041 042 043/** 044 * This class provides an implementation of the authority key identifier X.509 045 * certificate extension as described in 046 * <A HREF="https://www.ietf.org/rfc/rfc5280.txt">RFC 5280</A> section 4.2.1.1. 047 * The OID for this extension is 2.5.29.35 and the value has the following 048 * encoding: 049 * <PRE> 050 * AuthorityKeyIdentifier ::= SEQUENCE { 051 * keyIdentifier [0] KeyIdentifier OPTIONAL, 052 * authorityCertIssuer [1] GeneralNames OPTIONAL, 053 * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } 054 * </PRE> 055 * The actual format of the key identifier is not specified, although RFC 5280 056 * does specify a couple of possibilities. 057 */ 058@NotMutable() 059@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 060public final class AuthorityKeyIdentifierExtension 061 extends X509CertificateExtension 062{ 063 /** 064 * The OID (2.5.29.35) for authority key identifier extensions. 065 */ 066 public static final OID AUTHORITY_KEY_IDENTIFIER_OID = new OID("2.5.29.35"); 067 068 069 070 /** 071 * The DER type for the key identifier element in the value sequence. 072 */ 073 private static final byte TYPE_KEY_IDENTIFIER = (byte) 0x80; 074 075 076 077 /** 078 * The DER type for the authority cert issuer element in the value sequence. 079 */ 080 private static final byte TYPE_AUTHORITY_CERT_ISSUER = (byte) 0xA1; 081 082 083 084 /** 085 * The DER type for the authority cert serial number element in the value 086 * sequence. 087 */ 088 private static final byte TYPE_AUTHORITY_CERT_SERIAL_NUMBER = (byte) 0x82; 089 090 091 092 /** 093 * The serial version UID for this serializable class. 094 */ 095 private static final long serialVersionUID = 8913323557731547122L; 096 097 098 099 // The key identifier for this extension. 100 private final ASN1OctetString keyIdentifier; 101 102 // The serial number for the authority certificate. 103 private final BigInteger authorityCertSerialNumber; 104 105 // General names for the authority certificate. 106 private final GeneralNames authorityCertIssuer; 107 108 109 110 /** 111 * Creates a new authority key identifier extension with the provided 112 * information. 113 * 114 * @param isCritical Indicates whether this extension should 115 * be considered critical. 116 * @param keyIdentifier The key identifier. This may be 117 * {@code null} if it should not be 118 * included in the extension. 119 * @param authorityCertIssuer The authority certificate issuer. This 120 * may be {@code null} if it should not be 121 * included in the extension. 122 * @param authorityCertSerialNumber The authority certificate serial number. 123 * This may be {@code null} if it should 124 * not be included in the extension. 125 * 126 * @throws CertException If a problem is encountered while encoding the 127 * value. 128 */ 129 AuthorityKeyIdentifierExtension(final boolean isCritical, 130 final ASN1OctetString keyIdentifier, 131 final GeneralNames authorityCertIssuer, 132 final BigInteger authorityCertSerialNumber) 133 throws CertException 134 { 135 super(AUTHORITY_KEY_IDENTIFIER_OID, isCritical, 136 encodeValue(keyIdentifier, authorityCertIssuer, 137 authorityCertSerialNumber)); 138 139 this.keyIdentifier = keyIdentifier; 140 this.authorityCertIssuer = authorityCertIssuer; 141 this.authorityCertSerialNumber = authorityCertSerialNumber; 142 } 143 144 145 146 /** 147 * Creates a new authority key identifier extension from the provided generic 148 * extension. 149 * 150 * @param extension The extension to decode as a subject key identifier 151 * extension. 152 * 153 * @throws CertException If the provided extension cannot be decoded as a 154 * subject alternative name extension. 155 */ 156 AuthorityKeyIdentifierExtension(final X509CertificateExtension extension) 157 throws CertException 158 { 159 super(extension); 160 161 try 162 { 163 ASN1OctetString keyID = null; 164 BigInteger serialNumber = null; 165 GeneralNames generalNames = null; 166 167 for (final ASN1Element element : 168 ASN1Sequence.decodeAsSequence(extension.getValue()).elements()) 169 { 170 switch (element.getType()) 171 { 172 case TYPE_KEY_IDENTIFIER: 173 keyID = element.decodeAsOctetString(); 174 break; 175 case TYPE_AUTHORITY_CERT_ISSUER: 176 final ASN1Element generalNamesElement = 177 ASN1Element.decode(element.getValue()); 178 generalNames = new GeneralNames(generalNamesElement); 179 break; 180 case TYPE_AUTHORITY_CERT_SERIAL_NUMBER: 181 serialNumber = element.decodeAsBigInteger().getBigIntegerValue(); 182 break; 183 } 184 } 185 186 keyIdentifier = keyID; 187 authorityCertIssuer = generalNames; 188 authorityCertSerialNumber = serialNumber; 189 } 190 catch (final Exception e) 191 { 192 Debug.debugException(e); 193 throw new CertException( 194 ERR_AUTHORITY_KEY_ID_EXTENSION_CANNOT_PARSE.get( 195 String.valueOf(extension), StaticUtils.getExceptionMessage(e)), 196 e); 197 } 198 } 199 200 201 202 /** 203 * Encodes the provided information for use as the value of this extension. 204 * 205 * @param keyIdentifier The key identifier. This may be 206 * {@code null} if it should not be 207 * included in the extension. 208 * @param authorityCertIssuer The authority certificate issuer. This 209 * may be {@code null} if it should not be 210 * included in the extension. 211 * @param authorityCertSerialNumber The authority certificate serial number. 212 * This may be {@code null} if it should 213 * not be included in the extension. 214 * 215 * @return The encoded value. 216 * 217 * @throws CertException If a problem is encountered while encoding the 218 * value. 219 */ 220 private static byte[] encodeValue(final ASN1OctetString keyIdentifier, 221 final GeneralNames authorityCertIssuer, 222 final BigInteger authorityCertSerialNumber) 223 throws CertException 224 { 225 final ArrayList<ASN1Element> elements = new ArrayList<>(3); 226 if (keyIdentifier != null) 227 { 228 elements.add(new ASN1OctetString(TYPE_KEY_IDENTIFIER, 229 keyIdentifier.getValue())); 230 } 231 232 if (authorityCertIssuer != null) 233 { 234 elements.add(new ASN1Element(TYPE_AUTHORITY_CERT_ISSUER, 235 authorityCertIssuer.encode().encode())); 236 } 237 238 if (authorityCertSerialNumber != null) 239 { 240 elements.add(new ASN1BigInteger(TYPE_AUTHORITY_CERT_SERIAL_NUMBER, 241 authorityCertSerialNumber)); 242 } 243 244 return new ASN1Sequence(elements).encode(); 245 } 246 247 248 249 /** 250 * Retrieves the key identifier for this extension, if available. 251 * 252 * @return The key identifier for this extension, or {@code null} if it 253 * was not included in the extension. 254 */ 255 public ASN1OctetString getKeyIdentifier() 256 { 257 return keyIdentifier; 258 } 259 260 261 262 /** 263 * Retrieves the general names for the authority certificate, if available. 264 * 265 * @return The general names for the authority certificate, or {@code null} 266 * if it was not included in the extension. 267 */ 268 public GeneralNames getAuthorityCertIssuer() 269 { 270 return authorityCertIssuer; 271 } 272 273 274 275 /** 276 * Retrieves the serial number for the authority certificate, if available. 277 * 278 * @return The serial number for the authority certificate, or {@code null} 279 * if it was not included in the extension. 280 */ 281 public BigInteger getAuthorityCertSerialNumber() 282 { 283 return authorityCertSerialNumber; 284 } 285 286 287 288 /** 289 * {@inheritDoc} 290 */ 291 @Override() 292 public String getExtensionName() 293 { 294 return INFO_AUTHORITY_KEY_ID_EXTENSION_NAME.get(); 295 } 296 297 298 299 /** 300 * {@inheritDoc} 301 */ 302 @Override() 303 public void toString(final StringBuilder buffer) 304 { 305 buffer.append("AuthorityKeyIdentifierExtension(oid='"); 306 buffer.append(getOID()); 307 buffer.append("', isCritical="); 308 buffer.append(isCritical()); 309 310 if (keyIdentifier != null) 311 { 312 buffer.append(", keyIdentifierBytes='"); 313 StaticUtils.toHex(keyIdentifier.getValue(), ":", buffer); 314 buffer.append('\''); 315 } 316 317 if (authorityCertIssuer != null) 318 { 319 buffer.append(", authorityCertIssuer="); 320 authorityCertIssuer.toString(buffer); 321 } 322 323 if (authorityCertSerialNumber != null) 324 { 325 buffer.append(", authorityCertSerialNumber='"); 326 StaticUtils.toHex(authorityCertSerialNumber.toByteArray(), ":", buffer); 327 buffer.append('\''); 328 } 329 330 331 buffer.append(')'); 332 } 333}