15697Smcpowers /*
25697Smcpowers * ***** BEGIN LICENSE BLOCK *****
35697Smcpowers * Version: MPL 1.1/GPL 2.0/LGPL 2.1
45697Smcpowers *
55697Smcpowers * The contents of this file are subject to the Mozilla Public License Version
65697Smcpowers * 1.1 (the "License"); you may not use this file except in compliance with
75697Smcpowers * the License. You may obtain a copy of the License at
85697Smcpowers * http://www.mozilla.org/MPL/
95697Smcpowers *
105697Smcpowers * Software distributed under the License is distributed on an "AS IS" basis,
115697Smcpowers * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
125697Smcpowers * for the specific language governing rights and limitations under the
135697Smcpowers * License.
145697Smcpowers *
155697Smcpowers * The Original Code is the Elliptic Curve Cryptography library.
165697Smcpowers *
175697Smcpowers * The Initial Developer of the Original Code is
185697Smcpowers * Sun Microsystems, Inc.
195697Smcpowers * Portions created by the Initial Developer are Copyright (C) 2003
205697Smcpowers * the Initial Developer. All Rights Reserved.
215697Smcpowers *
225697Smcpowers * Contributor(s):
235697Smcpowers * Dr Vipul Gupta <vipul.gupta@sun.com> and
245697Smcpowers * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
255697Smcpowers *
265697Smcpowers * Alternatively, the contents of this file may be used under the terms of
275697Smcpowers * either the GNU General Public License Version 2 or later (the "GPL"), or
285697Smcpowers * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
295697Smcpowers * in which case the provisions of the GPL or the LGPL are applicable instead
305697Smcpowers * of those above. If you wish to allow use of your version of this file only
315697Smcpowers * under the terms of either the GPL or the LGPL, and not to allow others to
325697Smcpowers * use your version of this file under the terms of the MPL, indicate your
335697Smcpowers * decision by deleting the provisions above and replace them with the notice
345697Smcpowers * and other provisions required by the GPL or the LGPL. If you do not delete
355697Smcpowers * the provisions above, a recipient may use your version of this file under
365697Smcpowers * the terms of any one of the MPL, the GPL or the LGPL.
375697Smcpowers *
385697Smcpowers * ***** END LICENSE BLOCK ***** */
395697Smcpowers /*
40*10500SHai-May.Chao@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
415697Smcpowers * Use is subject to license terms.
425697Smcpowers *
435697Smcpowers * Sun elects to use this software under the MPL license.
445697Smcpowers */
455697Smcpowers
465697Smcpowers
475697Smcpowers #include "mplogic.h"
485697Smcpowers #include "ec.h"
495697Smcpowers #include "ecl.h"
505697Smcpowers
515697Smcpowers #include <sys/types.h>
525697Smcpowers #ifndef _KERNEL
535697Smcpowers #include <stdlib.h>
545697Smcpowers #include <string.h>
555697Smcpowers #include <strings.h>
565697Smcpowers #endif
575697Smcpowers #include "ecl-exp.h"
585697Smcpowers #include "mpi.h"
595697Smcpowers #include "ecc_impl.h"
605697Smcpowers
615697Smcpowers #ifdef _KERNEL
625697Smcpowers #define PORT_ZFree(p, l) bzero((p), (l)); kmem_free((p), (l))
635697Smcpowers #else
645697Smcpowers #define PORT_ZFree(p, l) bzero((p), (l)); free((p))
655697Smcpowers #endif
665697Smcpowers
675697Smcpowers /*
685697Smcpowers * Returns true if pointP is the point at infinity, false otherwise
695697Smcpowers */
705697Smcpowers PRBool
ec_point_at_infinity(SECItem * pointP)715697Smcpowers ec_point_at_infinity(SECItem *pointP)
725697Smcpowers {
735697Smcpowers unsigned int i;
745697Smcpowers
755697Smcpowers for (i = 1; i < pointP->len; i++) {
765697Smcpowers if (pointP->data[i] != 0x00) return PR_FALSE;
775697Smcpowers }
785697Smcpowers
795697Smcpowers return PR_TRUE;
805697Smcpowers }
815697Smcpowers
825697Smcpowers /*
835697Smcpowers * Computes scalar point multiplication pointQ = k1 * G + k2 * pointP for
845697Smcpowers * the curve whose parameters are encoded in params with base point G.
855697Smcpowers */
865697Smcpowers SECStatus
ec_points_mul(const ECParams * params,const mp_int * k1,const mp_int * k2,const SECItem * pointP,SECItem * pointQ,int kmflag)875697Smcpowers ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2,
885697Smcpowers const SECItem *pointP, SECItem *pointQ, int kmflag)
895697Smcpowers {
905697Smcpowers mp_int Px, Py, Qx, Qy;
915697Smcpowers mp_int Gx, Gy, order, irreducible, a, b;
925697Smcpowers #if 0 /* currently don't support non-named curves */
935697Smcpowers unsigned int irr_arr[5];
945697Smcpowers #endif
955697Smcpowers ECGroup *group = NULL;
965697Smcpowers SECStatus rv = SECFailure;
975697Smcpowers mp_err err = MP_OKAY;
985697Smcpowers int len;
995697Smcpowers
1005697Smcpowers #if EC_DEBUG
1015697Smcpowers int i;
1025697Smcpowers char mpstr[256];
1035697Smcpowers
1045697Smcpowers printf("ec_points_mul: params [len=%d]:", params->DEREncoding.len);
1055697Smcpowers for (i = 0; i < params->DEREncoding.len; i++)
1065697Smcpowers printf("%02x:", params->DEREncoding.data[i]);
1075697Smcpowers printf("\n");
1085697Smcpowers
1095697Smcpowers if (k1 != NULL) {
1105697Smcpowers mp_tohex(k1, mpstr);
1115697Smcpowers printf("ec_points_mul: scalar k1: %s\n", mpstr);
1125697Smcpowers mp_todecimal(k1, mpstr);
1135697Smcpowers printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr);
1145697Smcpowers }
1155697Smcpowers
1165697Smcpowers if (k2 != NULL) {
1175697Smcpowers mp_tohex(k2, mpstr);
1185697Smcpowers printf("ec_points_mul: scalar k2: %s\n", mpstr);
1195697Smcpowers mp_todecimal(k2, mpstr);
1205697Smcpowers printf("ec_points_mul: scalar k2: %s (dec)\n", mpstr);
1215697Smcpowers }
1225697Smcpowers
1235697Smcpowers if (pointP != NULL) {
1245697Smcpowers printf("ec_points_mul: pointP [len=%d]:", pointP->len);
1255697Smcpowers for (i = 0; i < pointP->len; i++)
1265697Smcpowers printf("%02x:", pointP->data[i]);
1275697Smcpowers printf("\n");
1285697Smcpowers }
1295697Smcpowers #endif
1305697Smcpowers
1315697Smcpowers /* NOTE: We only support uncompressed points for now */
1325697Smcpowers len = (params->fieldID.size + 7) >> 3;
1335697Smcpowers if (pointP != NULL) {
1345697Smcpowers if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
1355697Smcpowers (pointP->len != (2 * len + 1))) {
1365697Smcpowers return SECFailure;
1375697Smcpowers };
1385697Smcpowers }
1395697Smcpowers
1405697Smcpowers MP_DIGITS(&Px) = 0;
1415697Smcpowers MP_DIGITS(&Py) = 0;
1425697Smcpowers MP_DIGITS(&Qx) = 0;
1435697Smcpowers MP_DIGITS(&Qy) = 0;
1445697Smcpowers MP_DIGITS(&Gx) = 0;
1455697Smcpowers MP_DIGITS(&Gy) = 0;
1465697Smcpowers MP_DIGITS(&order) = 0;
1475697Smcpowers MP_DIGITS(&irreducible) = 0;
1485697Smcpowers MP_DIGITS(&a) = 0;
1495697Smcpowers MP_DIGITS(&b) = 0;
1505697Smcpowers CHECK_MPI_OK( mp_init(&Px, kmflag) );
1515697Smcpowers CHECK_MPI_OK( mp_init(&Py, kmflag) );
1525697Smcpowers CHECK_MPI_OK( mp_init(&Qx, kmflag) );
1535697Smcpowers CHECK_MPI_OK( mp_init(&Qy, kmflag) );
1545697Smcpowers CHECK_MPI_OK( mp_init(&Gx, kmflag) );
1555697Smcpowers CHECK_MPI_OK( mp_init(&Gy, kmflag) );
1565697Smcpowers CHECK_MPI_OK( mp_init(&order, kmflag) );
1575697Smcpowers CHECK_MPI_OK( mp_init(&irreducible, kmflag) );
1585697Smcpowers CHECK_MPI_OK( mp_init(&a, kmflag) );
1595697Smcpowers CHECK_MPI_OK( mp_init(&b, kmflag) );
1605697Smcpowers
1615697Smcpowers if ((k2 != NULL) && (pointP != NULL)) {
1625697Smcpowers /* Initialize Px and Py */
1635697Smcpowers CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size) len) );
1645697Smcpowers CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) );
1655697Smcpowers }
1665697Smcpowers
1675697Smcpowers /* construct from named params, if possible */
1685697Smcpowers if (params->name != ECCurve_noName) {
1695697Smcpowers group = ECGroup_fromName(params->name, kmflag);
1705697Smcpowers }
1715697Smcpowers
1725697Smcpowers #if 0 /* currently don't support non-named curves */
1735697Smcpowers if (group == NULL) {
1745697Smcpowers /* Set up mp_ints containing the curve coefficients */
1755697Smcpowers CHECK_MPI_OK( mp_read_unsigned_octets(&Gx, params->base.data + 1,
1765697Smcpowers (mp_size) len) );
1775697Smcpowers CHECK_MPI_OK( mp_read_unsigned_octets(&Gy, params->base.data + 1 + len,
1785697Smcpowers (mp_size) len) );
1795697Smcpowers SECITEM_TO_MPINT( params->order, &order );
1805697Smcpowers SECITEM_TO_MPINT( params->curve.a, &a );
1815697Smcpowers SECITEM_TO_MPINT( params->curve.b, &b );
1825697Smcpowers if (params->fieldID.type == ec_field_GFp) {
1835697Smcpowers SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible );
1845697Smcpowers group = ECGroup_consGFp(&irreducible, &a, &b, &Gx, &Gy, &order, params->cofactor);
1855697Smcpowers } else {
1865697Smcpowers SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible );
1875697Smcpowers irr_arr[0] = params->fieldID.size;
1885697Smcpowers irr_arr[1] = params->fieldID.k1;
1895697Smcpowers irr_arr[2] = params->fieldID.k2;
1905697Smcpowers irr_arr[3] = params->fieldID.k3;
1915697Smcpowers irr_arr[4] = 0;
1925697Smcpowers group = ECGroup_consGF2m(&irreducible, irr_arr, &a, &b, &Gx, &Gy, &order, params->cofactor);
1935697Smcpowers }
1945697Smcpowers }
1955697Smcpowers #endif
1965697Smcpowers if (group == NULL)
1975697Smcpowers goto cleanup;
1985697Smcpowers
1995697Smcpowers if ((k2 != NULL) && (pointP != NULL)) {
2005697Smcpowers CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy) );
2015697Smcpowers } else {
2025697Smcpowers CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) );
2035697Smcpowers }
2045697Smcpowers
2055697Smcpowers /* Construct the SECItem representation of point Q */
2065697Smcpowers pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED;
2075697Smcpowers CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1,
2085697Smcpowers (mp_size) len) );
2095697Smcpowers CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len,
2105697Smcpowers (mp_size) len) );
2115697Smcpowers
2125697Smcpowers rv = SECSuccess;
2135697Smcpowers
2145697Smcpowers #if EC_DEBUG
2155697Smcpowers printf("ec_points_mul: pointQ [len=%d]:", pointQ->len);
2165697Smcpowers for (i = 0; i < pointQ->len; i++)
2175697Smcpowers printf("%02x:", pointQ->data[i]);
2185697Smcpowers printf("\n");
2195697Smcpowers #endif
2205697Smcpowers
2215697Smcpowers cleanup:
2225697Smcpowers ECGroup_free(group);
2235697Smcpowers mp_clear(&Px);
2245697Smcpowers mp_clear(&Py);
2255697Smcpowers mp_clear(&Qx);
2265697Smcpowers mp_clear(&Qy);
2275697Smcpowers mp_clear(&Gx);
2285697Smcpowers mp_clear(&Gy);
2295697Smcpowers mp_clear(&order);
2305697Smcpowers mp_clear(&irreducible);
2315697Smcpowers mp_clear(&a);
2325697Smcpowers mp_clear(&b);
2335697Smcpowers if (err) {
2345697Smcpowers MP_TO_SEC_ERROR(err);
2355697Smcpowers rv = SECFailure;
2365697Smcpowers }
2375697Smcpowers
2385697Smcpowers return rv;
2395697Smcpowers }
2405697Smcpowers
2415697Smcpowers /* Generates a new EC key pair. The private key is a supplied
2425697Smcpowers * value and the public key is the result of performing a scalar
2435697Smcpowers * point multiplication of that value with the curve's base point.
2445697Smcpowers */
2455697Smcpowers SECStatus
ec_NewKey(ECParams * ecParams,ECPrivateKey ** privKey,const unsigned char * privKeyBytes,int privKeyLen,int kmflag)2465697Smcpowers ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey,
2475697Smcpowers const unsigned char *privKeyBytes, int privKeyLen, int kmflag)
2485697Smcpowers {
2495697Smcpowers SECStatus rv = SECFailure;
2505697Smcpowers PRArenaPool *arena;
2515697Smcpowers ECPrivateKey *key;
2525697Smcpowers mp_int k;
2535697Smcpowers mp_err err = MP_OKAY;
2545697Smcpowers int len;
2555697Smcpowers
2565697Smcpowers #if EC_DEBUG
2575697Smcpowers printf("ec_NewKey called\n");
2585697Smcpowers #endif
2595697Smcpowers
2605697Smcpowers int printf();
2615697Smcpowers if (!ecParams || !privKey || !privKeyBytes || (privKeyLen < 0)) {
2625697Smcpowers PORT_SetError(SEC_ERROR_INVALID_ARGS);
2635697Smcpowers return SECFailure;
2645697Smcpowers }
2655697Smcpowers
2665697Smcpowers /* Initialize an arena for the EC key. */
2675697Smcpowers if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))
2685697Smcpowers return SECFailure;
2695697Smcpowers
2705697Smcpowers key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey),
2715697Smcpowers kmflag);
2725697Smcpowers if (!key) {
2735697Smcpowers PORT_FreeArena(arena, PR_TRUE);
2745697Smcpowers return SECFailure;
2755697Smcpowers }
2765697Smcpowers
2775697Smcpowers /* Set the version number (SEC 1 section C.4 says it should be 1) */
2785697Smcpowers SECITEM_AllocItem(arena, &key->version, 1, kmflag);
2795697Smcpowers key->version.data[0] = 1;
2805697Smcpowers
2815697Smcpowers /* Copy all of the fields from the ECParams argument to the
2825697Smcpowers * ECParams structure within the private key.
2835697Smcpowers */
2845697Smcpowers key->ecParams.arena = arena;
2855697Smcpowers key->ecParams.type = ecParams->type;
2865697Smcpowers key->ecParams.fieldID.size = ecParams->fieldID.size;
2875697Smcpowers key->ecParams.fieldID.type = ecParams->fieldID.type;
2885697Smcpowers if (ecParams->fieldID.type == ec_field_GFp) {
2895697Smcpowers CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime,
2905697Smcpowers &ecParams->fieldID.u.prime, kmflag));
2915697Smcpowers } else {
2925697Smcpowers CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.poly,
2935697Smcpowers &ecParams->fieldID.u.poly, kmflag));
2945697Smcpowers }
2955697Smcpowers key->ecParams.fieldID.k1 = ecParams->fieldID.k1;
2965697Smcpowers key->ecParams.fieldID.k2 = ecParams->fieldID.k2;
2975697Smcpowers key->ecParams.fieldID.k3 = ecParams->fieldID.k3;
2985697Smcpowers CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a,
2995697Smcpowers &ecParams->curve.a, kmflag));
3005697Smcpowers CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b,
3015697Smcpowers &ecParams->curve.b, kmflag));
3025697Smcpowers CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed,
3035697Smcpowers &ecParams->curve.seed, kmflag));
3045697Smcpowers CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base,
3055697Smcpowers &ecParams->base, kmflag));
3065697Smcpowers CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order,
3075697Smcpowers &ecParams->order, kmflag));
3085697Smcpowers key->ecParams.cofactor = ecParams->cofactor;
3095697Smcpowers CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding,
3105697Smcpowers &ecParams->DEREncoding, kmflag));
3115697Smcpowers key->ecParams.name = ecParams->name;
3125697Smcpowers CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID,
3135697Smcpowers &ecParams->curveOID, kmflag));
3145697Smcpowers
3155697Smcpowers len = (ecParams->fieldID.size + 7) >> 3;
3165697Smcpowers SECITEM_AllocItem(arena, &key->publicValue, 2*len + 1, kmflag);
3175697Smcpowers len = ecParams->order.len;
3185697Smcpowers SECITEM_AllocItem(arena, &key->privateValue, len, kmflag);
3195697Smcpowers
3205697Smcpowers /* Copy private key */
3215697Smcpowers if (privKeyLen >= len) {
3225697Smcpowers memcpy(key->privateValue.data, privKeyBytes, len);
3235697Smcpowers } else {
3245697Smcpowers memset(key->privateValue.data, 0, (len - privKeyLen));
3255697Smcpowers memcpy(key->privateValue.data + (len - privKeyLen), privKeyBytes, privKeyLen);
3265697Smcpowers }
3275697Smcpowers
3285697Smcpowers /* Compute corresponding public key */
3295697Smcpowers MP_DIGITS(&k) = 0;
3305697Smcpowers CHECK_MPI_OK( mp_init(&k, kmflag) );
3315697Smcpowers CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data,
3325697Smcpowers (mp_size) len) );
3335697Smcpowers
3345697Smcpowers rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue), kmflag);
3355697Smcpowers if (rv != SECSuccess) goto cleanup;
3365697Smcpowers *privKey = key;
3375697Smcpowers
3385697Smcpowers cleanup:
3395697Smcpowers mp_clear(&k);
3405697Smcpowers if (rv)
3415697Smcpowers PORT_FreeArena(arena, PR_TRUE);
3425697Smcpowers
3435697Smcpowers #if EC_DEBUG
3445697Smcpowers printf("ec_NewKey returning %s\n",
3455697Smcpowers (rv == SECSuccess) ? "success" : "failure");
3465697Smcpowers #endif
3475697Smcpowers
3485697Smcpowers return rv;
3495697Smcpowers
3505697Smcpowers }
3515697Smcpowers
3525697Smcpowers /* Generates a new EC key pair. The private key is a supplied
3535697Smcpowers * random value (in seed) and the public key is the result of
3545697Smcpowers * performing a scalar point multiplication of that value with
3555697Smcpowers * the curve's base point.
3565697Smcpowers */
3575697Smcpowers SECStatus
EC_NewKeyFromSeed(ECParams * ecParams,ECPrivateKey ** privKey,const unsigned char * seed,int seedlen,int kmflag)3585697Smcpowers EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey,
3595697Smcpowers const unsigned char *seed, int seedlen, int kmflag)
3605697Smcpowers {
3615697Smcpowers SECStatus rv = SECFailure;
3625697Smcpowers rv = ec_NewKey(ecParams, privKey, seed, seedlen, kmflag);
3635697Smcpowers return rv;
3645697Smcpowers }
3655697Smcpowers
3665697Smcpowers /* Generate a random private key using the algorithm A.4.1 of ANSI X9.62,
3675697Smcpowers * modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the
3685697Smcpowers * random number generator.
3695697Smcpowers *
3705697Smcpowers * Parameters
3715697Smcpowers * - order: a buffer that holds the curve's group order
3725697Smcpowers * - len: the length in octets of the order buffer
3735697Smcpowers *
3745697Smcpowers * Return Value
3755697Smcpowers * Returns a buffer of len octets that holds the private key. The caller
3765697Smcpowers * is responsible for freeing the buffer with PORT_ZFree.
3775697Smcpowers */
3785697Smcpowers static unsigned char *
ec_GenerateRandomPrivateKey(const unsigned char * order,int len,int kmflag)3795697Smcpowers ec_GenerateRandomPrivateKey(const unsigned char *order, int len, int kmflag)
3805697Smcpowers {
3815697Smcpowers SECStatus rv = SECSuccess;
3825697Smcpowers mp_err err;
3835697Smcpowers unsigned char *privKeyBytes = NULL;
3845697Smcpowers mp_int privKeyVal, order_1, one;
3855697Smcpowers
3865697Smcpowers MP_DIGITS(&privKeyVal) = 0;
3875697Smcpowers MP_DIGITS(&order_1) = 0;
3885697Smcpowers MP_DIGITS(&one) = 0;
3895697Smcpowers CHECK_MPI_OK( mp_init(&privKeyVal, kmflag) );
3905697Smcpowers CHECK_MPI_OK( mp_init(&order_1, kmflag) );
3915697Smcpowers CHECK_MPI_OK( mp_init(&one, kmflag) );
3925697Smcpowers
3935697Smcpowers /* Generates 2*len random bytes using the global random bit generator
3945697Smcpowers * (which implements Algorithm 1 of FIPS 186-2 Change Notice 1) then
3955697Smcpowers * reduces modulo the group order.
3965697Smcpowers */
3975697Smcpowers if ((privKeyBytes = PORT_Alloc(2*len, kmflag)) == NULL) goto cleanup;
3985697Smcpowers CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) );
3995697Smcpowers CHECK_MPI_OK( mp_read_unsigned_octets(&privKeyVal, privKeyBytes, 2*len) );
4005697Smcpowers CHECK_MPI_OK( mp_read_unsigned_octets(&order_1, order, len) );
4015697Smcpowers CHECK_MPI_OK( mp_set_int(&one, 1) );
4025697Smcpowers CHECK_MPI_OK( mp_sub(&order_1, &one, &order_1) );
4035697Smcpowers CHECK_MPI_OK( mp_mod(&privKeyVal, &order_1, &privKeyVal) );
4045697Smcpowers CHECK_MPI_OK( mp_add(&privKeyVal, &one, &privKeyVal) );
4055697Smcpowers CHECK_MPI_OK( mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len) );
4065697Smcpowers memset(privKeyBytes+len, 0, len);
4075697Smcpowers cleanup:
4085697Smcpowers mp_clear(&privKeyVal);
4095697Smcpowers mp_clear(&order_1);
4105697Smcpowers mp_clear(&one);
4115697Smcpowers if (err < MP_OKAY) {
4125697Smcpowers MP_TO_SEC_ERROR(err);
4135697Smcpowers rv = SECFailure;
4145697Smcpowers }
4155697Smcpowers if (rv != SECSuccess && privKeyBytes) {
4165697Smcpowers #ifdef _KERNEL
4175697Smcpowers kmem_free(privKeyBytes, 2*len);
4185697Smcpowers #else
4195697Smcpowers free(privKeyBytes);
4205697Smcpowers #endif
4215697Smcpowers privKeyBytes = NULL;
4225697Smcpowers }
4235697Smcpowers return privKeyBytes;
4245697Smcpowers }
4255697Smcpowers
4265697Smcpowers /* Generates a new EC key pair. The private key is a random value and
4275697Smcpowers * the public key is the result of performing a scalar point multiplication
4285697Smcpowers * of that value with the curve's base point.
4295697Smcpowers */
4305697Smcpowers SECStatus
EC_NewKey(ECParams * ecParams,ECPrivateKey ** privKey,int kmflag)4315697Smcpowers EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey, int kmflag)
4325697Smcpowers {
4335697Smcpowers SECStatus rv = SECFailure;
4345697Smcpowers int len;
4355697Smcpowers unsigned char *privKeyBytes = NULL;
4365697Smcpowers
4375697Smcpowers if (!ecParams) {
4385697Smcpowers PORT_SetError(SEC_ERROR_INVALID_ARGS);
4395697Smcpowers return SECFailure;
4405697Smcpowers }
4415697Smcpowers
4425697Smcpowers len = ecParams->order.len;
4435697Smcpowers privKeyBytes = ec_GenerateRandomPrivateKey(ecParams->order.data, len,
4445697Smcpowers kmflag);
4455697Smcpowers if (privKeyBytes == NULL) goto cleanup;
4465697Smcpowers /* generate public key */
4475697Smcpowers CHECK_SEC_OK( ec_NewKey(ecParams, privKey, privKeyBytes, len, kmflag) );
4485697Smcpowers
4495697Smcpowers cleanup:
4505697Smcpowers if (privKeyBytes) {
4515697Smcpowers PORT_ZFree(privKeyBytes, len * 2);
4525697Smcpowers }
4535697Smcpowers #if EC_DEBUG
4545697Smcpowers printf("EC_NewKey returning %s\n",
4555697Smcpowers (rv == SECSuccess) ? "success" : "failure");
4565697Smcpowers #endif
4575697Smcpowers
4585697Smcpowers return rv;
4595697Smcpowers }
4605697Smcpowers
4615697Smcpowers /* Validates an EC public key as described in Section 5.2.2 of
4625697Smcpowers * X9.62. The ECDH primitive when used without the cofactor does
4635697Smcpowers * not address small subgroup attacks, which may occur when the
4645697Smcpowers * public key is not valid. These attacks can be prevented by
4655697Smcpowers * validating the public key before using ECDH.
4665697Smcpowers */
4675697Smcpowers SECStatus
EC_ValidatePublicKey(ECParams * ecParams,SECItem * publicValue,int kmflag)4685697Smcpowers EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue, int kmflag)
4695697Smcpowers {
4705697Smcpowers mp_int Px, Py;
4715697Smcpowers ECGroup *group = NULL;
4725697Smcpowers SECStatus rv = SECFailure;
4735697Smcpowers mp_err err = MP_OKAY;
4745697Smcpowers int len;
4755697Smcpowers
4765697Smcpowers if (!ecParams || !publicValue) {
4775697Smcpowers PORT_SetError(SEC_ERROR_INVALID_ARGS);
4785697Smcpowers return SECFailure;
4795697Smcpowers }
4805697Smcpowers
4815697Smcpowers /* NOTE: We only support uncompressed points for now */
4825697Smcpowers len = (ecParams->fieldID.size + 7) >> 3;
4835697Smcpowers if (publicValue->data[0] != EC_POINT_FORM_UNCOMPRESSED) {
4845697Smcpowers PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
4855697Smcpowers return SECFailure;
4865697Smcpowers } else if (publicValue->len != (2 * len + 1)) {
4875697Smcpowers PORT_SetError(SEC_ERROR_BAD_KEY);
4885697Smcpowers return SECFailure;
4895697Smcpowers }
4905697Smcpowers
4915697Smcpowers MP_DIGITS(&Px) = 0;
4925697Smcpowers MP_DIGITS(&Py) = 0;
4935697Smcpowers CHECK_MPI_OK( mp_init(&Px, kmflag) );
4945697Smcpowers CHECK_MPI_OK( mp_init(&Py, kmflag) );
4955697Smcpowers
4965697Smcpowers /* Initialize Px and Py */
4975697Smcpowers CHECK_MPI_OK( mp_read_unsigned_octets(&Px, publicValue->data + 1, (mp_size) len) );
4985697Smcpowers CHECK_MPI_OK( mp_read_unsigned_octets(&Py, publicValue->data + 1 + len, (mp_size) len) );
4995697Smcpowers
5005697Smcpowers /* construct from named params */
5015697Smcpowers group = ECGroup_fromName(ecParams->name, kmflag);
5025697Smcpowers if (group == NULL) {
5035697Smcpowers /*
5045697Smcpowers * ECGroup_fromName fails if ecParams->name is not a valid
5055697Smcpowers * ECCurveName value, or if we run out of memory, or perhaps
5065697Smcpowers * for other reasons. Unfortunately if ecParams->name is a
5075697Smcpowers * valid ECCurveName value, we don't know what the right error
5085697Smcpowers * code should be because ECGroup_fromName doesn't return an
5095697Smcpowers * error code to the caller. Set err to MP_UNDEF because
5105697Smcpowers * that's what ECGroup_fromName uses internally.
5115697Smcpowers */
5125697Smcpowers if ((ecParams->name <= ECCurve_noName) ||
5135697Smcpowers (ecParams->name >= ECCurve_pastLastCurve)) {
5145697Smcpowers err = MP_BADARG;
5155697Smcpowers } else {
5165697Smcpowers err = MP_UNDEF;
5175697Smcpowers }
5185697Smcpowers goto cleanup;
5195697Smcpowers }
5205697Smcpowers
5215697Smcpowers /* validate public point */
5225697Smcpowers if ((err = ECPoint_validate(group, &Px, &Py)) < MP_YES) {
5235697Smcpowers if (err == MP_NO) {
5245697Smcpowers PORT_SetError(SEC_ERROR_BAD_KEY);
5255697Smcpowers rv = SECFailure;
5265697Smcpowers err = MP_OKAY; /* don't change the error code */
5275697Smcpowers }
5285697Smcpowers goto cleanup;
5295697Smcpowers }
5305697Smcpowers
5315697Smcpowers rv = SECSuccess;
5325697Smcpowers
5335697Smcpowers cleanup:
5345697Smcpowers ECGroup_free(group);
5355697Smcpowers mp_clear(&Px);
5365697Smcpowers mp_clear(&Py);
5375697Smcpowers if (err) {
5385697Smcpowers MP_TO_SEC_ERROR(err);
5395697Smcpowers rv = SECFailure;
5405697Smcpowers }
5415697Smcpowers return rv;
5425697Smcpowers }
5435697Smcpowers
5445697Smcpowers /*
5455697Smcpowers ** Performs an ECDH key derivation by computing the scalar point
5465697Smcpowers ** multiplication of privateValue and publicValue (with or without the
5475697Smcpowers ** cofactor) and returns the x-coordinate of the resulting elliptic
5485697Smcpowers ** curve point in derived secret. If successful, derivedSecret->data
5495697Smcpowers ** is set to the address of the newly allocated buffer containing the
5505697Smcpowers ** derived secret, and derivedSecret->len is the size of the secret
5515697Smcpowers ** produced. It is the caller's responsibility to free the allocated
5525697Smcpowers ** buffer containing the derived secret.
5535697Smcpowers */
5545697Smcpowers SECStatus
ECDH_Derive(SECItem * publicValue,ECParams * ecParams,SECItem * privateValue,PRBool withCofactor,SECItem * derivedSecret,int kmflag)5555697Smcpowers ECDH_Derive(SECItem *publicValue,
5565697Smcpowers ECParams *ecParams,
5575697Smcpowers SECItem *privateValue,
5585697Smcpowers PRBool withCofactor,
5595697Smcpowers SECItem *derivedSecret,
5605697Smcpowers int kmflag)
5615697Smcpowers {
5625697Smcpowers SECStatus rv = SECFailure;
5635697Smcpowers unsigned int len = 0;
5645697Smcpowers SECItem pointQ = {siBuffer, NULL, 0};
5655697Smcpowers mp_int k; /* to hold the private value */
5665697Smcpowers mp_int cofactor;
5675697Smcpowers mp_err err = MP_OKAY;
5685697Smcpowers #if EC_DEBUG
5695697Smcpowers int i;
5705697Smcpowers #endif
5715697Smcpowers
5725697Smcpowers if (!publicValue || !ecParams || !privateValue ||
5735697Smcpowers !derivedSecret) {
5745697Smcpowers PORT_SetError(SEC_ERROR_INVALID_ARGS);
5755697Smcpowers return SECFailure;
5765697Smcpowers }
5775697Smcpowers
5785697Smcpowers memset(derivedSecret, 0, sizeof *derivedSecret);
5795697Smcpowers len = (ecParams->fieldID.size + 7) >> 3;
5805697Smcpowers pointQ.len = 2*len + 1;
5815697Smcpowers if ((pointQ.data = PORT_Alloc(2*len + 1, kmflag)) == NULL) goto cleanup;
5825697Smcpowers
5835697Smcpowers MP_DIGITS(&k) = 0;
5845697Smcpowers CHECK_MPI_OK( mp_init(&k, kmflag) );
5855697Smcpowers CHECK_MPI_OK( mp_read_unsigned_octets(&k, privateValue->data,
5865697Smcpowers (mp_size) privateValue->len) );
5875697Smcpowers
5885697Smcpowers if (withCofactor && (ecParams->cofactor != 1)) {
5895697Smcpowers /* multiply k with the cofactor */
5905697Smcpowers MP_DIGITS(&cofactor) = 0;
5915697Smcpowers CHECK_MPI_OK( mp_init(&cofactor, kmflag) );
5925697Smcpowers mp_set(&cofactor, ecParams->cofactor);
5935697Smcpowers CHECK_MPI_OK( mp_mul(&k, &cofactor, &k) );
5945697Smcpowers }
5955697Smcpowers
5965697Smcpowers /* Multiply our private key and peer's public point */
5975697Smcpowers if ((ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ, kmflag) != SECSuccess) ||
5985697Smcpowers ec_point_at_infinity(&pointQ))
5995697Smcpowers goto cleanup;
6005697Smcpowers
6015697Smcpowers /* Allocate memory for the derived secret and copy
6025697Smcpowers * the x co-ordinate of pointQ into it.
6035697Smcpowers */
6045697Smcpowers SECITEM_AllocItem(NULL, derivedSecret, len, kmflag);
6055697Smcpowers memcpy(derivedSecret->data, pointQ.data + 1, len);
6065697Smcpowers
6075697Smcpowers rv = SECSuccess;
6085697Smcpowers
6095697Smcpowers #if EC_DEBUG
6105697Smcpowers printf("derived_secret:\n");
6115697Smcpowers for (i = 0; i < derivedSecret->len; i++)
6125697Smcpowers printf("%02x:", derivedSecret->data[i]);
6135697Smcpowers printf("\n");
6145697Smcpowers #endif
6155697Smcpowers
6165697Smcpowers cleanup:
6175697Smcpowers mp_clear(&k);
6185697Smcpowers
6195697Smcpowers if (pointQ.data) {
6205697Smcpowers PORT_ZFree(pointQ.data, 2*len + 1);
6215697Smcpowers }
6225697Smcpowers
6235697Smcpowers return rv;
6245697Smcpowers }
6255697Smcpowers
6265697Smcpowers /* Computes the ECDSA signature (a concatenation of two values r and s)
6275697Smcpowers * on the digest using the given key and the random value kb (used in
6285697Smcpowers * computing s).
6295697Smcpowers */
6305697Smcpowers SECStatus
ECDSA_SignDigestWithSeed(ECPrivateKey * key,SECItem * signature,const SECItem * digest,const unsigned char * kb,const int kblen,int kmflag)6315697Smcpowers ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
6325697Smcpowers const SECItem *digest, const unsigned char *kb, const int kblen, int kmflag)
6335697Smcpowers {
6345697Smcpowers SECStatus rv = SECFailure;
6355697Smcpowers mp_int x1;
6365697Smcpowers mp_int d, k; /* private key, random integer */
6375697Smcpowers mp_int r, s; /* tuple (r, s) is the signature */
6385697Smcpowers mp_int n;
6395697Smcpowers mp_err err = MP_OKAY;
6405697Smcpowers ECParams *ecParams = NULL;
6415697Smcpowers SECItem kGpoint = { siBuffer, NULL, 0};
6425697Smcpowers int flen = 0; /* length in bytes of the field size */
6435697Smcpowers unsigned olen; /* length in bytes of the base point order */
6445697Smcpowers
6455697Smcpowers #if EC_DEBUG
6465697Smcpowers char mpstr[256];
6475697Smcpowers #endif
6485697Smcpowers
6495697Smcpowers /* Initialize MPI integers. */
6505697Smcpowers /* must happen before the first potential call to cleanup */
6515697Smcpowers MP_DIGITS(&x1) = 0;
6525697Smcpowers MP_DIGITS(&d) = 0;
6535697Smcpowers MP_DIGITS(&k) = 0;
6545697Smcpowers MP_DIGITS(&r) = 0;
6555697Smcpowers MP_DIGITS(&s) = 0;
6565697Smcpowers MP_DIGITS(&n) = 0;
6575697Smcpowers
6585697Smcpowers /* Check args */
6595697Smcpowers if (!key || !signature || !digest || !kb || (kblen < 0)) {
6605697Smcpowers PORT_SetError(SEC_ERROR_INVALID_ARGS);
6615697Smcpowers goto cleanup;
6625697Smcpowers }
6635697Smcpowers
6645697Smcpowers ecParams = &(key->ecParams);
6655697Smcpowers flen = (ecParams->fieldID.size + 7) >> 3;
6665697Smcpowers olen = ecParams->order.len;
6675697Smcpowers if (signature->data == NULL) {
6685697Smcpowers /* a call to get the signature length only */
6695697Smcpowers goto finish;
6705697Smcpowers }
6715697Smcpowers if (signature->len < 2*olen) {
6725697Smcpowers PORT_SetError(SEC_ERROR_OUTPUT_LEN);
6735697Smcpowers rv = SECBufferTooSmall;
6745697Smcpowers goto cleanup;
6755697Smcpowers }
6765697Smcpowers
6775697Smcpowers
6785697Smcpowers CHECK_MPI_OK( mp_init(&x1, kmflag) );
6795697Smcpowers CHECK_MPI_OK( mp_init(&d, kmflag) );
6805697Smcpowers CHECK_MPI_OK( mp_init(&k, kmflag) );
6815697Smcpowers CHECK_MPI_OK( mp_init(&r, kmflag) );
6825697Smcpowers CHECK_MPI_OK( mp_init(&s, kmflag) );
6835697Smcpowers CHECK_MPI_OK( mp_init(&n, kmflag) );
6845697Smcpowers
6855697Smcpowers SECITEM_TO_MPINT( ecParams->order, &n );
6865697Smcpowers SECITEM_TO_MPINT( key->privateValue, &d );
6875697Smcpowers CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) );
6885697Smcpowers /* Make sure k is in the interval [1, n-1] */
6895697Smcpowers if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) {
6905697Smcpowers #if EC_DEBUG
6915697Smcpowers printf("k is outside [1, n-1]\n");
6925697Smcpowers mp_tohex(&k, mpstr);
6935697Smcpowers printf("k : %s \n", mpstr);
6945697Smcpowers mp_tohex(&n, mpstr);
6955697Smcpowers printf("n : %s \n", mpstr);
6965697Smcpowers #endif
6975697Smcpowers PORT_SetError(SEC_ERROR_NEED_RANDOM);
6985697Smcpowers goto cleanup;
6995697Smcpowers }
7005697Smcpowers
7015697Smcpowers /*
7025697Smcpowers ** ANSI X9.62, Section 5.3.2, Step 2
7035697Smcpowers **
7045697Smcpowers ** Compute kG
7055697Smcpowers */
7065697Smcpowers kGpoint.len = 2*flen + 1;
7075697Smcpowers kGpoint.data = PORT_Alloc(2*flen + 1, kmflag);
7085697Smcpowers if ((kGpoint.data == NULL) ||
7095697Smcpowers (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint, kmflag)
7105697Smcpowers != SECSuccess))
7115697Smcpowers goto cleanup;
7125697Smcpowers
7135697Smcpowers /*
7145697Smcpowers ** ANSI X9.62, Section 5.3.3, Step 1
7155697Smcpowers **
7165697Smcpowers ** Extract the x co-ordinate of kG into x1
7175697Smcpowers */
7185697Smcpowers CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1,
7195697Smcpowers (mp_size) flen) );
7205697Smcpowers
7215697Smcpowers /*
7225697Smcpowers ** ANSI X9.62, Section 5.3.3, Step 2
7235697Smcpowers **
7245697Smcpowers ** r = x1 mod n NOTE: n is the order of the curve
7255697Smcpowers */
7265697Smcpowers CHECK_MPI_OK( mp_mod(&x1, &n, &r) );
7275697Smcpowers
7285697Smcpowers /*
7295697Smcpowers ** ANSI X9.62, Section 5.3.3, Step 3
7305697Smcpowers **
7315697Smcpowers ** verify r != 0
7325697Smcpowers */
7335697Smcpowers if (mp_cmp_z(&r) == 0) {
7345697Smcpowers PORT_SetError(SEC_ERROR_NEED_RANDOM);
7355697Smcpowers goto cleanup;
7365697Smcpowers }
7375697Smcpowers
7385697Smcpowers /*
7395697Smcpowers ** ANSI X9.62, Section 5.3.3, Step 4
7405697Smcpowers **
7415697Smcpowers ** s = (k**-1 * (HASH(M) + d*r)) mod n
7425697Smcpowers */
7435697Smcpowers SECITEM_TO_MPINT(*digest, &s); /* s = HASH(M) */
7445697Smcpowers
7455697Smcpowers /* In the definition of EC signing, digests are truncated
7465697Smcpowers * to the length of n in bits.
7475697Smcpowers * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
7485697Smcpowers if (digest->len*8 > ecParams->fieldID.size) {
7495697Smcpowers mpl_rsh(&s,&s,digest->len*8 - ecParams->fieldID.size);
7505697Smcpowers }
7515697Smcpowers
7525697Smcpowers #if EC_DEBUG
7535697Smcpowers mp_todecimal(&n, mpstr);
7545697Smcpowers printf("n : %s (dec)\n", mpstr);
7555697Smcpowers mp_todecimal(&d, mpstr);
7565697Smcpowers printf("d : %s (dec)\n", mpstr);
7575697Smcpowers mp_tohex(&x1, mpstr);
7585697Smcpowers printf("x1: %s\n", mpstr);
7595697Smcpowers mp_todecimal(&s, mpstr);
7605697Smcpowers printf("digest: %s (decimal)\n", mpstr);
7615697Smcpowers mp_todecimal(&r, mpstr);
7625697Smcpowers printf("r : %s (dec)\n", mpstr);
7635697Smcpowers mp_tohex(&r, mpstr);
7645697Smcpowers printf("r : %s\n", mpstr);
7655697Smcpowers #endif
7665697Smcpowers
7675697Smcpowers CHECK_MPI_OK( mp_invmod(&k, &n, &k) ); /* k = k**-1 mod n */
7685697Smcpowers CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) ); /* d = d * r mod n */
7695697Smcpowers CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) ); /* s = s + d mod n */
7705697Smcpowers CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) ); /* s = s * k mod n */
7715697Smcpowers
7725697Smcpowers #if EC_DEBUG
7735697Smcpowers mp_todecimal(&s, mpstr);
7745697Smcpowers printf("s : %s (dec)\n", mpstr);
7755697Smcpowers mp_tohex(&s, mpstr);
7765697Smcpowers printf("s : %s\n", mpstr);
7775697Smcpowers #endif
7785697Smcpowers
7795697Smcpowers /*
7805697Smcpowers ** ANSI X9.62, Section 5.3.3, Step 5
7815697Smcpowers **
7825697Smcpowers ** verify s != 0
7835697Smcpowers */
7845697Smcpowers if (mp_cmp_z(&s) == 0) {
7855697Smcpowers PORT_SetError(SEC_ERROR_NEED_RANDOM);
7865697Smcpowers goto cleanup;
7875697Smcpowers }
7885697Smcpowers
7895697Smcpowers /*
7905697Smcpowers **
7915697Smcpowers ** Signature is tuple (r, s)
7925697Smcpowers */
7935697Smcpowers CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, olen) );
7945697Smcpowers CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + olen, olen) );
7955697Smcpowers finish:
7965697Smcpowers signature->len = 2*olen;
7975697Smcpowers
7985697Smcpowers rv = SECSuccess;
7995697Smcpowers err = MP_OKAY;
8005697Smcpowers cleanup:
8015697Smcpowers mp_clear(&x1);
8025697Smcpowers mp_clear(&d);
8035697Smcpowers mp_clear(&k);
8045697Smcpowers mp_clear(&r);
8055697Smcpowers mp_clear(&s);
8065697Smcpowers mp_clear(&n);
8075697Smcpowers
8085697Smcpowers if (kGpoint.data) {
8095697Smcpowers PORT_ZFree(kGpoint.data, 2*flen + 1);
8105697Smcpowers }
8115697Smcpowers
8125697Smcpowers if (err) {
8135697Smcpowers MP_TO_SEC_ERROR(err);
8145697Smcpowers rv = SECFailure;
8155697Smcpowers }
8165697Smcpowers
8175697Smcpowers #if EC_DEBUG
8185697Smcpowers printf("ECDSA signing with seed %s\n",
8195697Smcpowers (rv == SECSuccess) ? "succeeded" : "failed");
8205697Smcpowers #endif
8215697Smcpowers
8225697Smcpowers return rv;
8235697Smcpowers }
8245697Smcpowers
8255697Smcpowers /*
8265697Smcpowers ** Computes the ECDSA signature on the digest using the given key
8275697Smcpowers ** and a random seed.
8285697Smcpowers */
8295697Smcpowers SECStatus
ECDSA_SignDigest(ECPrivateKey * key,SECItem * signature,const SECItem * digest,int kmflag)8305697Smcpowers ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest,
8315697Smcpowers int kmflag)
8325697Smcpowers {
8335697Smcpowers SECStatus rv = SECFailure;
8345697Smcpowers int len;
8355697Smcpowers unsigned char *kBytes= NULL;
8365697Smcpowers
8375697Smcpowers if (!key) {
8385697Smcpowers PORT_SetError(SEC_ERROR_INVALID_ARGS);
8395697Smcpowers return SECFailure;
8405697Smcpowers }
8415697Smcpowers
8425697Smcpowers /* Generate random value k */
8435697Smcpowers len = key->ecParams.order.len;
8445697Smcpowers kBytes = ec_GenerateRandomPrivateKey(key->ecParams.order.data, len,
8455697Smcpowers kmflag);
8465697Smcpowers if (kBytes == NULL) goto cleanup;
8475697Smcpowers
8485697Smcpowers /* Generate ECDSA signature with the specified k value */
8495697Smcpowers rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len, kmflag);
8505697Smcpowers
8515697Smcpowers cleanup:
8525697Smcpowers if (kBytes) {
8535697Smcpowers PORT_ZFree(kBytes, len * 2);
8545697Smcpowers }
8555697Smcpowers
8565697Smcpowers #if EC_DEBUG
8575697Smcpowers printf("ECDSA signing %s\n",
8585697Smcpowers (rv == SECSuccess) ? "succeeded" : "failed");
8595697Smcpowers #endif
8605697Smcpowers
8615697Smcpowers return rv;
8625697Smcpowers }
8635697Smcpowers
8645697Smcpowers /*
8655697Smcpowers ** Checks the signature on the given digest using the key provided.
8665697Smcpowers */
8675697Smcpowers SECStatus
ECDSA_VerifyDigest(ECPublicKey * key,const SECItem * signature,const SECItem * digest,int kmflag)8685697Smcpowers ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
8695697Smcpowers const SECItem *digest, int kmflag)
8705697Smcpowers {
8715697Smcpowers SECStatus rv = SECFailure;
8725697Smcpowers mp_int r_, s_; /* tuple (r', s') is received signature) */
8735697Smcpowers mp_int c, u1, u2, v; /* intermediate values used in verification */
8745697Smcpowers mp_int x1;
8755697Smcpowers mp_int n;
8765697Smcpowers mp_err err = MP_OKAY;
8775697Smcpowers ECParams *ecParams = NULL;
8785697Smcpowers SECItem pointC = { siBuffer, NULL, 0 };
8795697Smcpowers int slen; /* length in bytes of a half signature (r or s) */
8805697Smcpowers int flen; /* length in bytes of the field size */
8815697Smcpowers unsigned olen; /* length in bytes of the base point order */
8825697Smcpowers
8835697Smcpowers #if EC_DEBUG
8845697Smcpowers char mpstr[256];
8855697Smcpowers printf("ECDSA verification called\n");
8865697Smcpowers #endif
8875697Smcpowers
8885697Smcpowers /* Initialize MPI integers. */
8895697Smcpowers /* must happen before the first potential call to cleanup */
8905697Smcpowers MP_DIGITS(&r_) = 0;
8915697Smcpowers MP_DIGITS(&s_) = 0;
8925697Smcpowers MP_DIGITS(&c) = 0;
8935697Smcpowers MP_DIGITS(&u1) = 0;
8945697Smcpowers MP_DIGITS(&u2) = 0;
8955697Smcpowers MP_DIGITS(&x1) = 0;
8965697Smcpowers MP_DIGITS(&v) = 0;
8975697Smcpowers MP_DIGITS(&n) = 0;
8985697Smcpowers
8995697Smcpowers /* Check args */
9005697Smcpowers if (!key || !signature || !digest) {
9015697Smcpowers PORT_SetError(SEC_ERROR_INVALID_ARGS);
9025697Smcpowers goto cleanup;
9035697Smcpowers }
9045697Smcpowers
9055697Smcpowers ecParams = &(key->ecParams);
9065697Smcpowers flen = (ecParams->fieldID.size + 7) >> 3;
9075697Smcpowers olen = ecParams->order.len;
9085697Smcpowers if (signature->len == 0 || signature->len%2 != 0 ||
9095697Smcpowers signature->len > 2*olen) {
9105697Smcpowers PORT_SetError(SEC_ERROR_INPUT_LEN);
9115697Smcpowers goto cleanup;
9125697Smcpowers }
9135697Smcpowers slen = signature->len/2;
9145697Smcpowers
9155697Smcpowers SECITEM_AllocItem(NULL, &pointC, 2*flen + 1, kmflag);
9165697Smcpowers if (pointC.data == NULL)
9175697Smcpowers goto cleanup;
9185697Smcpowers
9195697Smcpowers CHECK_MPI_OK( mp_init(&r_, kmflag) );
9205697Smcpowers CHECK_MPI_OK( mp_init(&s_, kmflag) );
9215697Smcpowers CHECK_MPI_OK( mp_init(&c, kmflag) );
9225697Smcpowers CHECK_MPI_OK( mp_init(&u1, kmflag) );
9235697Smcpowers CHECK_MPI_OK( mp_init(&u2, kmflag) );
9245697Smcpowers CHECK_MPI_OK( mp_init(&x1, kmflag) );
9255697Smcpowers CHECK_MPI_OK( mp_init(&v, kmflag) );
9265697Smcpowers CHECK_MPI_OK( mp_init(&n, kmflag) );
9275697Smcpowers
9285697Smcpowers /*
9295697Smcpowers ** Convert received signature (r', s') into MPI integers.
9305697Smcpowers */
9315697Smcpowers CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, slen) );
9325697Smcpowers CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + slen, slen) );
9335697Smcpowers
9345697Smcpowers /*
9355697Smcpowers ** ANSI X9.62, Section 5.4.2, Steps 1 and 2
9365697Smcpowers **
9375697Smcpowers ** Verify that 0 < r' < n and 0 < s' < n
9385697Smcpowers */
9395697Smcpowers SECITEM_TO_MPINT(ecParams->order, &n);
9405697Smcpowers if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
9415697Smcpowers mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) {
9425697Smcpowers PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
9435697Smcpowers goto cleanup; /* will return rv == SECFailure */
9445697Smcpowers }
9455697Smcpowers
9465697Smcpowers /*
9475697Smcpowers ** ANSI X9.62, Section 5.4.2, Step 3
9485697Smcpowers **
9495697Smcpowers ** c = (s')**-1 mod n
9505697Smcpowers */
9515697Smcpowers CHECK_MPI_OK( mp_invmod(&s_, &n, &c) ); /* c = (s')**-1 mod n */
9525697Smcpowers
9535697Smcpowers /*
9545697Smcpowers ** ANSI X9.62, Section 5.4.2, Step 4
9555697Smcpowers **
9565697Smcpowers ** u1 = ((HASH(M')) * c) mod n
9575697Smcpowers */
9585697Smcpowers SECITEM_TO_MPINT(*digest, &u1); /* u1 = HASH(M) */
9595697Smcpowers
9605697Smcpowers /* In the definition of EC signing, digests are truncated
9615697Smcpowers * to the length of n in bits.
9625697Smcpowers * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
9635697Smcpowers if (digest->len*8 > ecParams->fieldID.size) { /* u1 = HASH(M') */
9645697Smcpowers mpl_rsh(&u1,&u1,digest->len*8- ecParams->fieldID.size);
9655697Smcpowers }
9665697Smcpowers
9675697Smcpowers #if EC_DEBUG
9685697Smcpowers mp_todecimal(&r_, mpstr);
9695697Smcpowers printf("r_: %s (dec)\n", mpstr);
9705697Smcpowers mp_todecimal(&s_, mpstr);
9715697Smcpowers printf("s_: %s (dec)\n", mpstr);
9725697Smcpowers mp_todecimal(&c, mpstr);
9735697Smcpowers printf("c : %s (dec)\n", mpstr);
9745697Smcpowers mp_todecimal(&u1, mpstr);
9755697Smcpowers printf("digest: %s (dec)\n", mpstr);
9765697Smcpowers #endif
9775697Smcpowers
9785697Smcpowers CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) ); /* u1 = u1 * c mod n */
9795697Smcpowers
9805697Smcpowers /*
9815697Smcpowers ** ANSI X9.62, Section 5.4.2, Step 4
9825697Smcpowers **
9835697Smcpowers ** u2 = ((r') * c) mod n
9845697Smcpowers */
9855697Smcpowers CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) );
9865697Smcpowers
9875697Smcpowers /*
9885697Smcpowers ** ANSI X9.62, Section 5.4.3, Step 1
9895697Smcpowers **
9905697Smcpowers ** Compute u1*G + u2*Q
9915697Smcpowers ** Here, A = u1.G B = u2.Q and C = A + B
9925697Smcpowers ** If the result, C, is the point at infinity, reject the signature
9935697Smcpowers */
9945697Smcpowers if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC, kmflag)
9955697Smcpowers != SECSuccess) {
9965697Smcpowers rv = SECFailure;
9975697Smcpowers goto cleanup;
9985697Smcpowers }
9995697Smcpowers if (ec_point_at_infinity(&pointC)) {
10005697Smcpowers PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
10015697Smcpowers rv = SECFailure;
10025697Smcpowers goto cleanup;
10035697Smcpowers }
10045697Smcpowers
10055697Smcpowers CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, flen) );
10065697Smcpowers
10075697Smcpowers /*
10085697Smcpowers ** ANSI X9.62, Section 5.4.4, Step 2
10095697Smcpowers **
10105697Smcpowers ** v = x1 mod n
10115697Smcpowers */
10125697Smcpowers CHECK_MPI_OK( mp_mod(&x1, &n, &v) );
10135697Smcpowers
10145697Smcpowers #if EC_DEBUG
10155697Smcpowers mp_todecimal(&r_, mpstr);
10165697Smcpowers printf("r_: %s (dec)\n", mpstr);
10175697Smcpowers mp_todecimal(&v, mpstr);
10185697Smcpowers printf("v : %s (dec)\n", mpstr);
10195697Smcpowers #endif
10205697Smcpowers
10215697Smcpowers /*
10225697Smcpowers ** ANSI X9.62, Section 5.4.4, Step 3
10235697Smcpowers **
10245697Smcpowers ** Verification: v == r'
10255697Smcpowers */
10265697Smcpowers if (mp_cmp(&v, &r_)) {
10275697Smcpowers PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
10285697Smcpowers rv = SECFailure; /* Signature failed to verify. */
10295697Smcpowers } else {
10305697Smcpowers rv = SECSuccess; /* Signature verified. */
10315697Smcpowers }
10325697Smcpowers
10335697Smcpowers #if EC_DEBUG
10345697Smcpowers mp_todecimal(&u1, mpstr);
10355697Smcpowers printf("u1: %s (dec)\n", mpstr);
10365697Smcpowers mp_todecimal(&u2, mpstr);
10375697Smcpowers printf("u2: %s (dec)\n", mpstr);
10385697Smcpowers mp_tohex(&x1, mpstr);
10395697Smcpowers printf("x1: %s\n", mpstr);
10405697Smcpowers mp_todecimal(&v, mpstr);
10415697Smcpowers printf("v : %s (dec)\n", mpstr);
10425697Smcpowers #endif
10435697Smcpowers
10445697Smcpowers cleanup:
10455697Smcpowers mp_clear(&r_);
10465697Smcpowers mp_clear(&s_);
10475697Smcpowers mp_clear(&c);
10485697Smcpowers mp_clear(&u1);
10495697Smcpowers mp_clear(&u2);
10505697Smcpowers mp_clear(&x1);
10515697Smcpowers mp_clear(&v);
10525697Smcpowers mp_clear(&n);
10535697Smcpowers
10545697Smcpowers if (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE);
10555697Smcpowers if (err) {
10565697Smcpowers MP_TO_SEC_ERROR(err);
10575697Smcpowers rv = SECFailure;
10585697Smcpowers }
10595697Smcpowers
10605697Smcpowers #if EC_DEBUG
10615697Smcpowers printf("ECDSA verification %s\n",
10625697Smcpowers (rv == SECSuccess) ? "succeeded" : "failed");
10635697Smcpowers #endif
10645697Smcpowers
10655697Smcpowers return rv;
10665697Smcpowers }
10675697Smcpowers
1068*10500SHai-May.Chao@Sun.COM /*
1069*10500SHai-May.Chao@Sun.COM * Copy all of the fields from srcParams into dstParams
1070*10500SHai-May.Chao@Sun.COM */
1071*10500SHai-May.Chao@Sun.COM SECStatus
EC_CopyParams(PRArenaPool * arena,ECParams * dstParams,const ECParams * srcParams)1072*10500SHai-May.Chao@Sun.COM EC_CopyParams(PRArenaPool *arena, ECParams *dstParams,
1073*10500SHai-May.Chao@Sun.COM const ECParams *srcParams)
1074*10500SHai-May.Chao@Sun.COM {
1075*10500SHai-May.Chao@Sun.COM SECStatus rv = SECFailure;
1076*10500SHai-May.Chao@Sun.COM
1077*10500SHai-May.Chao@Sun.COM dstParams->arena = arena;
1078*10500SHai-May.Chao@Sun.COM dstParams->type = srcParams->type;
1079*10500SHai-May.Chao@Sun.COM dstParams->fieldID.size = srcParams->fieldID.size;
1080*10500SHai-May.Chao@Sun.COM dstParams->fieldID.type = srcParams->fieldID.type;
1081*10500SHai-May.Chao@Sun.COM if (srcParams->fieldID.type == ec_field_GFp) {
1082*10500SHai-May.Chao@Sun.COM CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->fieldID.u.prime,
1083*10500SHai-May.Chao@Sun.COM &srcParams->fieldID.u.prime, 0));
1084*10500SHai-May.Chao@Sun.COM } else {
1085*10500SHai-May.Chao@Sun.COM CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->fieldID.u.poly,
1086*10500SHai-May.Chao@Sun.COM &srcParams->fieldID.u.poly, 0));
1087*10500SHai-May.Chao@Sun.COM }
1088*10500SHai-May.Chao@Sun.COM dstParams->fieldID.k1 = srcParams->fieldID.k1;
1089*10500SHai-May.Chao@Sun.COM dstParams->fieldID.k2 = srcParams->fieldID.k2;
1090*10500SHai-May.Chao@Sun.COM dstParams->fieldID.k3 = srcParams->fieldID.k3;
1091*10500SHai-May.Chao@Sun.COM CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curve.a,
1092*10500SHai-May.Chao@Sun.COM &srcParams->curve.a, 0));
1093*10500SHai-May.Chao@Sun.COM CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curve.b,
1094*10500SHai-May.Chao@Sun.COM &srcParams->curve.b, 0));
1095*10500SHai-May.Chao@Sun.COM CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curve.seed,
1096*10500SHai-May.Chao@Sun.COM &srcParams->curve.seed, 0));
1097*10500SHai-May.Chao@Sun.COM CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->base,
1098*10500SHai-May.Chao@Sun.COM &srcParams->base, 0));
1099*10500SHai-May.Chao@Sun.COM CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->order,
1100*10500SHai-May.Chao@Sun.COM &srcParams->order, 0));
1101*10500SHai-May.Chao@Sun.COM CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->DEREncoding,
1102*10500SHai-May.Chao@Sun.COM &srcParams->DEREncoding, 0));
1103*10500SHai-May.Chao@Sun.COM dstParams->name = srcParams->name;
1104*10500SHai-May.Chao@Sun.COM CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curveOID,
1105*10500SHai-May.Chao@Sun.COM &srcParams->curveOID, 0));
1106*10500SHai-May.Chao@Sun.COM dstParams->cofactor = srcParams->cofactor;
1107*10500SHai-May.Chao@Sun.COM
1108*10500SHai-May.Chao@Sun.COM return SECSuccess;
1109*10500SHai-May.Chao@Sun.COM
1110*10500SHai-May.Chao@Sun.COM cleanup:
1111*10500SHai-May.Chao@Sun.COM return SECFailure;
1112*10500SHai-May.Chao@Sun.COM }
1113