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