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