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}