1 /* 2 * Copyright (c) 1996, 2020, 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.provider; 27 28 import java.io.*; 29 import java.util.*; 30 import java.math.BigInteger; 31 import java.nio.ByteBuffer; 32 33 import java.security.*; 34 import java.security.SecureRandom; 35 import java.security.interfaces.*; 36 import java.security.spec.*; 37 38 import sun.security.util.Debug; 39 import sun.security.util.DerValue; 40 import sun.security.util.DerInputStream; 41 import sun.security.util.DerOutputStream; 42 import sun.security.x509.AlgIdDSA; 43 import sun.security.jca.JCAUtil; 44 45 /** 46 * The Digital Signature Standard (using the Digital Signature 47 * Algorithm), as described in fips186-3 of the National Instute of 48 * Standards and Technology (NIST), using SHA digest algorithms 49 * from FIPS180-3. 50 * 51 * This file contains both the signature implementation for the 52 * commonly used SHA1withDSA (DSS), SHA224withDSA, SHA256withDSA, 53 * as well as RawDSA, used by TLS among others. RawDSA expects 54 * the 20 byte SHA-1 digest as input via update rather than the 55 * original data like other signature implementations. 56 * 57 * @author Benjamin Renaud 58 * 59 * @since 1.1 60 * 61 * @see DSAPublicKey 62 * @see DSAPrivateKey 63 */ 64 abstract class DSA extends SignatureSpi { 65 66 /* Are we debugging? */ 67 private static final boolean debug = false; 68 69 /* The number of bits used in exponent blinding */ 70 private static final int BLINDING_BITS = 7; 71 72 /* The constant component of the exponent blinding value */ 73 private static final BigInteger BLINDING_CONSTANT = 74 BigInteger.valueOf(1 << BLINDING_BITS); 75 76 /* The parameter object */ 77 private DSAParams params; 78 79 /* algorithm parameters */ 80 private BigInteger presetP, presetQ, presetG; 81 82 /* The public key, if any */ 83 private BigInteger presetY; 84 85 /* The private key, if any */ 86 private BigInteger presetX; 87 88 /* The RNG used to output a seed for generating k */ 89 private SecureRandom signingRandom; 90 91 /* The message digest object used */ 92 private final MessageDigest md; 93 94 /** 95 * Construct a blank DSA object. It must be 96 * initialized before being usable for signing or verifying. 97 */ DSA(MessageDigest md)98 DSA(MessageDigest md) { 99 super(); 100 this.md = md; 101 } 102 checkKey(DSAParams params, int digestLen, String mdAlgo)103 private static void checkKey(DSAParams params, int digestLen, String mdAlgo) 104 throws InvalidKeyException { 105 // FIPS186-3 states in sec4.2 that a hash function which provides 106 // a lower security strength than the (L, N) pair ordinarily should 107 // not be used. 108 int valueN = params.getQ().bitLength(); 109 if (valueN > digestLen) { 110 throw new InvalidKeyException("The security strength of " + 111 mdAlgo + " digest algorithm is not sufficient for this key size"); 112 } 113 } 114 115 /** 116 * Initialize the DSA object with a DSA private key. 117 * 118 * @param privateKey the DSA private key 119 * 120 * @exception InvalidKeyException if the key is not a valid DSA private 121 * key. 122 */ engineInitSign(PrivateKey privateKey)123 protected void engineInitSign(PrivateKey privateKey) 124 throws InvalidKeyException { 125 if (!(privateKey instanceof java.security.interfaces.DSAPrivateKey)) { 126 throw new InvalidKeyException("not a DSA private key: " + 127 privateKey); 128 } 129 130 java.security.interfaces.DSAPrivateKey priv = 131 (java.security.interfaces.DSAPrivateKey)privateKey; 132 133 // check for algorithm specific constraints before doing initialization 134 DSAParams params = priv.getParams(); 135 if (params == null) { 136 throw new InvalidKeyException("DSA private key lacks parameters"); 137 } 138 139 // check key size against hash output size for signing 140 // skip this check for verification to minimize impact on existing apps 141 if (md.getAlgorithm() != "NullDigest20") { 142 checkKey(params, md.getDigestLength()*8, md.getAlgorithm()); 143 } 144 145 this.params = params; 146 this.presetX = priv.getX(); 147 this.presetY = null; 148 this.presetP = params.getP(); 149 this.presetQ = params.getQ(); 150 this.presetG = params.getG(); 151 this.md.reset(); 152 } 153 /** 154 * Initialize the DSA object with a DSA public key. 155 * 156 * @param publicKey the DSA public key. 157 * 158 * @exception InvalidKeyException if the key is not a valid DSA public 159 * key. 160 */ engineInitVerify(PublicKey publicKey)161 protected void engineInitVerify(PublicKey publicKey) 162 throws InvalidKeyException { 163 if (!(publicKey instanceof java.security.interfaces.DSAPublicKey)) { 164 throw new InvalidKeyException("not a DSA public key: " + 165 publicKey); 166 } 167 java.security.interfaces.DSAPublicKey pub = 168 (java.security.interfaces.DSAPublicKey)publicKey; 169 170 // check for algorithm specific constraints before doing initialization 171 DSAParams params = pub.getParams(); 172 if (params == null) { 173 throw new InvalidKeyException("DSA public key lacks parameters"); 174 } 175 this.params = params; 176 this.presetY = pub.getY(); 177 this.presetX = null; 178 this.presetP = params.getP(); 179 this.presetQ = params.getQ(); 180 this.presetG = params.getG(); 181 this.md.reset(); 182 } 183 184 /** 185 * Update a byte to be signed or verified. 186 */ engineUpdate(byte b)187 protected void engineUpdate(byte b) { 188 md.update(b); 189 } 190 191 /** 192 * Update an array of bytes to be signed or verified. 193 */ engineUpdate(byte[] data, int off, int len)194 protected void engineUpdate(byte[] data, int off, int len) { 195 md.update(data, off, len); 196 } 197 engineUpdate(ByteBuffer b)198 protected void engineUpdate(ByteBuffer b) { 199 md.update(b); 200 } 201 202 203 /** 204 * Sign all the data thus far updated. The signature is formatted 205 * according to the Canonical Encoding Rules, returned as a DER 206 * sequence of Integer, r and s. 207 * 208 * @return a signature block formatted according to the Canonical 209 * Encoding Rules. 210 * 211 * @exception SignatureException if the signature object was not 212 * properly initialized, or if another exception occurs. 213 * 214 * @see sun.security.DSA#engineUpdate 215 * @see sun.security.DSA#engineVerify 216 */ engineSign()217 protected byte[] engineSign() throws SignatureException { 218 BigInteger k = generateK(presetQ); 219 BigInteger r = generateR(presetP, presetQ, presetG, k); 220 BigInteger s = generateS(presetX, presetQ, r, k); 221 222 try { 223 DerOutputStream outseq = new DerOutputStream(100); 224 outseq.putInteger(r); 225 outseq.putInteger(s); 226 DerValue result = new DerValue(DerValue.tag_Sequence, 227 outseq.toByteArray()); 228 229 return result.toByteArray(); 230 231 } catch (IOException e) { 232 throw new SignatureException("error encoding signature"); 233 } 234 } 235 236 /** 237 * Verify all the data thus far updated. 238 * 239 * @param signature the alledged signature, encoded using the 240 * Canonical Encoding Rules, as a sequence of integers, r and s. 241 * 242 * @exception SignatureException if the signature object was not 243 * properly initialized, or if another exception occurs. 244 * 245 * @see sun.security.DSA#engineUpdate 246 * @see sun.security.DSA#engineSign 247 */ engineVerify(byte[] signature)248 protected boolean engineVerify(byte[] signature) 249 throws SignatureException { 250 return engineVerify(signature, 0, signature.length); 251 } 252 253 /** 254 * Verify all the data thus far updated. 255 * 256 * @param signature the alledged signature, encoded using the 257 * Canonical Encoding Rules, as a sequence of integers, r and s. 258 * 259 * @param offset the offset to start from in the array of bytes. 260 * 261 * @param length the number of bytes to use, starting at offset. 262 * 263 * @exception SignatureException if the signature object was not 264 * properly initialized, or if another exception occurs. 265 * 266 * @see sun.security.DSA#engineUpdate 267 * @see sun.security.DSA#engineSign 268 */ engineVerify(byte[] signature, int offset, int length)269 protected boolean engineVerify(byte[] signature, int offset, int length) 270 throws SignatureException { 271 272 BigInteger r = null; 273 BigInteger s = null; 274 // first decode the signature. 275 try { 276 // Enforce strict DER checking for signatures 277 DerInputStream in = 278 new DerInputStream(signature, offset, length, false); 279 DerValue[] values = in.getSequence(2); 280 281 // check number of components in the read sequence 282 // and trailing data 283 if ((values.length != 2) || (in.available() != 0)) { 284 throw new IOException("Invalid encoding for signature"); 285 } 286 r = values[0].getBigInteger(); 287 s = values[1].getBigInteger(); 288 } catch (IOException e) { 289 throw new SignatureException("Invalid encoding for signature", e); 290 } 291 292 // some implementations do not correctly encode values in the ASN.1 293 // 2's complement format. force r and s to be positive in order to 294 // to validate those signatures 295 if (r.signum() < 0) { 296 r = new BigInteger(1, r.toByteArray()); 297 } 298 if (s.signum() < 0) { 299 s = new BigInteger(1, s.toByteArray()); 300 } 301 302 if ((r.compareTo(presetQ) == -1) && (s.compareTo(presetQ) == -1)) { 303 BigInteger w = generateW(presetP, presetQ, presetG, s); 304 BigInteger v = generateV(presetY, presetP, presetQ, presetG, w, r); 305 return v.equals(r); 306 } else { 307 throw new SignatureException("invalid signature: out of range values"); 308 } 309 } 310 311 @Deprecated engineSetParameter(String key, Object param)312 protected void engineSetParameter(String key, Object param) { 313 throw new InvalidParameterException("No parameter accepted"); 314 } 315 316 @Override engineSetParameter(AlgorithmParameterSpec params)317 protected void engineSetParameter(AlgorithmParameterSpec params) 318 throws InvalidAlgorithmParameterException { 319 if (params != null) { 320 throw new InvalidAlgorithmParameterException("No parameter accepted"); 321 } 322 } 323 324 @Deprecated engineGetParameter(String key)325 protected Object engineGetParameter(String key) { 326 return null; 327 } 328 329 @Override engineGetParameters()330 protected AlgorithmParameters engineGetParameters() { 331 return null; 332 } 333 334 generateR(BigInteger p, BigInteger q, BigInteger g, BigInteger k)335 private BigInteger generateR(BigInteger p, BigInteger q, BigInteger g, 336 BigInteger k) { 337 338 // exponent blinding to hide information from timing channel 339 SecureRandom random = getSigningRandom(); 340 // start with a random blinding component 341 BigInteger blindingValue = new BigInteger(BLINDING_BITS, random); 342 // add the fixed blinding component 343 blindingValue = blindingValue.add(BLINDING_CONSTANT); 344 // replace k with a blinded value that is congruent (mod q) 345 k = k.add(q.multiply(blindingValue)); 346 347 BigInteger temp = g.modPow(k, p); 348 return temp.mod(q); 349 } 350 generateS(BigInteger x, BigInteger q, BigInteger r, BigInteger k)351 private BigInteger generateS(BigInteger x, BigInteger q, 352 BigInteger r, BigInteger k) throws SignatureException { 353 354 byte[] s2; 355 try { 356 s2 = md.digest(); 357 } catch (RuntimeException re) { 358 // Only for RawDSA due to its 20-byte length restriction 359 throw new SignatureException(re.getMessage()); 360 } 361 // get the leftmost min(N, outLen) bits of the digest value 362 int nBytes = q.bitLength()/8; 363 if (nBytes < s2.length) { 364 s2 = Arrays.copyOfRange(s2, 0, nBytes); 365 } 366 BigInteger z = new BigInteger(1, s2); 367 BigInteger k1 = k.modInverse(q); 368 369 return x.multiply(r).add(z).multiply(k1).mod(q); 370 } 371 generateW(BigInteger p, BigInteger q, BigInteger g, BigInteger s)372 private BigInteger generateW(BigInteger p, BigInteger q, 373 BigInteger g, BigInteger s) { 374 return s.modInverse(q); 375 } 376 generateV(BigInteger y, BigInteger p, BigInteger q, BigInteger g, BigInteger w, BigInteger r)377 private BigInteger generateV(BigInteger y, BigInteger p, 378 BigInteger q, BigInteger g, BigInteger w, BigInteger r) 379 throws SignatureException { 380 381 byte[] s2; 382 try { 383 s2 = md.digest(); 384 } catch (RuntimeException re) { 385 // Only for RawDSA due to its 20-byte length restriction 386 throw new SignatureException(re.getMessage()); 387 } 388 // get the leftmost min(N, outLen) bits of the digest value 389 int nBytes = q.bitLength()/8; 390 if (nBytes < s2.length) { 391 s2 = Arrays.copyOfRange(s2, 0, nBytes); 392 } 393 BigInteger z = new BigInteger(1, s2); 394 395 BigInteger u1 = z.multiply(w).mod(q); 396 BigInteger u2 = (r.multiply(w)).mod(q); 397 398 BigInteger t1 = g.modPow(u1,p); 399 BigInteger t2 = y.modPow(u2,p); 400 BigInteger t3 = t1.multiply(t2); 401 BigInteger t5 = t3.mod(p); 402 return t5.mod(q); 403 } 404 generateK(BigInteger q)405 protected BigInteger generateK(BigInteger q) { 406 // Implementation defined in FIPS 186-4 AppendixB.2.1. 407 SecureRandom random = getSigningRandom(); 408 byte[] kValue = new byte[(q.bitLength() + 7)/8 + 8]; 409 410 random.nextBytes(kValue); 411 return new BigInteger(1, kValue).mod( 412 q.subtract(BigInteger.ONE)).add(BigInteger.ONE); 413 } 414 415 // Use the application-specified SecureRandom Object if provided. 416 // Otherwise, use our default SecureRandom Object. getSigningRandom()417 protected SecureRandom getSigningRandom() { 418 if (signingRandom == null) { 419 if (appRandom != null) { 420 signingRandom = appRandom; 421 } else { 422 signingRandom = JCAUtil.getSecureRandom(); 423 } 424 } 425 return signingRandom; 426 } 427 428 /** 429 * Return a human readable rendition of the engine. 430 */ toString()431 public String toString() { 432 String printable = "DSA Signature"; 433 if (presetP != null && presetQ != null && presetG != null) { 434 printable += "\n\tp: " + Debug.toHexString(presetP); 435 printable += "\n\tq: " + Debug.toHexString(presetQ); 436 printable += "\n\tg: " + Debug.toHexString(presetG); 437 } else { 438 printable += "\n\t P, Q or G not initialized."; 439 } 440 if (presetY != null) { 441 printable += "\n\ty: " + Debug.toHexString(presetY); 442 } 443 if (presetY == null && presetX == null) { 444 printable += "\n\tUNINIIALIZED"; 445 } 446 return printable; 447 } 448 449 /** 450 * Standard SHA224withDSA implementation as defined in FIPS186-3. 451 */ 452 public static final class SHA224withDSA extends DSA { SHA224withDSA()453 public SHA224withDSA() throws NoSuchAlgorithmException { 454 super(MessageDigest.getInstance("SHA-224")); 455 } 456 } 457 458 /** 459 * Standard SHA256withDSA implementation as defined in FIPS186-3. 460 */ 461 public static final class SHA256withDSA extends DSA { SHA256withDSA()462 public SHA256withDSA() throws NoSuchAlgorithmException { 463 super(MessageDigest.getInstance("SHA-256")); 464 } 465 } 466 467 /** 468 * Standard SHA1withDSA implementation. 469 */ 470 public static final class SHA1withDSA extends DSA { SHA1withDSA()471 public SHA1withDSA() throws NoSuchAlgorithmException { 472 super(MessageDigest.getInstance("SHA-1")); 473 } 474 } 475 476 /** 477 * RawDSA implementation. 478 * 479 * RawDSA requires the data to be exactly 20 bytes long. If it is 480 * not, a SignatureException is thrown when sign()/verify() is called 481 * per JCA spec. 482 */ 483 public static final class RawDSA extends DSA { 484 // Internal special-purpose MessageDigest impl for RawDSA 485 // Only override whatever methods used 486 // NOTE: no clone support 487 public static final class NullDigest20 extends MessageDigest { 488 // 20 byte digest buffer 489 private final byte[] digestBuffer = new byte[20]; 490 491 // offset into the buffer; use Integer.MAX_VALUE to indicate 492 // out-of-bound condition 493 private int ofs = 0; 494 NullDigest20()495 protected NullDigest20() { 496 super("NullDigest20"); 497 } engineUpdate(byte input)498 protected void engineUpdate(byte input) { 499 if (ofs == digestBuffer.length) { 500 ofs = Integer.MAX_VALUE; 501 } else { 502 digestBuffer[ofs++] = input; 503 } 504 } engineUpdate(byte[] input, int offset, int len)505 protected void engineUpdate(byte[] input, int offset, int len) { 506 if (len > (digestBuffer.length - ofs)) { 507 ofs = Integer.MAX_VALUE; 508 } else { 509 System.arraycopy(input, offset, digestBuffer, ofs, len); 510 ofs += len; 511 } 512 } engineUpdate(ByteBuffer input)513 protected final void engineUpdate(ByteBuffer input) { 514 int inputLen = input.remaining(); 515 if (inputLen > (digestBuffer.length - ofs)) { 516 ofs = Integer.MAX_VALUE; 517 } else { 518 input.get(digestBuffer, ofs, inputLen); 519 ofs += inputLen; 520 } 521 } engineDigest()522 protected byte[] engineDigest() throws RuntimeException { 523 if (ofs != digestBuffer.length) { 524 throw new RuntimeException 525 ("Data for RawDSA must be exactly 20 bytes long"); 526 } 527 reset(); 528 return digestBuffer; 529 } engineDigest(byte[] buf, int offset, int len)530 protected int engineDigest(byte[] buf, int offset, int len) 531 throws DigestException { 532 if (ofs != digestBuffer.length) { 533 throw new DigestException 534 ("Data for RawDSA must be exactly 20 bytes long"); 535 } 536 if (len < digestBuffer.length) { 537 throw new DigestException 538 ("Output buffer too small; must be at least 20 bytes"); 539 } 540 System.arraycopy(digestBuffer, 0, buf, offset, digestBuffer.length); 541 reset(); 542 return digestBuffer.length; 543 } 544 engineReset()545 protected void engineReset() { 546 ofs = 0; 547 } engineGetDigestLength()548 protected final int engineGetDigestLength() { 549 return digestBuffer.length; 550 } 551 } 552 RawDSA()553 public RawDSA() throws NoSuchAlgorithmException { 554 super(new NullDigest20()); 555 } 556 } 557 } 558