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