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.math.BigInteger;
041import java.util.ArrayList;
042import java.util.Collections;
043import java.util.Iterator;
044import java.util.List;
045
046import com.unboundid.asn1.ASN1BigInteger;
047import com.unboundid.asn1.ASN1Element;
048import com.unboundid.asn1.ASN1Integer;
049import com.unboundid.asn1.ASN1OctetString;
050import com.unboundid.asn1.ASN1Sequence;
051import com.unboundid.util.Debug;
052import com.unboundid.util.NotMutable;
053import com.unboundid.util.NotNull;
054import com.unboundid.util.StaticUtils;
055import com.unboundid.util.ThreadSafety;
056import com.unboundid.util.ThreadSafetyLevel;
057
058import static com.unboundid.util.ssl.cert.CertMessages.*;
059
060
061
062/**
063 * This class provides a data structure for representing the information
064 * contained in an RSA private key.  As per
065 * <A HREF="https://www.ietf.org/rfc/rfc8017.txt">RFC 8017</A> section A.1.2,
066 * an RSA private key is identified by OID 1.2.840.113549.1.1.1 and the value is
067 * encoded as follows:
068 * <PRE>
069 *   RSAPrivateKey ::= SEQUENCE {
070 *       version           Version,
071 *       modulus           INTEGER,  -- n
072 *       publicExponent    INTEGER,  -- e
073 *       privateExponent   INTEGER,  -- d
074 *       prime1            INTEGER,  -- p
075 *       prime2            INTEGER,  -- q
076 *       exponent1         INTEGER,  -- d mod (p-1)
077 *       exponent2         INTEGER,  -- d mod (q-1)
078 *       coefficient       INTEGER,  -- (inverse of q) mod p
079 *       otherPrimeInfos   OtherPrimeInfos OPTIONAL
080 *   }
081 *
082 *   OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
083 *
084 *   OtherPrimeInfo ::= SEQUENCE {
085 *       prime             INTEGER,  -- ri
086 *       exponent          INTEGER,  -- di
087 *       coefficient       INTEGER   -- ti
088 *   }
089 * </PRE>
090 */
091@NotMutable()
092@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
093public final class RSAPrivateKey
094       extends DecodedPrivateKey
095{
096  /**
097   * The serial version UID for this serializable class.
098   */
099  private static final long serialVersionUID = -7101141316095373904L;
100
101
102
103  // The coefficient value for the RSA private key.
104  @NotNull private final BigInteger coefficient;
105
106  // The exponent1 value for the RSA private key.
107  @NotNull private final BigInteger exponent1;
108
109  // The exponent2 value for the RSA private key.
110  @NotNull private final BigInteger exponent2;
111
112  // The modulus for the RSA private key.
113  @NotNull private final BigInteger modulus;
114
115  // The prime1 value for the RSA private key.
116  @NotNull private final BigInteger prime1;
117
118  // The prime2 value for the RSA private key.
119  @NotNull private final BigInteger prime2;
120
121  // The private exponent for the RSA private key.
122  @NotNull private final BigInteger privateExponent;
123
124  // The public exponent for the RSA private key.
125  @NotNull private final BigInteger publicExponent;
126
127  // A list of information about additional primes used by the RSA private key.
128  @NotNull private final List<BigInteger[]> otherPrimeInfos;
129
130  // The private key version.
131  @NotNull private final RSAPrivateKeyVersion version;
132
133
134
135  /**
136   * Creates a new RSA private key with the provided information.
137   *
138   * @param  version          The version for this private key.  It must not be
139   *                          {@code null}.
140   * @param  modulus          The modulus for this RSA private key.  It must not
141   *                          be {@code null}.
142   * @param  publicExponent   The public exponent for this RSA private key.  It
143   *                          must not be {@code null}.
144   * @param  privateExponent  The private exponent for this RSA private key.  It
145   *                          must not be {@code null}.
146   * @param  prime1           The prime1 value for this RSA private key.  It
147   *                          must not be {@code null}.
148   * @param  prime2           The prime2 value for this RSA private key.  It
149   *                          must not be {@code null}.
150   * @param  exponent1        The exponent1 value for this RSA private key.  It
151   *                          must not be {@code null}.
152   * @param  exponent2        The exponent2 value for this RSA private key.  It
153   *                          must not be {@code null}.
154   * @param  coefficient      The coefficient for this RSA private key. It must
155   *                          not be {@code null}.
156   * @param  otherPrimeInfos  A list of information about additional primes used
157   *                          by the private key.  It must not be {@code null},
158   *                          but may be empty.  If it is non-empty, then each
159   *                          array must contain three items, which represent a
160   *                          prime, an exponent, and a coefficient,
161   *                          respectively.
162   */
163  RSAPrivateKey(@NotNull final RSAPrivateKeyVersion version,
164                @NotNull final BigInteger modulus,
165                @NotNull final BigInteger publicExponent,
166                @NotNull final BigInteger privateExponent,
167                @NotNull final BigInteger prime1,
168                @NotNull final BigInteger prime2,
169                @NotNull final BigInteger exponent1,
170                @NotNull final BigInteger exponent2,
171                @NotNull final BigInteger coefficient,
172                @NotNull final List<BigInteger[]> otherPrimeInfos)
173  {
174    this.version = version;
175    this.modulus = modulus;
176    this.publicExponent = publicExponent;
177    this.privateExponent = privateExponent;
178    this.prime1 = prime1;
179    this.prime2 = prime2;
180    this.exponent1 = exponent1;
181    this.exponent2 = exponent2;
182    this.coefficient = coefficient;
183    this.otherPrimeInfos = otherPrimeInfos;
184  }
185
186
187
188  /**
189   * Creates a new RSA decoded private key from the provided octet string.
190   *
191   * @param  encodedPrivateKey  The encoded private key to be decoded as an RSA
192   *                            private key.
193   *
194   * @throws  CertException  If the provided private key cannot be decoded as an
195   *                         RSA private key.
196   */
197  RSAPrivateKey(@NotNull final ASN1OctetString encodedPrivateKey)
198       throws CertException
199  {
200    try
201    {
202      final ASN1Element[] elements = ASN1Sequence.decodeAsSequence(
203           encodedPrivateKey.getValue()).elements();
204      final int versionIntValue = elements[0].decodeAsInteger().intValue();
205      version = RSAPrivateKeyVersion.valueOf(versionIntValue);
206      if (version == null)
207      {
208        throw new CertException(
209             ERR_RSA_PRIVATE_KEY_UNSUPPORTED_VERSION.get(versionIntValue));
210      }
211
212      modulus = elements[1].decodeAsBigInteger().getBigIntegerValue();
213      publicExponent = elements[2].decodeAsBigInteger().getBigIntegerValue();
214      privateExponent = elements[3].decodeAsBigInteger().getBigIntegerValue();
215      prime1 = elements[4].decodeAsBigInteger().getBigIntegerValue();
216      prime2 = elements[5].decodeAsBigInteger().getBigIntegerValue();
217      exponent1 = elements[6].decodeAsBigInteger().getBigIntegerValue();
218      exponent2 = elements[7].decodeAsBigInteger().getBigIntegerValue();
219      coefficient = elements[8].decodeAsBigInteger().getBigIntegerValue();
220
221      if (elements.length == 9)
222      {
223        otherPrimeInfos = Collections.emptyList();
224      }
225      else
226      {
227        final ASN1Element[] otherPrimesElements =
228             elements[9].decodeAsSequence().elements();
229        final ArrayList<BigInteger[]> otherPrimes =
230             new ArrayList<>(otherPrimesElements.length);
231        for (final ASN1Element e : otherPrimesElements)
232        {
233          final ASN1Element[] primeElements = e.decodeAsSequence().elements();
234          otherPrimes.add(
235               new BigInteger[]
236               {
237                 primeElements[0].decodeAsBigInteger().getBigIntegerValue(),
238                 primeElements[1].decodeAsBigInteger().getBigIntegerValue(),
239                 primeElements[2].decodeAsBigInteger().getBigIntegerValue()
240               });
241        }
242
243        otherPrimeInfos = Collections.unmodifiableList(otherPrimes);
244      }
245    }
246    catch (final CertException e)
247    {
248      Debug.debugException(e);
249      throw e;
250    }
251    catch (final Exception e)
252    {
253      Debug.debugException(e);
254      throw new CertException(
255           ERR_RSA_PRIVATE_KEY_CANNOT_DECODE.get(
256                StaticUtils.getExceptionMessage(e)),
257           e);
258    }
259  }
260
261
262
263  /**
264   * Encodes this RSA private key to an ASN.1 octet string.
265   *
266   * @return  The ASN.1 octet string containing the encoded private key.
267   */
268  @NotNull()
269  ASN1OctetString encode()
270  {
271    final ArrayList<ASN1Element> elements = new ArrayList<>(9);
272    elements.add(new ASN1Integer(version.getIntValue()));
273    elements.add(new ASN1BigInteger(modulus));
274    elements.add(new ASN1BigInteger(publicExponent));
275    elements.add(new ASN1BigInteger(privateExponent));
276    elements.add(new ASN1BigInteger(prime1));
277    elements.add(new ASN1BigInteger(prime2));
278    elements.add(new ASN1BigInteger(exponent1));
279    elements.add(new ASN1BigInteger(exponent2));
280    elements.add(new ASN1BigInteger(coefficient));
281
282    if (! otherPrimeInfos.isEmpty())
283    {
284      final ArrayList<ASN1Element> otherElements =
285           new ArrayList<>(otherPrimeInfos.size());
286      for (final BigInteger[] info : otherPrimeInfos)
287      {
288        otherElements.add(new ASN1Sequence(
289             new ASN1BigInteger(info[0]),
290             new ASN1BigInteger(info[1]),
291             new ASN1BigInteger(info[2])));
292      }
293
294      elements.add(new ASN1Sequence(otherElements));
295    }
296
297    return new ASN1OctetString(new ASN1Sequence(elements).encode());
298  }
299
300
301
302  /**
303   * Retrieves the version for the RSA private key.
304   *
305   * @return  The version for the RSA private key.
306   */
307  @NotNull()
308  public RSAPrivateKeyVersion getVersion()
309  {
310    return version;
311  }
312
313
314
315  /**
316   * Retrieves the modulus (n) for the RSA private key.
317   *
318   * @return  The modulus for the RSA private key.
319   */
320  @NotNull()
321  public BigInteger getModulus()
322  {
323    return modulus;
324  }
325
326
327
328  /**
329   * Retrieves the public exponent (e) for the RSA public key.
330   *
331   * @return  The public exponent for the RSA public key.
332   */
333  @NotNull()
334  public BigInteger getPublicExponent()
335  {
336    return publicExponent;
337  }
338
339
340
341  /**
342   * Retrieves the private exponent (d) for the RSA private key.
343   *
344   * @return  The private exponent for the RSA private key.
345   */
346  @NotNull()
347  public BigInteger getPrivateExponent()
348  {
349    return privateExponent;
350  }
351
352
353
354  /**
355   * Retrieves the prime1 (p) value for the RSA private key.
356   *
357   * @return  The prime1 value for the RSA private key.
358   */
359  @NotNull()
360  public BigInteger getPrime1()
361  {
362    return prime1;
363  }
364
365
366
367  /**
368   * Retrieves the prime2 (q) value for the RSA private key.
369   *
370   * @return  The prime2 value for the RSA private key.
371   */
372  @NotNull()
373  public BigInteger getPrime2()
374  {
375    return prime2;
376  }
377
378
379
380  /**
381   * Retrieves the exponent1 value for the RSA private key.
382   *
383   * @return  The exponent1 value for the RSA private key.
384   */
385  @NotNull()
386  public BigInteger getExponent1()
387  {
388    return exponent1;
389  }
390
391
392
393  /**
394   * Retrieves the exponent2 value for the RSA private key.
395   *
396   * @return  The exponent2 value for the RSA private key.
397   */
398  @NotNull()
399  public BigInteger getExponent2()
400  {
401    return exponent2;
402  }
403
404
405
406  /**
407   * Retrieves the coefficient for the RSA private key.
408   *
409   * @return  The coefficient for the RSA private key.
410   */
411  @NotNull()
412  public BigInteger getCoefficient()
413  {
414    return coefficient;
415  }
416
417
418
419  /**
420   * Retrieves a list of information about other primes used by the private key.
421   * If the list is non-empty, then each item will be an array of three
422   * {@code BigInteger} values, which represent a prime, an exponent, and a
423   * coefficient, respectively.
424   *
425   * @return  A list of information about other primes used by the private key.
426   */
427  @NotNull()
428  public List<BigInteger[]> getOtherPrimeInfos()
429  {
430    return otherPrimeInfos;
431  }
432
433
434
435  /**
436   * {@inheritDoc}
437   */
438  @Override()
439  public void toString(@NotNull final StringBuilder buffer)
440  {
441    buffer.append("RSAPrivateKey(version='");
442    buffer.append(version.getName());
443    buffer.append("', modulus=");
444    StaticUtils.toHex(modulus.toByteArray(), ":", buffer);
445    buffer.append(", publicExponent=");
446    StaticUtils.toHex(publicExponent.toByteArray(), ":", buffer);
447    buffer.append(", privateExponent=");
448    StaticUtils.toHex(privateExponent.toByteArray(), ":", buffer);
449    buffer.append(", prime1=");
450    StaticUtils.toHex(prime1.toByteArray(), ":", buffer);
451    buffer.append(", prime2=");
452    StaticUtils.toHex(prime2.toByteArray(), ":", buffer);
453    buffer.append(", exponent1=");
454    StaticUtils.toHex(exponent1.toByteArray(), ":", buffer);
455    buffer.append(", exponent2=");
456    StaticUtils.toHex(exponent2.toByteArray(), ":", buffer);
457    buffer.append(", coefficient=");
458    StaticUtils.toHex(coefficient.toByteArray(), ":", buffer);
459
460    if (! otherPrimeInfos.isEmpty())
461    {
462      buffer.append(", otherPrimeInfos={");
463
464      final Iterator<BigInteger[]> iterator = otherPrimeInfos.iterator();
465      while (iterator.hasNext())
466      {
467        final BigInteger[] array = iterator.next();
468        buffer.append("PrimeInfo(prime=");
469        StaticUtils.toHex(array[0].toByteArray(), ":", buffer);
470        buffer.append(", exponent=");
471        StaticUtils.toHex(array[1].toByteArray(), ":", buffer);
472        buffer.append(", coefficient=");
473        StaticUtils.toHex(array[2].toByteArray(), ":", buffer);
474        buffer.append(')');
475
476        if (iterator.hasNext())
477        {
478          buffer.append(", ");
479        }
480      }
481
482      buffer.append('}');
483    }
484
485    buffer.append(')');
486  }
487}