           /*
            * ***** BEGIN LICENSE BLOCK *****
            * Version: MPL 1.1/GPL 2.0/LGPL 2.1
            *
            * The contents of this file are subject to the Mozilla Public License Version
            * 1.1 (the "License"); you may not use this file except in compliance with
            * the License. You may obtain a copy of the License at
            * http://www.mozilla.org/MPL/
            *
            * Software distributed under the License is distributed on an "AS IS" basis,
            * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
            * for the specific language governing rights and limitations under the
            * License.
            *
            * The Original Code is the Elliptic Curve Cryptography library.
            *
            * The Initial Developer of the Original Code is
            * Sun Microsystems, Inc.
            * Portions created by the Initial Developer are Copyright (C) 2003
            * the Initial Developer. All Rights Reserved.
            *
            * Contributor(s):
            *   Dr Vipul Gupta <vipul.gupta@sun.com> and
            *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
            *
            * Alternatively, the contents of this file may be used under the terms of
            * either the GNU General Public License Version 2 or later (the "GPL"), or
            * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
            * in which case the provisions of the GPL or the LGPL are applicable instead
            * of those above. If you wish to allow use of your version of this file only
            * under the terms of either the GPL or the LGPL, and not to allow others to
            * use your version of this file under the terms of the MPL, indicate your
            * decision by deleting the provisions above and replace them with the notice
            * and other provisions required by the GPL or the LGPL. If you do not delete
            * the provisions above, a recipient may use your version of this file under
            * the terms of any one of the MPL, the GPL or the LGPL.
            *
            * ***** END LICENSE BLOCK ***** */
           
           #include "blapi.h"
           #include "prerr.h"
           #include "secerr.h"
           #include "secmpi.h"
           #include "secitem.h"
           #include "mplogic.h"
           #include "ec.h"
           #include "ecl.h"
           
           #ifdef NSS_ENABLE_ECC
           
           /* 
            * Returns true if pointP is the point at infinity, false otherwise
            */
           PRBool
           ec_point_at_infinity(SECItem *pointP)
           {
               unsigned int i;
           
  13319 ->     for (i = 1; i < pointP->len; i++) {
  13319 -> 	if (pointP->data[i] != 0x00) return PR_FALSE;
               }
           
     ##### ->     return PR_TRUE;
           }
           
           /* 
            * Computes scalar point multiplication pointQ = k1 * G + k2 * pointP for
            * the curve whose parameters are encoded in params with base point G.
            */
           SECStatus 
           ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2,
                        const SECItem *pointP, SECItem *pointQ)
           {
               mp_int Px, Py, Qx, Qy;
               mp_int Gx, Gy, order, irreducible, a, b;
           #if 0 /* currently don't support non-named curves */
               unsigned int irr_arr[5];
           #endif
  19203 ->     ECGroup *group = NULL;
  19203 ->     SECStatus rv = SECFailure;
  19203 ->     mp_err err = MP_OKAY;
               int len;
           
           #if EC_DEBUG
               int i;
               char mpstr[256];
           
               printf("ec_points_mul: params [len=%d]:", params->DEREncoding.len);
               for (i = 0; i < params->DEREncoding.len; i++) 
           	    printf("%02x:", params->DEREncoding.data[i]);
               printf("\n");
           
           	if (k1 != NULL) {
           		mp_tohex(k1, mpstr);
           		printf("ec_points_mul: scalar k1: %s\n", mpstr);
           		mp_todecimal(k1, mpstr);
           		printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr);
           	}
           
           	if (k2 != NULL) {
           		mp_tohex(k2, mpstr);
           		printf("ec_points_mul: scalar k2: %s\n", mpstr);
           		mp_todecimal(k2, mpstr);
           		printf("ec_points_mul: scalar k2: %s (dec)\n", mpstr);
           	}
           
           	if (pointP != NULL) {
           		printf("ec_points_mul: pointP [len=%d]:", pointP->len);
           		for (i = 0; i < pointP->len; i++) 
           			printf("%02x:", pointP->data[i]);
           		printf("\n");
           	}
           #endif
           
           	/* NOTE: We only support uncompressed points for now */
  19203 -> 	len = (params->fieldID.size + 7) >> 3;
  19203 -> 	if (pointP != NULL) {
           		if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
  12166 -> 			(pointP->len != (2 * len + 1))) {
     ##### -> 			return SECFailure;
           		};
           	}
           
  19203 -> 	MP_DIGITS(&Px) = 0;
  19203 -> 	MP_DIGITS(&Py) = 0;
  19203 -> 	MP_DIGITS(&Qx) = 0;
  19203 -> 	MP_DIGITS(&Qy) = 0;
  19200 -> 	MP_DIGITS(&Gx) = 0;
  19203 -> 	MP_DIGITS(&Gy) = 0;
  19203 -> 	MP_DIGITS(&order) = 0;
  19203 -> 	MP_DIGITS(&irreducible) = 0;
  19203 -> 	MP_DIGITS(&a) = 0;
  19203 -> 	MP_DIGITS(&b) = 0;
  19203 -> 	CHECK_MPI_OK( mp_init(&Px) );
  19203 -> 	CHECK_MPI_OK( mp_init(&Py) );
  19203 -> 	CHECK_MPI_OK( mp_init(&Qx) );
  19203 -> 	CHECK_MPI_OK( mp_init(&Qy) );
  19203 -> 	CHECK_MPI_OK( mp_init(&Gx) );
  19203 -> 	CHECK_MPI_OK( mp_init(&Gy) );
  19203 -> 	CHECK_MPI_OK( mp_init(&order) );
  19203 -> 	CHECK_MPI_OK( mp_init(&irreducible) );
  19203 -> 	CHECK_MPI_OK( mp_init(&a) );
  19203 -> 	CHECK_MPI_OK( mp_init(&b) );
           
  19203 -> 	if ((k2 != NULL) && (pointP != NULL)) {
           		/* Initialize Px and Py */
  12166 -> 		CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size) len) );
  12166 -> 		CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) );
           	}
           
           	/* construct from named params, if possible */
  19203 -> 	if (params->name != ECCurve_noName) {
  19203 -> 		group = ECGroup_fromName(params->name);
           	}
           
           #if 0 /* currently don't support non-named curves */
           	if (group == NULL) {
           		/* Set up mp_ints containing the curve coefficients */
           		CHECK_MPI_OK( mp_read_unsigned_octets(&Gx, params->base.data + 1, 
           										  (mp_size) len) );
           		CHECK_MPI_OK( mp_read_unsigned_octets(&Gy, params->base.data + 1 + len, 
           										  (mp_size) len) );
           		SECITEM_TO_MPINT( params->order, &order );
           		SECITEM_TO_MPINT( params->curve.a, &a );
           		SECITEM_TO_MPINT( params->curve.b, &b );
           		if (params->fieldID.type == ec_field_GFp) {
           			SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible );
           			group = ECGroup_consGFp(&irreducible, &a, &b, &Gx, &Gy, &order, params->cofactor);
           		} else {
           			SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible );
           			irr_arr[0] = params->fieldID.size;
           			irr_arr[1] = params->fieldID.k1;
           			irr_arr[2] = params->fieldID.k2;
           			irr_arr[3] = params->fieldID.k3;
           			irr_arr[4] = 0;
           			group = ECGroup_consGF2m(&irreducible, irr_arr, &a, &b, &Gx, &Gy, &order, params->cofactor);
           		}
           	}
           #endif
  19203 -> 	if (group == NULL)
     ##### -> 		goto cleanup;
           
  19203 -> 	if ((k2 != NULL) && (pointP != NULL)) {
  12166 -> 		CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy) );
           	} else {
   7037 -> 		CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) );
               }
           
               /* Construct the SECItem representation of point Q */
  19203 ->     pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED;
  19203 ->     CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1,
           	                              (mp_size) len) );
  19203 ->     CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len,
           	                              (mp_size) len) );
           
  19203 ->     rv = SECSuccess;
           
           #if EC_DEBUG
               printf("ec_points_mul: pointQ [len=%d]:", pointQ->len);
               for (i = 0; i < pointQ->len; i++) 
           	    printf("%02x:", pointQ->data[i]);
               printf("\n");
           #endif
           
           cleanup:
  19203 ->     ECGroup_free(group);
  19203 ->     mp_clear(&Px);
  19203 ->     mp_clear(&Py);
  19203 ->     mp_clear(&Qx);
  19203 ->     mp_clear(&Qy);
  19203 ->     mp_clear(&Gx);
  19203 ->     mp_clear(&Gy);
  19203 ->     mp_clear(&order);
  19203 ->     mp_clear(&irreducible);
  19203 ->     mp_clear(&a);
  19203 ->     mp_clear(&b);
  19203 ->     if (err) {
     ##### -> 	MP_TO_SEC_ERROR(err);
     ##### -> 	rv = SECFailure;
               }
           
  19203 ->     return rv;
           }
           #endif /* NSS_ENABLE_ECC */
           
           /* Generates a new EC key pair. The private key is a supplied
            * value and the public key is the result of performing a scalar 
            * point multiplication of that value with the curve's base point.
            */
           SECStatus 
           ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey, 
               const unsigned char *privKeyBytes, int privKeyLen)
           {
   2787 ->     SECStatus rv = SECFailure;
           #ifdef NSS_ENABLE_ECC
               PRArenaPool *arena;
               ECPrivateKey *key;
               mp_int k;
   2787 ->     mp_err err = MP_OKAY;
               int len;
           
           #if EC_DEBUG
               printf("ec_NewKey called\n");
           #endif
           
   2787 ->     if (!ecParams || !privKey || !privKeyBytes || (privKeyLen < 0)) {
     ##### -> 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
     ##### -> 	return SECFailure;
               }
           
               /* Initialize an arena for the EC key. */
   2787 ->     if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))
     ##### -> 	return SECFailure;
           
   2787 ->     key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey));
   2787 ->     if (!key) {
     ##### -> 	PORT_FreeArena(arena, PR_TRUE);
     ##### -> 	return SECFailure;
               }
           
               /* Set the version number (SEC 1 section C.4 says it should be 1) */
   2787 ->     SECITEM_AllocItem(arena, &key->version, 1);
   2787 ->     key->version.data[0] = 1;
           
               /* Copy all of the fields from the ECParams argument to the
                * ECParams structure within the private key.
                */
   2787 ->     key->ecParams.arena = arena;
   2787 ->     key->ecParams.type = ecParams->type;
   2787 ->     key->ecParams.fieldID.size = ecParams->fieldID.size;
   2787 ->     key->ecParams.fieldID.type = ecParams->fieldID.type;
   2787 ->     if (ecParams->fieldID.type == ec_field_GFp) {
   2588 -> 	CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime,
           	    &ecParams->fieldID.u.prime));
               } else {
    199 -> 	CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.poly,
           	    &ecParams->fieldID.u.poly));
               }
   2787 ->     key->ecParams.fieldID.k1 = ecParams->fieldID.k1;
   2787 ->     key->ecParams.fieldID.k2 = ecParams->fieldID.k2;
   2787 ->     key->ecParams.fieldID.k3 = ecParams->fieldID.k3;
   2787 ->     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a,
           	&ecParams->curve.a));
   2787 ->     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b,
           	&ecParams->curve.b));
   2787 ->     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed,
           	&ecParams->curve.seed));
   2787 ->     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base,
           	&ecParams->base));
   2787 ->     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order,
           	&ecParams->order));
   2787 ->     key->ecParams.cofactor = ecParams->cofactor;
   2787 ->     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding,
           	&ecParams->DEREncoding));
   2787 ->     key->ecParams.name = ecParams->name;
   2787 ->     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID,
           	&ecParams->curveOID));
           
   2787 ->     len = (ecParams->fieldID.size + 7) >> 3;
   2787 ->     SECITEM_AllocItem(arena, &key->publicValue, 2*len + 1);
   2787 ->     len = ecParams->order.len;
   2787 ->     SECITEM_AllocItem(arena, &key->privateValue, len);
           
               /* Copy private key */
   2787 ->     if (privKeyLen >= len) {
   2632 -> 	memcpy(key->privateValue.data, privKeyBytes, len);
               } else {
    155 -> 	memset(key->privateValue.data, 0, (len - privKeyLen));
    155 -> 	memcpy(key->privateValue.data + (len - privKeyLen), privKeyBytes, privKeyLen);
               }
           
               /* Compute corresponding public key */
   2787 ->     MP_DIGITS(&k) = 0;
   2787 ->     CHECK_MPI_OK( mp_init(&k) );
   2787 ->     CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data, 
           	(mp_size) len) );
           
   2787 ->     rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue));
   2787 ->     if (rv != SECSuccess) goto cleanup;
   2787 ->     *privKey = key;
           
           cleanup:
   2787 ->     mp_clear(&k);
   2787 ->     if (rv)
     ##### -> 	PORT_FreeArena(arena, PR_TRUE);
           
           #if EC_DEBUG
               printf("ec_NewKey returning %s\n", 
           	(rv == SECSuccess) ? "success" : "failure");
           #endif
           #else
               PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
           #endif /* NSS_ENABLE_ECC */
           
   2787 ->     return rv;
           
           }
           
           /* Generates a new EC key pair. The private key is a supplied
            * random value (in seed) and the public key is the result of 
            * performing a scalar point multiplication of that value with 
            * the curve's base point.
            */
           SECStatus 
           EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey, 
               const unsigned char *seed, int seedlen)
           {
    310 ->     SECStatus rv = SECFailure;
           #ifdef NSS_ENABLE_ECC
    310 ->     rv = ec_NewKey(ecParams, privKey, seed, seedlen);
           #else
               PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
           #endif /* NSS_ENABLE_ECC */
    310 ->     return rv;
           }
           
           /* Generate a random private key using the algorithm A.4.1 of ANSI X9.62,
            * modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the
            * random number generator.
            *
            * Parameters
            * - order: a buffer that holds the curve's group order
            * - len: the length in octets of the order buffer
            *
            * Return Value
            * Returns a buffer of len octets that holds the private key. The caller
            * is responsible for freeing the buffer with PORT_ZFree.
            */
           static unsigned char *
           ec_GenerateRandomPrivateKey(const unsigned char *order, int len)
           {
   6417 ->     SECStatus rv = SECSuccess;
               mp_err err;
   6417 ->     unsigned char *privKeyBytes = NULL;
               mp_int privKeyVal, order_1, one;
           
   6417 ->     MP_DIGITS(&privKeyVal) = 0;
   6417 ->     MP_DIGITS(&order_1) = 0;
   6417 ->     MP_DIGITS(&one) = 0;
   6417 ->     CHECK_MPI_OK( mp_init(&privKeyVal) );
   6417 ->     CHECK_MPI_OK( mp_init(&order_1) );
   6417 ->     CHECK_MPI_OK( mp_init(&one) );
           
               /* Generates 2*len random bytes using the global random bit generator
                * (which implements Algorithm 1 of FIPS 186-2 Change Notice 1) then
                * reduces modulo the group order.
                */
   6417 ->     if ((privKeyBytes = PORT_Alloc(2*len)) == NULL) goto cleanup;
   6417 ->     CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) );
   6417 ->     CHECK_MPI_OK( mp_read_unsigned_octets(&privKeyVal, privKeyBytes, 2*len) );
   6417 ->     CHECK_MPI_OK( mp_read_unsigned_octets(&order_1, order, len) );
   6417 ->     CHECK_MPI_OK( mp_set_int(&one, 1) );
   6417 ->     CHECK_MPI_OK( mp_sub(&order_1, &one, &order_1) );
   6417 ->     CHECK_MPI_OK( mp_mod(&privKeyVal, &order_1, &privKeyVal) );
   6417 ->     CHECK_MPI_OK( mp_add(&privKeyVal, &one, &privKeyVal) );
   6417 ->     CHECK_MPI_OK( mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len) );
   6417 ->     memset(privKeyBytes+len, 0, len);
           cleanup:
   6417 ->     mp_clear(&privKeyVal);
   6417 ->     mp_clear(&order_1);
   6417 ->     mp_clear(&one);
   6417 ->     if (err < MP_OKAY) {
     ##### -> 	MP_TO_SEC_ERROR(err);
     ##### -> 	rv = SECFailure;
               }
   6417 ->     if (rv != SECSuccess && privKeyBytes) {
     ##### -> 	PORT_Free(privKeyBytes);
     ##### -> 	privKeyBytes = NULL;
               }
   6417 ->     return privKeyBytes;
           }
           
           /* Generates a new EC key pair. The private key is a random value and
            * the public key is the result of performing a scalar point multiplication
            * of that value with the curve's base point.
            */
           SECStatus 
           EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey)
           {
   2477 ->     SECStatus rv = SECFailure;
           #ifdef NSS_ENABLE_ECC
               int len;
   2477 ->     unsigned char *privKeyBytes = NULL;
           
   2477 ->     if (!ecParams) {
     ##### -> 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
     ##### -> 	return SECFailure;
               }
           
   2477 ->     len = ecParams->order.len;
   2477 ->     privKeyBytes = ec_GenerateRandomPrivateKey(ecParams->order.data, len);
   2477 ->     if (privKeyBytes == NULL) goto cleanup;
               /* generate public key */
   2477 ->     CHECK_SEC_OK( ec_NewKey(ecParams, privKey, privKeyBytes, len) );
           
           cleanup:
   2477 ->     if (privKeyBytes) {
   2477 -> 	PORT_ZFree(privKeyBytes, len);
               }
           #if EC_DEBUG
               printf("EC_NewKey returning %s\n", 
           	(rv == SECSuccess) ? "success" : "failure");
           #endif
           #else
               PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
           #endif /* NSS_ENABLE_ECC */
               
   2477 ->     return rv;
           }
           
           /* Validates an EC public key as described in Section 5.2.2 of
            * X9.62. The ECDH primitive when used without the cofactor does
            * not address small subgroup attacks, which may occur when the
            * public key is not valid. These attacks can be prevented by 
            * validating the public key before using ECDH.
            */
           SECStatus 
           EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue)
           {
           #ifdef NSS_ENABLE_ECC
               mp_int Px, Py;
   5148 ->     ECGroup *group = NULL;
   5148 ->     SECStatus rv = SECFailure;
   5148 ->     mp_err err = MP_OKAY;
               int len;
           
   5148 ->     if (!ecParams || !publicValue) {
     ##### -> 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
     ##### -> 	return SECFailure;
               }
           	
               /* NOTE: We only support uncompressed points for now */
   5148 ->     len = (ecParams->fieldID.size + 7) >> 3;
   5148 ->     if (publicValue->data[0] != EC_POINT_FORM_UNCOMPRESSED) {
     ##### -> 	PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
     ##### -> 	return SECFailure;
   5148 ->     } else if (publicValue->len != (2 * len + 1)) {
     ##### -> 	PORT_SetError(SEC_ERROR_BAD_KEY);
     ##### -> 	return SECFailure;
               }
           
   5148 ->     MP_DIGITS(&Px) = 0;
   5148 ->     MP_DIGITS(&Py) = 0;
   5147 ->     CHECK_MPI_OK( mp_init(&Px) );
   5148 ->     CHECK_MPI_OK( mp_init(&Py) );
           
               /* Initialize Px and Py */
   5148 ->     CHECK_MPI_OK( mp_read_unsigned_octets(&Px, publicValue->data + 1, (mp_size) len) );
   5148 ->     CHECK_MPI_OK( mp_read_unsigned_octets(&Py, publicValue->data + 1 + len, (mp_size) len) );
           
               /* construct from named params */
   5148 ->     group = ECGroup_fromName(ecParams->name);
   5148 ->     if (group == NULL) {
           	/*
           	 * ECGroup_fromName fails if ecParams->name is not a valid
           	 * ECCurveName value, or if we run out of memory, or perhaps
           	 * for other reasons.  Unfortunately if ecParams->name is a
           	 * valid ECCurveName value, we don't know what the right error
           	 * code should be because ECGroup_fromName doesn't return an
           	 * error code to the caller.  Set err to MP_UNDEF because
           	 * that's what ECGroup_fromName uses internally.
           	 */
           	if ((ecParams->name <= ECCurve_noName) ||
     ##### -> 	    (ecParams->name >= ECCurve_pastLastCurve)) {
     ##### -> 	    err = MP_BADARG;
           	} else {
     ##### -> 	    err = MP_UNDEF;
           	}
     ##### -> 	goto cleanup;
               }
           
               /* validate public point */
   5148 ->     if ((err = ECPoint_validate(group, &Px, &Py)) < MP_YES) {
     ##### -> 	if (err == MP_NO) {
     ##### -> 	    PORT_SetError(SEC_ERROR_BAD_KEY);
     ##### -> 	    rv = SECFailure;
     ##### -> 	    err = MP_OKAY;  /* don't change the error code */
           	}
     ##### -> 	goto cleanup;
               }
           
   5148 ->     rv = SECSuccess;
           
           cleanup:
   5148 ->     ECGroup_free(group);
   5148 ->     mp_clear(&Px);
   5148 ->     mp_clear(&Py);
   5148 ->     if (err) {
     ##### -> 	MP_TO_SEC_ERROR(err);
     ##### -> 	rv = SECFailure;
               }
   5148 ->     return rv;
           #else
               PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
               return SECFailure;
           #endif /* NSS_ENABLE_ECC */
           }
           
           /* 
           ** Performs an ECDH key derivation by computing the scalar point
           ** multiplication of privateValue and publicValue (with or without the
           ** cofactor) and returns the x-coordinate of the resulting elliptic
           ** curve point in derived secret.  If successful, derivedSecret->data
           ** is set to the address of the newly allocated buffer containing the
           ** derived secret, and derivedSecret->len is the size of the secret
           ** produced. It is the caller's responsibility to free the allocated
           ** buffer containing the derived secret.
           */
           SECStatus 
           ECDH_Derive(SECItem  *publicValue, 
                       ECParams *ecParams,
                       SECItem  *privateValue,
                       PRBool    withCofactor,
                       SECItem  *derivedSecret)
           {
   4528 ->     SECStatus rv = SECFailure;
           #ifdef NSS_ENABLE_ECC
   4528 ->     unsigned int len = 0;
   4528 ->     SECItem pointQ = {siBuffer, NULL, 0};
               mp_int k; /* to hold the private value */
               mp_int cofactor;
   4528 ->     mp_err err = MP_OKAY;
           #if EC_DEBUG
               int i;
           #endif
           
               if (!publicValue || !ecParams || !privateValue || 
   4528 -> 	!derivedSecret) {
     ##### -> 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
     ##### -> 	return SECFailure;
               }
           
   4528 ->     memset(derivedSecret, 0, sizeof *derivedSecret);
   4528 ->     len = (ecParams->fieldID.size + 7) >> 3;  
   4528 ->     pointQ.len = 2*len + 1;
   4528 ->     if ((pointQ.data = PORT_Alloc(2*len + 1)) == NULL) goto cleanup;
           
   4528 ->     MP_DIGITS(&k) = 0;
   4528 ->     CHECK_MPI_OK( mp_init(&k) );
   4528 ->     CHECK_MPI_OK( mp_read_unsigned_octets(&k, privateValue->data, 
           	                                  (mp_size) privateValue->len) );
           
   4528 ->     if (withCofactor && (ecParams->cofactor != 1)) {
           	    /* multiply k with the cofactor */
     ##### -> 	    MP_DIGITS(&cofactor) = 0;
     ##### -> 	    CHECK_MPI_OK( mp_init(&cofactor) );
     ##### -> 	    mp_set(&cofactor, ecParams->cofactor);
     ##### -> 	    CHECK_MPI_OK( mp_mul(&k, &cofactor, &k) );
               }
           
               /* Multiply our private key and peer's public point */
               if ((ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ) != SECSuccess) ||
   4528 -> 	ec_point_at_infinity(&pointQ))
     ##### -> 	goto cleanup;
           
               /* Allocate memory for the derived secret and copy
                * the x co-ordinate of pointQ into it.
                */
   4528 ->     SECITEM_AllocItem(NULL, derivedSecret, len);
   4528 ->     memcpy(derivedSecret->data, pointQ.data + 1, len);
           
   4528 ->     rv = SECSuccess;
           
           #if EC_DEBUG
               printf("derived_secret:\n");
               for (i = 0; i < derivedSecret->len; i++) 
           	printf("%02x:", derivedSecret->data[i]);
               printf("\n");
           #endif
           
           cleanup:
   4528 ->     mp_clear(&k);
           
   4528 ->     if (pointQ.data) {
   4528 -> 	PORT_ZFree(pointQ.data, 2*len + 1);
               }
           #else
               PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
           #endif /* NSS_ENABLE_ECC */
           
   4528 ->     return rv;
           }
           
           /* Computes the ECDSA signature (a concatenation of two values r and s)
            * on the digest using the given key and the random value kb (used in
            * computing s).
            */
           SECStatus 
           ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, 
               const SECItem *digest, const unsigned char *kb, const int kblen)
           {
   4250 ->     SECStatus rv = SECFailure;
           #ifdef NSS_ENABLE_ECC
               mp_int x1;
               mp_int d, k;     /* private key, random integer */
               mp_int r, s;     /* tuple (r, s) is the signature */
               mp_int n;
   4250 ->     mp_err err = MP_OKAY;
   4250 ->     ECParams *ecParams = NULL;
   4250 ->     SECItem kGpoint = { siBuffer, NULL, 0};
   4250 ->     int flen = 0;    /* length in bytes of the field size */
               unsigned olen;   /* length in bytes of the base point order */
           
           #if EC_DEBUG
               char mpstr[256];
           #endif
           
               /* Initialize MPI integers. */
               /* must happen before the first potential call to cleanup */
   4250 ->     MP_DIGITS(&x1) = 0;
   4250 ->     MP_DIGITS(&d) = 0;
   4250 ->     MP_DIGITS(&k) = 0;
   4250 ->     MP_DIGITS(&r) = 0;
   4250 ->     MP_DIGITS(&s) = 0;
   4250 ->     MP_DIGITS(&n) = 0;
           
               /* Check args */
   4250 ->     if (!key || !signature || !digest || !kb || (kblen < 0)) {
     ##### -> 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
     ##### -> 	goto cleanup;
               }
           
   4250 ->     ecParams = &(key->ecParams);
   4250 ->     flen = (ecParams->fieldID.size + 7) >> 3;
   4250 ->     olen = ecParams->order.len;  
   4250 ->     if (signature->data == NULL) {
           	/* a call to get the signature length only */
     ##### -> 	goto finish;
               }
   4250 ->     if (signature->len < 2*olen) {
     ##### -> 	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
     ##### -> 	goto cleanup;
               }
           
           
   4250 ->     CHECK_MPI_OK( mp_init(&x1) );
   4250 ->     CHECK_MPI_OK( mp_init(&d) );
   4250 ->     CHECK_MPI_OK( mp_init(&k) );
   4250 ->     CHECK_MPI_OK( mp_init(&r) );
   4250 ->     CHECK_MPI_OK( mp_init(&s) );
   4250 ->     CHECK_MPI_OK( mp_init(&n) );
           
   4250 ->     SECITEM_TO_MPINT( ecParams->order, &n );
   4250 ->     SECITEM_TO_MPINT( key->privateValue, &d );
   4250 ->     CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) );
               /* Make sure k is in the interval [1, n-1] */
   4250 ->     if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) {
           #if EC_DEBUG
                   printf("k is outside [1, n-1]\n");
                   mp_tohex(&k, mpstr);
           	printf("k : %s \n", mpstr);
                   mp_tohex(&n, mpstr);
           	printf("n : %s \n", mpstr);
           #endif
     ##### -> 	PORT_SetError(SEC_ERROR_NEED_RANDOM);
     ##### -> 	goto cleanup;
               }
           
               /* 
               ** ANSI X9.62, Section 5.3.2, Step 2
               **
               ** Compute kG
               */
   4250 ->     kGpoint.len = 2*flen + 1;
   4250 ->     kGpoint.data = PORT_Alloc(2*flen + 1);
               if ((kGpoint.data == NULL) ||
           	(ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint)
   4250 -> 	    != SECSuccess))
     ##### -> 	goto cleanup;
           
               /* 
               ** ANSI X9.62, Section 5.3.3, Step 1
               **
               ** Extract the x co-ordinate of kG into x1
               */
   4250 ->     CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1, 
           	                                  (mp_size) flen) );
           
               /* 
               ** ANSI X9.62, Section 5.3.3, Step 2
               **
               ** r = x1 mod n  NOTE: n is the order of the curve
               */
   4250 ->     CHECK_MPI_OK( mp_mod(&x1, &n, &r) );
           
               /*
               ** ANSI X9.62, Section 5.3.3, Step 3
               **
               ** verify r != 0 
               */
   4250 ->     if (mp_cmp_z(&r) == 0) {
     ##### -> 	PORT_SetError(SEC_ERROR_NEED_RANDOM);
     ##### -> 	goto cleanup;
               }
           
               /*                                  
               ** ANSI X9.62, Section 5.3.3, Step 4
               **
               ** s = (k**-1 * (HASH(M) + d*r)) mod n 
               */
   4250 ->     SECITEM_TO_MPINT(*digest, &s);        /* s = HASH(M)     */
           
               /* In the definition of EC signing, digests are truncated
                * to the length of n in bits. 
                * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
   4250 ->     if (digest->len*8 > ecParams->fieldID.size) {
     18 -> 	mpl_rsh(&s,&s,digest->len*8 - ecParams->fieldID.size);
               }
           
           #if EC_DEBUG
               mp_todecimal(&n, mpstr);
               printf("n : %s (dec)\n", mpstr);
               mp_todecimal(&d, mpstr);
               printf("d : %s (dec)\n", mpstr);
               mp_tohex(&x1, mpstr);
               printf("x1: %s\n", mpstr);
               mp_todecimal(&s, mpstr);
               printf("digest: %s (decimal)\n", mpstr);
               mp_todecimal(&r, mpstr);
               printf("r : %s (dec)\n", mpstr);
               mp_tohex(&r, mpstr);
               printf("r : %s\n", mpstr);
           #endif
           
   4250 ->     CHECK_MPI_OK( mp_invmod(&k, &n, &k) );      /* k = k**-1 mod n */
   4250 ->     CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) );  /* d = d * r mod n */
   4250 ->     CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) );  /* s = s + d mod n */
   4250 ->     CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) );  /* s = s * k mod n */
           
           #if EC_DEBUG
               mp_todecimal(&s, mpstr);
               printf("s : %s (dec)\n", mpstr);
               mp_tohex(&s, mpstr);
               printf("s : %s\n", mpstr);
           #endif
           
               /*
               ** ANSI X9.62, Section 5.3.3, Step 5
               **
               ** verify s != 0
               */
   4250 ->     if (mp_cmp_z(&s) == 0) {
     ##### -> 	PORT_SetError(SEC_ERROR_NEED_RANDOM);
     ##### -> 	goto cleanup;
               }
           
              /*
               **
               ** Signature is tuple (r, s)
               */
   4250 ->     CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, olen) );
   4250 ->     CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + olen, olen) );
           finish:
   4250 ->     signature->len = 2*olen;
           
   4250 ->     rv = SECSuccess;
   4250 ->     err = MP_OKAY;
           cleanup:
   4250 ->     mp_clear(&x1);
   4250 ->     mp_clear(&d);
   4250 ->     mp_clear(&k);
   4250 ->     mp_clear(&r);
   4250 ->     mp_clear(&s);
   4250 ->     mp_clear(&n);
           
   4250 ->     if (kGpoint.data) {
   4250 -> 	PORT_ZFree(kGpoint.data, 2*flen + 1);
               }
           
   4250 ->     if (err) {
     ##### -> 	MP_TO_SEC_ERROR(err);
     ##### -> 	rv = SECFailure;
               }
           
           #if EC_DEBUG
               printf("ECDSA signing with seed %s\n",
           	(rv == SECSuccess) ? "succeeded" : "failed");
           #endif
           #else
               PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
           #endif /* NSS_ENABLE_ECC */
           
   4250 ->    return rv;
           }
           
           /*
           ** Computes the ECDSA signature on the digest using the given key 
           ** and a random seed.
           */
           SECStatus 
           ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest)
           {
   3940 ->     SECStatus rv = SECFailure;
           #ifdef NSS_ENABLE_ECC
               int len;
   3940 ->     unsigned char *kBytes= NULL;
           
   3940 ->     if (!key) {
     ##### -> 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
     ##### -> 	return SECFailure;
               }
           
               /* Generate random value k */
   3940 ->     len = key->ecParams.order.len;
   3940 ->     kBytes = ec_GenerateRandomPrivateKey(key->ecParams.order.data, len);
   3940 ->     if (kBytes == NULL) goto cleanup;
           
               /* Generate ECDSA signature with the specified k value */
   3940 ->     rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len);
           
           cleanup:    
   3940 ->     if (kBytes) {
   3940 -> 	PORT_ZFree(kBytes, len);
               }
           
           #if EC_DEBUG
               printf("ECDSA signing %s\n",
           	(rv == SECSuccess) ? "succeeded" : "failed");
           #endif
           #else
               PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
           #endif /* NSS_ENABLE_ECC */
           
   3940 ->     return rv;
           }
           
           /*
           ** Checks the signature on the given digest using the key provided.
           */
           SECStatus 
           ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, 
                            const SECItem *digest)
           {
   7638 ->     SECStatus rv = SECFailure;
           #ifdef NSS_ENABLE_ECC
               mp_int r_, s_;           /* tuple (r', s') is received signature) */
               mp_int c, u1, u2, v;     /* intermediate values used in verification */
               mp_int x1;
               mp_int n;
   7638 ->     mp_err err = MP_OKAY;
   7638 ->     ECParams *ecParams = NULL;
   7638 ->     SECItem pointC = { siBuffer, NULL, 0 };
               int slen;       /* length in bytes of a half signature (r or s) */
               int flen;       /* length in bytes of the field size */
               unsigned olen;  /* length in bytes of the base point order */
           
           #if EC_DEBUG
               char mpstr[256];
               printf("ECDSA verification called\n");
           #endif
           
               /* Initialize MPI integers. */
               /* must happen before the first potential call to cleanup */
   7638 ->     MP_DIGITS(&r_) = 0;
   7638 ->     MP_DIGITS(&s_) = 0;
   7638 ->     MP_DIGITS(&c) = 0;
   7638 ->     MP_DIGITS(&u1) = 0;
   7638 ->     MP_DIGITS(&u2) = 0;
   7638 ->     MP_DIGITS(&x1) = 0;
   7638 ->     MP_DIGITS(&v)  = 0;
   7638 ->     MP_DIGITS(&n)  = 0;
           
               /* Check args */
   7638 ->     if (!key || !signature || !digest) {
     ##### -> 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
     ##### -> 	goto cleanup;
               }
           
   7638 ->     ecParams = &(key->ecParams);
   7638 ->     flen = (ecParams->fieldID.size + 7) >> 3;  
   7638 ->     olen = ecParams->order.len;  
               if (signature->len == 0 || signature->len%2 != 0 ||
   7638 -> 	signature->len > 2*olen) {
     ##### -> 	PORT_SetError(SEC_ERROR_INPUT_LEN);
     ##### -> 	goto cleanup;
               }
   7638 ->     slen = signature->len/2;
           
   7638 ->     SECITEM_AllocItem(NULL, &pointC, 2*flen + 1);
   7638 ->     if (pointC.data == NULL)
     ##### -> 	goto cleanup;
           
   7638 ->     CHECK_MPI_OK( mp_init(&r_) );
   7638 ->     CHECK_MPI_OK( mp_init(&s_) );
   7638 ->     CHECK_MPI_OK( mp_init(&c)  );
   7638 ->     CHECK_MPI_OK( mp_init(&u1) );
   7638 ->     CHECK_MPI_OK( mp_init(&u2) );
   7638 ->     CHECK_MPI_OK( mp_init(&x1)  );
   7638 ->     CHECK_MPI_OK( mp_init(&v)  );
   7638 ->     CHECK_MPI_OK( mp_init(&n)  );
           
               /*
               ** Convert received signature (r', s') into MPI integers.
               */
   7638 ->     CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, slen) );
   7638 ->     CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + slen, slen) );
                                                     
               /* 
               ** ANSI X9.62, Section 5.4.2, Steps 1 and 2
               **
               ** Verify that 0 < r' < n and 0 < s' < n
               */
   7638 ->     SECITEM_TO_MPINT(ecParams->order, &n);
               if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
   7638 ->         mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) {
     ##### -> 	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
     ##### -> 	goto cleanup; /* will return rv == SECFailure */
               }
           
               /*
               ** ANSI X9.62, Section 5.4.2, Step 3
               **
               ** c = (s')**-1 mod n
               */
   7638 ->     CHECK_MPI_OK( mp_invmod(&s_, &n, &c) );      /* c = (s')**-1 mod n */
           
               /*
               ** ANSI X9.62, Section 5.4.2, Step 4
               **
               ** u1 = ((HASH(M')) * c) mod n
               */
   7638 ->     SECITEM_TO_MPINT(*digest, &u1);                  /* u1 = HASH(M)     */
           
               /* In the definition of EC signing, digests are truncated
                * to the length of n in bits. 
                * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
   7638 ->     if (digest->len*8 > ecParams->fieldID.size) {  /* u1 = HASH(M')     */
     18 -> 	mpl_rsh(&u1,&u1,digest->len*8- ecParams->fieldID.size);
               }
           
           #if EC_DEBUG
               mp_todecimal(&r_, mpstr);
               printf("r_: %s (dec)\n", mpstr);
               mp_todecimal(&s_, mpstr);
               printf("s_: %s (dec)\n", mpstr);
               mp_todecimal(&c, mpstr);
               printf("c : %s (dec)\n", mpstr);
               mp_todecimal(&u1, mpstr);
               printf("digest: %s (dec)\n", mpstr);
           #endif
           
   7638 ->     CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) );  /* u1 = u1 * c mod n */
           
               /*
               ** ANSI X9.62, Section 5.4.2, Step 4
               **
               ** u2 = ((r') * c) mod n
               */
   7638 ->     CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) );
           
               /*
               ** ANSI X9.62, Section 5.4.3, Step 1
               **
               ** Compute u1*G + u2*Q
               ** Here, A = u1.G     B = u2.Q    and   C = A + B
               ** If the result, C, is the point at infinity, reject the signature
               */
               if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC)
   7638 -> 	!= SECSuccess) {
     ##### -> 	rv = SECFailure;
     ##### -> 	goto cleanup;
               }
   7638 ->     if (ec_point_at_infinity(&pointC)) {
     ##### -> 	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
     ##### -> 	rv = SECFailure;
     ##### -> 	goto cleanup;
               }
           
   7638 ->     CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, flen) );
           
               /*
               ** ANSI X9.62, Section 5.4.4, Step 2
               **
               ** v = x1 mod n
               */
   7638 ->     CHECK_MPI_OK( mp_mod(&x1, &n, &v) );
           
           #if EC_DEBUG
               mp_todecimal(&r_, mpstr);
               printf("r_: %s (dec)\n", mpstr);
               mp_todecimal(&v, mpstr);
               printf("v : %s (dec)\n", mpstr);
           #endif
           
               /*
               ** ANSI X9.62, Section 5.4.4, Step 3
               **
               ** Verification:  v == r'
               */
   7638 ->     if (mp_cmp(&v, &r_)) {
     ##### -> 	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
     ##### -> 	rv = SECFailure; /* Signature failed to verify. */
               } else {
   7638 -> 	rv = SECSuccess; /* Signature verified. */
               }
           
           #if EC_DEBUG
               mp_todecimal(&u1, mpstr);
               printf("u1: %s (dec)\n", mpstr);
               mp_todecimal(&u2, mpstr);
               printf("u2: %s (dec)\n", mpstr);
               mp_tohex(&x1, mpstr);
               printf("x1: %s\n", mpstr);
               mp_todecimal(&v, mpstr);
               printf("v : %s (dec)\n", mpstr);
           #endif
           
           cleanup:
   7638 ->     mp_clear(&r_);
   7638 ->     mp_clear(&s_);
   7638 ->     mp_clear(&c);
   7638 ->     mp_clear(&u1);
   7638 ->     mp_clear(&u2);
   7638 ->     mp_clear(&x1);
   7638 ->     mp_clear(&v);
   7638 ->     mp_clear(&n);
           
   7638 ->     if (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE);
   7638 ->     if (err) {
     ##### -> 	MP_TO_SEC_ERROR(err);
     ##### -> 	rv = SECFailure;
               }
           
           #if EC_DEBUG
               printf("ECDSA verification %s\n",
           	(rv == SECSuccess) ? "succeeded" : "failed");
           #endif
           #else
               PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
           #endif /* NSS_ENABLE_ECC */
           
   7638 ->     return rv;
           }
           


		 Top 10 Blocks

		 Line	   Count

		   79	   19203
		   80	   19203
		   81	   19203
		  116	   19203
		  117	   19203
		  124	   19203
		  125	   19203
		  126	   19203
		  127	   19203
		  129	   19203


	  372	Basic blocks in this file
	  299	Basic blocks executed
	80.38	Percent of the file executed

      2172988	Total basic block executions
      5841.37	Average executions per basic block
