xref: /titanic_44/usr/src/common/crypto/ecc/ec.c (revision f9fbec18f5b458b560ecf45d3db8e8bd56bf6942)
1*f9fbec18Smcpowers /*
2*f9fbec18Smcpowers  * ***** BEGIN LICENSE BLOCK *****
3*f9fbec18Smcpowers  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4*f9fbec18Smcpowers  *
5*f9fbec18Smcpowers  * The contents of this file are subject to the Mozilla Public License Version
6*f9fbec18Smcpowers  * 1.1 (the "License"); you may not use this file except in compliance with
7*f9fbec18Smcpowers  * the License. You may obtain a copy of the License at
8*f9fbec18Smcpowers  * http://www.mozilla.org/MPL/
9*f9fbec18Smcpowers  *
10*f9fbec18Smcpowers  * Software distributed under the License is distributed on an "AS IS" basis,
11*f9fbec18Smcpowers  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12*f9fbec18Smcpowers  * for the specific language governing rights and limitations under the
13*f9fbec18Smcpowers  * License.
14*f9fbec18Smcpowers  *
15*f9fbec18Smcpowers  * The Original Code is the Elliptic Curve Cryptography library.
16*f9fbec18Smcpowers  *
17*f9fbec18Smcpowers  * The Initial Developer of the Original Code is
18*f9fbec18Smcpowers  * Sun Microsystems, Inc.
19*f9fbec18Smcpowers  * Portions created by the Initial Developer are Copyright (C) 2003
20*f9fbec18Smcpowers  * the Initial Developer. All Rights Reserved.
21*f9fbec18Smcpowers  *
22*f9fbec18Smcpowers  * Contributor(s):
23*f9fbec18Smcpowers  *   Dr Vipul Gupta <vipul.gupta@sun.com> and
24*f9fbec18Smcpowers  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
25*f9fbec18Smcpowers  *
26*f9fbec18Smcpowers  * Alternatively, the contents of this file may be used under the terms of
27*f9fbec18Smcpowers  * either the GNU General Public License Version 2 or later (the "GPL"), or
28*f9fbec18Smcpowers  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29*f9fbec18Smcpowers  * in which case the provisions of the GPL or the LGPL are applicable instead
30*f9fbec18Smcpowers  * of those above. If you wish to allow use of your version of this file only
31*f9fbec18Smcpowers  * under the terms of either the GPL or the LGPL, and not to allow others to
32*f9fbec18Smcpowers  * use your version of this file under the terms of the MPL, indicate your
33*f9fbec18Smcpowers  * decision by deleting the provisions above and replace them with the notice
34*f9fbec18Smcpowers  * and other provisions required by the GPL or the LGPL. If you do not delete
35*f9fbec18Smcpowers  * the provisions above, a recipient may use your version of this file under
36*f9fbec18Smcpowers  * the terms of any one of the MPL, the GPL or the LGPL.
37*f9fbec18Smcpowers  *
38*f9fbec18Smcpowers  * ***** END LICENSE BLOCK ***** */
39*f9fbec18Smcpowers /*
40*f9fbec18Smcpowers  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
41*f9fbec18Smcpowers  * Use is subject to license terms.
42*f9fbec18Smcpowers  *
43*f9fbec18Smcpowers  * Sun elects to use this software under the MPL license.
44*f9fbec18Smcpowers  */
45*f9fbec18Smcpowers 
46*f9fbec18Smcpowers #pragma ident	"%Z%%M%	%I%	%E% SMI"
47*f9fbec18Smcpowers 
48*f9fbec18Smcpowers #include "mplogic.h"
49*f9fbec18Smcpowers #include "ec.h"
50*f9fbec18Smcpowers #include "ecl.h"
51*f9fbec18Smcpowers 
52*f9fbec18Smcpowers #include <sys/types.h>
53*f9fbec18Smcpowers #ifndef _KERNEL
54*f9fbec18Smcpowers #include <stdlib.h>
55*f9fbec18Smcpowers #include <string.h>
56*f9fbec18Smcpowers #include <strings.h>
57*f9fbec18Smcpowers #endif
58*f9fbec18Smcpowers #include "ecl-exp.h"
59*f9fbec18Smcpowers #include "mpi.h"
60*f9fbec18Smcpowers #include "ecc_impl.h"
61*f9fbec18Smcpowers 
62*f9fbec18Smcpowers #ifdef _KERNEL
63*f9fbec18Smcpowers #define	PORT_ZFree(p, l)		bzero((p), (l)); kmem_free((p), (l))
64*f9fbec18Smcpowers #else
65*f9fbec18Smcpowers #define	PORT_ZFree(p, l)		bzero((p), (l)); free((p))
66*f9fbec18Smcpowers #endif
67*f9fbec18Smcpowers 
68*f9fbec18Smcpowers /*
69*f9fbec18Smcpowers  * Returns true if pointP is the point at infinity, false otherwise
70*f9fbec18Smcpowers  */
71*f9fbec18Smcpowers PRBool
72*f9fbec18Smcpowers ec_point_at_infinity(SECItem *pointP)
73*f9fbec18Smcpowers {
74*f9fbec18Smcpowers     unsigned int i;
75*f9fbec18Smcpowers 
76*f9fbec18Smcpowers     for (i = 1; i < pointP->len; i++) {
77*f9fbec18Smcpowers 	if (pointP->data[i] != 0x00) return PR_FALSE;
78*f9fbec18Smcpowers     }
79*f9fbec18Smcpowers 
80*f9fbec18Smcpowers     return PR_TRUE;
81*f9fbec18Smcpowers }
82*f9fbec18Smcpowers 
83*f9fbec18Smcpowers /*
84*f9fbec18Smcpowers  * Computes scalar point multiplication pointQ = k1 * G + k2 * pointP for
85*f9fbec18Smcpowers  * the curve whose parameters are encoded in params with base point G.
86*f9fbec18Smcpowers  */
87*f9fbec18Smcpowers SECStatus
88*f9fbec18Smcpowers ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2,
89*f9fbec18Smcpowers              const SECItem *pointP, SECItem *pointQ, int kmflag)
90*f9fbec18Smcpowers {
91*f9fbec18Smcpowers     mp_int Px, Py, Qx, Qy;
92*f9fbec18Smcpowers     mp_int Gx, Gy, order, irreducible, a, b;
93*f9fbec18Smcpowers #if 0 /* currently don't support non-named curves */
94*f9fbec18Smcpowers     unsigned int irr_arr[5];
95*f9fbec18Smcpowers #endif
96*f9fbec18Smcpowers     ECGroup *group = NULL;
97*f9fbec18Smcpowers     SECStatus rv = SECFailure;
98*f9fbec18Smcpowers     mp_err err = MP_OKAY;
99*f9fbec18Smcpowers     int len;
100*f9fbec18Smcpowers 
101*f9fbec18Smcpowers #if EC_DEBUG
102*f9fbec18Smcpowers     int i;
103*f9fbec18Smcpowers     char mpstr[256];
104*f9fbec18Smcpowers 
105*f9fbec18Smcpowers     printf("ec_points_mul: params [len=%d]:", params->DEREncoding.len);
106*f9fbec18Smcpowers     for (i = 0; i < params->DEREncoding.len; i++)
107*f9fbec18Smcpowers 	    printf("%02x:", params->DEREncoding.data[i]);
108*f9fbec18Smcpowers     printf("\n");
109*f9fbec18Smcpowers 
110*f9fbec18Smcpowers 	if (k1 != NULL) {
111*f9fbec18Smcpowers 		mp_tohex(k1, mpstr);
112*f9fbec18Smcpowers 		printf("ec_points_mul: scalar k1: %s\n", mpstr);
113*f9fbec18Smcpowers 		mp_todecimal(k1, mpstr);
114*f9fbec18Smcpowers 		printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr);
115*f9fbec18Smcpowers 	}
116*f9fbec18Smcpowers 
117*f9fbec18Smcpowers 	if (k2 != NULL) {
118*f9fbec18Smcpowers 		mp_tohex(k2, mpstr);
119*f9fbec18Smcpowers 		printf("ec_points_mul: scalar k2: %s\n", mpstr);
120*f9fbec18Smcpowers 		mp_todecimal(k2, mpstr);
121*f9fbec18Smcpowers 		printf("ec_points_mul: scalar k2: %s (dec)\n", mpstr);
122*f9fbec18Smcpowers 	}
123*f9fbec18Smcpowers 
124*f9fbec18Smcpowers 	if (pointP != NULL) {
125*f9fbec18Smcpowers 		printf("ec_points_mul: pointP [len=%d]:", pointP->len);
126*f9fbec18Smcpowers 		for (i = 0; i < pointP->len; i++)
127*f9fbec18Smcpowers 			printf("%02x:", pointP->data[i]);
128*f9fbec18Smcpowers 		printf("\n");
129*f9fbec18Smcpowers 	}
130*f9fbec18Smcpowers #endif
131*f9fbec18Smcpowers 
132*f9fbec18Smcpowers 	/* NOTE: We only support uncompressed points for now */
133*f9fbec18Smcpowers 	len = (params->fieldID.size + 7) >> 3;
134*f9fbec18Smcpowers 	if (pointP != NULL) {
135*f9fbec18Smcpowers 		if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
136*f9fbec18Smcpowers 			(pointP->len != (2 * len + 1))) {
137*f9fbec18Smcpowers 			return SECFailure;
138*f9fbec18Smcpowers 		};
139*f9fbec18Smcpowers 	}
140*f9fbec18Smcpowers 
141*f9fbec18Smcpowers 	MP_DIGITS(&Px) = 0;
142*f9fbec18Smcpowers 	MP_DIGITS(&Py) = 0;
143*f9fbec18Smcpowers 	MP_DIGITS(&Qx) = 0;
144*f9fbec18Smcpowers 	MP_DIGITS(&Qy) = 0;
145*f9fbec18Smcpowers 	MP_DIGITS(&Gx) = 0;
146*f9fbec18Smcpowers 	MP_DIGITS(&Gy) = 0;
147*f9fbec18Smcpowers 	MP_DIGITS(&order) = 0;
148*f9fbec18Smcpowers 	MP_DIGITS(&irreducible) = 0;
149*f9fbec18Smcpowers 	MP_DIGITS(&a) = 0;
150*f9fbec18Smcpowers 	MP_DIGITS(&b) = 0;
151*f9fbec18Smcpowers 	CHECK_MPI_OK( mp_init(&Px, kmflag) );
152*f9fbec18Smcpowers 	CHECK_MPI_OK( mp_init(&Py, kmflag) );
153*f9fbec18Smcpowers 	CHECK_MPI_OK( mp_init(&Qx, kmflag) );
154*f9fbec18Smcpowers 	CHECK_MPI_OK( mp_init(&Qy, kmflag) );
155*f9fbec18Smcpowers 	CHECK_MPI_OK( mp_init(&Gx, kmflag) );
156*f9fbec18Smcpowers 	CHECK_MPI_OK( mp_init(&Gy, kmflag) );
157*f9fbec18Smcpowers 	CHECK_MPI_OK( mp_init(&order, kmflag) );
158*f9fbec18Smcpowers 	CHECK_MPI_OK( mp_init(&irreducible, kmflag) );
159*f9fbec18Smcpowers 	CHECK_MPI_OK( mp_init(&a, kmflag) );
160*f9fbec18Smcpowers 	CHECK_MPI_OK( mp_init(&b, kmflag) );
161*f9fbec18Smcpowers 
162*f9fbec18Smcpowers 	if ((k2 != NULL) && (pointP != NULL)) {
163*f9fbec18Smcpowers 		/* Initialize Px and Py */
164*f9fbec18Smcpowers 		CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size) len) );
165*f9fbec18Smcpowers 		CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) );
166*f9fbec18Smcpowers 	}
167*f9fbec18Smcpowers 
168*f9fbec18Smcpowers 	/* construct from named params, if possible */
169*f9fbec18Smcpowers 	if (params->name != ECCurve_noName) {
170*f9fbec18Smcpowers 		group = ECGroup_fromName(params->name, kmflag);
171*f9fbec18Smcpowers 	}
172*f9fbec18Smcpowers 
173*f9fbec18Smcpowers #if 0 /* currently don't support non-named curves */
174*f9fbec18Smcpowers 	if (group == NULL) {
175*f9fbec18Smcpowers 		/* Set up mp_ints containing the curve coefficients */
176*f9fbec18Smcpowers 		CHECK_MPI_OK( mp_read_unsigned_octets(&Gx, params->base.data + 1,
177*f9fbec18Smcpowers 										  (mp_size) len) );
178*f9fbec18Smcpowers 		CHECK_MPI_OK( mp_read_unsigned_octets(&Gy, params->base.data + 1 + len,
179*f9fbec18Smcpowers 										  (mp_size) len) );
180*f9fbec18Smcpowers 		SECITEM_TO_MPINT( params->order, &order );
181*f9fbec18Smcpowers 		SECITEM_TO_MPINT( params->curve.a, &a );
182*f9fbec18Smcpowers 		SECITEM_TO_MPINT( params->curve.b, &b );
183*f9fbec18Smcpowers 		if (params->fieldID.type == ec_field_GFp) {
184*f9fbec18Smcpowers 			SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible );
185*f9fbec18Smcpowers 			group = ECGroup_consGFp(&irreducible, &a, &b, &Gx, &Gy, &order, params->cofactor);
186*f9fbec18Smcpowers 		} else {
187*f9fbec18Smcpowers 			SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible );
188*f9fbec18Smcpowers 			irr_arr[0] = params->fieldID.size;
189*f9fbec18Smcpowers 			irr_arr[1] = params->fieldID.k1;
190*f9fbec18Smcpowers 			irr_arr[2] = params->fieldID.k2;
191*f9fbec18Smcpowers 			irr_arr[3] = params->fieldID.k3;
192*f9fbec18Smcpowers 			irr_arr[4] = 0;
193*f9fbec18Smcpowers 			group = ECGroup_consGF2m(&irreducible, irr_arr, &a, &b, &Gx, &Gy, &order, params->cofactor);
194*f9fbec18Smcpowers 		}
195*f9fbec18Smcpowers 	}
196*f9fbec18Smcpowers #endif
197*f9fbec18Smcpowers 	if (group == NULL)
198*f9fbec18Smcpowers 		goto cleanup;
199*f9fbec18Smcpowers 
200*f9fbec18Smcpowers 	if ((k2 != NULL) && (pointP != NULL)) {
201*f9fbec18Smcpowers 		CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy) );
202*f9fbec18Smcpowers 	} else {
203*f9fbec18Smcpowers 		CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) );
204*f9fbec18Smcpowers     }
205*f9fbec18Smcpowers 
206*f9fbec18Smcpowers     /* Construct the SECItem representation of point Q */
207*f9fbec18Smcpowers     pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED;
208*f9fbec18Smcpowers     CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1,
209*f9fbec18Smcpowers 	                              (mp_size) len) );
210*f9fbec18Smcpowers     CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len,
211*f9fbec18Smcpowers 	                              (mp_size) len) );
212*f9fbec18Smcpowers 
213*f9fbec18Smcpowers     rv = SECSuccess;
214*f9fbec18Smcpowers 
215*f9fbec18Smcpowers #if EC_DEBUG
216*f9fbec18Smcpowers     printf("ec_points_mul: pointQ [len=%d]:", pointQ->len);
217*f9fbec18Smcpowers     for (i = 0; i < pointQ->len; i++)
218*f9fbec18Smcpowers 	    printf("%02x:", pointQ->data[i]);
219*f9fbec18Smcpowers     printf("\n");
220*f9fbec18Smcpowers #endif
221*f9fbec18Smcpowers 
222*f9fbec18Smcpowers cleanup:
223*f9fbec18Smcpowers     ECGroup_free(group);
224*f9fbec18Smcpowers     mp_clear(&Px);
225*f9fbec18Smcpowers     mp_clear(&Py);
226*f9fbec18Smcpowers     mp_clear(&Qx);
227*f9fbec18Smcpowers     mp_clear(&Qy);
228*f9fbec18Smcpowers     mp_clear(&Gx);
229*f9fbec18Smcpowers     mp_clear(&Gy);
230*f9fbec18Smcpowers     mp_clear(&order);
231*f9fbec18Smcpowers     mp_clear(&irreducible);
232*f9fbec18Smcpowers     mp_clear(&a);
233*f9fbec18Smcpowers     mp_clear(&b);
234*f9fbec18Smcpowers     if (err) {
235*f9fbec18Smcpowers 	MP_TO_SEC_ERROR(err);
236*f9fbec18Smcpowers 	rv = SECFailure;
237*f9fbec18Smcpowers     }
238*f9fbec18Smcpowers 
239*f9fbec18Smcpowers     return rv;
240*f9fbec18Smcpowers }
241*f9fbec18Smcpowers 
242*f9fbec18Smcpowers /* Generates a new EC key pair. The private key is a supplied
243*f9fbec18Smcpowers  * value and the public key is the result of performing a scalar
244*f9fbec18Smcpowers  * point multiplication of that value with the curve's base point.
245*f9fbec18Smcpowers  */
246*f9fbec18Smcpowers SECStatus
247*f9fbec18Smcpowers ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey,
248*f9fbec18Smcpowers     const unsigned char *privKeyBytes, int privKeyLen, int kmflag)
249*f9fbec18Smcpowers {
250*f9fbec18Smcpowers     SECStatus rv = SECFailure;
251*f9fbec18Smcpowers     PRArenaPool *arena;
252*f9fbec18Smcpowers     ECPrivateKey *key;
253*f9fbec18Smcpowers     mp_int k;
254*f9fbec18Smcpowers     mp_err err = MP_OKAY;
255*f9fbec18Smcpowers     int len;
256*f9fbec18Smcpowers 
257*f9fbec18Smcpowers #if EC_DEBUG
258*f9fbec18Smcpowers     printf("ec_NewKey called\n");
259*f9fbec18Smcpowers #endif
260*f9fbec18Smcpowers 
261*f9fbec18Smcpowers int printf();
262*f9fbec18Smcpowers     if (!ecParams || !privKey || !privKeyBytes || (privKeyLen < 0)) {
263*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
264*f9fbec18Smcpowers 	return SECFailure;
265*f9fbec18Smcpowers     }
266*f9fbec18Smcpowers 
267*f9fbec18Smcpowers     /* Initialize an arena for the EC key. */
268*f9fbec18Smcpowers     if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))
269*f9fbec18Smcpowers 	return SECFailure;
270*f9fbec18Smcpowers 
271*f9fbec18Smcpowers     key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey),
272*f9fbec18Smcpowers 	kmflag);
273*f9fbec18Smcpowers     if (!key) {
274*f9fbec18Smcpowers 	PORT_FreeArena(arena, PR_TRUE);
275*f9fbec18Smcpowers 	return SECFailure;
276*f9fbec18Smcpowers     }
277*f9fbec18Smcpowers 
278*f9fbec18Smcpowers     /* Set the version number (SEC 1 section C.4 says it should be 1) */
279*f9fbec18Smcpowers     SECITEM_AllocItem(arena, &key->version, 1, kmflag);
280*f9fbec18Smcpowers     key->version.data[0] = 1;
281*f9fbec18Smcpowers 
282*f9fbec18Smcpowers     /* Copy all of the fields from the ECParams argument to the
283*f9fbec18Smcpowers      * ECParams structure within the private key.
284*f9fbec18Smcpowers      */
285*f9fbec18Smcpowers     key->ecParams.arena = arena;
286*f9fbec18Smcpowers     key->ecParams.type = ecParams->type;
287*f9fbec18Smcpowers     key->ecParams.fieldID.size = ecParams->fieldID.size;
288*f9fbec18Smcpowers     key->ecParams.fieldID.type = ecParams->fieldID.type;
289*f9fbec18Smcpowers     if (ecParams->fieldID.type == ec_field_GFp) {
290*f9fbec18Smcpowers 	CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime,
291*f9fbec18Smcpowers 	    &ecParams->fieldID.u.prime, kmflag));
292*f9fbec18Smcpowers     } else {
293*f9fbec18Smcpowers 	CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.poly,
294*f9fbec18Smcpowers 	    &ecParams->fieldID.u.poly, kmflag));
295*f9fbec18Smcpowers     }
296*f9fbec18Smcpowers     key->ecParams.fieldID.k1 = ecParams->fieldID.k1;
297*f9fbec18Smcpowers     key->ecParams.fieldID.k2 = ecParams->fieldID.k2;
298*f9fbec18Smcpowers     key->ecParams.fieldID.k3 = ecParams->fieldID.k3;
299*f9fbec18Smcpowers     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a,
300*f9fbec18Smcpowers 	&ecParams->curve.a, kmflag));
301*f9fbec18Smcpowers     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b,
302*f9fbec18Smcpowers 	&ecParams->curve.b, kmflag));
303*f9fbec18Smcpowers     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed,
304*f9fbec18Smcpowers 	&ecParams->curve.seed, kmflag));
305*f9fbec18Smcpowers     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base,
306*f9fbec18Smcpowers 	&ecParams->base, kmflag));
307*f9fbec18Smcpowers     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order,
308*f9fbec18Smcpowers 	&ecParams->order, kmflag));
309*f9fbec18Smcpowers     key->ecParams.cofactor = ecParams->cofactor;
310*f9fbec18Smcpowers     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding,
311*f9fbec18Smcpowers 	&ecParams->DEREncoding, kmflag));
312*f9fbec18Smcpowers     key->ecParams.name = ecParams->name;
313*f9fbec18Smcpowers     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID,
314*f9fbec18Smcpowers 	&ecParams->curveOID, kmflag));
315*f9fbec18Smcpowers 
316*f9fbec18Smcpowers     len = (ecParams->fieldID.size + 7) >> 3;
317*f9fbec18Smcpowers     SECITEM_AllocItem(arena, &key->publicValue, 2*len + 1, kmflag);
318*f9fbec18Smcpowers     len = ecParams->order.len;
319*f9fbec18Smcpowers     SECITEM_AllocItem(arena, &key->privateValue, len, kmflag);
320*f9fbec18Smcpowers 
321*f9fbec18Smcpowers     /* Copy private key */
322*f9fbec18Smcpowers     if (privKeyLen >= len) {
323*f9fbec18Smcpowers 	memcpy(key->privateValue.data, privKeyBytes, len);
324*f9fbec18Smcpowers     } else {
325*f9fbec18Smcpowers 	memset(key->privateValue.data, 0, (len - privKeyLen));
326*f9fbec18Smcpowers 	memcpy(key->privateValue.data + (len - privKeyLen), privKeyBytes, privKeyLen);
327*f9fbec18Smcpowers     }
328*f9fbec18Smcpowers 
329*f9fbec18Smcpowers     /* Compute corresponding public key */
330*f9fbec18Smcpowers     MP_DIGITS(&k) = 0;
331*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&k, kmflag) );
332*f9fbec18Smcpowers     CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data,
333*f9fbec18Smcpowers 	(mp_size) len) );
334*f9fbec18Smcpowers 
335*f9fbec18Smcpowers     rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue), kmflag);
336*f9fbec18Smcpowers     if (rv != SECSuccess) goto cleanup;
337*f9fbec18Smcpowers     *privKey = key;
338*f9fbec18Smcpowers 
339*f9fbec18Smcpowers cleanup:
340*f9fbec18Smcpowers     mp_clear(&k);
341*f9fbec18Smcpowers     if (rv)
342*f9fbec18Smcpowers 	PORT_FreeArena(arena, PR_TRUE);
343*f9fbec18Smcpowers 
344*f9fbec18Smcpowers #if EC_DEBUG
345*f9fbec18Smcpowers     printf("ec_NewKey returning %s\n",
346*f9fbec18Smcpowers 	(rv == SECSuccess) ? "success" : "failure");
347*f9fbec18Smcpowers #endif
348*f9fbec18Smcpowers 
349*f9fbec18Smcpowers     return rv;
350*f9fbec18Smcpowers 
351*f9fbec18Smcpowers }
352*f9fbec18Smcpowers 
353*f9fbec18Smcpowers /* Generates a new EC key pair. The private key is a supplied
354*f9fbec18Smcpowers  * random value (in seed) and the public key is the result of
355*f9fbec18Smcpowers  * performing a scalar point multiplication of that value with
356*f9fbec18Smcpowers  * the curve's base point.
357*f9fbec18Smcpowers  */
358*f9fbec18Smcpowers SECStatus
359*f9fbec18Smcpowers EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey,
360*f9fbec18Smcpowers     const unsigned char *seed, int seedlen, int kmflag)
361*f9fbec18Smcpowers {
362*f9fbec18Smcpowers     SECStatus rv = SECFailure;
363*f9fbec18Smcpowers     rv = ec_NewKey(ecParams, privKey, seed, seedlen, kmflag);
364*f9fbec18Smcpowers     return rv;
365*f9fbec18Smcpowers }
366*f9fbec18Smcpowers 
367*f9fbec18Smcpowers /* Generate a random private key using the algorithm A.4.1 of ANSI X9.62,
368*f9fbec18Smcpowers  * modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the
369*f9fbec18Smcpowers  * random number generator.
370*f9fbec18Smcpowers  *
371*f9fbec18Smcpowers  * Parameters
372*f9fbec18Smcpowers  * - order: a buffer that holds the curve's group order
373*f9fbec18Smcpowers  * - len: the length in octets of the order buffer
374*f9fbec18Smcpowers  *
375*f9fbec18Smcpowers  * Return Value
376*f9fbec18Smcpowers  * Returns a buffer of len octets that holds the private key. The caller
377*f9fbec18Smcpowers  * is responsible for freeing the buffer with PORT_ZFree.
378*f9fbec18Smcpowers  */
379*f9fbec18Smcpowers static unsigned char *
380*f9fbec18Smcpowers ec_GenerateRandomPrivateKey(const unsigned char *order, int len, int kmflag)
381*f9fbec18Smcpowers {
382*f9fbec18Smcpowers     SECStatus rv = SECSuccess;
383*f9fbec18Smcpowers     mp_err err;
384*f9fbec18Smcpowers     unsigned char *privKeyBytes = NULL;
385*f9fbec18Smcpowers     mp_int privKeyVal, order_1, one;
386*f9fbec18Smcpowers 
387*f9fbec18Smcpowers     MP_DIGITS(&privKeyVal) = 0;
388*f9fbec18Smcpowers     MP_DIGITS(&order_1) = 0;
389*f9fbec18Smcpowers     MP_DIGITS(&one) = 0;
390*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&privKeyVal, kmflag) );
391*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&order_1, kmflag) );
392*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&one, kmflag) );
393*f9fbec18Smcpowers 
394*f9fbec18Smcpowers     /* Generates 2*len random bytes using the global random bit generator
395*f9fbec18Smcpowers      * (which implements Algorithm 1 of FIPS 186-2 Change Notice 1) then
396*f9fbec18Smcpowers      * reduces modulo the group order.
397*f9fbec18Smcpowers      */
398*f9fbec18Smcpowers     if ((privKeyBytes = PORT_Alloc(2*len, kmflag)) == NULL) goto cleanup;
399*f9fbec18Smcpowers     CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) );
400*f9fbec18Smcpowers     CHECK_MPI_OK( mp_read_unsigned_octets(&privKeyVal, privKeyBytes, 2*len) );
401*f9fbec18Smcpowers     CHECK_MPI_OK( mp_read_unsigned_octets(&order_1, order, len) );
402*f9fbec18Smcpowers     CHECK_MPI_OK( mp_set_int(&one, 1) );
403*f9fbec18Smcpowers     CHECK_MPI_OK( mp_sub(&order_1, &one, &order_1) );
404*f9fbec18Smcpowers     CHECK_MPI_OK( mp_mod(&privKeyVal, &order_1, &privKeyVal) );
405*f9fbec18Smcpowers     CHECK_MPI_OK( mp_add(&privKeyVal, &one, &privKeyVal) );
406*f9fbec18Smcpowers     CHECK_MPI_OK( mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len) );
407*f9fbec18Smcpowers     memset(privKeyBytes+len, 0, len);
408*f9fbec18Smcpowers cleanup:
409*f9fbec18Smcpowers     mp_clear(&privKeyVal);
410*f9fbec18Smcpowers     mp_clear(&order_1);
411*f9fbec18Smcpowers     mp_clear(&one);
412*f9fbec18Smcpowers     if (err < MP_OKAY) {
413*f9fbec18Smcpowers 	MP_TO_SEC_ERROR(err);
414*f9fbec18Smcpowers 	rv = SECFailure;
415*f9fbec18Smcpowers     }
416*f9fbec18Smcpowers     if (rv != SECSuccess && privKeyBytes) {
417*f9fbec18Smcpowers #ifdef _KERNEL
418*f9fbec18Smcpowers 	kmem_free(privKeyBytes, 2*len);
419*f9fbec18Smcpowers #else
420*f9fbec18Smcpowers 	free(privKeyBytes);
421*f9fbec18Smcpowers #endif
422*f9fbec18Smcpowers 	privKeyBytes = NULL;
423*f9fbec18Smcpowers     }
424*f9fbec18Smcpowers     return privKeyBytes;
425*f9fbec18Smcpowers }
426*f9fbec18Smcpowers 
427*f9fbec18Smcpowers /* Generates a new EC key pair. The private key is a random value and
428*f9fbec18Smcpowers  * the public key is the result of performing a scalar point multiplication
429*f9fbec18Smcpowers  * of that value with the curve's base point.
430*f9fbec18Smcpowers  */
431*f9fbec18Smcpowers SECStatus
432*f9fbec18Smcpowers EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey, int kmflag)
433*f9fbec18Smcpowers {
434*f9fbec18Smcpowers     SECStatus rv = SECFailure;
435*f9fbec18Smcpowers     int len;
436*f9fbec18Smcpowers     unsigned char *privKeyBytes = NULL;
437*f9fbec18Smcpowers 
438*f9fbec18Smcpowers     if (!ecParams) {
439*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
440*f9fbec18Smcpowers 	return SECFailure;
441*f9fbec18Smcpowers     }
442*f9fbec18Smcpowers 
443*f9fbec18Smcpowers     len = ecParams->order.len;
444*f9fbec18Smcpowers     privKeyBytes = ec_GenerateRandomPrivateKey(ecParams->order.data, len,
445*f9fbec18Smcpowers 	kmflag);
446*f9fbec18Smcpowers     if (privKeyBytes == NULL) goto cleanup;
447*f9fbec18Smcpowers     /* generate public key */
448*f9fbec18Smcpowers     CHECK_SEC_OK( ec_NewKey(ecParams, privKey, privKeyBytes, len, kmflag) );
449*f9fbec18Smcpowers 
450*f9fbec18Smcpowers cleanup:
451*f9fbec18Smcpowers     if (privKeyBytes) {
452*f9fbec18Smcpowers 	PORT_ZFree(privKeyBytes, len * 2);
453*f9fbec18Smcpowers     }
454*f9fbec18Smcpowers #if EC_DEBUG
455*f9fbec18Smcpowers     printf("EC_NewKey returning %s\n",
456*f9fbec18Smcpowers 	(rv == SECSuccess) ? "success" : "failure");
457*f9fbec18Smcpowers #endif
458*f9fbec18Smcpowers 
459*f9fbec18Smcpowers     return rv;
460*f9fbec18Smcpowers }
461*f9fbec18Smcpowers 
462*f9fbec18Smcpowers /* Validates an EC public key as described in Section 5.2.2 of
463*f9fbec18Smcpowers  * X9.62. The ECDH primitive when used without the cofactor does
464*f9fbec18Smcpowers  * not address small subgroup attacks, which may occur when the
465*f9fbec18Smcpowers  * public key is not valid. These attacks can be prevented by
466*f9fbec18Smcpowers  * validating the public key before using ECDH.
467*f9fbec18Smcpowers  */
468*f9fbec18Smcpowers SECStatus
469*f9fbec18Smcpowers EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue, int kmflag)
470*f9fbec18Smcpowers {
471*f9fbec18Smcpowers     mp_int Px, Py;
472*f9fbec18Smcpowers     ECGroup *group = NULL;
473*f9fbec18Smcpowers     SECStatus rv = SECFailure;
474*f9fbec18Smcpowers     mp_err err = MP_OKAY;
475*f9fbec18Smcpowers     int len;
476*f9fbec18Smcpowers 
477*f9fbec18Smcpowers     if (!ecParams || !publicValue) {
478*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
479*f9fbec18Smcpowers 	return SECFailure;
480*f9fbec18Smcpowers     }
481*f9fbec18Smcpowers 
482*f9fbec18Smcpowers     /* NOTE: We only support uncompressed points for now */
483*f9fbec18Smcpowers     len = (ecParams->fieldID.size + 7) >> 3;
484*f9fbec18Smcpowers     if (publicValue->data[0] != EC_POINT_FORM_UNCOMPRESSED) {
485*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
486*f9fbec18Smcpowers 	return SECFailure;
487*f9fbec18Smcpowers     } else if (publicValue->len != (2 * len + 1)) {
488*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_BAD_KEY);
489*f9fbec18Smcpowers 	return SECFailure;
490*f9fbec18Smcpowers     }
491*f9fbec18Smcpowers 
492*f9fbec18Smcpowers     MP_DIGITS(&Px) = 0;
493*f9fbec18Smcpowers     MP_DIGITS(&Py) = 0;
494*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&Px, kmflag) );
495*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&Py, kmflag) );
496*f9fbec18Smcpowers 
497*f9fbec18Smcpowers     /* Initialize Px and Py */
498*f9fbec18Smcpowers     CHECK_MPI_OK( mp_read_unsigned_octets(&Px, publicValue->data + 1, (mp_size) len) );
499*f9fbec18Smcpowers     CHECK_MPI_OK( mp_read_unsigned_octets(&Py, publicValue->data + 1 + len, (mp_size) len) );
500*f9fbec18Smcpowers 
501*f9fbec18Smcpowers     /* construct from named params */
502*f9fbec18Smcpowers     group = ECGroup_fromName(ecParams->name, kmflag);
503*f9fbec18Smcpowers     if (group == NULL) {
504*f9fbec18Smcpowers 	/*
505*f9fbec18Smcpowers 	 * ECGroup_fromName fails if ecParams->name is not a valid
506*f9fbec18Smcpowers 	 * ECCurveName value, or if we run out of memory, or perhaps
507*f9fbec18Smcpowers 	 * for other reasons.  Unfortunately if ecParams->name is a
508*f9fbec18Smcpowers 	 * valid ECCurveName value, we don't know what the right error
509*f9fbec18Smcpowers 	 * code should be because ECGroup_fromName doesn't return an
510*f9fbec18Smcpowers 	 * error code to the caller.  Set err to MP_UNDEF because
511*f9fbec18Smcpowers 	 * that's what ECGroup_fromName uses internally.
512*f9fbec18Smcpowers 	 */
513*f9fbec18Smcpowers 	if ((ecParams->name <= ECCurve_noName) ||
514*f9fbec18Smcpowers 	    (ecParams->name >= ECCurve_pastLastCurve)) {
515*f9fbec18Smcpowers 	    err = MP_BADARG;
516*f9fbec18Smcpowers 	} else {
517*f9fbec18Smcpowers 	    err = MP_UNDEF;
518*f9fbec18Smcpowers 	}
519*f9fbec18Smcpowers 	goto cleanup;
520*f9fbec18Smcpowers     }
521*f9fbec18Smcpowers 
522*f9fbec18Smcpowers     /* validate public point */
523*f9fbec18Smcpowers     if ((err = ECPoint_validate(group, &Px, &Py)) < MP_YES) {
524*f9fbec18Smcpowers 	if (err == MP_NO) {
525*f9fbec18Smcpowers 	    PORT_SetError(SEC_ERROR_BAD_KEY);
526*f9fbec18Smcpowers 	    rv = SECFailure;
527*f9fbec18Smcpowers 	    err = MP_OKAY;  /* don't change the error code */
528*f9fbec18Smcpowers 	}
529*f9fbec18Smcpowers 	goto cleanup;
530*f9fbec18Smcpowers     }
531*f9fbec18Smcpowers 
532*f9fbec18Smcpowers     rv = SECSuccess;
533*f9fbec18Smcpowers 
534*f9fbec18Smcpowers cleanup:
535*f9fbec18Smcpowers     ECGroup_free(group);
536*f9fbec18Smcpowers     mp_clear(&Px);
537*f9fbec18Smcpowers     mp_clear(&Py);
538*f9fbec18Smcpowers     if (err) {
539*f9fbec18Smcpowers 	MP_TO_SEC_ERROR(err);
540*f9fbec18Smcpowers 	rv = SECFailure;
541*f9fbec18Smcpowers     }
542*f9fbec18Smcpowers     return rv;
543*f9fbec18Smcpowers }
544*f9fbec18Smcpowers 
545*f9fbec18Smcpowers /*
546*f9fbec18Smcpowers ** Performs an ECDH key derivation by computing the scalar point
547*f9fbec18Smcpowers ** multiplication of privateValue and publicValue (with or without the
548*f9fbec18Smcpowers ** cofactor) and returns the x-coordinate of the resulting elliptic
549*f9fbec18Smcpowers ** curve point in derived secret.  If successful, derivedSecret->data
550*f9fbec18Smcpowers ** is set to the address of the newly allocated buffer containing the
551*f9fbec18Smcpowers ** derived secret, and derivedSecret->len is the size of the secret
552*f9fbec18Smcpowers ** produced. It is the caller's responsibility to free the allocated
553*f9fbec18Smcpowers ** buffer containing the derived secret.
554*f9fbec18Smcpowers */
555*f9fbec18Smcpowers SECStatus
556*f9fbec18Smcpowers ECDH_Derive(SECItem  *publicValue,
557*f9fbec18Smcpowers             ECParams *ecParams,
558*f9fbec18Smcpowers             SECItem  *privateValue,
559*f9fbec18Smcpowers             PRBool    withCofactor,
560*f9fbec18Smcpowers             SECItem  *derivedSecret,
561*f9fbec18Smcpowers 	    int kmflag)
562*f9fbec18Smcpowers {
563*f9fbec18Smcpowers     SECStatus rv = SECFailure;
564*f9fbec18Smcpowers     unsigned int len = 0;
565*f9fbec18Smcpowers     SECItem pointQ = {siBuffer, NULL, 0};
566*f9fbec18Smcpowers     mp_int k; /* to hold the private value */
567*f9fbec18Smcpowers     mp_int cofactor;
568*f9fbec18Smcpowers     mp_err err = MP_OKAY;
569*f9fbec18Smcpowers #if EC_DEBUG
570*f9fbec18Smcpowers     int i;
571*f9fbec18Smcpowers #endif
572*f9fbec18Smcpowers 
573*f9fbec18Smcpowers     if (!publicValue || !ecParams || !privateValue ||
574*f9fbec18Smcpowers 	!derivedSecret) {
575*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
576*f9fbec18Smcpowers 	return SECFailure;
577*f9fbec18Smcpowers     }
578*f9fbec18Smcpowers 
579*f9fbec18Smcpowers     memset(derivedSecret, 0, sizeof *derivedSecret);
580*f9fbec18Smcpowers     len = (ecParams->fieldID.size + 7) >> 3;
581*f9fbec18Smcpowers     pointQ.len = 2*len + 1;
582*f9fbec18Smcpowers     if ((pointQ.data = PORT_Alloc(2*len + 1, kmflag)) == NULL) goto cleanup;
583*f9fbec18Smcpowers 
584*f9fbec18Smcpowers     MP_DIGITS(&k) = 0;
585*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&k, kmflag) );
586*f9fbec18Smcpowers     CHECK_MPI_OK( mp_read_unsigned_octets(&k, privateValue->data,
587*f9fbec18Smcpowers 	                                  (mp_size) privateValue->len) );
588*f9fbec18Smcpowers 
589*f9fbec18Smcpowers     if (withCofactor && (ecParams->cofactor != 1)) {
590*f9fbec18Smcpowers 	    /* multiply k with the cofactor */
591*f9fbec18Smcpowers 	    MP_DIGITS(&cofactor) = 0;
592*f9fbec18Smcpowers 	    CHECK_MPI_OK( mp_init(&cofactor, kmflag) );
593*f9fbec18Smcpowers 	    mp_set(&cofactor, ecParams->cofactor);
594*f9fbec18Smcpowers 	    CHECK_MPI_OK( mp_mul(&k, &cofactor, &k) );
595*f9fbec18Smcpowers     }
596*f9fbec18Smcpowers 
597*f9fbec18Smcpowers     /* Multiply our private key and peer's public point */
598*f9fbec18Smcpowers     if ((ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ, kmflag) != SECSuccess) ||
599*f9fbec18Smcpowers 	ec_point_at_infinity(&pointQ))
600*f9fbec18Smcpowers 	goto cleanup;
601*f9fbec18Smcpowers 
602*f9fbec18Smcpowers     /* Allocate memory for the derived secret and copy
603*f9fbec18Smcpowers      * the x co-ordinate of pointQ into it.
604*f9fbec18Smcpowers      */
605*f9fbec18Smcpowers     SECITEM_AllocItem(NULL, derivedSecret, len, kmflag);
606*f9fbec18Smcpowers     memcpy(derivedSecret->data, pointQ.data + 1, len);
607*f9fbec18Smcpowers 
608*f9fbec18Smcpowers     rv = SECSuccess;
609*f9fbec18Smcpowers 
610*f9fbec18Smcpowers #if EC_DEBUG
611*f9fbec18Smcpowers     printf("derived_secret:\n");
612*f9fbec18Smcpowers     for (i = 0; i < derivedSecret->len; i++)
613*f9fbec18Smcpowers 	printf("%02x:", derivedSecret->data[i]);
614*f9fbec18Smcpowers     printf("\n");
615*f9fbec18Smcpowers #endif
616*f9fbec18Smcpowers 
617*f9fbec18Smcpowers cleanup:
618*f9fbec18Smcpowers     mp_clear(&k);
619*f9fbec18Smcpowers 
620*f9fbec18Smcpowers     if (pointQ.data) {
621*f9fbec18Smcpowers 	PORT_ZFree(pointQ.data, 2*len + 1);
622*f9fbec18Smcpowers     }
623*f9fbec18Smcpowers 
624*f9fbec18Smcpowers     return rv;
625*f9fbec18Smcpowers }
626*f9fbec18Smcpowers 
627*f9fbec18Smcpowers /* Computes the ECDSA signature (a concatenation of two values r and s)
628*f9fbec18Smcpowers  * on the digest using the given key and the random value kb (used in
629*f9fbec18Smcpowers  * computing s).
630*f9fbec18Smcpowers  */
631*f9fbec18Smcpowers SECStatus
632*f9fbec18Smcpowers ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
633*f9fbec18Smcpowers     const SECItem *digest, const unsigned char *kb, const int kblen, int kmflag)
634*f9fbec18Smcpowers {
635*f9fbec18Smcpowers     SECStatus rv = SECFailure;
636*f9fbec18Smcpowers     mp_int x1;
637*f9fbec18Smcpowers     mp_int d, k;     /* private key, random integer */
638*f9fbec18Smcpowers     mp_int r, s;     /* tuple (r, s) is the signature */
639*f9fbec18Smcpowers     mp_int n;
640*f9fbec18Smcpowers     mp_err err = MP_OKAY;
641*f9fbec18Smcpowers     ECParams *ecParams = NULL;
642*f9fbec18Smcpowers     SECItem kGpoint = { siBuffer, NULL, 0};
643*f9fbec18Smcpowers     int flen = 0;    /* length in bytes of the field size */
644*f9fbec18Smcpowers     unsigned olen;   /* length in bytes of the base point order */
645*f9fbec18Smcpowers 
646*f9fbec18Smcpowers #if EC_DEBUG
647*f9fbec18Smcpowers     char mpstr[256];
648*f9fbec18Smcpowers #endif
649*f9fbec18Smcpowers 
650*f9fbec18Smcpowers     /* Initialize MPI integers. */
651*f9fbec18Smcpowers     /* must happen before the first potential call to cleanup */
652*f9fbec18Smcpowers     MP_DIGITS(&x1) = 0;
653*f9fbec18Smcpowers     MP_DIGITS(&d) = 0;
654*f9fbec18Smcpowers     MP_DIGITS(&k) = 0;
655*f9fbec18Smcpowers     MP_DIGITS(&r) = 0;
656*f9fbec18Smcpowers     MP_DIGITS(&s) = 0;
657*f9fbec18Smcpowers     MP_DIGITS(&n) = 0;
658*f9fbec18Smcpowers 
659*f9fbec18Smcpowers     /* Check args */
660*f9fbec18Smcpowers     if (!key || !signature || !digest || !kb || (kblen < 0)) {
661*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
662*f9fbec18Smcpowers 	goto cleanup;
663*f9fbec18Smcpowers     }
664*f9fbec18Smcpowers 
665*f9fbec18Smcpowers     ecParams = &(key->ecParams);
666*f9fbec18Smcpowers     flen = (ecParams->fieldID.size + 7) >> 3;
667*f9fbec18Smcpowers     olen = ecParams->order.len;
668*f9fbec18Smcpowers     if (signature->data == NULL) {
669*f9fbec18Smcpowers 	/* a call to get the signature length only */
670*f9fbec18Smcpowers 	goto finish;
671*f9fbec18Smcpowers     }
672*f9fbec18Smcpowers     if (signature->len < 2*olen) {
673*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
674*f9fbec18Smcpowers 	rv = SECBufferTooSmall;
675*f9fbec18Smcpowers 	goto cleanup;
676*f9fbec18Smcpowers     }
677*f9fbec18Smcpowers 
678*f9fbec18Smcpowers 
679*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&x1, kmflag) );
680*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&d, kmflag) );
681*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&k, kmflag) );
682*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&r, kmflag) );
683*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&s, kmflag) );
684*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&n, kmflag) );
685*f9fbec18Smcpowers 
686*f9fbec18Smcpowers     SECITEM_TO_MPINT( ecParams->order, &n );
687*f9fbec18Smcpowers     SECITEM_TO_MPINT( key->privateValue, &d );
688*f9fbec18Smcpowers     CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) );
689*f9fbec18Smcpowers     /* Make sure k is in the interval [1, n-1] */
690*f9fbec18Smcpowers     if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) {
691*f9fbec18Smcpowers #if EC_DEBUG
692*f9fbec18Smcpowers         printf("k is outside [1, n-1]\n");
693*f9fbec18Smcpowers         mp_tohex(&k, mpstr);
694*f9fbec18Smcpowers 	printf("k : %s \n", mpstr);
695*f9fbec18Smcpowers         mp_tohex(&n, mpstr);
696*f9fbec18Smcpowers 	printf("n : %s \n", mpstr);
697*f9fbec18Smcpowers #endif
698*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_NEED_RANDOM);
699*f9fbec18Smcpowers 	goto cleanup;
700*f9fbec18Smcpowers     }
701*f9fbec18Smcpowers 
702*f9fbec18Smcpowers     /*
703*f9fbec18Smcpowers     ** ANSI X9.62, Section 5.3.2, Step 2
704*f9fbec18Smcpowers     **
705*f9fbec18Smcpowers     ** Compute kG
706*f9fbec18Smcpowers     */
707*f9fbec18Smcpowers     kGpoint.len = 2*flen + 1;
708*f9fbec18Smcpowers     kGpoint.data = PORT_Alloc(2*flen + 1, kmflag);
709*f9fbec18Smcpowers     if ((kGpoint.data == NULL) ||
710*f9fbec18Smcpowers 	(ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint, kmflag)
711*f9fbec18Smcpowers 	    != SECSuccess))
712*f9fbec18Smcpowers 	goto cleanup;
713*f9fbec18Smcpowers 
714*f9fbec18Smcpowers     /*
715*f9fbec18Smcpowers     ** ANSI X9.62, Section 5.3.3, Step 1
716*f9fbec18Smcpowers     **
717*f9fbec18Smcpowers     ** Extract the x co-ordinate of kG into x1
718*f9fbec18Smcpowers     */
719*f9fbec18Smcpowers     CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1,
720*f9fbec18Smcpowers 	                                  (mp_size) flen) );
721*f9fbec18Smcpowers 
722*f9fbec18Smcpowers     /*
723*f9fbec18Smcpowers     ** ANSI X9.62, Section 5.3.3, Step 2
724*f9fbec18Smcpowers     **
725*f9fbec18Smcpowers     ** r = x1 mod n  NOTE: n is the order of the curve
726*f9fbec18Smcpowers     */
727*f9fbec18Smcpowers     CHECK_MPI_OK( mp_mod(&x1, &n, &r) );
728*f9fbec18Smcpowers 
729*f9fbec18Smcpowers     /*
730*f9fbec18Smcpowers     ** ANSI X9.62, Section 5.3.3, Step 3
731*f9fbec18Smcpowers     **
732*f9fbec18Smcpowers     ** verify r != 0
733*f9fbec18Smcpowers     */
734*f9fbec18Smcpowers     if (mp_cmp_z(&r) == 0) {
735*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_NEED_RANDOM);
736*f9fbec18Smcpowers 	goto cleanup;
737*f9fbec18Smcpowers     }
738*f9fbec18Smcpowers 
739*f9fbec18Smcpowers     /*
740*f9fbec18Smcpowers     ** ANSI X9.62, Section 5.3.3, Step 4
741*f9fbec18Smcpowers     **
742*f9fbec18Smcpowers     ** s = (k**-1 * (HASH(M) + d*r)) mod n
743*f9fbec18Smcpowers     */
744*f9fbec18Smcpowers     SECITEM_TO_MPINT(*digest, &s);        /* s = HASH(M)     */
745*f9fbec18Smcpowers 
746*f9fbec18Smcpowers     /* In the definition of EC signing, digests are truncated
747*f9fbec18Smcpowers      * to the length of n in bits.
748*f9fbec18Smcpowers      * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
749*f9fbec18Smcpowers     if (digest->len*8 > ecParams->fieldID.size) {
750*f9fbec18Smcpowers 	mpl_rsh(&s,&s,digest->len*8 - ecParams->fieldID.size);
751*f9fbec18Smcpowers     }
752*f9fbec18Smcpowers 
753*f9fbec18Smcpowers #if EC_DEBUG
754*f9fbec18Smcpowers     mp_todecimal(&n, mpstr);
755*f9fbec18Smcpowers     printf("n : %s (dec)\n", mpstr);
756*f9fbec18Smcpowers     mp_todecimal(&d, mpstr);
757*f9fbec18Smcpowers     printf("d : %s (dec)\n", mpstr);
758*f9fbec18Smcpowers     mp_tohex(&x1, mpstr);
759*f9fbec18Smcpowers     printf("x1: %s\n", mpstr);
760*f9fbec18Smcpowers     mp_todecimal(&s, mpstr);
761*f9fbec18Smcpowers     printf("digest: %s (decimal)\n", mpstr);
762*f9fbec18Smcpowers     mp_todecimal(&r, mpstr);
763*f9fbec18Smcpowers     printf("r : %s (dec)\n", mpstr);
764*f9fbec18Smcpowers     mp_tohex(&r, mpstr);
765*f9fbec18Smcpowers     printf("r : %s\n", mpstr);
766*f9fbec18Smcpowers #endif
767*f9fbec18Smcpowers 
768*f9fbec18Smcpowers     CHECK_MPI_OK( mp_invmod(&k, &n, &k) );      /* k = k**-1 mod n */
769*f9fbec18Smcpowers     CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) );  /* d = d * r mod n */
770*f9fbec18Smcpowers     CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) );  /* s = s + d mod n */
771*f9fbec18Smcpowers     CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) );  /* s = s * k mod n */
772*f9fbec18Smcpowers 
773*f9fbec18Smcpowers #if EC_DEBUG
774*f9fbec18Smcpowers     mp_todecimal(&s, mpstr);
775*f9fbec18Smcpowers     printf("s : %s (dec)\n", mpstr);
776*f9fbec18Smcpowers     mp_tohex(&s, mpstr);
777*f9fbec18Smcpowers     printf("s : %s\n", mpstr);
778*f9fbec18Smcpowers #endif
779*f9fbec18Smcpowers 
780*f9fbec18Smcpowers     /*
781*f9fbec18Smcpowers     ** ANSI X9.62, Section 5.3.3, Step 5
782*f9fbec18Smcpowers     **
783*f9fbec18Smcpowers     ** verify s != 0
784*f9fbec18Smcpowers     */
785*f9fbec18Smcpowers     if (mp_cmp_z(&s) == 0) {
786*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_NEED_RANDOM);
787*f9fbec18Smcpowers 	goto cleanup;
788*f9fbec18Smcpowers     }
789*f9fbec18Smcpowers 
790*f9fbec18Smcpowers    /*
791*f9fbec18Smcpowers     **
792*f9fbec18Smcpowers     ** Signature is tuple (r, s)
793*f9fbec18Smcpowers     */
794*f9fbec18Smcpowers     CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, olen) );
795*f9fbec18Smcpowers     CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + olen, olen) );
796*f9fbec18Smcpowers finish:
797*f9fbec18Smcpowers     signature->len = 2*olen;
798*f9fbec18Smcpowers 
799*f9fbec18Smcpowers     rv = SECSuccess;
800*f9fbec18Smcpowers     err = MP_OKAY;
801*f9fbec18Smcpowers cleanup:
802*f9fbec18Smcpowers     mp_clear(&x1);
803*f9fbec18Smcpowers     mp_clear(&d);
804*f9fbec18Smcpowers     mp_clear(&k);
805*f9fbec18Smcpowers     mp_clear(&r);
806*f9fbec18Smcpowers     mp_clear(&s);
807*f9fbec18Smcpowers     mp_clear(&n);
808*f9fbec18Smcpowers 
809*f9fbec18Smcpowers     if (kGpoint.data) {
810*f9fbec18Smcpowers 	PORT_ZFree(kGpoint.data, 2*flen + 1);
811*f9fbec18Smcpowers     }
812*f9fbec18Smcpowers 
813*f9fbec18Smcpowers     if (err) {
814*f9fbec18Smcpowers 	MP_TO_SEC_ERROR(err);
815*f9fbec18Smcpowers 	rv = SECFailure;
816*f9fbec18Smcpowers     }
817*f9fbec18Smcpowers 
818*f9fbec18Smcpowers #if EC_DEBUG
819*f9fbec18Smcpowers     printf("ECDSA signing with seed %s\n",
820*f9fbec18Smcpowers 	(rv == SECSuccess) ? "succeeded" : "failed");
821*f9fbec18Smcpowers #endif
822*f9fbec18Smcpowers 
823*f9fbec18Smcpowers    return rv;
824*f9fbec18Smcpowers }
825*f9fbec18Smcpowers 
826*f9fbec18Smcpowers /*
827*f9fbec18Smcpowers ** Computes the ECDSA signature on the digest using the given key
828*f9fbec18Smcpowers ** and a random seed.
829*f9fbec18Smcpowers */
830*f9fbec18Smcpowers SECStatus
831*f9fbec18Smcpowers ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest,
832*f9fbec18Smcpowers     int kmflag)
833*f9fbec18Smcpowers {
834*f9fbec18Smcpowers     SECStatus rv = SECFailure;
835*f9fbec18Smcpowers     int len;
836*f9fbec18Smcpowers     unsigned char *kBytes= NULL;
837*f9fbec18Smcpowers 
838*f9fbec18Smcpowers     if (!key) {
839*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
840*f9fbec18Smcpowers 	return SECFailure;
841*f9fbec18Smcpowers     }
842*f9fbec18Smcpowers 
843*f9fbec18Smcpowers     /* Generate random value k */
844*f9fbec18Smcpowers     len = key->ecParams.order.len;
845*f9fbec18Smcpowers     kBytes = ec_GenerateRandomPrivateKey(key->ecParams.order.data, len,
846*f9fbec18Smcpowers 	kmflag);
847*f9fbec18Smcpowers     if (kBytes == NULL) goto cleanup;
848*f9fbec18Smcpowers 
849*f9fbec18Smcpowers     /* Generate ECDSA signature with the specified k value */
850*f9fbec18Smcpowers     rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len, kmflag);
851*f9fbec18Smcpowers 
852*f9fbec18Smcpowers cleanup:
853*f9fbec18Smcpowers     if (kBytes) {
854*f9fbec18Smcpowers 	PORT_ZFree(kBytes, len * 2);
855*f9fbec18Smcpowers     }
856*f9fbec18Smcpowers 
857*f9fbec18Smcpowers #if EC_DEBUG
858*f9fbec18Smcpowers     printf("ECDSA signing %s\n",
859*f9fbec18Smcpowers 	(rv == SECSuccess) ? "succeeded" : "failed");
860*f9fbec18Smcpowers #endif
861*f9fbec18Smcpowers 
862*f9fbec18Smcpowers     return rv;
863*f9fbec18Smcpowers }
864*f9fbec18Smcpowers 
865*f9fbec18Smcpowers /*
866*f9fbec18Smcpowers ** Checks the signature on the given digest using the key provided.
867*f9fbec18Smcpowers */
868*f9fbec18Smcpowers SECStatus
869*f9fbec18Smcpowers ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
870*f9fbec18Smcpowers                  const SECItem *digest, int kmflag)
871*f9fbec18Smcpowers {
872*f9fbec18Smcpowers     SECStatus rv = SECFailure;
873*f9fbec18Smcpowers     mp_int r_, s_;           /* tuple (r', s') is received signature) */
874*f9fbec18Smcpowers     mp_int c, u1, u2, v;     /* intermediate values used in verification */
875*f9fbec18Smcpowers     mp_int x1;
876*f9fbec18Smcpowers     mp_int n;
877*f9fbec18Smcpowers     mp_err err = MP_OKAY;
878*f9fbec18Smcpowers     ECParams *ecParams = NULL;
879*f9fbec18Smcpowers     SECItem pointC = { siBuffer, NULL, 0 };
880*f9fbec18Smcpowers     int slen;       /* length in bytes of a half signature (r or s) */
881*f9fbec18Smcpowers     int flen;       /* length in bytes of the field size */
882*f9fbec18Smcpowers     unsigned olen;  /* length in bytes of the base point order */
883*f9fbec18Smcpowers 
884*f9fbec18Smcpowers #if EC_DEBUG
885*f9fbec18Smcpowers     char mpstr[256];
886*f9fbec18Smcpowers     printf("ECDSA verification called\n");
887*f9fbec18Smcpowers #endif
888*f9fbec18Smcpowers 
889*f9fbec18Smcpowers     /* Initialize MPI integers. */
890*f9fbec18Smcpowers     /* must happen before the first potential call to cleanup */
891*f9fbec18Smcpowers     MP_DIGITS(&r_) = 0;
892*f9fbec18Smcpowers     MP_DIGITS(&s_) = 0;
893*f9fbec18Smcpowers     MP_DIGITS(&c) = 0;
894*f9fbec18Smcpowers     MP_DIGITS(&u1) = 0;
895*f9fbec18Smcpowers     MP_DIGITS(&u2) = 0;
896*f9fbec18Smcpowers     MP_DIGITS(&x1) = 0;
897*f9fbec18Smcpowers     MP_DIGITS(&v)  = 0;
898*f9fbec18Smcpowers     MP_DIGITS(&n)  = 0;
899*f9fbec18Smcpowers 
900*f9fbec18Smcpowers     /* Check args */
901*f9fbec18Smcpowers     if (!key || !signature || !digest) {
902*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
903*f9fbec18Smcpowers 	goto cleanup;
904*f9fbec18Smcpowers     }
905*f9fbec18Smcpowers 
906*f9fbec18Smcpowers     ecParams = &(key->ecParams);
907*f9fbec18Smcpowers     flen = (ecParams->fieldID.size + 7) >> 3;
908*f9fbec18Smcpowers     olen = ecParams->order.len;
909*f9fbec18Smcpowers     if (signature->len == 0 || signature->len%2 != 0 ||
910*f9fbec18Smcpowers 	signature->len > 2*olen) {
911*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_INPUT_LEN);
912*f9fbec18Smcpowers 	goto cleanup;
913*f9fbec18Smcpowers     }
914*f9fbec18Smcpowers     slen = signature->len/2;
915*f9fbec18Smcpowers 
916*f9fbec18Smcpowers     SECITEM_AllocItem(NULL, &pointC, 2*flen + 1, kmflag);
917*f9fbec18Smcpowers     if (pointC.data == NULL)
918*f9fbec18Smcpowers 	goto cleanup;
919*f9fbec18Smcpowers 
920*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&r_, kmflag) );
921*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&s_, kmflag) );
922*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&c, kmflag)  );
923*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&u1, kmflag) );
924*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&u2, kmflag) );
925*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&x1, kmflag)  );
926*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&v, kmflag)  );
927*f9fbec18Smcpowers     CHECK_MPI_OK( mp_init(&n, kmflag)  );
928*f9fbec18Smcpowers 
929*f9fbec18Smcpowers     /*
930*f9fbec18Smcpowers     ** Convert received signature (r', s') into MPI integers.
931*f9fbec18Smcpowers     */
932*f9fbec18Smcpowers     CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, slen) );
933*f9fbec18Smcpowers     CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + slen, slen) );
934*f9fbec18Smcpowers 
935*f9fbec18Smcpowers     /*
936*f9fbec18Smcpowers     ** ANSI X9.62, Section 5.4.2, Steps 1 and 2
937*f9fbec18Smcpowers     **
938*f9fbec18Smcpowers     ** Verify that 0 < r' < n and 0 < s' < n
939*f9fbec18Smcpowers     */
940*f9fbec18Smcpowers     SECITEM_TO_MPINT(ecParams->order, &n);
941*f9fbec18Smcpowers     if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
942*f9fbec18Smcpowers         mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) {
943*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
944*f9fbec18Smcpowers 	goto cleanup; /* will return rv == SECFailure */
945*f9fbec18Smcpowers     }
946*f9fbec18Smcpowers 
947*f9fbec18Smcpowers     /*
948*f9fbec18Smcpowers     ** ANSI X9.62, Section 5.4.2, Step 3
949*f9fbec18Smcpowers     **
950*f9fbec18Smcpowers     ** c = (s')**-1 mod n
951*f9fbec18Smcpowers     */
952*f9fbec18Smcpowers     CHECK_MPI_OK( mp_invmod(&s_, &n, &c) );      /* c = (s')**-1 mod n */
953*f9fbec18Smcpowers 
954*f9fbec18Smcpowers     /*
955*f9fbec18Smcpowers     ** ANSI X9.62, Section 5.4.2, Step 4
956*f9fbec18Smcpowers     **
957*f9fbec18Smcpowers     ** u1 = ((HASH(M')) * c) mod n
958*f9fbec18Smcpowers     */
959*f9fbec18Smcpowers     SECITEM_TO_MPINT(*digest, &u1);                  /* u1 = HASH(M)     */
960*f9fbec18Smcpowers 
961*f9fbec18Smcpowers     /* In the definition of EC signing, digests are truncated
962*f9fbec18Smcpowers      * to the length of n in bits.
963*f9fbec18Smcpowers      * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
964*f9fbec18Smcpowers     if (digest->len*8 > ecParams->fieldID.size) {  /* u1 = HASH(M')     */
965*f9fbec18Smcpowers 	mpl_rsh(&u1,&u1,digest->len*8- ecParams->fieldID.size);
966*f9fbec18Smcpowers     }
967*f9fbec18Smcpowers 
968*f9fbec18Smcpowers #if EC_DEBUG
969*f9fbec18Smcpowers     mp_todecimal(&r_, mpstr);
970*f9fbec18Smcpowers     printf("r_: %s (dec)\n", mpstr);
971*f9fbec18Smcpowers     mp_todecimal(&s_, mpstr);
972*f9fbec18Smcpowers     printf("s_: %s (dec)\n", mpstr);
973*f9fbec18Smcpowers     mp_todecimal(&c, mpstr);
974*f9fbec18Smcpowers     printf("c : %s (dec)\n", mpstr);
975*f9fbec18Smcpowers     mp_todecimal(&u1, mpstr);
976*f9fbec18Smcpowers     printf("digest: %s (dec)\n", mpstr);
977*f9fbec18Smcpowers #endif
978*f9fbec18Smcpowers 
979*f9fbec18Smcpowers     CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) );  /* u1 = u1 * c mod n */
980*f9fbec18Smcpowers 
981*f9fbec18Smcpowers     /*
982*f9fbec18Smcpowers     ** ANSI X9.62, Section 5.4.2, Step 4
983*f9fbec18Smcpowers     **
984*f9fbec18Smcpowers     ** u2 = ((r') * c) mod n
985*f9fbec18Smcpowers     */
986*f9fbec18Smcpowers     CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) );
987*f9fbec18Smcpowers 
988*f9fbec18Smcpowers     /*
989*f9fbec18Smcpowers     ** ANSI X9.62, Section 5.4.3, Step 1
990*f9fbec18Smcpowers     **
991*f9fbec18Smcpowers     ** Compute u1*G + u2*Q
992*f9fbec18Smcpowers     ** Here, A = u1.G     B = u2.Q    and   C = A + B
993*f9fbec18Smcpowers     ** If the result, C, is the point at infinity, reject the signature
994*f9fbec18Smcpowers     */
995*f9fbec18Smcpowers     if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC, kmflag)
996*f9fbec18Smcpowers 	!= SECSuccess) {
997*f9fbec18Smcpowers 	rv = SECFailure;
998*f9fbec18Smcpowers 	goto cleanup;
999*f9fbec18Smcpowers     }
1000*f9fbec18Smcpowers     if (ec_point_at_infinity(&pointC)) {
1001*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
1002*f9fbec18Smcpowers 	rv = SECFailure;
1003*f9fbec18Smcpowers 	goto cleanup;
1004*f9fbec18Smcpowers     }
1005*f9fbec18Smcpowers 
1006*f9fbec18Smcpowers     CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, flen) );
1007*f9fbec18Smcpowers 
1008*f9fbec18Smcpowers     /*
1009*f9fbec18Smcpowers     ** ANSI X9.62, Section 5.4.4, Step 2
1010*f9fbec18Smcpowers     **
1011*f9fbec18Smcpowers     ** v = x1 mod n
1012*f9fbec18Smcpowers     */
1013*f9fbec18Smcpowers     CHECK_MPI_OK( mp_mod(&x1, &n, &v) );
1014*f9fbec18Smcpowers 
1015*f9fbec18Smcpowers #if EC_DEBUG
1016*f9fbec18Smcpowers     mp_todecimal(&r_, mpstr);
1017*f9fbec18Smcpowers     printf("r_: %s (dec)\n", mpstr);
1018*f9fbec18Smcpowers     mp_todecimal(&v, mpstr);
1019*f9fbec18Smcpowers     printf("v : %s (dec)\n", mpstr);
1020*f9fbec18Smcpowers #endif
1021*f9fbec18Smcpowers 
1022*f9fbec18Smcpowers     /*
1023*f9fbec18Smcpowers     ** ANSI X9.62, Section 5.4.4, Step 3
1024*f9fbec18Smcpowers     **
1025*f9fbec18Smcpowers     ** Verification:  v == r'
1026*f9fbec18Smcpowers     */
1027*f9fbec18Smcpowers     if (mp_cmp(&v, &r_)) {
1028*f9fbec18Smcpowers 	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
1029*f9fbec18Smcpowers 	rv = SECFailure; /* Signature failed to verify. */
1030*f9fbec18Smcpowers     } else {
1031*f9fbec18Smcpowers 	rv = SECSuccess; /* Signature verified. */
1032*f9fbec18Smcpowers     }
1033*f9fbec18Smcpowers 
1034*f9fbec18Smcpowers #if EC_DEBUG
1035*f9fbec18Smcpowers     mp_todecimal(&u1, mpstr);
1036*f9fbec18Smcpowers     printf("u1: %s (dec)\n", mpstr);
1037*f9fbec18Smcpowers     mp_todecimal(&u2, mpstr);
1038*f9fbec18Smcpowers     printf("u2: %s (dec)\n", mpstr);
1039*f9fbec18Smcpowers     mp_tohex(&x1, mpstr);
1040*f9fbec18Smcpowers     printf("x1: %s\n", mpstr);
1041*f9fbec18Smcpowers     mp_todecimal(&v, mpstr);
1042*f9fbec18Smcpowers     printf("v : %s (dec)\n", mpstr);
1043*f9fbec18Smcpowers #endif
1044*f9fbec18Smcpowers 
1045*f9fbec18Smcpowers cleanup:
1046*f9fbec18Smcpowers     mp_clear(&r_);
1047*f9fbec18Smcpowers     mp_clear(&s_);
1048*f9fbec18Smcpowers     mp_clear(&c);
1049*f9fbec18Smcpowers     mp_clear(&u1);
1050*f9fbec18Smcpowers     mp_clear(&u2);
1051*f9fbec18Smcpowers     mp_clear(&x1);
1052*f9fbec18Smcpowers     mp_clear(&v);
1053*f9fbec18Smcpowers     mp_clear(&n);
1054*f9fbec18Smcpowers 
1055*f9fbec18Smcpowers     if (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE);
1056*f9fbec18Smcpowers     if (err) {
1057*f9fbec18Smcpowers 	MP_TO_SEC_ERROR(err);
1058*f9fbec18Smcpowers 	rv = SECFailure;
1059*f9fbec18Smcpowers     }
1060*f9fbec18Smcpowers 
1061*f9fbec18Smcpowers #if EC_DEBUG
1062*f9fbec18Smcpowers     printf("ECDSA verification %s\n",
1063*f9fbec18Smcpowers 	(rv == SECSuccess) ? "succeeded" : "failed");
1064*f9fbec18Smcpowers #endif
1065*f9fbec18Smcpowers 
1066*f9fbec18Smcpowers     return rv;
1067*f9fbec18Smcpowers }
1068*f9fbec18Smcpowers 
1069