andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public
andre@0:  * License, v. 2.0. If a copy of the MPL was not distributed with this
andre@0:  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
andre@0: 
andre@0: #ifdef FREEBL_NO_DEPEND
andre@0: #include "stubs.h"
andre@0: #endif
andre@0: 
andre@0: 
andre@0: #include "blapi.h"
andre@0: #include "prerr.h"
andre@0: #include "secerr.h"
andre@0: #include "secmpi.h"
andre@0: #include "secitem.h"
andre@0: #include "mplogic.h"
andre@0: #include "ec.h"
andre@0: #include "ecl.h"
andre@0: 
andre@0: #ifndef NSS_DISABLE_ECC
andre@0: 
andre@0: /* 
andre@0:  * Returns true if pointP is the point at infinity, false otherwise
andre@0:  */
andre@0: PRBool
andre@0: ec_point_at_infinity(SECItem *pointP)
andre@0: {
andre@0:     unsigned int i;
andre@0: 
andre@0:     for (i = 1; i < pointP->len; i++) {
andre@0: 	if (pointP->data[i] != 0x00) return PR_FALSE;
andre@0:     }
andre@0: 
andre@0:     return PR_TRUE;
andre@0: }
andre@0: 
andre@0: /* 
andre@0:  * Computes scalar point multiplication pointQ = k1 * G + k2 * pointP for
andre@0:  * the curve whose parameters are encoded in params with base point G.
andre@0:  */
andre@0: SECStatus 
andre@0: ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2,
andre@0:              const SECItem *pointP, SECItem *pointQ)
andre@0: {
andre@0:     mp_int Px, Py, Qx, Qy;
andre@0:     mp_int Gx, Gy, order, irreducible, a, b;
andre@0: #if 0 /* currently don't support non-named curves */
andre@0:     unsigned int irr_arr[5];
andre@0: #endif
andre@0:     ECGroup *group = NULL;
andre@0:     SECStatus rv = SECFailure;
andre@0:     mp_err err = MP_OKAY;
andre@0:     int len;
andre@0: 
andre@0: #if EC_DEBUG
andre@0:     int i;
andre@0:     char mpstr[256];
andre@0: 
andre@0:     printf("ec_points_mul: params [len=%d]:", params->DEREncoding.len);
andre@0:     for (i = 0; i < params->DEREncoding.len; i++) 
andre@0: 	    printf("%02x:", params->DEREncoding.data[i]);
andre@0:     printf("\n");
andre@0: 
andre@0: 	if (k1 != NULL) {
andre@0: 		mp_tohex(k1, mpstr);
andre@0: 		printf("ec_points_mul: scalar k1: %s\n", mpstr);
andre@0: 		mp_todecimal(k1, mpstr);
andre@0: 		printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr);
andre@0: 	}
andre@0: 
andre@0: 	if (k2 != NULL) {
andre@0: 		mp_tohex(k2, mpstr);
andre@0: 		printf("ec_points_mul: scalar k2: %s\n", mpstr);
andre@0: 		mp_todecimal(k2, mpstr);
andre@0: 		printf("ec_points_mul: scalar k2: %s (dec)\n", mpstr);
andre@0: 	}
andre@0: 
andre@0: 	if (pointP != NULL) {
andre@0: 		printf("ec_points_mul: pointP [len=%d]:", pointP->len);
andre@0: 		for (i = 0; i < pointP->len; i++) 
andre@0: 			printf("%02x:", pointP->data[i]);
andre@0: 		printf("\n");
andre@0: 	}
andre@0: #endif
andre@0: 
andre@0: 	/* NOTE: We only support uncompressed points for now */
andre@0: 	len = (params->fieldID.size + 7) >> 3;
andre@0: 	if (pointP != NULL) {
andre@0: 		if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
andre@0: 			(pointP->len != (2 * len + 1))) {
andre@0: 			PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
andre@0: 			return SECFailure;
andre@0: 		};
andre@0: 	}
andre@0: 
andre@0: 	MP_DIGITS(&Px) = 0;
andre@0: 	MP_DIGITS(&Py) = 0;
andre@0: 	MP_DIGITS(&Qx) = 0;
andre@0: 	MP_DIGITS(&Qy) = 0;
andre@0: 	MP_DIGITS(&Gx) = 0;
andre@0: 	MP_DIGITS(&Gy) = 0;
andre@0: 	MP_DIGITS(&order) = 0;
andre@0: 	MP_DIGITS(&irreducible) = 0;
andre@0: 	MP_DIGITS(&a) = 0;
andre@0: 	MP_DIGITS(&b) = 0;
andre@0: 	CHECK_MPI_OK( mp_init(&Px) );
andre@0: 	CHECK_MPI_OK( mp_init(&Py) );
andre@0: 	CHECK_MPI_OK( mp_init(&Qx) );
andre@0: 	CHECK_MPI_OK( mp_init(&Qy) );
andre@0: 	CHECK_MPI_OK( mp_init(&Gx) );
andre@0: 	CHECK_MPI_OK( mp_init(&Gy) );
andre@0: 	CHECK_MPI_OK( mp_init(&order) );
andre@0: 	CHECK_MPI_OK( mp_init(&irreducible) );
andre@0: 	CHECK_MPI_OK( mp_init(&a) );
andre@0: 	CHECK_MPI_OK( mp_init(&b) );
andre@0: 
andre@0: 	if ((k2 != NULL) && (pointP != NULL)) {
andre@0: 		/* Initialize Px and Py */
andre@0: 		CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size) len) );
andre@0: 		CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) );
andre@0: 	}
andre@0: 
andre@0: 	/* construct from named params, if possible */
andre@0: 	if (params->name != ECCurve_noName) {
andre@0: 		group = ECGroup_fromName(params->name);
andre@0: 	}
andre@0: 
andre@0: #if 0 /* currently don't support non-named curves */
andre@0: 	if (group == NULL) {
andre@0: 		/* Set up mp_ints containing the curve coefficients */
andre@0: 		CHECK_MPI_OK( mp_read_unsigned_octets(&Gx, params->base.data + 1, 
andre@0: 										  (mp_size) len) );
andre@0: 		CHECK_MPI_OK( mp_read_unsigned_octets(&Gy, params->base.data + 1 + len, 
andre@0: 										  (mp_size) len) );
andre@0: 		SECITEM_TO_MPINT( params->order, &order );
andre@0: 		SECITEM_TO_MPINT( params->curve.a, &a );
andre@0: 		SECITEM_TO_MPINT( params->curve.b, &b );
andre@0: 		if (params->fieldID.type == ec_field_GFp) {
andre@0: 			SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible );
andre@0: 			group = ECGroup_consGFp(&irreducible, &a, &b, &Gx, &Gy, &order, params->cofactor);
andre@0: 		} else {
andre@0: 			SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible );
andre@0: 			irr_arr[0] = params->fieldID.size;
andre@0: 			irr_arr[1] = params->fieldID.k1;
andre@0: 			irr_arr[2] = params->fieldID.k2;
andre@0: 			irr_arr[3] = params->fieldID.k3;
andre@0: 			irr_arr[4] = 0;
andre@0: 			group = ECGroup_consGF2m(&irreducible, irr_arr, &a, &b, &Gx, &Gy, &order, params->cofactor);
andre@0: 		}
andre@0: 	}
andre@0: #endif
andre@0: 	if (group == NULL)
andre@0: 		goto cleanup;
andre@0: 
andre@0: 	if ((k2 != NULL) && (pointP != NULL)) {
andre@0: 		CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy) );
andre@0: 	} else {
andre@0: 		CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) );
andre@0:     }
andre@0: 
andre@0:     /* Construct the SECItem representation of point Q */
andre@0:     pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED;
andre@0:     CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1,
andre@0: 	                              (mp_size) len) );
andre@0:     CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len,
andre@0: 	                              (mp_size) len) );
andre@0: 
andre@0:     rv = SECSuccess;
andre@0: 
andre@0: #if EC_DEBUG
andre@0:     printf("ec_points_mul: pointQ [len=%d]:", pointQ->len);
andre@0:     for (i = 0; i < pointQ->len; i++) 
andre@0: 	    printf("%02x:", pointQ->data[i]);
andre@0:     printf("\n");
andre@0: #endif
andre@0: 
andre@0: cleanup:
andre@0:     ECGroup_free(group);
andre@0:     mp_clear(&Px);
andre@0:     mp_clear(&Py);
andre@0:     mp_clear(&Qx);
andre@0:     mp_clear(&Qy);
andre@0:     mp_clear(&Gx);
andre@0:     mp_clear(&Gy);
andre@0:     mp_clear(&order);
andre@0:     mp_clear(&irreducible);
andre@0:     mp_clear(&a);
andre@0:     mp_clear(&b);
andre@0:     if (err) {
andre@0: 	MP_TO_SEC_ERROR(err);
andre@0: 	rv = SECFailure;
andre@0:     }
andre@0: 
andre@0:     return rv;
andre@0: }
andre@0: #endif /* NSS_DISABLE_ECC */
andre@0: 
andre@0: /* Generates a new EC key pair. The private key is a supplied
andre@0:  * value and the public key is the result of performing a scalar 
andre@0:  * point multiplication of that value with the curve's base point.
andre@0:  */
andre@0: SECStatus 
andre@0: ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey, 
andre@0:     const unsigned char *privKeyBytes, int privKeyLen)
andre@0: {
andre@0:     SECStatus rv = SECFailure;
andre@0: #ifndef NSS_DISABLE_ECC
andre@0:     PLArenaPool *arena;
andre@0:     ECPrivateKey *key;
andre@0:     mp_int k;
andre@0:     mp_err err = MP_OKAY;
andre@0:     int len;
andre@0: 
andre@0: #if EC_DEBUG
andre@0:     printf("ec_NewKey called\n");
andre@0: #endif
andre@0:     MP_DIGITS(&k) = 0;
andre@0: 
andre@0:     if (!ecParams || !privKey || !privKeyBytes || (privKeyLen < 0)) {
andre@0: 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
andre@0: 	return SECFailure;
andre@0:     }
andre@0: 
andre@0:     /* Initialize an arena for the EC key. */
andre@0:     if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))
andre@0: 	return SECFailure;
andre@0: 
andre@0:     key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey));
andre@0:     if (!key) {
andre@0: 	PORT_FreeArena(arena, PR_TRUE);
andre@0: 	return SECFailure;
andre@0:     }
andre@0: 
andre@0:     /* Set the version number (SEC 1 section C.4 says it should be 1) */
andre@0:     SECITEM_AllocItem(arena, &key->version, 1);
andre@0:     key->version.data[0] = 1;
andre@0: 
andre@0:     /* Copy all of the fields from the ECParams argument to the
andre@0:      * ECParams structure within the private key.
andre@0:      */
andre@0:     key->ecParams.arena = arena;
andre@0:     key->ecParams.type = ecParams->type;
andre@0:     key->ecParams.fieldID.size = ecParams->fieldID.size;
andre@0:     key->ecParams.fieldID.type = ecParams->fieldID.type;
andre@0:     if (ecParams->fieldID.type == ec_field_GFp) {
andre@0: 	CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime,
andre@0: 	    &ecParams->fieldID.u.prime));
andre@0:     } else {
andre@0: 	CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.poly,
andre@0: 	    &ecParams->fieldID.u.poly));
andre@0:     }
andre@0:     key->ecParams.fieldID.k1 = ecParams->fieldID.k1;
andre@0:     key->ecParams.fieldID.k2 = ecParams->fieldID.k2;
andre@0:     key->ecParams.fieldID.k3 = ecParams->fieldID.k3;
andre@0:     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a,
andre@0: 	&ecParams->curve.a));
andre@0:     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b,
andre@0: 	&ecParams->curve.b));
andre@0:     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed,
andre@0: 	&ecParams->curve.seed));
andre@0:     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base,
andre@0: 	&ecParams->base));
andre@0:     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order,
andre@0: 	&ecParams->order));
andre@0:     key->ecParams.cofactor = ecParams->cofactor;
andre@0:     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding,
andre@0: 	&ecParams->DEREncoding));
andre@0:     key->ecParams.name = ecParams->name;
andre@0:     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID,
andre@0: 	&ecParams->curveOID));
andre@0: 
andre@0:     len = (ecParams->fieldID.size + 7) >> 3;
andre@0:     SECITEM_AllocItem(arena, &key->publicValue, 2*len + 1);
andre@0:     len = ecParams->order.len;
andre@0:     SECITEM_AllocItem(arena, &key->privateValue, len);
andre@0: 
andre@0:     /* Copy private key */
andre@0:     if (privKeyLen >= len) {
andre@0: 	memcpy(key->privateValue.data, privKeyBytes, len);
andre@0:     } else {
andre@0: 	memset(key->privateValue.data, 0, (len - privKeyLen));
andre@0: 	memcpy(key->privateValue.data + (len - privKeyLen), privKeyBytes, privKeyLen);
andre@0:     }
andre@0: 
andre@0:     /* Compute corresponding public key */
andre@0:     CHECK_MPI_OK( mp_init(&k) );
andre@0:     CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data, 
andre@0: 	(mp_size) len) );
andre@0: 
andre@0:     rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue));
andre@0:     if (rv != SECSuccess) goto cleanup;
andre@0:     *privKey = key;
andre@0: 
andre@0: cleanup:
andre@0:     mp_clear(&k);
andre@0:     if (rv)
andre@0: 	PORT_FreeArena(arena, PR_TRUE);
andre@0: 
andre@0: #if EC_DEBUG
andre@0:     printf("ec_NewKey returning %s\n", 
andre@0: 	(rv == SECSuccess) ? "success" : "failure");
andre@0: #endif
andre@0: #else
andre@0:     PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
andre@0: #endif /* NSS_DISABLE_ECC */
andre@0: 
andre@0:     return rv;
andre@0: 
andre@0: }
andre@0: 
andre@0: /* Generates a new EC key pair. The private key is a supplied
andre@0:  * random value (in seed) and the public key is the result of 
andre@0:  * performing a scalar point multiplication of that value with 
andre@0:  * the curve's base point.
andre@0:  */
andre@0: SECStatus 
andre@0: EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey, 
andre@0:     const unsigned char *seed, int seedlen)
andre@0: {
andre@0:     SECStatus rv = SECFailure;
andre@0: #ifndef NSS_DISABLE_ECC
andre@0:     rv = ec_NewKey(ecParams, privKey, seed, seedlen);
andre@0: #else
andre@0:     PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
andre@0: #endif /* NSS_DISABLE_ECC */
andre@0:     return rv;
andre@0: }
andre@0: 
andre@0: #ifndef NSS_DISABLE_ECC
andre@0: /* Generate a random private key using the algorithm A.4.1 of ANSI X9.62,
andre@0:  * modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the
andre@0:  * random number generator.
andre@0:  *
andre@0:  * Parameters
andre@0:  * - order: a buffer that holds the curve's group order
andre@0:  * - len: the length in octets of the order buffer
andre@0:  *
andre@0:  * Return Value
andre@0:  * Returns a buffer of len octets that holds the private key. The caller
andre@0:  * is responsible for freeing the buffer with PORT_ZFree.
andre@0:  */
andre@0: static unsigned char *
andre@0: ec_GenerateRandomPrivateKey(const unsigned char *order, int len)
andre@0: {
andre@0:     SECStatus rv = SECSuccess;
andre@0:     mp_err err;
andre@0:     unsigned char *privKeyBytes = NULL;
andre@0:     mp_int privKeyVal, order_1, one;
andre@0: 
andre@0:     MP_DIGITS(&privKeyVal) = 0;
andre@0:     MP_DIGITS(&order_1) = 0;
andre@0:     MP_DIGITS(&one) = 0;
andre@0:     CHECK_MPI_OK( mp_init(&privKeyVal) );
andre@0:     CHECK_MPI_OK( mp_init(&order_1) );
andre@0:     CHECK_MPI_OK( mp_init(&one) );
andre@0: 
andre@0:     /* Generates 2*len random bytes using the global random bit generator
andre@0:      * (which implements Algorithm 1 of FIPS 186-2 Change Notice 1) then
andre@0:      * reduces modulo the group order.
andre@0:      */
andre@0:     if ((privKeyBytes = PORT_Alloc(2*len)) == NULL) goto cleanup;
andre@0:     CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) );
andre@0:     CHECK_MPI_OK( mp_read_unsigned_octets(&privKeyVal, privKeyBytes, 2*len) );
andre@0:     CHECK_MPI_OK( mp_read_unsigned_octets(&order_1, order, len) );
andre@0:     CHECK_MPI_OK( mp_set_int(&one, 1) );
andre@0:     CHECK_MPI_OK( mp_sub(&order_1, &one, &order_1) );
andre@0:     CHECK_MPI_OK( mp_mod(&privKeyVal, &order_1, &privKeyVal) );
andre@0:     CHECK_MPI_OK( mp_add(&privKeyVal, &one, &privKeyVal) );
andre@0:     CHECK_MPI_OK( mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len) );
andre@0:     memset(privKeyBytes+len, 0, len);
andre@0: cleanup:
andre@0:     mp_clear(&privKeyVal);
andre@0:     mp_clear(&order_1);
andre@0:     mp_clear(&one);
andre@0:     if (err < MP_OKAY) {
andre@0: 	MP_TO_SEC_ERROR(err);
andre@0: 	rv = SECFailure;
andre@0:     }
andre@0:     if (rv != SECSuccess && privKeyBytes) {
andre@0: 	PORT_Free(privKeyBytes);
andre@0: 	privKeyBytes = NULL;
andre@0:     }
andre@0:     return privKeyBytes;
andre@0: }
andre@0: #endif /* NSS_DISABLE_ECC */
andre@0: 
andre@0: /* Generates a new EC key pair. The private key is a random value and
andre@0:  * the public key is the result of performing a scalar point multiplication
andre@0:  * of that value with the curve's base point.
andre@0:  */
andre@0: SECStatus 
andre@0: EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey)
andre@0: {
andre@0:     SECStatus rv = SECFailure;
andre@0: #ifndef NSS_DISABLE_ECC
andre@0:     int len;
andre@0:     unsigned char *privKeyBytes = NULL;
andre@0: 
andre@0:     if (!ecParams) {
andre@0: 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
andre@0: 	return SECFailure;
andre@0:     }
andre@0: 
andre@0:     len = ecParams->order.len;
andre@0:     privKeyBytes = ec_GenerateRandomPrivateKey(ecParams->order.data, len);
andre@0:     if (privKeyBytes == NULL) goto cleanup;
andre@0:     /* generate public key */
andre@0:     CHECK_SEC_OK( ec_NewKey(ecParams, privKey, privKeyBytes, len) );
andre@0: 
andre@0: cleanup:
andre@0:     if (privKeyBytes) {
andre@0: 	PORT_ZFree(privKeyBytes, len);
andre@0:     }
andre@0: #if EC_DEBUG
andre@0:     printf("EC_NewKey returning %s\n", 
andre@0: 	(rv == SECSuccess) ? "success" : "failure");
andre@0: #endif
andre@0: #else
andre@0:     PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
andre@0: #endif /* NSS_DISABLE_ECC */
andre@0:     
andre@0:     return rv;
andre@0: }
andre@0: 
andre@0: /* Validates an EC public key as described in Section 5.2.2 of
andre@0:  * X9.62. The ECDH primitive when used without the cofactor does
andre@0:  * not address small subgroup attacks, which may occur when the
andre@0:  * public key is not valid. These attacks can be prevented by 
andre@0:  * validating the public key before using ECDH.
andre@0:  */
andre@0: SECStatus 
andre@0: EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue)
andre@0: {
andre@0: #ifndef NSS_DISABLE_ECC
andre@0:     mp_int Px, Py;
andre@0:     ECGroup *group = NULL;
andre@0:     SECStatus rv = SECFailure;
andre@0:     mp_err err = MP_OKAY;
andre@0:     int len;
andre@0: 
andre@0:     if (!ecParams || !publicValue) {
andre@0: 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
andre@0: 	return SECFailure;
andre@0:     }
andre@0: 	
andre@0:     /* NOTE: We only support uncompressed points for now */
andre@0:     len = (ecParams->fieldID.size + 7) >> 3;
andre@0:     if (publicValue->data[0] != EC_POINT_FORM_UNCOMPRESSED) {
andre@0: 	PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
andre@0: 	return SECFailure;
andre@0:     } else if (publicValue->len != (2 * len + 1)) {
andre@0: 	PORT_SetError(SEC_ERROR_BAD_KEY);
andre@0: 	return SECFailure;
andre@0:     }
andre@0: 
andre@0:     MP_DIGITS(&Px) = 0;
andre@0:     MP_DIGITS(&Py) = 0;
andre@0:     CHECK_MPI_OK( mp_init(&Px) );
andre@0:     CHECK_MPI_OK( mp_init(&Py) );
andre@0: 
andre@0:     /* Initialize Px and Py */
andre@0:     CHECK_MPI_OK( mp_read_unsigned_octets(&Px, publicValue->data + 1, (mp_size) len) );
andre@0:     CHECK_MPI_OK( mp_read_unsigned_octets(&Py, publicValue->data + 1 + len, (mp_size) len) );
andre@0: 
andre@0:     /* construct from named params */
andre@0:     group = ECGroup_fromName(ecParams->name);
andre@0:     if (group == NULL) {
andre@0: 	/*
andre@0: 	 * ECGroup_fromName fails if ecParams->name is not a valid
andre@0: 	 * ECCurveName value, or if we run out of memory, or perhaps
andre@0: 	 * for other reasons.  Unfortunately if ecParams->name is a
andre@0: 	 * valid ECCurveName value, we don't know what the right error
andre@0: 	 * code should be because ECGroup_fromName doesn't return an
andre@0: 	 * error code to the caller.  Set err to MP_UNDEF because
andre@0: 	 * that's what ECGroup_fromName uses internally.
andre@0: 	 */
andre@0: 	if ((ecParams->name <= ECCurve_noName) ||
andre@0: 	    (ecParams->name >= ECCurve_pastLastCurve)) {
andre@0: 	    err = MP_BADARG;
andre@0: 	} else {
andre@0: 	    err = MP_UNDEF;
andre@0: 	}
andre@0: 	goto cleanup;
andre@0:     }
andre@0: 
andre@0:     /* validate public point */
andre@0:     if ((err = ECPoint_validate(group, &Px, &Py)) < MP_YES) {
andre@0: 	if (err == MP_NO) {
andre@0: 	    PORT_SetError(SEC_ERROR_BAD_KEY);
andre@0: 	    rv = SECFailure;
andre@0: 	    err = MP_OKAY;  /* don't change the error code */
andre@0: 	}
andre@0: 	goto cleanup;
andre@0:     }
andre@0: 
andre@0:     rv = SECSuccess;
andre@0: 
andre@0: cleanup:
andre@0:     ECGroup_free(group);
andre@0:     mp_clear(&Px);
andre@0:     mp_clear(&Py);
andre@0:     if (err) {
andre@0: 	MP_TO_SEC_ERROR(err);
andre@0: 	rv = SECFailure;
andre@0:     }
andre@0:     return rv;
andre@0: #else
andre@0:     PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
andre@0:     return SECFailure;
andre@0: #endif /* NSS_DISABLE_ECC */
andre@0: }
andre@0: 
andre@0: /* 
andre@0: ** Performs an ECDH key derivation by computing the scalar point
andre@0: ** multiplication of privateValue and publicValue (with or without the
andre@0: ** cofactor) and returns the x-coordinate of the resulting elliptic
andre@0: ** curve point in derived secret.  If successful, derivedSecret->data
andre@0: ** is set to the address of the newly allocated buffer containing the
andre@0: ** derived secret, and derivedSecret->len is the size of the secret
andre@0: ** produced. It is the caller's responsibility to free the allocated
andre@0: ** buffer containing the derived secret.
andre@0: */
andre@0: SECStatus 
andre@0: ECDH_Derive(SECItem  *publicValue, 
andre@0:             ECParams *ecParams,
andre@0:             SECItem  *privateValue,
andre@0:             PRBool    withCofactor,
andre@0:             SECItem  *derivedSecret)
andre@0: {
andre@0:     SECStatus rv = SECFailure;
andre@0: #ifndef NSS_DISABLE_ECC
andre@0:     unsigned int len = 0;
andre@0:     SECItem pointQ = {siBuffer, NULL, 0};
andre@0:     mp_int k; /* to hold the private value */
andre@0:     mp_int cofactor;
andre@0:     mp_err err = MP_OKAY;
andre@0: #if EC_DEBUG
andre@0:     int i;
andre@0: #endif
andre@0: 
andre@0:     if (!publicValue || !ecParams || !privateValue || 
andre@0: 	!derivedSecret) {
andre@0: 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
andre@0: 	return SECFailure;
andre@0:     }
andre@0: 
andre@0:     MP_DIGITS(&k) = 0;
andre@0:     memset(derivedSecret, 0, sizeof *derivedSecret);
andre@0:     len = (ecParams->fieldID.size + 7) >> 3;  
andre@0:     pointQ.len = 2*len + 1;
andre@0:     if ((pointQ.data = PORT_Alloc(2*len + 1)) == NULL) goto cleanup;
andre@0: 
andre@0:     CHECK_MPI_OK( mp_init(&k) );
andre@0:     CHECK_MPI_OK( mp_read_unsigned_octets(&k, privateValue->data, 
andre@0: 	                                  (mp_size) privateValue->len) );
andre@0: 
andre@0:     if (withCofactor && (ecParams->cofactor != 1)) {
andre@0: 	    /* multiply k with the cofactor */
andre@0: 	    MP_DIGITS(&cofactor) = 0;
andre@0: 	    CHECK_MPI_OK( mp_init(&cofactor) );
andre@0: 	    mp_set(&cofactor, ecParams->cofactor);
andre@0: 	    CHECK_MPI_OK( mp_mul(&k, &cofactor, &k) );
andre@0:     }
andre@0: 
andre@0:     /* Multiply our private key and peer's public point */
andre@0:     if (ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ) != SECSuccess)
andre@0: 	goto cleanup;
andre@0:     if (ec_point_at_infinity(&pointQ)) {
andre@0: 	PORT_SetError(SEC_ERROR_BAD_KEY);  /* XXX better error code? */
andre@0: 	goto cleanup;
andre@0:     }
andre@0: 
andre@0:     /* Allocate memory for the derived secret and copy
andre@0:      * the x co-ordinate of pointQ into it.
andre@0:      */
andre@0:     SECITEM_AllocItem(NULL, derivedSecret, len);
andre@0:     memcpy(derivedSecret->data, pointQ.data + 1, len);
andre@0: 
andre@0:     rv = SECSuccess;
andre@0: 
andre@0: #if EC_DEBUG
andre@0:     printf("derived_secret:\n");
andre@0:     for (i = 0; i < derivedSecret->len; i++) 
andre@0: 	printf("%02x:", derivedSecret->data[i]);
andre@0:     printf("\n");
andre@0: #endif
andre@0: 
andre@0: cleanup:
andre@0:     mp_clear(&k);
andre@0: 
andre@0:     if (err) {
andre@0: 	MP_TO_SEC_ERROR(err);
andre@0:     }
andre@0: 
andre@0:     if (pointQ.data) {
andre@0: 	PORT_ZFree(pointQ.data, 2*len + 1);
andre@0:     }
andre@0: #else
andre@0:     PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
andre@0: #endif /* NSS_DISABLE_ECC */
andre@0: 
andre@0:     return rv;
andre@0: }
andre@0: 
andre@0: /* Computes the ECDSA signature (a concatenation of two values r and s)
andre@0:  * on the digest using the given key and the random value kb (used in
andre@0:  * computing s).
andre@0:  */
andre@0: SECStatus 
andre@0: ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, 
andre@0:     const SECItem *digest, const unsigned char *kb, const int kblen)
andre@0: {
andre@0:     SECStatus rv = SECFailure;
andre@0: #ifndef NSS_DISABLE_ECC
andre@0:     mp_int x1;
andre@0:     mp_int d, k;     /* private key, random integer */
andre@0:     mp_int r, s;     /* tuple (r, s) is the signature */
andre@0:     mp_int n;
andre@0:     mp_err err = MP_OKAY;
andre@0:     ECParams *ecParams = NULL;
andre@0:     SECItem kGpoint = { siBuffer, NULL, 0};
andre@0:     int flen = 0;    /* length in bytes of the field size */
andre@0:     unsigned olen;   /* length in bytes of the base point order */
andre@0:     unsigned obits;  /* length in bits  of the base point order */
andre@0: 
andre@0: #if EC_DEBUG
andre@0:     char mpstr[256];
andre@0: #endif
andre@0: 
andre@0:     /* Initialize MPI integers. */
andre@0:     /* must happen before the first potential call to cleanup */
andre@0:     MP_DIGITS(&x1) = 0;
andre@0:     MP_DIGITS(&d) = 0;
andre@0:     MP_DIGITS(&k) = 0;
andre@0:     MP_DIGITS(&r) = 0;
andre@0:     MP_DIGITS(&s) = 0;
andre@0:     MP_DIGITS(&n) = 0;
andre@0: 
andre@0:     /* Check args */
andre@0:     if (!key || !signature || !digest || !kb || (kblen < 0)) {
andre@0: 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
andre@0: 	goto cleanup;
andre@0:     }
andre@0: 
andre@0:     ecParams = &(key->ecParams);
andre@0:     flen = (ecParams->fieldID.size + 7) >> 3;
andre@0:     olen = ecParams->order.len;  
andre@0:     if (signature->data == NULL) {
andre@0: 	/* a call to get the signature length only */
andre@0: 	goto finish;
andre@0:     }
andre@0:     if (signature->len < 2*olen) {
andre@0: 	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
andre@0: 	goto cleanup;
andre@0:     }
andre@0: 
andre@0: 
andre@0:     CHECK_MPI_OK( mp_init(&x1) );
andre@0:     CHECK_MPI_OK( mp_init(&d) );
andre@0:     CHECK_MPI_OK( mp_init(&k) );
andre@0:     CHECK_MPI_OK( mp_init(&r) );
andre@0:     CHECK_MPI_OK( mp_init(&s) );
andre@0:     CHECK_MPI_OK( mp_init(&n) );
andre@0: 
andre@0:     SECITEM_TO_MPINT( ecParams->order, &n );
andre@0:     SECITEM_TO_MPINT( key->privateValue, &d );
andre@0: 
andre@0:     CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) );
andre@0:     /* Make sure k is in the interval [1, n-1] */
andre@0:     if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) {
andre@0: #if EC_DEBUG
andre@0:         printf("k is outside [1, n-1]\n");
andre@0:         mp_tohex(&k, mpstr);
andre@0: 	printf("k : %s \n", mpstr);
andre@0:         mp_tohex(&n, mpstr);
andre@0: 	printf("n : %s \n", mpstr);
andre@0: #endif
andre@0: 	PORT_SetError(SEC_ERROR_NEED_RANDOM);
andre@0: 	goto cleanup;
andre@0:     }
andre@0: 
andre@0:     /*
andre@0:     ** We do not want timing information to leak the length of k,
andre@0:     ** so we compute k*G using an equivalent scalar of fixed
andre@0:     ** bit-length.
andre@0:     ** Fix based on patch for ECDSA timing attack in the paper
andre@0:     ** by Billy Bob Brumley and Nicola Tuveri at
andre@0:     **   http://eprint.iacr.org/2011/232
andre@0:     **
andre@0:     ** How do we convert k to a value of a fixed bit-length?
andre@0:     ** k starts off as an integer satisfying 0 <= k < n.  Hence,
andre@0:     ** n <= k+n < 2n, which means k+n has either the same number
andre@0:     ** of bits as n or one more bit than n.  If k+n has the same
andre@0:     ** number of bits as n, the second addition ensures that the
andre@0:     ** final value has exactly one more bit than n.  Thus, we
andre@0:     ** always end up with a value that exactly one more bit than n.
andre@0:     */
andre@0:     CHECK_MPI_OK( mp_add(&k, &n, &k) );
andre@0:     if (mpl_significant_bits(&k) <= mpl_significant_bits(&n)) {
andre@0: 	CHECK_MPI_OK( mp_add(&k, &n, &k) );
andre@0:     }
andre@0: 
andre@0:     /* 
andre@0:     ** ANSI X9.62, Section 5.3.2, Step 2
andre@0:     **
andre@0:     ** Compute kG
andre@0:     */
andre@0:     kGpoint.len = 2*flen + 1;
andre@0:     kGpoint.data = PORT_Alloc(2*flen + 1);
andre@0:     if ((kGpoint.data == NULL) ||
andre@0: 	(ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint)
andre@0: 	    != SECSuccess))
andre@0: 	goto cleanup;
andre@0: 
andre@0:     /* 
andre@0:     ** ANSI X9.62, Section 5.3.3, Step 1
andre@0:     **
andre@0:     ** Extract the x co-ordinate of kG into x1
andre@0:     */
andre@0:     CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1, 
andre@0: 	                                  (mp_size) flen) );
andre@0: 
andre@0:     /* 
andre@0:     ** ANSI X9.62, Section 5.3.3, Step 2
andre@0:     **
andre@0:     ** r = x1 mod n  NOTE: n is the order of the curve
andre@0:     */
andre@0:     CHECK_MPI_OK( mp_mod(&x1, &n, &r) );
andre@0: 
andre@0:     /*
andre@0:     ** ANSI X9.62, Section 5.3.3, Step 3
andre@0:     **
andre@0:     ** verify r != 0 
andre@0:     */
andre@0:     if (mp_cmp_z(&r) == 0) {
andre@0: 	PORT_SetError(SEC_ERROR_NEED_RANDOM);
andre@0: 	goto cleanup;
andre@0:     }
andre@0: 
andre@0:     /*                                  
andre@0:     ** ANSI X9.62, Section 5.3.3, Step 4
andre@0:     **
andre@0:     ** s = (k**-1 * (HASH(M) + d*r)) mod n 
andre@0:     */
andre@0:     SECITEM_TO_MPINT(*digest, &s);        /* s = HASH(M)     */
andre@0: 
andre@0:     /* In the definition of EC signing, digests are truncated
andre@0:      * to the length of n in bits. 
andre@0:      * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
andre@0:     CHECK_MPI_OK( (obits = mpl_significant_bits(&n)) );
andre@0:     if (digest->len*8 > obits) {
andre@0: 	mpl_rsh(&s,&s,digest->len*8 - obits);
andre@0:     }
andre@0: 
andre@0: #if EC_DEBUG
andre@0:     mp_todecimal(&n, mpstr);
andre@0:     printf("n : %s (dec)\n", mpstr);
andre@0:     mp_todecimal(&d, mpstr);
andre@0:     printf("d : %s (dec)\n", mpstr);
andre@0:     mp_tohex(&x1, mpstr);
andre@0:     printf("x1: %s\n", mpstr);
andre@0:     mp_todecimal(&s, mpstr);
andre@0:     printf("digest: %s (decimal)\n", mpstr);
andre@0:     mp_todecimal(&r, mpstr);
andre@0:     printf("r : %s (dec)\n", mpstr);
andre@0:     mp_tohex(&r, mpstr);
andre@0:     printf("r : %s\n", mpstr);
andre@0: #endif
andre@0: 
andre@0:     CHECK_MPI_OK( mp_invmod(&k, &n, &k) );      /* k = k**-1 mod n */
andre@0:     CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) );  /* d = d * r mod n */
andre@0:     CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) );  /* s = s + d mod n */
andre@0:     CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) );  /* s = s * k mod n */
andre@0: 
andre@0: #if EC_DEBUG
andre@0:     mp_todecimal(&s, mpstr);
andre@0:     printf("s : %s (dec)\n", mpstr);
andre@0:     mp_tohex(&s, mpstr);
andre@0:     printf("s : %s\n", mpstr);
andre@0: #endif
andre@0: 
andre@0:     /*
andre@0:     ** ANSI X9.62, Section 5.3.3, Step 5
andre@0:     **
andre@0:     ** verify s != 0
andre@0:     */
andre@0:     if (mp_cmp_z(&s) == 0) {
andre@0: 	PORT_SetError(SEC_ERROR_NEED_RANDOM);
andre@0: 	goto cleanup;
andre@0:     }
andre@0: 
andre@0:    /*
andre@0:     **
andre@0:     ** Signature is tuple (r, s)
andre@0:     */
andre@0:     CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, olen) );
andre@0:     CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + olen, olen) );
andre@0: finish:
andre@0:     signature->len = 2*olen;
andre@0: 
andre@0:     rv = SECSuccess;
andre@0:     err = MP_OKAY;
andre@0: cleanup:
andre@0:     mp_clear(&x1);
andre@0:     mp_clear(&d);
andre@0:     mp_clear(&k);
andre@0:     mp_clear(&r);
andre@0:     mp_clear(&s);
andre@0:     mp_clear(&n);
andre@0: 
andre@0:     if (kGpoint.data) {
andre@0: 	PORT_ZFree(kGpoint.data, 2*flen + 1);
andre@0:     }
andre@0: 
andre@0:     if (err) {
andre@0: 	MP_TO_SEC_ERROR(err);
andre@0: 	rv = SECFailure;
andre@0:     }
andre@0: 
andre@0: #if EC_DEBUG
andre@0:     printf("ECDSA signing with seed %s\n",
andre@0: 	(rv == SECSuccess) ? "succeeded" : "failed");
andre@0: #endif
andre@0: #else
andre@0:     PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
andre@0: #endif /* NSS_DISABLE_ECC */
andre@0: 
andre@0:    return rv;
andre@0: }
andre@0: 
andre@0: /*
andre@0: ** Computes the ECDSA signature on the digest using the given key 
andre@0: ** and a random seed.
andre@0: */
andre@0: SECStatus 
andre@0: ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest)
andre@0: {
andre@0:     SECStatus rv = SECFailure;
andre@0: #ifndef NSS_DISABLE_ECC
andre@0:     int len;
andre@0:     unsigned char *kBytes= NULL;
andre@0: 
andre@0:     if (!key) {
andre@0: 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
andre@0: 	return SECFailure;
andre@0:     }
andre@0: 
andre@0:     /* Generate random value k */
andre@0:     len = key->ecParams.order.len;
andre@0:     kBytes = ec_GenerateRandomPrivateKey(key->ecParams.order.data, len);
andre@0:     if (kBytes == NULL) goto cleanup;
andre@0: 
andre@0:     /* Generate ECDSA signature with the specified k value */
andre@0:     rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len);
andre@0: 
andre@0: cleanup:    
andre@0:     if (kBytes) {
andre@0: 	PORT_ZFree(kBytes, len);
andre@0:     }
andre@0: 
andre@0: #if EC_DEBUG
andre@0:     printf("ECDSA signing %s\n",
andre@0: 	(rv == SECSuccess) ? "succeeded" : "failed");
andre@0: #endif
andre@0: #else
andre@0:     PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
andre@0: #endif /* NSS_DISABLE_ECC */
andre@0: 
andre@0:     return rv;
andre@0: }
andre@0: 
andre@0: /*
andre@0: ** Checks the signature on the given digest using the key provided.
andre@0: */
andre@0: SECStatus 
andre@0: ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, 
andre@0:                  const SECItem *digest)
andre@0: {
andre@0:     SECStatus rv = SECFailure;
andre@0: #ifndef NSS_DISABLE_ECC
andre@0:     mp_int r_, s_;           /* tuple (r', s') is received signature) */
andre@0:     mp_int c, u1, u2, v;     /* intermediate values used in verification */
andre@0:     mp_int x1;
andre@0:     mp_int n;
andre@0:     mp_err err = MP_OKAY;
andre@0:     ECParams *ecParams = NULL;
andre@0:     SECItem pointC = { siBuffer, NULL, 0 };
andre@0:     int slen;       /* length in bytes of a half signature (r or s) */
andre@0:     int flen;       /* length in bytes of the field size */
andre@0:     unsigned olen;  /* length in bytes of the base point order */
andre@0:     unsigned obits; /* length in bits  of the base point order */
andre@0: 
andre@0: #if EC_DEBUG
andre@0:     char mpstr[256];
andre@0:     printf("ECDSA verification called\n");
andre@0: #endif
andre@0: 
andre@0:     /* Initialize MPI integers. */
andre@0:     /* must happen before the first potential call to cleanup */
andre@0:     MP_DIGITS(&r_) = 0;
andre@0:     MP_DIGITS(&s_) = 0;
andre@0:     MP_DIGITS(&c) = 0;
andre@0:     MP_DIGITS(&u1) = 0;
andre@0:     MP_DIGITS(&u2) = 0;
andre@0:     MP_DIGITS(&x1) = 0;
andre@0:     MP_DIGITS(&v)  = 0;
andre@0:     MP_DIGITS(&n)  = 0;
andre@0: 
andre@0:     /* Check args */
andre@0:     if (!key || !signature || !digest) {
andre@0: 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
andre@0: 	goto cleanup;
andre@0:     }
andre@0: 
andre@0:     ecParams = &(key->ecParams);
andre@0:     flen = (ecParams->fieldID.size + 7) >> 3;  
andre@0:     olen = ecParams->order.len;  
andre@0:     if (signature->len == 0 || signature->len%2 != 0 ||
andre@0: 	signature->len > 2*olen) {
andre@0: 	PORT_SetError(SEC_ERROR_INPUT_LEN);
andre@0: 	goto cleanup;
andre@0:     }
andre@0:     slen = signature->len/2;
andre@0: 
andre@0:     SECITEM_AllocItem(NULL, &pointC, 2*flen + 1);
andre@0:     if (pointC.data == NULL)
andre@0: 	goto cleanup;
andre@0: 
andre@0:     CHECK_MPI_OK( mp_init(&r_) );
andre@0:     CHECK_MPI_OK( mp_init(&s_) );
andre@0:     CHECK_MPI_OK( mp_init(&c)  );
andre@0:     CHECK_MPI_OK( mp_init(&u1) );
andre@0:     CHECK_MPI_OK( mp_init(&u2) );
andre@0:     CHECK_MPI_OK( mp_init(&x1)  );
andre@0:     CHECK_MPI_OK( mp_init(&v)  );
andre@0:     CHECK_MPI_OK( mp_init(&n)  );
andre@0: 
andre@0:     /*
andre@0:     ** Convert received signature (r', s') into MPI integers.
andre@0:     */
andre@0:     CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, slen) );
andre@0:     CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + slen, slen) );
andre@0:                                           
andre@0:     /* 
andre@0:     ** ANSI X9.62, Section 5.4.2, Steps 1 and 2
andre@0:     **
andre@0:     ** Verify that 0 < r' < n and 0 < s' < n
andre@0:     */
andre@0:     SECITEM_TO_MPINT(ecParams->order, &n);
andre@0:     if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
andre@0:         mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) {
andre@0: 	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
andre@0: 	goto cleanup; /* will return rv == SECFailure */
andre@0:     }
andre@0: 
andre@0:     /*
andre@0:     ** ANSI X9.62, Section 5.4.2, Step 3
andre@0:     **
andre@0:     ** c = (s')**-1 mod n
andre@0:     */
andre@0:     CHECK_MPI_OK( mp_invmod(&s_, &n, &c) );      /* c = (s')**-1 mod n */
andre@0: 
andre@0:     /*
andre@0:     ** ANSI X9.62, Section 5.4.2, Step 4
andre@0:     **
andre@0:     ** u1 = ((HASH(M')) * c) mod n
andre@0:     */
andre@0:     SECITEM_TO_MPINT(*digest, &u1);                  /* u1 = HASH(M)     */
andre@0: 
andre@0:     /* In the definition of EC signing, digests are truncated
andre@0:      * to the length of n in bits. 
andre@0:      * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
andre@0:     CHECK_MPI_OK( (obits = mpl_significant_bits(&n)) );
andre@0:     if (digest->len*8 > obits) {  /* u1 = HASH(M')     */
andre@0: 	mpl_rsh(&u1,&u1,digest->len*8 - obits);
andre@0:     }
andre@0: 
andre@0: #if EC_DEBUG
andre@0:     mp_todecimal(&r_, mpstr);
andre@0:     printf("r_: %s (dec)\n", mpstr);
andre@0:     mp_todecimal(&s_, mpstr);
andre@0:     printf("s_: %s (dec)\n", mpstr);
andre@0:     mp_todecimal(&c, mpstr);
andre@0:     printf("c : %s (dec)\n", mpstr);
andre@0:     mp_todecimal(&u1, mpstr);
andre@0:     printf("digest: %s (dec)\n", mpstr);
andre@0: #endif
andre@0: 
andre@0:     CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) );  /* u1 = u1 * c mod n */
andre@0: 
andre@0:     /*
andre@0:     ** ANSI X9.62, Section 5.4.2, Step 4
andre@0:     **
andre@0:     ** u2 = ((r') * c) mod n
andre@0:     */
andre@0:     CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) );
andre@0: 
andre@0:     /*
andre@0:     ** ANSI X9.62, Section 5.4.3, Step 1
andre@0:     **
andre@0:     ** Compute u1*G + u2*Q
andre@0:     ** Here, A = u1.G     B = u2.Q    and   C = A + B
andre@0:     ** If the result, C, is the point at infinity, reject the signature
andre@0:     */
andre@0:     if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC)
andre@0: 	!= SECSuccess) {
andre@0: 	rv = SECFailure;
andre@0: 	goto cleanup;
andre@0:     }
andre@0:     if (ec_point_at_infinity(&pointC)) {
andre@0: 	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
andre@0: 	rv = SECFailure;
andre@0: 	goto cleanup;
andre@0:     }
andre@0: 
andre@0:     CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, flen) );
andre@0: 
andre@0:     /*
andre@0:     ** ANSI X9.62, Section 5.4.4, Step 2
andre@0:     **
andre@0:     ** v = x1 mod n
andre@0:     */
andre@0:     CHECK_MPI_OK( mp_mod(&x1, &n, &v) );
andre@0: 
andre@0: #if EC_DEBUG
andre@0:     mp_todecimal(&r_, mpstr);
andre@0:     printf("r_: %s (dec)\n", mpstr);
andre@0:     mp_todecimal(&v, mpstr);
andre@0:     printf("v : %s (dec)\n", mpstr);
andre@0: #endif
andre@0: 
andre@0:     /*
andre@0:     ** ANSI X9.62, Section 5.4.4, Step 3
andre@0:     **
andre@0:     ** Verification:  v == r'
andre@0:     */
andre@0:     if (mp_cmp(&v, &r_)) {
andre@0: 	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
andre@0: 	rv = SECFailure; /* Signature failed to verify. */
andre@0:     } else {
andre@0: 	rv = SECSuccess; /* Signature verified. */
andre@0:     }
andre@0: 
andre@0: #if EC_DEBUG
andre@0:     mp_todecimal(&u1, mpstr);
andre@0:     printf("u1: %s (dec)\n", mpstr);
andre@0:     mp_todecimal(&u2, mpstr);
andre@0:     printf("u2: %s (dec)\n", mpstr);
andre@0:     mp_tohex(&x1, mpstr);
andre@0:     printf("x1: %s\n", mpstr);
andre@0:     mp_todecimal(&v, mpstr);
andre@0:     printf("v : %s (dec)\n", mpstr);
andre@0: #endif
andre@0: 
andre@0: cleanup:
andre@0:     mp_clear(&r_);
andre@0:     mp_clear(&s_);
andre@0:     mp_clear(&c);
andre@0:     mp_clear(&u1);
andre@0:     mp_clear(&u2);
andre@0:     mp_clear(&x1);
andre@0:     mp_clear(&v);
andre@0:     mp_clear(&n);
andre@0: 
andre@0:     if (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE);
andre@0:     if (err) {
andre@0: 	MP_TO_SEC_ERROR(err);
andre@0: 	rv = SECFailure;
andre@0:     }
andre@0: 
andre@0: #if EC_DEBUG
andre@0:     printf("ECDSA verification %s\n",
andre@0: 	(rv == SECSuccess) ? "succeeded" : "failed");
andre@0: #endif
andre@0: #else
andre@0:     PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
andre@0: #endif /* NSS_DISABLE_ECC */
andre@0: 
andre@0:     return rv;
andre@0: }
andre@0: