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.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 generalNames = new GeneralNames(element); 177 break; 178 case TYPE_AUTHORITY_CERT_SERIAL_NUMBER: 179 serialNumber = element.decodeAsBigInteger().getBigIntegerValue(); 180 break; 181 } 182 } 183 184 keyIdentifier = keyID; 185 authorityCertIssuer = generalNames; 186 authorityCertSerialNumber = serialNumber; 187 } 188 catch (final Exception e) 189 { 190 Debug.debugException(e); 191 throw new CertException( 192 ERR_AUTHORITY_KEY_ID_EXTENSION_CANNOT_PARSE.get( 193 String.valueOf(extension), StaticUtils.getExceptionMessage(e)), 194 e); 195 } 196 } 197 198 199 200 /** 201 * Encodes the provided information for use as the value of this extension. 202 * 203 * @param keyIdentifier The key identifier. This may be 204 * {@code null} if it should not be 205 * included in the extension. 206 * @param authorityCertIssuer The authority certificate issuer. This 207 * may be {@code null} if it should not be 208 * included in the extension. 209 * @param authorityCertSerialNumber The authority certificate serial number. 210 * This may be {@code null} if it should 211 * not be included in the extension. 212 * 213 * @return The encoded value. 214 * 215 * @throws CertException If a problem is encountered while encoding the 216 * value. 217 */ 218 private static byte[] encodeValue(final ASN1OctetString keyIdentifier, 219 final GeneralNames authorityCertIssuer, 220 final BigInteger authorityCertSerialNumber) 221 throws CertException 222 { 223 final ArrayList<ASN1Element> elements = new ArrayList<>(3); 224 if (keyIdentifier != null) 225 { 226 elements.add(new ASN1OctetString(TYPE_KEY_IDENTIFIER, 227 keyIdentifier.getValue())); 228 } 229 230 if (authorityCertIssuer != null) 231 { 232 elements.add(new ASN1Element(TYPE_AUTHORITY_CERT_ISSUER, 233 authorityCertIssuer.encode().getValue())); 234 } 235 236 if (authorityCertSerialNumber != null) 237 { 238 elements.add(new ASN1BigInteger(TYPE_AUTHORITY_CERT_SERIAL_NUMBER, 239 authorityCertSerialNumber)); 240 } 241 242 return new ASN1Sequence(elements).encode(); 243 } 244 245 246 247 /** 248 * Retrieves the key identifier for this extension, if available. 249 * 250 * @return The key identifier for this extension, or {@code null} if it 251 * was not included in the extension. 252 */ 253 public ASN1OctetString getKeyIdentifier() 254 { 255 return keyIdentifier; 256 } 257 258 259 260 /** 261 * Retrieves the general names for the authority certificate, if available. 262 * 263 * @return The general names for the authority certificate, or {@code null} 264 * if it was not included in the extension. 265 */ 266 public GeneralNames getAuthorityCertIssuer() 267 { 268 return authorityCertIssuer; 269 } 270 271 272 273 /** 274 * Retrieves the serial number for the authority certificate, if available. 275 * 276 * @return The serial number for the authority certificate, or {@code null} 277 * if it was not included in the extension. 278 */ 279 public BigInteger getAuthorityCertSerialNumber() 280 { 281 return authorityCertSerialNumber; 282 } 283 284 285 286 /** 287 * {@inheritDoc} 288 */ 289 @Override() 290 public String getExtensionName() 291 { 292 return INFO_AUTHORITY_KEY_ID_EXTENSION_NAME.get(); 293 } 294 295 296 297 /** 298 * {@inheritDoc} 299 */ 300 @Override() 301 public void toString(final StringBuilder buffer) 302 { 303 buffer.append("AuthorityKeyIdentifierExtension(oid='"); 304 buffer.append(getOID()); 305 buffer.append("', isCritical="); 306 buffer.append(isCritical()); 307 308 if (keyIdentifier != null) 309 { 310 buffer.append(", keyIdentifierBytes='"); 311 StaticUtils.toHex(keyIdentifier.getValue(), ":", buffer); 312 buffer.append('\''); 313 } 314 315 if (authorityCertIssuer != null) 316 { 317 buffer.append(", authorityCertIssuer="); 318 authorityCertIssuer.toString(buffer); 319 } 320 321 if (authorityCertSerialNumber != null) 322 { 323 buffer.append(", authorityCertSerialNumber='"); 324 StaticUtils.toHex(authorityCertSerialNumber.toByteArray(), ":", buffer); 325 buffer.append('\''); 326 } 327 328 329 buffer.append(')'); 330 } 331}