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}