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