3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is the Netscape security libraries.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1994-2000
21 * the Initial Developer. All Rights Reserved.
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
38 /* $Id: dsa.c,v 1.18 2005/10/12 00:48:25 wtchang%redhat.com Exp $ */
51 /* XXX to be replaced by define in blapit.h */
52 #define NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE 2048
54 /* DSA-specific random number function defined in prng_fips1861.c. */
56 DSA_GenerateGlobalRandomBytes(void *dest
, size_t len
, const unsigned char *q
);
58 static void translate_mpi_error(mp_err err
)
64 dsa_NewKey(const PQGParams
*params
, DSAPrivateKey
**privKey
,
65 const unsigned char *xb
)
73 if (!params
|| !privKey
) {
74 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
77 /* Initialize an arena for the DSA key. */
78 arena
= PORT_NewArena(NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE
);
80 PORT_SetError(SEC_ERROR_NO_MEMORY
);
83 key
= (DSAPrivateKey
*)PORT_ArenaZAlloc(arena
, sizeof(DSAPrivateKey
));
85 PORT_SetError(SEC_ERROR_NO_MEMORY
);
86 PORT_FreeArena(arena
, PR_TRUE
);
89 key
->params
.arena
= arena
;
90 /* Initialize MPI integers. */
95 CHECK_MPI_OK( mp_init(&p
) );
96 CHECK_MPI_OK( mp_init(&g
) );
97 CHECK_MPI_OK( mp_init(&x
) );
98 CHECK_MPI_OK( mp_init(&y
) );
99 /* Copy over the PQG params */
100 CHECK_MPI_OK( SECITEM_CopyItem(arena
, &key
->params
.prime
,
102 CHECK_MPI_OK( SECITEM_CopyItem(arena
, &key
->params
.subPrime
,
103 ¶ms
->subPrime
) );
104 CHECK_MPI_OK( SECITEM_CopyItem(arena
, &key
->params
.base
, ¶ms
->base
) );
105 /* Convert stored p, g, and received x into MPI integers. */
106 SECITEM_TO_MPINT(params
->prime
, &p
);
107 SECITEM_TO_MPINT(params
->base
, &g
);
108 OCTETS_TO_MPINT(xb
, &x
, DSA_SUBPRIME_LEN
);
109 /* Store x in private key */
110 SECITEM_AllocItem(arena
, &key
->privateValue
, DSA_SUBPRIME_LEN
);
111 memcpy(key
->privateValue
.data
, xb
, DSA_SUBPRIME_LEN
);
112 /* Compute public key y = g**x mod p */
113 CHECK_MPI_OK( mp_exptmod(&g
, &x
, &p
, &y
) );
114 /* Store y in public key */
115 MPINT_TO_SECITEM(&y
, &key
->publicValue
, arena
);
124 PORT_FreeArena(key
->params
.arena
, PR_TRUE
);
126 translate_mpi_error(err
);
133 ** Generate and return a new DSA public and private key pair,
134 ** both of which are encoded into a single DSAPrivateKey struct.
135 ** "params" is a pointer to the PQG parameters for the domain
136 ** Uses a random seed.
139 DSA_NewKey(const PQGParams
*params
, DSAPrivateKey
**privKey
)
142 unsigned char seed
[DSA_SUBPRIME_LEN
];
148 /* Generate seed bytes for x according to FIPS 186-1 appendix 3 */
149 if (DSA_GenerateGlobalRandomBytes(seed
, DSA_SUBPRIME_LEN
,
150 params
->subPrime
.data
))
152 /* Disallow values of 0 and 1 for x. */
154 for (i
= 0; i
< DSA_SUBPRIME_LEN
-1; i
++) {
160 if (!good
&& seed
[i
] > 1) {
163 } while (!good
&& --retries
> 0);
166 PORT_SetError(SEC_ERROR_NEED_RANDOM
);
170 /* Generate a new DSA key using random seed. */
171 rv
= dsa_NewKey(params
, privKey
, seed
);
175 /* For FIPS compliance testing. Seed must be exactly 20 bytes long */
177 DSA_NewKeyFromSeed(const PQGParams
*params
,
178 const unsigned char *seed
,
179 DSAPrivateKey
**privKey
)
182 rv
= dsa_NewKey(params
, privKey
, seed
);
187 dsa_SignDigest(DSAPrivateKey
*key
, SECItem
*signature
, const SECItem
*digest
,
188 const unsigned char *kb
)
190 mp_int p
, q
, g
; /* PQG parameters */
191 mp_int x
, k
; /* private key & pseudo-random integer */
192 mp_int r
, s
; /* tuple (r, s) is signature) */
193 mp_err err
= MP_OKAY
;
194 SECStatus rv
= SECSuccess
;
196 /* FIPS-compliance dictates that digest is a SHA1 hash. */
198 if (!key
|| !signature
|| !digest
||
199 (signature
->len
< DSA_SIGNATURE_LEN
) ||
200 (digest
->len
!= SHA1_LENGTH
)) {
201 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
205 /* Initialize MPI integers. */
213 CHECK_MPI_OK( mp_init(&p
) );
214 CHECK_MPI_OK( mp_init(&q
) );
215 CHECK_MPI_OK( mp_init(&g
) );
216 CHECK_MPI_OK( mp_init(&x
) );
217 CHECK_MPI_OK( mp_init(&k
) );
218 CHECK_MPI_OK( mp_init(&r
) );
219 CHECK_MPI_OK( mp_init(&s
) );
221 ** Convert stored PQG and private key into MPI integers.
223 SECITEM_TO_MPINT(key
->params
.prime
, &p
);
224 SECITEM_TO_MPINT(key
->params
.subPrime
, &q
);
225 SECITEM_TO_MPINT(key
->params
.base
, &g
);
226 SECITEM_TO_MPINT(key
->privateValue
, &x
);
227 OCTETS_TO_MPINT(kb
, &k
, DSA_SUBPRIME_LEN
);
229 ** FIPS 186-1, Section 5, Step 1
231 ** r = (g**k mod p) mod q
233 CHECK_MPI_OK( mp_exptmod(&g
, &k
, &p
, &r
) ); /* r = g**k mod p */
234 CHECK_MPI_OK( mp_mod(&r
, &q
, &r
) ); /* r = r mod q */
236 ** FIPS 186-1, Section 5, Step 2
238 ** s = (k**-1 * (SHA1(M) + x*r)) mod q
240 SECITEM_TO_MPINT(*digest
, &s
); /* s = SHA1(M) */
241 CHECK_MPI_OK( mp_invmod(&k
, &q
, &k
) ); /* k = k**-1 mod q */
242 CHECK_MPI_OK( mp_mulmod(&x
, &r
, &q
, &x
) ); /* x = x * r mod q */
243 CHECK_MPI_OK( mp_addmod(&s
, &x
, &q
, &s
) ); /* s = s + x mod q */
244 CHECK_MPI_OK( mp_mulmod(&s
, &k
, &q
, &s
) ); /* s = s * k mod q */
246 ** verify r != 0 and s != 0
247 ** mentioned as optional in FIPS 186-1.
249 if (mp_cmp_z(&r
) == 0 || mp_cmp_z(&s
) == 0) {
250 PORT_SetError(SEC_ERROR_NEED_RANDOM
);
257 ** Signature is tuple (r, s)
259 err
= mp_to_fixlen_octets(&r
, signature
->data
, DSA_SUBPRIME_LEN
);
260 if (err
< 0) goto cleanup
;
261 err
= mp_to_fixlen_octets(&s
, signature
->data
+ DSA_SUBPRIME_LEN
,
263 if (err
< 0) goto cleanup
;
265 signature
->len
= DSA_SIGNATURE_LEN
;
275 translate_mpi_error(err
);
281 /* signature is caller-supplied buffer of at least 40 bytes.
282 ** On input, signature->len == size of buffer to hold signature.
283 ** digest->len == size of digest.
284 ** On output, signature->len == size of signature in buffer.
285 ** Uses a random seed.
288 DSA_SignDigest(DSAPrivateKey
*key
, SECItem
*signature
, const SECItem
*digest
)
292 unsigned char kSeed
[DSA_SUBPRIME_LEN
];
298 rv
= DSA_GenerateGlobalRandomBytes(kSeed
, DSA_SUBPRIME_LEN
,
299 key
->params
.subPrime
.data
);
300 if (rv
!= SECSuccess
)
302 /* Disallow a value of 0 for k. */
304 for (i
= 0; i
< DSA_SUBPRIME_LEN
; i
++) {
311 PORT_SetError(SEC_ERROR_NEED_RANDOM
);
315 rv
= dsa_SignDigest(key
, signature
, digest
, kSeed
);
316 } while (rv
!= SECSuccess
&& PORT_GetError() == SEC_ERROR_NEED_RANDOM
&&
321 /* For FIPS compliance testing. Seed must be exactly 20 bytes. */
323 DSA_SignDigestWithSeed(DSAPrivateKey
* key
,
325 const SECItem
* digest
,
326 const unsigned char * seed
)
329 rv
= dsa_SignDigest(key
, signature
, digest
, seed
);
333 /* signature is caller-supplied buffer of at least 20 bytes.
334 ** On input, signature->len == size of buffer to hold signature.
335 ** digest->len == size of digest.
338 DSA_VerifyDigest(DSAPublicKey
*key
, const SECItem
*signature
,
339 const SECItem
*digest
)
341 /* FIPS-compliance dictates that digest is a SHA1 hash. */
342 mp_int p
, q
, g
; /* PQG parameters */
343 mp_int r_
, s_
; /* tuple (r', s') is received signature) */
344 mp_int u1
, u2
, v
, w
; /* intermediate values used in verification */
345 mp_int y
; /* public key */
347 SECStatus verified
= SECFailure
;
350 if (!key
|| !signature
|| !digest
||
351 (signature
->len
!= DSA_SIGNATURE_LEN
) ||
352 (digest
->len
!= SHA1_LENGTH
)) {
353 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
356 /* Initialize MPI integers. */
367 CHECK_MPI_OK( mp_init(&p
) );
368 CHECK_MPI_OK( mp_init(&q
) );
369 CHECK_MPI_OK( mp_init(&g
) );
370 CHECK_MPI_OK( mp_init(&y
) );
371 CHECK_MPI_OK( mp_init(&r_
) );
372 CHECK_MPI_OK( mp_init(&s_
) );
373 CHECK_MPI_OK( mp_init(&u1
) );
374 CHECK_MPI_OK( mp_init(&u2
) );
375 CHECK_MPI_OK( mp_init(&v
) );
376 CHECK_MPI_OK( mp_init(&w
) );
378 ** Convert stored PQG and public key into MPI integers.
380 SECITEM_TO_MPINT(key
->params
.prime
, &p
);
381 SECITEM_TO_MPINT(key
->params
.subPrime
, &q
);
382 SECITEM_TO_MPINT(key
->params
.base
, &g
);
383 SECITEM_TO_MPINT(key
->publicValue
, &y
);
385 ** Convert received signature (r', s') into MPI integers.
387 OCTETS_TO_MPINT(signature
->data
, &r_
, DSA_SUBPRIME_LEN
);
388 OCTETS_TO_MPINT(signature
->data
+ DSA_SUBPRIME_LEN
, &s_
, DSA_SUBPRIME_LEN
);
390 ** Verify that 0 < r' < q and 0 < s' < q
392 if (mp_cmp_z(&r_
) <= 0 || mp_cmp_z(&s_
) <= 0 ||
393 mp_cmp(&r_
, &q
) >= 0 || mp_cmp(&s_
, &q
) >= 0) {
394 /* err is zero here. */
395 PORT_SetError(SEC_ERROR_BAD_SIGNATURE
);
396 goto cleanup
; /* will return verified == SECFailure */
399 ** FIPS 186-1, Section 6, Step 1
401 ** w = (s')**-1 mod q
403 CHECK_MPI_OK( mp_invmod(&s_
, &q
, &w
) ); /* w = (s')**-1 mod q */
405 ** FIPS 186-1, Section 6, Step 2
407 ** u1 = ((SHA1(M')) * w) mod q
409 SECITEM_TO_MPINT(*digest
, &u1
); /* u1 = SHA1(M') */
410 CHECK_MPI_OK( mp_mulmod(&u1
, &w
, &q
, &u1
) ); /* u1 = u1 * w mod q */
412 ** FIPS 186-1, Section 6, Step 3
414 ** u2 = ((r') * w) mod q
416 CHECK_MPI_OK( mp_mulmod(&r_
, &w
, &q
, &u2
) );
418 ** FIPS 186-1, Section 6, Step 4
420 ** v = ((g**u1 * y**u2) mod p) mod q
422 CHECK_MPI_OK( mp_exptmod(&g
, &u1
, &p
, &g
) ); /* g = g**u1 mod p */
423 CHECK_MPI_OK( mp_exptmod(&y
, &u2
, &p
, &y
) ); /* y = y**u2 mod p */
424 CHECK_MPI_OK( mp_mulmod(&g
, &y
, &p
, &v
) ); /* v = g * y mod p */
425 CHECK_MPI_OK( mp_mod(&v
, &q
, &v
) ); /* v = v mod q */
427 ** Verification: v == r'
429 if (mp_cmp(&v
, &r_
)) {
430 PORT_SetError(SEC_ERROR_BAD_SIGNATURE
);
431 verified
= SECFailure
; /* Signature failed to verify. */
433 verified
= SECSuccess
; /* Signature verified. */
447 translate_mpi_error(err
);