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 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 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 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 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 * 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 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 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 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 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 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 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 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