|
1 /* |
|
2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 package sun.security.rsa; |
|
27 |
|
28 import java.io.IOException; |
|
29 import java.nio.ByteBuffer; |
|
30 |
|
31 import java.security.*; |
|
32 import java.security.spec.AlgorithmParameterSpec; |
|
33 import java.security.spec.PSSParameterSpec; |
|
34 import java.security.spec.MGF1ParameterSpec; |
|
35 import java.security.interfaces.*; |
|
36 |
|
37 import java.util.Arrays; |
|
38 import java.util.Hashtable; |
|
39 |
|
40 import sun.security.util.*; |
|
41 import sun.security.jca.JCAUtil; |
|
42 |
|
43 |
|
44 /** |
|
45 * PKCS#1 v2.2 RSASSA-PSS signatures with various message digest algorithms. |
|
46 * RSASSA-PSS implementation takes the message digest algorithm, MGF algorithm, |
|
47 * and salt length values through the required signature PSS parameters. |
|
48 * We support SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, and |
|
49 * SHA-512/256 message digest algorithms and MGF1 mask generation function. |
|
50 * |
|
51 * @since 11 |
|
52 */ |
|
53 public class RSAPSSSignature extends SignatureSpi { |
|
54 |
|
55 private static final boolean DEBUG = false; |
|
56 |
|
57 // utility method for comparing digest algorithms |
|
58 // NOTE that first argument is assumed to be standard digest name |
|
59 private boolean isDigestEqual(String stdAlg, String givenAlg) { |
|
60 if (stdAlg == null || givenAlg == null) return false; |
|
61 |
|
62 if (givenAlg.indexOf("-") != -1) { |
|
63 return stdAlg.equalsIgnoreCase(givenAlg); |
|
64 } else { |
|
65 if (stdAlg.equals("SHA-1")) { |
|
66 return (givenAlg.equalsIgnoreCase("SHA") |
|
67 || givenAlg.equalsIgnoreCase("SHA1")); |
|
68 } else { |
|
69 StringBuilder sb = new StringBuilder(givenAlg); |
|
70 // case-insensitive check |
|
71 if (givenAlg.regionMatches(true, 0, "SHA", 0, 3)) { |
|
72 givenAlg = sb.insert(3, "-").toString(); |
|
73 return stdAlg.equalsIgnoreCase(givenAlg); |
|
74 } else { |
|
75 throw new ProviderException("Unsupported digest algorithm " |
|
76 + givenAlg); |
|
77 } |
|
78 } |
|
79 } |
|
80 } |
|
81 |
|
82 private static final byte[] EIGHT_BYTES_OF_ZEROS = new byte[8]; |
|
83 |
|
84 private static final Hashtable<String, Integer> DIGEST_LENGTHS = |
|
85 new Hashtable<String, Integer>(); |
|
86 static { |
|
87 DIGEST_LENGTHS.put("SHA-1", 20); |
|
88 DIGEST_LENGTHS.put("SHA", 20); |
|
89 DIGEST_LENGTHS.put("SHA1", 20); |
|
90 DIGEST_LENGTHS.put("SHA-224", 28); |
|
91 DIGEST_LENGTHS.put("SHA224", 28); |
|
92 DIGEST_LENGTHS.put("SHA-256", 32); |
|
93 DIGEST_LENGTHS.put("SHA256", 32); |
|
94 DIGEST_LENGTHS.put("SHA-384", 48); |
|
95 DIGEST_LENGTHS.put("SHA384", 48); |
|
96 DIGEST_LENGTHS.put("SHA-512", 64); |
|
97 DIGEST_LENGTHS.put("SHA512", 64); |
|
98 DIGEST_LENGTHS.put("SHA-512/224", 28); |
|
99 DIGEST_LENGTHS.put("SHA512/224", 28); |
|
100 DIGEST_LENGTHS.put("SHA-512/256", 32); |
|
101 DIGEST_LENGTHS.put("SHA512/256", 32); |
|
102 } |
|
103 |
|
104 // message digest implementation we use for hashing the data |
|
105 private MessageDigest md; |
|
106 // flag indicating whether the digest is reset |
|
107 private boolean digestReset = true; |
|
108 |
|
109 // private key, if initialized for signing |
|
110 private RSAPrivateKey privKey = null; |
|
111 // public key, if initialized for verifying |
|
112 private RSAPublicKey pubKey = null; |
|
113 // PSS parameters from signatures and keys respectively |
|
114 private PSSParameterSpec sigParams = null; // required for PSS signatures |
|
115 |
|
116 // PRNG used to generate salt bytes if none given |
|
117 private SecureRandom random; |
|
118 |
|
119 /** |
|
120 * Construct a new RSAPSSSignatur with arbitrary digest algorithm |
|
121 */ |
|
122 public RSAPSSSignature() { |
|
123 this.md = null; |
|
124 } |
|
125 |
|
126 // initialize for verification. See JCA doc |
|
127 @Override |
|
128 protected void engineInitVerify(PublicKey publicKey) |
|
129 throws InvalidKeyException { |
|
130 if (!(publicKey instanceof RSAPublicKey)) { |
|
131 throw new InvalidKeyException("key must be RSAPublicKey"); |
|
132 } |
|
133 this.pubKey = (RSAPublicKey) isValid((RSAKey)publicKey); |
|
134 this.privKey = null; |
|
135 |
|
136 } |
|
137 |
|
138 // initialize for signing. See JCA doc |
|
139 @Override |
|
140 protected void engineInitSign(PrivateKey privateKey) |
|
141 throws InvalidKeyException { |
|
142 engineInitSign(privateKey, null); |
|
143 } |
|
144 |
|
145 // initialize for signing. See JCA doc |
|
146 @Override |
|
147 protected void engineInitSign(PrivateKey privateKey, SecureRandom random) |
|
148 throws InvalidKeyException { |
|
149 if (!(privateKey instanceof RSAPrivateKey)) { |
|
150 throw new InvalidKeyException("key must be RSAPrivateKey"); |
|
151 } |
|
152 this.privKey = (RSAPrivateKey) isValid((RSAKey)privateKey); |
|
153 this.pubKey = null; |
|
154 this.random = |
|
155 (random == null? JCAUtil.getSecureRandom() : random); |
|
156 } |
|
157 |
|
158 /** |
|
159 * Utility method for checking the key PSS parameters against signature |
|
160 * PSS parameters. |
|
161 * Returns false if any of the digest/MGF algorithms and trailerField |
|
162 * values does not match or if the salt length in key parameters is |
|
163 * larger than the value in signature parameters. |
|
164 */ |
|
165 private static boolean isCompatible(AlgorithmParameterSpec keyParams, |
|
166 PSSParameterSpec sigParams) { |
|
167 if (keyParams == null) { |
|
168 // key with null PSS parameters means no restriction |
|
169 return true; |
|
170 } |
|
171 if (!(keyParams instanceof PSSParameterSpec)) { |
|
172 return false; |
|
173 } |
|
174 // nothing to compare yet, defer the check to when sigParams is set |
|
175 if (sigParams == null) { |
|
176 return true; |
|
177 } |
|
178 PSSParameterSpec pssKeyParams = (PSSParameterSpec) keyParams; |
|
179 // first check the salt length requirement |
|
180 if (pssKeyParams.getSaltLength() > sigParams.getSaltLength()) { |
|
181 return false; |
|
182 } |
|
183 |
|
184 // compare equality of the rest of fields based on DER encoding |
|
185 PSSParameterSpec keyParams2 = |
|
186 new PSSParameterSpec(pssKeyParams.getDigestAlgorithm(), |
|
187 pssKeyParams.getMGFAlgorithm(), |
|
188 pssKeyParams.getMGFParameters(), |
|
189 sigParams.getSaltLength(), |
|
190 pssKeyParams.getTrailerField()); |
|
191 PSSParameters ap = new PSSParameters(); |
|
192 try { |
|
193 ap.engineInit(keyParams2); |
|
194 byte[] encoded = ap.engineGetEncoded(); |
|
195 ap.engineInit(sigParams); |
|
196 byte[] encoded2 = ap.engineGetEncoded(); |
|
197 return Arrays.equals(encoded, encoded2); |
|
198 } catch (Exception e) { |
|
199 if (DEBUG) { |
|
200 e.printStackTrace(); |
|
201 } |
|
202 return false; |
|
203 } |
|
204 } |
|
205 |
|
206 /** |
|
207 * Validate the specified RSAKey and its associated parameters against |
|
208 * internal signature parameters. |
|
209 */ |
|
210 private RSAKey isValid(RSAKey rsaKey) throws InvalidKeyException { |
|
211 try { |
|
212 AlgorithmParameterSpec keyParams = rsaKey.getParams(); |
|
213 // validate key parameters |
|
214 if (!isCompatible(rsaKey.getParams(), this.sigParams)) { |
|
215 throw new InvalidKeyException |
|
216 ("Key contains incompatible PSS parameter values"); |
|
217 } |
|
218 // validate key length |
|
219 if (this.sigParams != null) { |
|
220 Integer hLen = |
|
221 DIGEST_LENGTHS.get(this.sigParams.getDigestAlgorithm()); |
|
222 if (hLen == null) { |
|
223 throw new ProviderException("Unsupported digest algo: " + |
|
224 this.sigParams.getDigestAlgorithm()); |
|
225 } |
|
226 checkKeyLength(rsaKey, hLen, this.sigParams.getSaltLength()); |
|
227 } |
|
228 return rsaKey; |
|
229 } catch (SignatureException e) { |
|
230 throw new InvalidKeyException(e); |
|
231 } |
|
232 } |
|
233 |
|
234 /** |
|
235 * Validate the specified Signature PSS parameters. |
|
236 */ |
|
237 private PSSParameterSpec validateSigParams(AlgorithmParameterSpec p) |
|
238 throws InvalidAlgorithmParameterException { |
|
239 if (p == null) { |
|
240 throw new InvalidAlgorithmParameterException |
|
241 ("Parameters cannot be null"); |
|
242 } |
|
243 if (!(p instanceof PSSParameterSpec)) { |
|
244 throw new InvalidAlgorithmParameterException |
|
245 ("parameters must be type PSSParameterSpec"); |
|
246 } |
|
247 // no need to validate again if same as current signature parameters |
|
248 PSSParameterSpec params = (PSSParameterSpec) p; |
|
249 if (params == this.sigParams) return params; |
|
250 |
|
251 RSAKey key = (this.privKey == null? this.pubKey : this.privKey); |
|
252 // check against keyParams if set |
|
253 if (key != null) { |
|
254 if (!isCompatible(key.getParams(), params)) { |
|
255 throw new InvalidAlgorithmParameterException |
|
256 ("Signature parameters does not match key parameters"); |
|
257 } |
|
258 } |
|
259 // now sanity check the parameter values |
|
260 if (!(params.getMGFAlgorithm().equalsIgnoreCase("MGF1"))) { |
|
261 throw new InvalidAlgorithmParameterException("Only supports MGF1"); |
|
262 |
|
263 } |
|
264 if (params.getTrailerField() != 1) { |
|
265 throw new InvalidAlgorithmParameterException |
|
266 ("Only supports TrailerFieldBC(1)"); |
|
267 |
|
268 } |
|
269 String digestAlgo = params.getDigestAlgorithm(); |
|
270 // check key length again |
|
271 if (key != null) { |
|
272 try { |
|
273 int hLen = DIGEST_LENGTHS.get(digestAlgo); |
|
274 checkKeyLength(key, hLen, params.getSaltLength()); |
|
275 } catch (SignatureException e) { |
|
276 throw new InvalidAlgorithmParameterException(e); |
|
277 } |
|
278 } |
|
279 return params; |
|
280 } |
|
281 |
|
282 /** |
|
283 * Ensure the object is initialized with key and parameters and |
|
284 * reset digest |
|
285 */ |
|
286 private void ensureInit() throws SignatureException { |
|
287 RSAKey key = (this.privKey == null? this.pubKey : this.privKey); |
|
288 if (key == null) { |
|
289 throw new SignatureException("Missing key"); |
|
290 } |
|
291 if (this.sigParams == null) { |
|
292 // Parameters are required for signature verification |
|
293 throw new SignatureException |
|
294 ("Parameters required for RSASSA-PSS signatures"); |
|
295 } |
|
296 } |
|
297 |
|
298 /** |
|
299 * Utility method for checking key length against digest length and |
|
300 * salt length |
|
301 */ |
|
302 private static void checkKeyLength(RSAKey key, int digestLen, |
|
303 int saltLen) throws SignatureException { |
|
304 if (key != null) { |
|
305 int keyLength = getKeyLengthInBits(key) >> 3; |
|
306 int minLength = Math.addExact(Math.addExact(digestLen, saltLen), 2); |
|
307 if (keyLength < minLength) { |
|
308 throw new SignatureException |
|
309 ("Key is too short, need min " + minLength); |
|
310 } |
|
311 } |
|
312 } |
|
313 |
|
314 /** |
|
315 * Reset the message digest if it is not already reset. |
|
316 */ |
|
317 private void resetDigest() { |
|
318 if (digestReset == false) { |
|
319 this.md.reset(); |
|
320 digestReset = true; |
|
321 } |
|
322 } |
|
323 |
|
324 /** |
|
325 * Return the message digest value. |
|
326 */ |
|
327 private byte[] getDigestValue() { |
|
328 digestReset = true; |
|
329 return this.md.digest(); |
|
330 } |
|
331 |
|
332 // update the signature with the plaintext data. See JCA doc |
|
333 @Override |
|
334 protected void engineUpdate(byte b) throws SignatureException { |
|
335 ensureInit(); |
|
336 this.md.update(b); |
|
337 digestReset = false; |
|
338 } |
|
339 |
|
340 // update the signature with the plaintext data. See JCA doc |
|
341 @Override |
|
342 protected void engineUpdate(byte[] b, int off, int len) |
|
343 throws SignatureException { |
|
344 ensureInit(); |
|
345 this.md.update(b, off, len); |
|
346 digestReset = false; |
|
347 } |
|
348 |
|
349 // update the signature with the plaintext data. See JCA doc |
|
350 @Override |
|
351 protected void engineUpdate(ByteBuffer b) { |
|
352 try { |
|
353 ensureInit(); |
|
354 } catch (SignatureException se) { |
|
355 // hack for working around API bug |
|
356 throw new RuntimeException(se.getMessage()); |
|
357 } |
|
358 this.md.update(b); |
|
359 digestReset = false; |
|
360 } |
|
361 |
|
362 // sign the data and return the signature. See JCA doc |
|
363 @Override |
|
364 protected byte[] engineSign() throws SignatureException { |
|
365 ensureInit(); |
|
366 byte[] mHash = getDigestValue(); |
|
367 try { |
|
368 byte[] encoded = encodeSignature(mHash); |
|
369 byte[] encrypted = RSACore.rsa(encoded, privKey, true); |
|
370 return encrypted; |
|
371 } catch (GeneralSecurityException e) { |
|
372 throw new SignatureException("Could not sign data", e); |
|
373 } catch (IOException e) { |
|
374 throw new SignatureException("Could not encode data", e); |
|
375 } |
|
376 } |
|
377 |
|
378 // verify the data and return the result. See JCA doc |
|
379 // should be reset to the state after engineInitVerify call. |
|
380 @Override |
|
381 protected boolean engineVerify(byte[] sigBytes) throws SignatureException { |
|
382 ensureInit(); |
|
383 try { |
|
384 if (sigBytes.length != RSACore.getByteLength(this.pubKey)) { |
|
385 throw new SignatureException |
|
386 ("Signature length not correct: got " |
|
387 + sigBytes.length + " but was expecting " |
|
388 + RSACore.getByteLength(this.pubKey)); |
|
389 } |
|
390 byte[] mHash = getDigestValue(); |
|
391 byte[] decrypted = RSACore.rsa(sigBytes, this.pubKey); |
|
392 return decodeSignature(mHash, decrypted); |
|
393 } catch (javax.crypto.BadPaddingException e) { |
|
394 // occurs if the app has used the wrong RSA public key |
|
395 // or if sigBytes is invalid |
|
396 // return false rather than propagating the exception for |
|
397 // compatibility/ease of use |
|
398 return false; |
|
399 } catch (IOException e) { |
|
400 throw new SignatureException("Signature encoding error", e); |
|
401 } finally { |
|
402 resetDigest(); |
|
403 } |
|
404 } |
|
405 |
|
406 // return the modulus length in bits |
|
407 private static int getKeyLengthInBits(RSAKey k) { |
|
408 if (k != null) { |
|
409 return k.getModulus().bitLength(); |
|
410 } |
|
411 return -1; |
|
412 } |
|
413 |
|
414 /** |
|
415 * Encode the digest 'mHash', return the to-be-signed data. |
|
416 * Also used by the PKCS#11 provider. |
|
417 */ |
|
418 private byte[] encodeSignature(byte[] mHash) |
|
419 throws IOException, DigestException { |
|
420 AlgorithmParameterSpec mgfParams = this.sigParams.getMGFParameters(); |
|
421 String mgfDigestAlgo; |
|
422 if (mgfParams != null) { |
|
423 mgfDigestAlgo = |
|
424 ((MGF1ParameterSpec) mgfParams).getDigestAlgorithm(); |
|
425 } else { |
|
426 mgfDigestAlgo = this.md.getAlgorithm(); |
|
427 } |
|
428 try { |
|
429 int emBits = getKeyLengthInBits(this.privKey) - 1; |
|
430 int emLen =(emBits + 7) >> 3; |
|
431 int hLen = this.md.getDigestLength(); |
|
432 int dbLen = emLen - hLen - 1; |
|
433 int sLen = this.sigParams.getSaltLength(); |
|
434 |
|
435 // maps DB into the corresponding region of EM and |
|
436 // stores its bytes directly into EM |
|
437 byte[] em = new byte[emLen]; |
|
438 |
|
439 // step7 and some of step8 |
|
440 em[dbLen - sLen - 1] = (byte) 1; // set DB's padding2 into EM |
|
441 em[em.length - 1] = (byte) 0xBC; // set trailer field of EM |
|
442 |
|
443 if (!digestReset) { |
|
444 throw new ProviderException("Digest should be reset"); |
|
445 } |
|
446 // step5: generates M' using padding1, mHash, and salt |
|
447 this.md.update(EIGHT_BYTES_OF_ZEROS); |
|
448 digestReset = false; // mark digest as it now has data |
|
449 this.md.update(mHash); |
|
450 if (sLen != 0) { |
|
451 // step4: generate random salt |
|
452 byte[] salt = new byte[sLen]; |
|
453 this.random.nextBytes(salt); |
|
454 this.md.update(salt); |
|
455 |
|
456 // step8: set DB's salt into EM |
|
457 System.arraycopy(salt, 0, em, dbLen - sLen, sLen); |
|
458 } |
|
459 // step6: generate H using M' |
|
460 this.md.digest(em, dbLen, hLen); // set H field of EM |
|
461 digestReset = true; |
|
462 |
|
463 // step7 and 8 are already covered by the code which setting up |
|
464 // EM as above |
|
465 |
|
466 // step9 and 10: feed H into MGF and xor with DB in EM |
|
467 MGF1 mgf1 = new MGF1(mgfDigestAlgo); |
|
468 mgf1.generateAndXor(em, dbLen, hLen, dbLen, em, 0); |
|
469 |
|
470 // step11: set the leftmost (8emLen - emBits) bits of the leftmost |
|
471 // octet to 0 |
|
472 int numZeroBits = (emLen << 3) - emBits; |
|
473 if (numZeroBits != 0) { |
|
474 byte MASK = (byte) (0xff >>> numZeroBits); |
|
475 em[0] = (byte) (em[0] & MASK); |
|
476 } |
|
477 |
|
478 // step12: em should now holds maskedDB || hash h || 0xBC |
|
479 return em; |
|
480 } catch (NoSuchAlgorithmException e) { |
|
481 throw new IOException(e.toString()); |
|
482 } |
|
483 } |
|
484 |
|
485 /** |
|
486 * Decode the signature data. Verify that the object identifier matches |
|
487 * and return the message digest. |
|
488 */ |
|
489 private boolean decodeSignature(byte[] mHash, byte[] em) |
|
490 throws IOException { |
|
491 int hLen = mHash.length; |
|
492 int sLen = this.sigParams.getSaltLength(); |
|
493 int emLen = em.length; |
|
494 int emBits = getKeyLengthInBits(this.pubKey) - 1; |
|
495 |
|
496 // step3 |
|
497 if (emLen < (hLen + sLen + 2)) { |
|
498 return false; |
|
499 } |
|
500 |
|
501 // step4 |
|
502 if (em[emLen - 1] != (byte) 0xBC) { |
|
503 return false; |
|
504 } |
|
505 |
|
506 // step6: check if the leftmost (8emLen - emBits) bits of the leftmost |
|
507 // octet are 0 |
|
508 int numZeroBits = (emLen << 3) - emBits; |
|
509 if (numZeroBits != 0) { |
|
510 byte MASK = (byte) (0xff << (8 - numZeroBits)); |
|
511 if ((em[0] & MASK) != 0) { |
|
512 return false; |
|
513 } |
|
514 } |
|
515 String mgfDigestAlgo; |
|
516 AlgorithmParameterSpec mgfParams = this.sigParams.getMGFParameters(); |
|
517 if (mgfParams != null) { |
|
518 mgfDigestAlgo = |
|
519 ((MGF1ParameterSpec) mgfParams).getDigestAlgorithm(); |
|
520 } else { |
|
521 mgfDigestAlgo = this.md.getAlgorithm(); |
|
522 } |
|
523 // step 7 and 8 |
|
524 int dbLen = emLen - hLen - 1; |
|
525 try { |
|
526 MGF1 mgf1 = new MGF1(mgfDigestAlgo); |
|
527 mgf1.generateAndXor(em, dbLen, hLen, dbLen, em, 0); |
|
528 } catch (NoSuchAlgorithmException nsae) { |
|
529 throw new IOException(nsae.toString()); |
|
530 } |
|
531 |
|
532 // step9: set the leftmost (8emLen - emBits) bits of the leftmost |
|
533 // octet to 0 |
|
534 if (numZeroBits != 0) { |
|
535 byte MASK = (byte) (0xff >>> numZeroBits); |
|
536 em[0] = (byte) (em[0] & MASK); |
|
537 } |
|
538 |
|
539 // step10 |
|
540 int i = 0; |
|
541 for (; i < dbLen - sLen - 1; i++) { |
|
542 if (em[i] != 0) { |
|
543 return false; |
|
544 } |
|
545 } |
|
546 if (em[i] != 0x01) { |
|
547 return false; |
|
548 } |
|
549 // step12 and 13 |
|
550 this.md.update(EIGHT_BYTES_OF_ZEROS); |
|
551 digestReset = false; |
|
552 this.md.update(mHash); |
|
553 if (sLen > 0) { |
|
554 this.md.update(em, (dbLen - sLen), sLen); |
|
555 } |
|
556 byte[] digest2 = this.md.digest(); |
|
557 digestReset = true; |
|
558 |
|
559 // step14 |
|
560 byte[] digestInEM = Arrays.copyOfRange(em, dbLen, emLen - 1); |
|
561 return MessageDigest.isEqual(digest2, digestInEM); |
|
562 } |
|
563 |
|
564 // set parameter, not supported. See JCA doc |
|
565 @Deprecated |
|
566 @Override |
|
567 protected void engineSetParameter(String param, Object value) |
|
568 throws InvalidParameterException { |
|
569 throw new UnsupportedOperationException("setParameter() not supported"); |
|
570 } |
|
571 |
|
572 @Override |
|
573 protected void engineSetParameter(AlgorithmParameterSpec params) |
|
574 throws InvalidAlgorithmParameterException { |
|
575 this.sigParams = validateSigParams(params); |
|
576 // disallow changing parameters when digest has been used |
|
577 if (!digestReset) { |
|
578 throw new ProviderException |
|
579 ("Cannot set parameters during operations"); |
|
580 } |
|
581 String newHashAlg = this.sigParams.getDigestAlgorithm(); |
|
582 // re-allocate md if not yet assigned or algorithm changed |
|
583 if ((this.md == null) || |
|
584 !(this.md.getAlgorithm().equalsIgnoreCase(newHashAlg))) { |
|
585 try { |
|
586 this.md = MessageDigest.getInstance(newHashAlg); |
|
587 } catch (NoSuchAlgorithmException nsae) { |
|
588 // should not happen as we pick default digest algorithm |
|
589 throw new InvalidAlgorithmParameterException |
|
590 ("Unsupported digest algorithm " + |
|
591 newHashAlg, nsae); |
|
592 } |
|
593 } |
|
594 } |
|
595 |
|
596 // get parameter, not supported. See JCA doc |
|
597 @Deprecated |
|
598 @Override |
|
599 protected Object engineGetParameter(String param) |
|
600 throws InvalidParameterException { |
|
601 throw new UnsupportedOperationException("getParameter() not supported"); |
|
602 } |
|
603 |
|
604 @Override |
|
605 protected AlgorithmParameters engineGetParameters() { |
|
606 if (this.sigParams == null) { |
|
607 throw new ProviderException("Missing required PSS parameters"); |
|
608 } |
|
609 try { |
|
610 AlgorithmParameters ap = |
|
611 AlgorithmParameters.getInstance("RSASSA-PSS"); |
|
612 ap.init(this.sigParams); |
|
613 return ap; |
|
614 } catch (GeneralSecurityException gse) { |
|
615 throw new ProviderException(gse.getMessage()); |
|
616 } |
|
617 } |
|
618 } |