|
1 | 1 | /* |
2 | | - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. |
| 2 | + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. |
3 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | 4 | * |
5 | 5 | * This code is free software; you can redistribute it and/or modify it |
@@ -74,30 +74,52 @@ public final class RSAPrivateCrtKeyImpl |
74 | 74 | private transient AlgorithmParameterSpec keyParams; |
75 | 75 |
|
76 | 76 | /** |
77 | | - * Generate a new key from its encoding. Returns a CRT key if possible |
78 | | - * and a non-CRT key otherwise. Used by RSAKeyFactory. |
| 77 | + * Generate a new RSAPrivate(Crt)Key from the specified type, |
| 78 | + * format and encoding. Returns a CRT key if possible and a non-CRT |
| 79 | + * key otherwise. |
| 80 | + * Also used by SunPKCS11 provider. |
79 | 81 | */ |
80 | | - public static RSAPrivateKey newKey(byte[] encoded) |
81 | | - throws InvalidKeyException { |
| 82 | + public static RSAPrivateKey newKey(KeyType type, String format, |
| 83 | + byte[] encoded) throws InvalidKeyException { |
82 | 84 | if (encoded == null || encoded.length == 0) { |
83 | 85 | throw new InvalidKeyException("Missing key encoding"); |
84 | 86 | } |
85 | | - RSAPrivateCrtKeyImpl key = new RSAPrivateCrtKeyImpl(encoded); |
86 | | - // check all CRT-specific components are available, if any one |
87 | | - // missing, return a non-CRT key instead |
88 | | - if ((key.getPublicExponent().signum() == 0) || |
89 | | - (key.getPrimeExponentP().signum() == 0) || |
90 | | - (key.getPrimeExponentQ().signum() == 0) || |
91 | | - (key.getPrimeP().signum() == 0) || |
92 | | - (key.getPrimeQ().signum() == 0) || |
93 | | - (key.getCrtCoefficient().signum() == 0)) { |
94 | | - return new RSAPrivateKeyImpl( |
95 | | - key.type, key.keyParams, |
96 | | - key.getModulus(), |
97 | | - key.getPrivateExponent() |
98 | | - ); |
99 | | - } else { |
100 | | - return key; |
| 87 | + switch (format) { |
| 88 | + case "PKCS#8": |
| 89 | + RSAPrivateCrtKeyImpl key = new RSAPrivateCrtKeyImpl(encoded); |
| 90 | + RSAKeyFactory.checkKeyAlgo(key, type.keyAlgo); |
| 91 | + // check all CRT-specific components are available, if any one |
| 92 | + // missing, return a non-CRT key instead |
| 93 | + if ((key.getPublicExponent().signum() == 0) || |
| 94 | + (key.getPrimeExponentP().signum() == 0) || |
| 95 | + (key.getPrimeExponentQ().signum() == 0) || |
| 96 | + (key.getPrimeP().signum() == 0) || |
| 97 | + (key.getPrimeQ().signum() == 0) || |
| 98 | + (key.getCrtCoefficient().signum() == 0)) { |
| 99 | + return new RSAPrivateKeyImpl(key.type, key.keyParams, |
| 100 | + key.getModulus(), key.getPrivateExponent()); |
| 101 | + } else { |
| 102 | + return key; |
| 103 | + } |
| 104 | + case "PKCS#1": |
| 105 | + try { |
| 106 | + BigInteger[] comps = parseASN1(encoded); |
| 107 | + if ((comps[1].signum() == 0) || (comps[3].signum() == 0) || |
| 108 | + (comps[4].signum() == 0) || (comps[5].signum() == 0) || |
| 109 | + (comps[6].signum() == 0) || (comps[7].signum() == 0)) { |
| 110 | + return new RSAPrivateKeyImpl(type, null, comps[0], |
| 111 | + comps[2]); |
| 112 | + } else { |
| 113 | + return new RSAPrivateCrtKeyImpl(type, null, comps[0], |
| 114 | + comps[1], comps[2], comps[3], comps[4], comps[5], |
| 115 | + comps[6], comps[7]); |
| 116 | + } |
| 117 | + } catch (IOException ioe) { |
| 118 | + throw new InvalidKeyException("Invalid PKCS#1 encoding", ioe); |
| 119 | + } |
| 120 | + default: |
| 121 | + throw new InvalidKeyException("Unsupported RSA Private(Crt)Key " |
| 122 | + + "format: " + format); |
101 | 123 | } |
102 | 124 | } |
103 | 125 |
|
@@ -126,7 +148,7 @@ public static RSAPrivateKey newKey(KeyType type, |
126 | 148 | /** |
127 | 149 | * Construct a key from its encoding. Called from newKey above. |
128 | 150 | */ |
129 | | - RSAPrivateCrtKeyImpl(byte[] encoded) throws InvalidKeyException { |
| 151 | + private RSAPrivateCrtKeyImpl(byte[] encoded) throws InvalidKeyException { |
130 | 152 | super(encoded); |
131 | 153 | parseKeyBits(); |
132 | 154 | RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e); |
@@ -258,37 +280,47 @@ public String toString() { |
258 | 280 | + "\n modulus: " + n + "\n private exponent: " + d; |
259 | 281 | } |
260 | 282 |
|
| 283 | + // utility method for parsing DER encoding of RSA private keys in PKCS#1 |
| 284 | + // format as defined in RFC 8017 Appendix A.1.2, i.e. SEQ of version, n, |
| 285 | + // e, d, p, q, pe, qe, and coeff, and return the parsed components. |
| 286 | + private static BigInteger[] parseASN1(byte[] raw) throws IOException { |
| 287 | + DerValue derValue = new DerValue(raw); |
| 288 | + if (derValue.tag != DerValue.tag_Sequence) { |
| 289 | + throw new IOException("Not a SEQUENCE"); |
| 290 | + } |
| 291 | + int version = derValue.data.getInteger(); |
| 292 | + if (version != 0) { |
| 293 | + throw new IOException("Version must be 0"); |
| 294 | + } |
| 295 | + |
| 296 | + BigInteger[] result = new BigInteger[8]; // n, e, d, p, q, pe, qe, coeff |
| 297 | + /* |
| 298 | + * Some implementations do not correctly encode ASN.1 INTEGER values |
| 299 | + * in 2's complement format, resulting in a negative integer when |
| 300 | + * decoded. Correct the error by converting it to a positive integer. |
| 301 | + * |
| 302 | + * See CR 6255949 |
| 303 | + */ |
| 304 | + for (int i = 0; i < result.length; i++) { |
| 305 | + result[i] = derValue.data.getPositiveBigInteger(); |
| 306 | + } |
| 307 | + if (derValue.data.available() != 0) { |
| 308 | + throw new IOException("Extra data available"); |
| 309 | + } |
| 310 | + return result; |
| 311 | + } |
| 312 | + |
261 | 313 | private void parseKeyBits() throws InvalidKeyException { |
262 | 314 | try { |
263 | | - DerInputStream in = new DerInputStream(key); |
264 | | - DerValue derValue = in.getDerValue(); |
265 | | - if (derValue.tag != DerValue.tag_Sequence) { |
266 | | - throw new IOException("Not a SEQUENCE"); |
267 | | - } |
268 | | - DerInputStream data = derValue.data; |
269 | | - int version = data.getInteger(); |
270 | | - if (version != 0) { |
271 | | - throw new IOException("Version must be 0"); |
272 | | - } |
273 | | - |
274 | | - /* |
275 | | - * Some implementations do not correctly encode ASN.1 INTEGER values |
276 | | - * in 2's complement format, resulting in a negative integer when |
277 | | - * decoded. Correct the error by converting it to a positive integer. |
278 | | - * |
279 | | - * See CR 6255949 |
280 | | - */ |
281 | | - n = data.getPositiveBigInteger(); |
282 | | - e = data.getPositiveBigInteger(); |
283 | | - d = data.getPositiveBigInteger(); |
284 | | - p = data.getPositiveBigInteger(); |
285 | | - q = data.getPositiveBigInteger(); |
286 | | - pe = data.getPositiveBigInteger(); |
287 | | - qe = data.getPositiveBigInteger(); |
288 | | - coeff = data.getPositiveBigInteger(); |
289 | | - if (derValue.data.available() != 0) { |
290 | | - throw new IOException("Extra data available"); |
291 | | - } |
| 315 | + BigInteger[] comps = parseASN1(key); |
| 316 | + n = comps[0]; |
| 317 | + e = comps[1]; |
| 318 | + d = comps[2]; |
| 319 | + p = comps[3]; |
| 320 | + q = comps[4]; |
| 321 | + pe = comps[5]; |
| 322 | + qe = comps[6]; |
| 323 | + coeff = comps[7]; |
292 | 324 | } catch (IOException e) { |
293 | 325 | throw new InvalidKeyException("Invalid RSA private key", e); |
294 | 326 | } |
|
0 commit comments