001/*
002 * Copyright 2017-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2017-2024 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-2024 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.io.Serializable;
041import java.security.KeyFactory;
042import java.security.KeyPair;
043import java.security.MessageDigest;
044import java.security.PrivateKey;
045import java.security.PublicKey;
046import java.security.Signature;
047import java.security.spec.X509EncodedKeySpec;
048import java.util.ArrayList;
049import java.util.Collections;
050import java.util.Iterator;
051import java.util.List;
052
053import com.unboundid.asn1.ASN1BitString;
054import com.unboundid.asn1.ASN1Element;
055import com.unboundid.asn1.ASN1Integer;
056import com.unboundid.asn1.ASN1ObjectIdentifier;
057import com.unboundid.asn1.ASN1OctetString;
058import com.unboundid.asn1.ASN1Sequence;
059import com.unboundid.asn1.ASN1Set;
060import com.unboundid.ldap.sdk.DN;
061import com.unboundid.util.Base64;
062import com.unboundid.util.CryptoHelper;
063import com.unboundid.util.Debug;
064import com.unboundid.util.NotMutable;
065import com.unboundid.util.NotNull;
066import com.unboundid.util.Nullable;
067import com.unboundid.util.ObjectPair;
068import com.unboundid.util.OID;
069import com.unboundid.util.StaticUtils;
070import com.unboundid.util.ThreadSafety;
071import com.unboundid.util.ThreadSafetyLevel;
072
073import static com.unboundid.util.ssl.cert.CertMessages.*;
074
075
076
077/**
078 * This class provides support for decoding a PKCS #10 certificate signing
079 * request (aka certification request or CSR) as defined in
080 * <A HREF="https://www.ietf.org/rfc/rfc2986.txt">RFC 2986</A>.  The certificate
081 * signing request is encoded using the ASN.1 Distinguished Encoding Rules
082 * (DER), which is a subset of BER, and is supported by the code in the
083 * {@code com.unboundid.asn1} package.  The ASN.1 specification is as follows:
084 * <PRE>
085 *   CertificationRequest ::= SEQUENCE {
086 *        certificationRequestInfo CertificationRequestInfo,
087 *        signatureAlgorithm AlgorithmIdentifier,
088 *        signature          BIT STRING
089 *   }
090 *
091 *   CertificationRequestInfo ::= SEQUENCE {
092 *        version       INTEGER { v1(0) } (v1,...),
093 *        subject       Name,
094 *        subjectPKInfo SubjectPublicKeyInfo,
095 *        attributes    [0] Attributes
096 *   }
097 *
098 *   SubjectPublicKeyInfo ::= SEQUENCE {
099 *        algorithm        AlgorithmIdentifier,
100 *        subjectPublicKey BIT STRING
101 *   }
102 *
103 *   PKInfoAlgorithms ALGORITHM ::= {
104 *        ...  -- add any locally defined algorithms here -- }
105 *
106 *   Attributes ::= SET OF Attribute
107 *
108 *   CRIAttributes  ATTRIBUTE  ::= {
109 *        ... -- add any locally defined attributes here -- }
110 *
111 *   Attribute ::= SEQUENCE {
112 *        type   OBJECT IDENTIFIER,
113 *        values SET SIZE(1..MAX)
114 *   }
115 *
116 *   AlgorithmIdentifier ::= SEQUENCE {
117 *        algorithm          OBJECT IDENTIFIER,
118 *        parameters         ANY OPTIONAL
119 *   }
120 *
121 *   SignatureAlgorithms ALGORITHM ::= {
122 *        ... -- add any locally defined algorithms here -- }
123 * </PRE>
124 */
125@NotMutable()
126@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
127public final class PKCS10CertificateSigningRequest
128       implements Serializable
129{
130  /**
131   * The DER type for the attributes element.
132   */
133  private static final byte TYPE_ATTRIBUTES = (byte) 0xA0;
134
135
136
137  /**
138   * The OID for the request attribute that holds the set of requested
139   * certificate extensions.
140   */
141  @NotNull private static final OID  ATTRIBUTE_OID_EXTENSIONS =
142       new OID("1.2.840.113549.1.9.14");
143
144
145
146  /**
147   * The serial version UID for this serializable class.
148   */
149  private static final long serialVersionUID = -1665446530589389194L;
150
151
152
153  // The signature value for the request.
154  @NotNull private final ASN1BitString signatureValue;
155
156  // The encoded public key for the request.
157  @NotNull private final ASN1BitString encodedPublicKey;
158
159  // The ASN.1 element with the encoded public key algorithm parameters.
160  @Nullable private final ASN1Element publicKeyAlgorithmParameters;
161
162  // The ASN.1 element with the encoded signature algorithm parameters.
163  @Nullable private final ASN1Element signatureAlgorithmParameters;
164
165  // The bytes that comprise the encoded representation of the PKCS #10
166  // certificate signing request.
167  @NotNull private final byte[] pkcs10CertificateSigningRequestBytes;
168
169  // The decoded public key for this request, if available.
170  @Nullable private final DecodedPublicKey decodedPublicKey;
171
172  // The subject DN for the request.
173  @NotNull private final DN subjectDN;
174
175  // The list of attributes for the request.
176  @NotNull private final List<ObjectPair<OID,ASN1Set>> requestAttributes;
177
178  // The list of extensions for the request.
179  @NotNull private final List<X509CertificateExtension> extensions;
180
181  // The OID for the public key algorithm.
182  @NotNull private final OID publicKeyAlgorithmOID;
183
184  // The OID for the signature algorithm.
185  @NotNull private final OID signatureAlgorithmOID;
186
187  // The PKCS #10 certificate signing request version.
188  @NotNull private final PKCS10CertificateSigningRequestVersion version;
189
190  // The public key algorithm name that corresponds with the public key
191  // algorithm OID, if available.
192  @Nullable private final String publicKeyAlgorithmName;
193
194  // The signature algorithm name that corresponds with the signature algorithm
195  // OID, if available.
196  @Nullable private final String signatureAlgorithmName;
197
198
199
200  /**
201   * Creates a new PKCS #10 certificate signing request with the provided
202   * information.  This is primarily intended for unit testing and other
203   * internal use.
204   *
205   * @param  version                       The version number for the
206   *                                       certificate signing request.
207   * @param  signatureAlgorithmOID         The signature algorithm OID for the
208   *                                       request.  This must not be
209   *                                       {@code null}.
210   * @param  signatureAlgorithmParameters  The encoded signature algorithm
211   *                                       parameters for the request.  This
212   *                                       may be {@code null} if there are no
213   *                                       parameters.
214   * @param  signatureValue                The encoded signature for the
215   *                                       request.  This must not be
216   *                                       {@code null}.
217   * @param  subjectDN                     The subject DN for the request.  This
218   *                                       This must not be {@code null}.
219   * @param  publicKeyAlgorithmOID         The OID of the public key algorithm
220   *                                       for the request.  This must not be
221   *                                       {@code null}.
222   * @param  publicKeyAlgorithmParameters  The encoded public key algorithm
223   *                                       parameters for the request.  This may
224   *                                       be {@code null} if there are no
225   *                                       parameters.
226   * @param  encodedPublicKey              The encoded public key for the
227   *                                       request.  This must not be
228   *                                       {@code null}.
229   * @param  decodedPublicKey              The decoded public key for the
230   *                                       request.  This may be {@code null} if
231   *                                       it is not available.
232   * @param  nonExtensionAttributes        Any attributes to include in the
233   *                                       request other than the set of
234   *                                       extensions.  This may be {@code null}
235   *                                       or empty if no additional attributes
236   *                                       are needed.
237   * @param  extensions                    The set of extensions included in the
238   *                                       request.  This must not be
239   *                                       {@code null} but may be empty.
240   *
241   * @throws  CertException  If a problem is encountered while creating the
242   *                         certificate signing request.
243   */
244  PKCS10CertificateSigningRequest(
245       @NotNull final PKCS10CertificateSigningRequestVersion version,
246       @NotNull final OID signatureAlgorithmOID,
247       @Nullable final ASN1Element signatureAlgorithmParameters,
248       @NotNull final ASN1BitString signatureValue,
249       @NotNull final DN subjectDN, @NotNull final OID publicKeyAlgorithmOID,
250       @Nullable final ASN1Element publicKeyAlgorithmParameters,
251       @NotNull final ASN1BitString encodedPublicKey,
252       @Nullable final DecodedPublicKey decodedPublicKey,
253       @Nullable final List<ObjectPair<OID,ASN1Set>> nonExtensionAttributes,
254       @NotNull final X509CertificateExtension... extensions)
255       throws CertException
256  {
257    this.version = version;
258    this.signatureAlgorithmOID = signatureAlgorithmOID;
259    this.signatureAlgorithmParameters = signatureAlgorithmParameters;
260    this.signatureValue = signatureValue;
261    this.subjectDN = subjectDN;
262    this.publicKeyAlgorithmOID = publicKeyAlgorithmOID;
263    this.publicKeyAlgorithmParameters = publicKeyAlgorithmParameters;
264    this.encodedPublicKey = encodedPublicKey;
265    this.decodedPublicKey = decodedPublicKey;
266    this.extensions = StaticUtils.toList(extensions);
267
268    final SignatureAlgorithmIdentifier signatureAlgorithmIdentifier =
269         SignatureAlgorithmIdentifier.forOID(signatureAlgorithmOID);
270    if (signatureAlgorithmIdentifier == null)
271    {
272      signatureAlgorithmName = null;
273    }
274    else
275    {
276      signatureAlgorithmName =
277           signatureAlgorithmIdentifier.getUserFriendlyName();
278    }
279
280    final PublicKeyAlgorithmIdentifier publicKeyAlgorithmIdentifier =
281         PublicKeyAlgorithmIdentifier.forOID(publicKeyAlgorithmOID);
282    if (publicKeyAlgorithmIdentifier == null)
283    {
284      publicKeyAlgorithmName = null;
285    }
286    else
287    {
288      publicKeyAlgorithmName = publicKeyAlgorithmIdentifier.getName();
289    }
290
291    final ArrayList<ObjectPair<OID, ASN1Set>> attrs = new ArrayList<>(10);
292    if (nonExtensionAttributes != null)
293    {
294      attrs.addAll(nonExtensionAttributes);
295    }
296
297    if (extensions.length > 0)
298    {
299      final ArrayList<ASN1Element> extensionElements =
300           new ArrayList<>(extensions.length);
301      for (final X509CertificateExtension e : extensions)
302      {
303        extensionElements.add(e.encode());
304      }
305
306      attrs.add(new ObjectPair<>(ATTRIBUTE_OID_EXTENSIONS,
307           new ASN1Set(new ASN1Sequence(extensionElements))));
308    }
309
310    requestAttributes = Collections.unmodifiableList(attrs);
311
312    pkcs10CertificateSigningRequestBytes = encode().encode();
313  }
314
315
316
317  /**
318   * Decodes the contents of the provided byte array as a PKCS #10 certificate
319   * signing request.
320   *
321   * @param  encodedRequest  The byte array containing the encoded PKCS #10
322   *                         certificate signing request.  This must not be
323   *                         {@code null}.
324   *
325   * @throws  CertException  If the contents of the provided byte array could
326   *                         not be decoded as a valid PKCS #10 certificate
327   *                         signing request.
328   */
329  public PKCS10CertificateSigningRequest(
330              @NotNull final byte[] encodedRequest)
331         throws CertException
332  {
333    pkcs10CertificateSigningRequestBytes = encodedRequest;
334
335    final ASN1Element[] requestElements;
336    try
337    {
338      requestElements =
339           ASN1Sequence.decodeAsSequence(encodedRequest).elements();
340    }
341    catch (final Exception e)
342    {
343      Debug.debugException(e);
344      throw new CertException(
345           ERR_CSR_DECODE_NOT_SEQUENCE.get(StaticUtils.getExceptionMessage(e)),
346           e);
347    }
348
349    if (requestElements.length != 3)
350    {
351      throw new CertException(
352           ERR_CSR_DECODE_UNEXPECTED_SEQUENCE_ELEMENT_COUNT.get(
353                requestElements.length));
354    }
355
356    final ASN1Element[] requestInfoElements;
357    try
358    {
359      requestInfoElements =
360           ASN1Sequence.decodeAsSequence(requestElements[0]).elements();
361    }
362    catch (final Exception e)
363    {
364      Debug.debugException(e);
365      throw new CertException(
366           ERR_CSR_DECODE_FIRST_ELEMENT_NOT_SEQUENCE.get(
367                StaticUtils.getExceptionMessage(e)),
368           e);
369    }
370
371    try
372    {
373      final int versionIntValue =
374           requestInfoElements[0].decodeAsInteger().intValue();
375      version = PKCS10CertificateSigningRequestVersion.valueOf(versionIntValue);
376      if (version == null)
377      {
378        throw new CertException(
379             ERR_CSR_DECODE_UNSUPPORTED_VERSION.get(version));
380      }
381    }
382    catch (final CertException e)
383    {
384      Debug.debugException(e);
385      throw e;
386    }
387    catch (final Exception e)
388    {
389      Debug.debugException(e);
390      throw new CertException(
391           ERR_CSR_DECODE_CANNOT_PARSE_VERSION.get(
392                StaticUtils.getExceptionMessage(e)),
393           e);
394    }
395
396    try
397    {
398      subjectDN = X509Certificate.decodeName(requestInfoElements[1]);
399    }
400    catch (final Exception e)
401    {
402      Debug.debugException(e);
403      throw new CertException(
404           ERR_CSR_DECODE_CANNOT_PARSE_SUBJECT_DN.get(
405                StaticUtils.getExceptionMessage(e)),
406           e);
407    }
408
409    try
410    {
411      final ASN1Element[] subjectPublicKeyInfoElements =
412           requestInfoElements[2].decodeAsSequence().elements();
413      final ASN1Element[] publicKeyAlgorithmElements =
414           subjectPublicKeyInfoElements[0].decodeAsSequence().elements();
415      publicKeyAlgorithmOID =
416           publicKeyAlgorithmElements[0].decodeAsObjectIdentifier().getOID();
417      if (publicKeyAlgorithmElements.length > 1)
418      {
419        publicKeyAlgorithmParameters = publicKeyAlgorithmElements[1];
420      }
421      else
422      {
423        publicKeyAlgorithmParameters = null;
424      }
425
426      encodedPublicKey = subjectPublicKeyInfoElements[1].decodeAsBitString();
427    }
428    catch (final Exception e)
429    {
430      Debug.debugException(e);
431      throw new CertException(
432           ERR_CSR_DECODE_CANNOT_PARSE_PUBLIC_KEY_INFO.get(
433                StaticUtils.getExceptionMessage(e)),
434           e);
435    }
436
437    final PublicKeyAlgorithmIdentifier publicKeyAlgorithmIdentifier =
438         PublicKeyAlgorithmIdentifier.forOID(publicKeyAlgorithmOID);
439    if (publicKeyAlgorithmIdentifier == null)
440    {
441      publicKeyAlgorithmName = null;
442      decodedPublicKey = null;
443    }
444    else
445    {
446      publicKeyAlgorithmName = publicKeyAlgorithmIdentifier.getName();
447
448      DecodedPublicKey pk = null;
449      switch (publicKeyAlgorithmIdentifier)
450      {
451        case RSA:
452          try
453          {
454            pk = new RSAPublicKey(encodedPublicKey);
455          }
456          catch (final Exception e)
457          {
458            Debug.debugException(e);
459          }
460          break;
461
462        case EC:
463          try
464          {
465            pk = new EllipticCurvePublicKey(encodedPublicKey);
466          }
467          catch (final Exception e)
468          {
469            Debug.debugException(e);
470          }
471          break;
472      }
473
474      decodedPublicKey = pk;
475    }
476
477    final ArrayList<ObjectPair<OID,ASN1Set>> attrList = new ArrayList<>(10);
478    final ArrayList<X509CertificateExtension> extList = new ArrayList<>(10);
479    if (requestInfoElements.length > 3)
480    {
481      for (int i=3; i < requestInfoElements.length; i++)
482      {
483        final ASN1Element element = requestInfoElements[i];
484        if (element.getType() == TYPE_ATTRIBUTES)
485        {
486          try
487          {
488            for (final ASN1Element attrSetElement :
489                 element.decodeAsSet().elements())
490            {
491              final ASN1Element[] attrElements =
492                   attrSetElement.decodeAsSequence().elements();
493              final OID attrOID =
494                   attrElements[0].decodeAsObjectIdentifier().getOID();
495              final ASN1Set attrValues = attrElements[1].decodeAsSet();
496              attrList.add(new ObjectPair<>(attrOID, attrValues));
497            }
498          }
499          catch (final Exception e)
500          {
501            Debug.debugException(e);
502            throw new CertException(
503                 ERR_CSR_DECODE_CANNOT_PARSE_ATTRS.get(
504                      StaticUtils.getExceptionMessage(e)),
505                 e);
506          }
507
508          for (final ObjectPair<OID,ASN1Set> p : attrList)
509          {
510            if (p.getFirst().equals(ATTRIBUTE_OID_EXTENSIONS))
511            {
512              try
513              {
514                for (final ASN1Element extElement :
515                     p.getSecond().elements()[0].decodeAsSequence().elements())
516                {
517                  extList.add(X509CertificateExtension.decode(extElement));
518                }
519              }
520              catch (final Exception e)
521              {
522                Debug.debugException(e);
523                throw new CertException(
524                     ERR_CSR_DECODE_CANNOT_PARSE_EXT_ATTR.get(
525                          p.getFirst(), StaticUtils.getExceptionMessage(e)),
526                     e);
527              }
528            }
529          }
530        }
531      }
532    }
533
534    requestAttributes = Collections.unmodifiableList(attrList);
535    extensions = Collections.unmodifiableList(extList);
536
537
538    try
539    {
540      final ASN1Element[] signatureAlgorithmElements =
541           requestElements[1].decodeAsSequence().elements();
542      signatureAlgorithmOID =
543           signatureAlgorithmElements[0].decodeAsObjectIdentifier().getOID();
544      if (signatureAlgorithmElements.length > 1)
545      {
546        signatureAlgorithmParameters = signatureAlgorithmElements[1];
547      }
548      else
549      {
550        signatureAlgorithmParameters = null;
551      }
552    }
553    catch (final Exception e)
554    {
555      Debug.debugException(e);
556      throw new CertException(
557           ERR_CSR_DECODE_CANNOT_PARSE_SIG_ALG.get(
558                StaticUtils.getExceptionMessage(e)),
559           e);
560    }
561
562    final SignatureAlgorithmIdentifier signatureAlgorithmIdentifier =
563         SignatureAlgorithmIdentifier.forOID(signatureAlgorithmOID);
564    if (signatureAlgorithmIdentifier == null)
565    {
566      signatureAlgorithmName = null;
567    }
568    else
569    {
570      signatureAlgorithmName =
571           signatureAlgorithmIdentifier.getUserFriendlyName();
572    }
573
574    try
575    {
576      signatureValue = requestElements[2].decodeAsBitString();
577    }
578    catch (final Exception e)
579    {
580      Debug.debugException(e);
581      throw new CertException(
582           ERR_CSR_DECODE_CANNOT_PARSE_SIG_VALUE.get(
583                StaticUtils.getExceptionMessage(e)),
584           e);
585    }
586  }
587
588
589
590  /**
591   * Encodes this PKCS #10 certificate signing request to an ASN.1 element.
592   *
593   * @return  The encoded PKCS #10 certificate signing request.
594   *
595   * @throws  CertException  If a problem is encountered while trying to encode
596   *                         the PKCS #10 certificate signing request.
597   */
598  @NotNull()
599  private ASN1Element encode()
600          throws CertException
601  {
602    try
603    {
604      final ArrayList<ASN1Element> requestInfoElements = new ArrayList<>(4);
605      requestInfoElements.add(new ASN1Integer(version.getIntValue()));
606      requestInfoElements.add(X509Certificate.encodeName(subjectDN));
607
608      if (publicKeyAlgorithmParameters == null)
609      {
610        requestInfoElements.add(new ASN1Sequence(
611             new ASN1Sequence(
612                  new ASN1ObjectIdentifier(publicKeyAlgorithmOID)),
613             encodedPublicKey));
614      }
615      else
616      {
617        requestInfoElements.add(new ASN1Sequence(
618             new ASN1Sequence(
619                  new ASN1ObjectIdentifier(publicKeyAlgorithmOID),
620                  publicKeyAlgorithmParameters),
621             encodedPublicKey));
622      }
623
624      final ArrayList<ASN1Element> attrElements =
625           new ArrayList<>(requestAttributes.size());
626      for (final ObjectPair<OID,ASN1Set> attr : requestAttributes)
627      {
628        attrElements.add(
629             new ASN1Sequence(
630                  new ASN1ObjectIdentifier(attr.getFirst()),
631                  attr.getSecond()));
632      }
633
634      requestInfoElements.add(new ASN1Set(TYPE_ATTRIBUTES, attrElements));
635
636
637      final ArrayList<ASN1Element> certificationRequestElements =
638           new ArrayList<>(3);
639      certificationRequestElements.add(new ASN1Sequence(requestInfoElements));
640
641      if (signatureAlgorithmParameters == null)
642      {
643        certificationRequestElements.add(new ASN1Sequence(
644             new ASN1ObjectIdentifier(signatureAlgorithmOID)));
645      }
646      else
647      {
648        certificationRequestElements.add(new ASN1Sequence(
649             new ASN1ObjectIdentifier(signatureAlgorithmOID),
650             signatureAlgorithmParameters));
651      }
652
653      certificationRequestElements.add(signatureValue);
654
655      return new ASN1Sequence(certificationRequestElements);
656    }
657    catch (final Exception e)
658    {
659      Debug.debugException(e);
660      throw new CertException(
661           ERR_CSR_ENCODE_ERROR.get(toString(),
662                StaticUtils.getExceptionMessage(e)),
663           e);
664    }
665  }
666
667
668
669  /**
670   * Generates a PKCS #10 certificate signing request with the provided
671   * information.
672   *
673   * @param  signatureAlgorithm  The algorithm to use to generate the signature.
674   *                             This must not be {@code null}.
675   * @param  keyPair             The key pair to use for the certificate signing
676   *                             request.  This must not be {@code null}.
677   * @param  subjectDN           The subject DN for the certificate signing
678   *                             request.  This must not be {@code null}.
679   * @param  extensions          The set of extensions to include in the
680   *                             certificate signing request.  This may be
681   *                             {@code null} or empty if the request should not
682   *                             include any custom extensions.
683   *
684   * @return  The generated PKCS #10 certificate signing request.
685   *
686   * @throws  CertException  If a problem is encountered while creating the
687   *                         certificate signing request.
688   */
689  @NotNull()
690  public static PKCS10CertificateSigningRequest
691                     generateCertificateSigningRequest(
692              @NotNull final SignatureAlgorithmIdentifier signatureAlgorithm,
693              @NotNull final KeyPair keyPair, @NotNull final DN subjectDN,
694              @Nullable final X509CertificateExtension... extensions)
695         throws CertException
696  {
697    // Extract the parameters and encoded public key from the generated key
698    // pair.  And while we're at it, generate a subject key identifier from
699    // the encoded public key.
700    DecodedPublicKey decodedPublicKey = null;
701    final ASN1BitString encodedPublicKey;
702    final ASN1Element publicKeyAlgorithmParameters;
703    final byte[] subjectKeyIdentifier;
704    final OID publicKeyAlgorithmOID;
705    try
706    {
707      final ASN1Element[] pkElements = ASN1Sequence.decodeAsSequence(
708           keyPair.getPublic().getEncoded()).elements();
709      final ASN1Element[] pkAlgIDElements = ASN1Sequence.decodeAsSequence(
710           pkElements[0]).elements();
711      publicKeyAlgorithmOID =
712           pkAlgIDElements[0].decodeAsObjectIdentifier().getOID();
713      if (pkAlgIDElements.length == 1)
714      {
715        publicKeyAlgorithmParameters = null;
716      }
717      else
718      {
719        publicKeyAlgorithmParameters = pkAlgIDElements[1];
720      }
721
722      encodedPublicKey = pkElements[1].decodeAsBitString();
723
724      try
725      {
726        if (publicKeyAlgorithmOID.equals(
727             PublicKeyAlgorithmIdentifier.RSA.getOID()))
728        {
729          decodedPublicKey = new RSAPublicKey(encodedPublicKey);
730        }
731        else if (publicKeyAlgorithmOID.equals(
732             PublicKeyAlgorithmIdentifier.EC.getOID()))
733        {
734          decodedPublicKey = new EllipticCurvePublicKey(encodedPublicKey);
735        }
736      }
737      catch (final Exception e)
738      {
739        Debug.debugException(e);
740      }
741
742      final MessageDigest sha256 = CryptoHelper.getMessageDigest(
743           SubjectKeyIdentifierExtension.
744                SUBJECT_KEY_IDENTIFIER_DIGEST_ALGORITHM);
745      subjectKeyIdentifier = sha256.digest(encodedPublicKey.getBytes());
746    }
747    catch (final Exception e)
748    {
749      Debug.debugException(e);
750      throw new CertException(
751           ERR_CSR_GEN_CANNOT_PARSE_KEY_PAIR.get(
752                StaticUtils.getExceptionMessage(e)),
753           e);
754    }
755
756
757    // Construct the set of all extensions for the certificate.
758    final ArrayList<X509CertificateExtension> extensionList =
759         new ArrayList<>(10);
760    extensionList.add(new SubjectKeyIdentifierExtension(false,
761         new ASN1OctetString(subjectKeyIdentifier)));
762    if (extensions != null)
763    {
764      for (final X509CertificateExtension e : extensions)
765      {
766        if (! e.getOID().equals(SubjectKeyIdentifierExtension.
767             SUBJECT_KEY_IDENTIFIER_OID))
768        {
769          extensionList.add(e);
770        }
771      }
772    }
773
774    final X509CertificateExtension[] allExtensions =
775         new X509CertificateExtension[extensionList.size()];
776    extensionList.toArray(allExtensions);
777
778
779    final ASN1BitString encodedSignature = generateSignature(signatureAlgorithm,
780         keyPair.getPrivate(), subjectDN, publicKeyAlgorithmOID,
781         publicKeyAlgorithmParameters, encodedPublicKey, allExtensions);
782
783    return new PKCS10CertificateSigningRequest(
784         PKCS10CertificateSigningRequestVersion.V1, signatureAlgorithm.getOID(),
785         null, encodedSignature, subjectDN, publicKeyAlgorithmOID,
786         publicKeyAlgorithmParameters, encodedPublicKey, decodedPublicKey,
787         null, allExtensions);
788  }
789
790
791
792  /**
793   * Generates a signature for the certificate signing request with the provided
794   * information.
795   *
796   * @param  signatureAlgorithm            The signature algorithm to use to
797   *                                       generate the signature.  This must
798   *                                       not be {@code null}.
799   * @param  privateKey                    The private key to use to sign the
800   *                                       certificate signing request.  This
801   *                                       must not be {@code null}.
802   * @param  subjectDN                     The subject DN for the certificate
803   *                                       signing request.  This must not be
804   *                                       {@code null}.
805   * @param  publicKeyAlgorithmOID         The OID for the public key algorithm.
806   *                                       This must not be {@code null}.
807   * @param  publicKeyAlgorithmParameters  The encoded public key algorithm
808   *                                       parameters.  This may be
809   *                                       {@code null} if no parameters are
810   *                                       needed.
811   * @param  encodedPublicKey              The encoded representation of the
812   *                                       public key.  This must not be
813   *                                       {@code null}.
814   * @param  extensions                    The set of extensions to include in
815   *                                       the certificate signing request.
816   *                                       This must not be {@code null} but
817   *                                       may be empty.
818   *
819   * @return  An encoded representation of the generated signature.
820   *
821   * @throws  CertException  If a problem is encountered while generating the
822   *                         certificate.
823   */
824  @NotNull()
825  private static ASN1BitString generateSignature(
826               @NotNull final SignatureAlgorithmIdentifier signatureAlgorithm,
827               @NotNull final PrivateKey privateKey,
828               @NotNull final DN subjectDN,
829               @NotNull final OID publicKeyAlgorithmOID,
830               @Nullable final ASN1Element publicKeyAlgorithmParameters,
831               @NotNull final ASN1BitString encodedPublicKey,
832               @NotNull final X509CertificateExtension... extensions)
833          throws CertException
834  {
835    // Get and initialize the signature generator.
836    final Signature signature;
837    try
838    {
839      signature = CryptoHelper.getSignature(signatureAlgorithm.getJavaName());
840    }
841    catch (final Exception e)
842    {
843      Debug.debugException(e);
844      throw new CertException(
845           ERR_CSR_GEN_SIGNATURE_CANNOT_GET_SIGNATURE_GENERATOR.get(
846                signatureAlgorithm.getJavaName(),
847                StaticUtils.getExceptionMessage(e)),
848           e);
849    }
850
851    try
852    {
853      signature.initSign(privateKey);
854    }
855    catch (final Exception e)
856    {
857      Debug.debugException(e);
858      throw new CertException(
859           ERR_CSR_GEN_SIGNATURE_CANNOT_INIT_SIGNATURE_GENERATOR.get(
860                signatureAlgorithm.getJavaName(),
861                StaticUtils.getExceptionMessage(e)),
862           e);
863    }
864
865
866    // Construct the requestInfo element of the certificate signing request and
867    // compute its signature.
868    try
869    {
870      final ArrayList<ASN1Element> requestInfoElements = new ArrayList<>(4);
871      requestInfoElements.add(new ASN1Integer(
872           PKCS10CertificateSigningRequestVersion.V1.getIntValue()));
873      requestInfoElements.add(X509Certificate.encodeName(subjectDN));
874
875      if (publicKeyAlgorithmParameters == null)
876      {
877        requestInfoElements.add(new ASN1Sequence(
878             new ASN1Sequence(
879                  new ASN1ObjectIdentifier(publicKeyAlgorithmOID)),
880             encodedPublicKey));
881      }
882      else
883      {
884        requestInfoElements.add(new ASN1Sequence(
885             new ASN1Sequence(
886                  new ASN1ObjectIdentifier(publicKeyAlgorithmOID),
887                  publicKeyAlgorithmParameters),
888             encodedPublicKey));
889      }
890
891      final ArrayList<ASN1Element> attrElements = new ArrayList<>(1);
892      if ((extensions != null) && (extensions.length > 0))
893      {
894        final ArrayList<ASN1Element> extensionElements =
895             new ArrayList<>(extensions.length);
896        for (final X509CertificateExtension e : extensions)
897        {
898          extensionElements.add(e.encode());
899        }
900
901        attrElements.add(new ASN1Sequence(
902             new ASN1ObjectIdentifier(ATTRIBUTE_OID_EXTENSIONS),
903             new ASN1Set(new ASN1Sequence(extensionElements))));
904      }
905      requestInfoElements.add(new ASN1Set(TYPE_ATTRIBUTES, attrElements));
906
907      final byte[] certificationRequestInfoBytes =
908           new ASN1Sequence(requestInfoElements).encode();
909      signature.update(certificationRequestInfoBytes);
910      final byte[] signatureBytes = signature.sign();
911
912      return new ASN1BitString(ASN1BitString.getBitsForBytes(signatureBytes));
913    }
914    catch (final Exception e)
915    {
916      Debug.debugException(e);
917      throw new CertException(
918           ERR_CSR_GEN_SIGNATURE_CANNOT_COMPUTE.get(
919                signatureAlgorithm.getJavaName(),
920                StaticUtils.getExceptionMessage(e)),
921           e);
922    }
923  }
924
925
926
927  /**
928   * Retrieves the bytes that comprise the encoded representation of this
929   * PKCS #10 certificate signing request.
930   *
931   * @return  The bytes that comprise the encoded representation of this
932   *          PKCS #10 certificate signing request.
933   */
934  @NotNull()
935  public byte[] getPKCS10CertificateSigningRequestBytes()
936  {
937    return pkcs10CertificateSigningRequestBytes;
938  }
939
940
941
942  /**
943   * Retrieves the certificate signing request version.
944   *
945   * @return  The certificate signing request version.
946   */
947  @NotNull()
948  public PKCS10CertificateSigningRequestVersion getVersion()
949  {
950    return version;
951  }
952
953
954
955  /**
956   * Retrieves the certificate signing request signature algorithm OID.
957   *
958   * @return  The certificate signing request signature algorithm OID.
959   */
960  @NotNull()
961  public OID getSignatureAlgorithmOID()
962  {
963    return signatureAlgorithmOID;
964  }
965
966
967
968  /**
969   * Retrieves the certificate signing request signature algorithm name, if
970   * available.
971   *
972   * @return  The certificate signing request signature algorithm name, or
973   *          {@code null} if the signature algorithm OID does not correspond to
974   *          any known algorithm name.
975   */
976  @Nullable()
977  public String getSignatureAlgorithmName()
978  {
979    return signatureAlgorithmName;
980  }
981
982
983
984  /**
985   * Retrieves the signature algorithm name if it is available, or the string
986   * representation of the signature algorithm OID if not.
987   *
988   * @return  The signature algorithm name or OID.
989   */
990  @NotNull()
991  public String getSignatureAlgorithmNameOrOID()
992  {
993    if (signatureAlgorithmName != null)
994    {
995      return signatureAlgorithmName;
996    }
997    else
998    {
999      return signatureAlgorithmOID.toString();
1000    }
1001  }
1002
1003
1004
1005  /**
1006   * Retrieves the encoded signature algorithm parameters, if present.
1007   *
1008   * @return  The encoded signature algorithm parameters, or {@code null} if
1009   *          there are no signature algorithm parameters.
1010   */
1011  @Nullable()
1012  public ASN1Element getSignatureAlgorithmParameters()
1013  {
1014    return signatureAlgorithmParameters;
1015  }
1016
1017
1018
1019  /**
1020   * Retrieves the certificate signing request subject DN.
1021   *
1022   * @return  The certificate signing request subject DN.
1023   */
1024  @NotNull()
1025  public DN getSubjectDN()
1026  {
1027    return subjectDN;
1028  }
1029
1030
1031
1032  /**
1033   * Retrieves the certificate signing request public key algorithm OID.
1034   *
1035   * @return  The certificate signing request public key algorithm OID.
1036   */
1037  @NotNull()
1038  public OID getPublicKeyAlgorithmOID()
1039  {
1040    return publicKeyAlgorithmOID;
1041  }
1042
1043
1044
1045  /**
1046   * Retrieves the certificate signing request public key algorithm name, if
1047   * available.
1048   *
1049   * @return  The certificate signing request public key algorithm name, or
1050   *          {@code null} if the public key algorithm OID does not correspond
1051   *          to any known algorithm name.
1052   */
1053  @Nullable()
1054  public String getPublicKeyAlgorithmName()
1055  {
1056    return publicKeyAlgorithmName;
1057  }
1058
1059
1060
1061  /**
1062   * Retrieves the public key algorithm name if it is available, or the string
1063   * representation of the public key algorithm OID if not.
1064   *
1065   * @return  The signature algorithm name or OID.
1066   */
1067  @NotNull()
1068  public String getPublicKeyAlgorithmNameOrOID()
1069  {
1070    if (publicKeyAlgorithmName != null)
1071    {
1072      return publicKeyAlgorithmName;
1073    }
1074    else
1075    {
1076      return publicKeyAlgorithmOID.toString();
1077    }
1078  }
1079
1080
1081
1082  /**
1083   * Retrieves the encoded public key algorithm parameters, if present.
1084   *
1085   * @return  The encoded public key algorithm parameters, or {@code null} if
1086   *          there are no public key algorithm parameters.
1087   */
1088  @Nullable()
1089  public ASN1Element getPublicKeyAlgorithmParameters()
1090  {
1091    return publicKeyAlgorithmParameters;
1092  }
1093
1094
1095
1096  /**
1097   * Retrieves the encoded public key as a bit string.
1098   *
1099   * @return  The encoded public key as a bit string.
1100   */
1101  @NotNull()
1102  public ASN1BitString getEncodedPublicKey()
1103  {
1104    return encodedPublicKey;
1105  }
1106
1107
1108
1109  /**
1110   * Retrieves a decoded representation of the public key, if available.
1111   *
1112   * @return  A decoded representation of the public key, or {@code null} if the
1113   *          public key could not be decoded.
1114   */
1115  @Nullable()
1116  public DecodedPublicKey getDecodedPublicKey()
1117  {
1118    return decodedPublicKey;
1119  }
1120
1121
1122
1123  /**
1124   * Retrieves the encoded request attributes included in the certificate
1125   * signing request.
1126   *
1127   * @return  The encoded request attributes included in the certificate signing
1128   *          request.
1129   */
1130  @NotNull()
1131  public List<ObjectPair<OID,ASN1Set>> getRequestAttributes()
1132  {
1133    return requestAttributes;
1134  }
1135
1136
1137
1138  /**
1139   * Retrieves the list of certificate extensions included in the certificate
1140   * signing request.
1141   *
1142   * @return  The list of certificate extensions included in the certificate
1143   *          signing request.
1144   */
1145  @NotNull()
1146  public List<X509CertificateExtension> getExtensions()
1147  {
1148    return extensions;
1149  }
1150
1151
1152
1153  /**
1154   * Retrieves the signature value for the certificate signing request.
1155   *
1156   * @return  The signature value for the certificate signing request.
1157   */
1158  @NotNull()
1159  public ASN1BitString getSignatureValue()
1160  {
1161    return signatureValue;
1162  }
1163
1164
1165
1166  /**
1167   * Verifies the signature for this certificate signing request.
1168   *
1169   * @throws  CertException  If the certificate signing request's signature
1170   *                         could not be verified.
1171   */
1172  public void verifySignature()
1173         throws CertException
1174  {
1175    // Generate the public key for this certificate signing request.
1176    final PublicKey publicKey;
1177    try
1178    {
1179      final byte[] encodedPublicKeyBytes;
1180      if (publicKeyAlgorithmParameters == null)
1181      {
1182        encodedPublicKeyBytes = new ASN1Sequence(
1183             new ASN1Sequence(
1184                  new ASN1ObjectIdentifier(publicKeyAlgorithmOID)),
1185             encodedPublicKey).encode();
1186      }
1187      else
1188      {
1189        encodedPublicKeyBytes = new ASN1Sequence(
1190             new ASN1Sequence(
1191                  new ASN1ObjectIdentifier(publicKeyAlgorithmOID),
1192                  publicKeyAlgorithmParameters),
1193             encodedPublicKey).encode();
1194      }
1195
1196      final KeyFactory keyFactory =
1197           CryptoHelper.getKeyFactory(getPublicKeyAlgorithmNameOrOID());
1198      publicKey = keyFactory.generatePublic(
1199           new X509EncodedKeySpec(encodedPublicKeyBytes));
1200    }
1201    catch (final Exception e)
1202    {
1203      Debug.debugException(e);
1204      throw new CertException(
1205           ERR_CSR_VERIFY_SIGNATURE_CANNOT_GET_PUBLIC_KEY.get(
1206                StaticUtils.getExceptionMessage(e)),
1207           e);
1208    }
1209
1210
1211    // Get and initialize the signature generator.
1212    final Signature signature;
1213    final SignatureAlgorithmIdentifier signatureAlgorithm;
1214    try
1215    {
1216      signatureAlgorithm =
1217           SignatureAlgorithmIdentifier.forOID(signatureAlgorithmOID);
1218      signature = CryptoHelper.getSignature(signatureAlgorithm.getJavaName());
1219    }
1220    catch (final Exception e)
1221    {
1222      Debug.debugException(e);
1223      throw new CertException(
1224           ERR_CSR_VERIFY_SIGNATURE_CANNOT_GET_SIGNATURE_VERIFIER.get(
1225                getSignatureAlgorithmNameOrOID(),
1226                StaticUtils.getExceptionMessage(e)),
1227           e);
1228    }
1229
1230    try
1231    {
1232      signature.initVerify(publicKey);
1233    }
1234    catch (final Exception e)
1235    {
1236      Debug.debugException(e);
1237      throw new CertException(
1238           ERR_CSR_VERIFY_SIGNATURE_CANNOT_INIT_SIGNATURE_VERIFIER.get(
1239                signatureAlgorithm.getJavaName(),
1240                StaticUtils.getExceptionMessage(e)),
1241           e);
1242    }
1243
1244
1245    // Construct the requestInfo element of the certificate signing request and
1246    // compute its signature.
1247    final boolean signatureIsValid;
1248    try
1249    {
1250      final ASN1Element[] requestInfoElements =
1251           ASN1Sequence.decodeAsSequence(
1252                pkcs10CertificateSigningRequestBytes).elements();
1253      final byte[] requestInfoBytes = requestInfoElements[0].encode();
1254      signature.update(requestInfoBytes);
1255      signatureIsValid = signature.verify(signatureValue.getBytes());
1256    }
1257    catch (final Exception e)
1258    {
1259      Debug.debugException(e);
1260      throw new CertException(
1261           ERR_CSR_VERIFY_SIGNATURE_ERROR.get(subjectDN,
1262                StaticUtils.getExceptionMessage(e)),
1263           e);
1264    }
1265
1266    if (! signatureIsValid)
1267    {
1268      throw new CertException(
1269           ERR_CSR_VERIFY_SIGNATURE_NOT_VALID.get(subjectDN));
1270    }
1271  }
1272
1273
1274
1275  /**
1276   * Retrieves a string representation of the decoded X.509 certificate.
1277   *
1278   * @return  A string representation of the decoded X.509 certificate.
1279   */
1280  @Override()
1281  @NotNull()
1282  public String toString()
1283  {
1284    final StringBuilder buffer = new StringBuilder();
1285    toString(buffer);
1286    return buffer.toString();
1287  }
1288
1289
1290
1291  /**
1292   * Appends a string representation of the decoded X.509 certificate to the
1293   * provided buffer.
1294   *
1295   * @param  buffer  The buffer to which the information should be appended.
1296   */
1297  public void toString(@NotNull final StringBuilder buffer)
1298  {
1299    buffer.append("PKCS10CertificateSigningRequest(version='");
1300    buffer.append(version.getName());
1301    buffer.append("', subjectDN='");
1302    buffer.append(subjectDN);
1303    buffer.append("', publicKeyAlgorithmOID='");
1304    buffer.append(publicKeyAlgorithmOID.toString());
1305    buffer.append('\'');
1306
1307    if (publicKeyAlgorithmName != null)
1308    {
1309      buffer.append(", publicKeyAlgorithmName='");
1310      buffer.append(publicKeyAlgorithmName);
1311      buffer.append('\'');
1312    }
1313
1314    buffer.append(", subjectPublicKey=");
1315    if (decodedPublicKey == null)
1316    {
1317      buffer.append('\'');
1318
1319      try
1320      {
1321        StaticUtils.toHex(encodedPublicKey.getBytes(), ":", buffer);
1322      }
1323      catch (final Exception e)
1324      {
1325        Debug.debugException(e);
1326        encodedPublicKey.toString(buffer);
1327      }
1328
1329      buffer.append('\'');
1330    }
1331    else
1332    {
1333      decodedPublicKey.toString(buffer);
1334
1335      if (decodedPublicKey instanceof EllipticCurvePublicKey)
1336      {
1337        try
1338        {
1339          final OID namedCurveOID =
1340               publicKeyAlgorithmParameters.decodeAsObjectIdentifier().getOID();
1341          buffer.append(", ellipticCurvePublicKeyParameters=namedCurve='");
1342          buffer.append(NamedCurve.getNameOrOID(namedCurveOID));
1343          buffer.append('\'');
1344        }
1345        catch (final Exception e)
1346        {
1347          Debug.debugException(e);
1348        }
1349      }
1350    }
1351
1352    buffer.append(", signatureAlgorithmOID='");
1353    buffer.append(signatureAlgorithmOID.toString());
1354    buffer.append('\'');
1355
1356    if (signatureAlgorithmName != null)
1357    {
1358      buffer.append(", signatureAlgorithmName='");
1359      buffer.append(signatureAlgorithmName);
1360      buffer.append('\'');
1361    }
1362
1363    if (! extensions.isEmpty())
1364    {
1365      buffer.append(", extensions={");
1366
1367      final Iterator<X509CertificateExtension> iterator = extensions.iterator();
1368      while (iterator.hasNext())
1369      {
1370        iterator.next().toString(buffer);
1371        if (iterator.hasNext())
1372        {
1373          buffer.append(", ");
1374        }
1375      }
1376
1377      buffer.append('}');
1378    }
1379
1380    buffer.append(", signatureValue='");
1381
1382    try
1383    {
1384      StaticUtils.toHex(signatureValue.getBytes(), ":", buffer);
1385    }
1386    catch (final Exception e)
1387    {
1388      Debug.debugException(e);
1389      buffer.append(signatureValue.toString());
1390    }
1391
1392    buffer.append("')");
1393  }
1394
1395
1396
1397  /**
1398   * Retrieves a list of the lines that comprise a PEM representation of this
1399   * PKCS #10 certificate signing request.
1400   *
1401   * @return  A list of the lines that comprise a PEM representation of this
1402   *          PKCS #10 certificate signing request.
1403   */
1404  @NotNull()
1405  public List<String> toPEM()
1406  {
1407    final ArrayList<String> lines = new ArrayList<>(10);
1408    lines.add("-----BEGIN CERTIFICATE REQUEST-----");
1409
1410    final String csrBase64 =
1411         Base64.encode(pkcs10CertificateSigningRequestBytes);
1412    lines.addAll(StaticUtils.wrapLine(csrBase64, 64));
1413
1414    lines.add("-----END CERTIFICATE REQUEST-----");
1415
1416    return Collections.unmodifiableList(lines);
1417  }
1418
1419
1420
1421  /**
1422   * Retrieves a multi-line string containing a PEM representation of this
1423   * PKCS #10 certificate signing request.
1424   *
1425   * @return  A multi-line string containing a PEM representation of this
1426   *          PKCS #10 certificate signing request.
1427   */
1428  @NotNull()
1429  public String toPEMString()
1430  {
1431    final StringBuilder buffer = new StringBuilder();
1432    buffer.append("-----BEGIN CERTIFICATE REQUEST-----");
1433    buffer.append(StaticUtils.EOL);
1434
1435    final String csrBase64 =
1436         Base64.encode(pkcs10CertificateSigningRequestBytes);
1437    for (final String line : StaticUtils.wrapLine(csrBase64, 64))
1438    {
1439      buffer.append(line);
1440      buffer.append(StaticUtils.EOL);
1441    }
1442    buffer.append("-----END CERTIFICATE REQUEST-----");
1443    buffer.append(StaticUtils.EOL);
1444
1445    return buffer.toString();
1446  }
1447}