summaryrefslogtreecommitdiff
path: root/nss/lib/freebl/ec.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-01-04 14:24:24 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-01-04 14:24:24 +0000
commitdc1565216a5d20ae0d75872151523252309a1292 (patch)
treed57454ba9a40386552179eddf60d28bd1e8f3d54 /nss/lib/freebl/ec.c
parent26c046fbc57d53136b4fb3b5e0d18298318125d4 (diff)
downloadnss-dc1565216a5d20ae0d75872151523252309a1292.tar.gz
nss-3.28.1nss-3.28.1
Diffstat (limited to 'nss/lib/freebl/ec.c')
-rw-r--r--nss/lib/freebl/ec.c832
1 files changed, 449 insertions, 383 deletions
diff --git a/nss/lib/freebl/ec.c b/nss/lib/freebl/ec.c
index 4435f91..a9b7c05 100644
--- a/nss/lib/freebl/ec.c
+++ b/nss/lib/freebl/ec.c
@@ -6,7 +6,6 @@
#include "stubs.h"
#endif
-
#include "blapi.h"
#include "prerr.h"
#include "secerr.h"
@@ -18,7 +17,25 @@
#ifndef NSS_DISABLE_ECC
-/*
+static const ECMethod kMethods[] = {
+ { ECCurve25519,
+ ec_Curve25519_pt_mul,
+ ec_Curve25519_pt_validate }
+};
+
+static const ECMethod *
+ec_get_method_from_name(ECCurveName name)
+{
+ int i;
+ for (i = 0; i < sizeof(kMethods) / sizeof(kMethods[0]); ++i) {
+ if (kMethods[i].name == name) {
+ return &kMethods[i];
+ }
+ }
+ return NULL;
+}
+
+/*
* Returns true if pointP is the point at infinity, false otherwise
*/
PRBool
@@ -27,25 +44,23 @@ ec_point_at_infinity(SECItem *pointP)
unsigned int i;
for (i = 1; i < pointP->len; i++) {
- if (pointP->data[i] != 0x00) return PR_FALSE;
+ 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
+SECStatus
ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2,
- const SECItem *pointP, SECItem *pointQ)
+ 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
ECGroup *group = NULL;
SECStatus rv = SECFailure;
mp_err err = MP_OKAY;
@@ -56,120 +71,96 @@ ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2,
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]);
+ 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
+ if (k1 != NULL) {
+ mp_tohex((mp_int *)k1, mpstr);
+ printf("ec_points_mul: scalar k1: %s\n", mpstr);
+ mp_todecimal((mp_int *)k1, mpstr);
+ printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr);
+ }
- /* NOTE: We only support uncompressed points for now */
- len = (params->fieldID.size + 7) >> 3;
- if (pointP != NULL) {
- if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
- (pointP->len != (2 * len + 1))) {
- PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
- return SECFailure;
- };
- }
-
- MP_DIGITS(&Px) = 0;
- MP_DIGITS(&Py) = 0;
- MP_DIGITS(&Qx) = 0;
- MP_DIGITS(&Qy) = 0;
- MP_DIGITS(&Gx) = 0;
- MP_DIGITS(&Gy) = 0;
- MP_DIGITS(&order) = 0;
- MP_DIGITS(&irreducible) = 0;
- MP_DIGITS(&a) = 0;
- MP_DIGITS(&b) = 0;
- CHECK_MPI_OK( mp_init(&Px) );
- CHECK_MPI_OK( mp_init(&Py) );
- CHECK_MPI_OK( mp_init(&Qx) );
- CHECK_MPI_OK( mp_init(&Qy) );
- CHECK_MPI_OK( mp_init(&Gx) );
- CHECK_MPI_OK( mp_init(&Gy) );
- CHECK_MPI_OK( mp_init(&order) );
- CHECK_MPI_OK( mp_init(&irreducible) );
- CHECK_MPI_OK( mp_init(&a) );
- CHECK_MPI_OK( mp_init(&b) );
-
- if ((k2 != NULL) && (pointP != NULL)) {
- /* Initialize Px and Py */
- CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size) len) );
- CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) );
- }
-
- /* construct from named params, if possible */
- if (params->name != ECCurve_noName) {
- 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);
- }
- }
+ if (k2 != NULL) {
+ mp_tohex((mp_int *)k2, mpstr);
+ printf("ec_points_mul: scalar k2: %s\n", mpstr);
+ mp_todecimal((mp_int *)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
- if (group == NULL)
- goto cleanup;
- if ((k2 != NULL) && (pointP != NULL)) {
- CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy) );
- } else {
- CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) );
+ /* NOTE: We only support uncompressed points for now */
+ len = (params->fieldID.size + 7) >> 3;
+ if (pointP != NULL) {
+ if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
+ (pointP->len != (2 * len + 1))) {
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
+ return SECFailure;
+ };
+ }
+
+ MP_DIGITS(&Px) = 0;
+ MP_DIGITS(&Py) = 0;
+ MP_DIGITS(&Qx) = 0;
+ MP_DIGITS(&Qy) = 0;
+ MP_DIGITS(&Gx) = 0;
+ MP_DIGITS(&Gy) = 0;
+ MP_DIGITS(&order) = 0;
+ MP_DIGITS(&irreducible) = 0;
+ MP_DIGITS(&a) = 0;
+ MP_DIGITS(&b) = 0;
+ CHECK_MPI_OK(mp_init(&Px));
+ CHECK_MPI_OK(mp_init(&Py));
+ CHECK_MPI_OK(mp_init(&Qx));
+ CHECK_MPI_OK(mp_init(&Qy));
+ CHECK_MPI_OK(mp_init(&Gx));
+ CHECK_MPI_OK(mp_init(&Gy));
+ CHECK_MPI_OK(mp_init(&order));
+ CHECK_MPI_OK(mp_init(&irreducible));
+ CHECK_MPI_OK(mp_init(&a));
+ CHECK_MPI_OK(mp_init(&b));
+
+ if ((k2 != NULL) && (pointP != NULL)) {
+ /* Initialize Px and Py */
+ CHECK_MPI_OK(mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size)len));
+ CHECK_MPI_OK(mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size)len));
+ }
+
+ /* construct from named params, if possible */
+ if (params->name != ECCurve_noName) {
+ group = ECGroup_fromName(params->name);
+ }
+
+ if (group == NULL)
+ goto cleanup;
+
+ if ((k2 != NULL) && (pointP != NULL)) {
+ CHECK_MPI_OK(ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy));
+ } else {
+ CHECK_MPI_OK(ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy));
}
/* Construct the SECItem representation of point Q */
pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED;
- CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1,
- (mp_size) len) );
- CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len,
- (mp_size) len) );
+ CHECK_MPI_OK(mp_to_fixlen_octets(&Qx, pointQ->data + 1,
+ (mp_size)len));
+ CHECK_MPI_OK(mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len,
+ (mp_size)len));
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]);
+ for (i = 0; i < pointQ->len; i++)
+ printf("%02x:", pointQ->data[i]);
printf("\n");
#endif
@@ -186,8 +177,8 @@ cleanup:
mp_clear(&a);
mp_clear(&b);
if (err) {
- MP_TO_SEC_ERROR(err);
- rv = SECFailure;
+ MP_TO_SEC_ERROR(err);
+ rv = SECFailure;
}
return rv;
@@ -195,12 +186,12 @@ cleanup:
#endif /* NSS_DISABLE_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
+ * 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)
+SECStatus
+ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey,
+ const unsigned char *privKeyBytes, int privKeyLen)
{
SECStatus rv = SECFailure;
#ifndef NSS_DISABLE_ECC
@@ -215,19 +206,20 @@ ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey,
#endif
MP_DIGITS(&k) = 0;
- if (!ecParams || !privKey || !privKeyBytes || (privKeyLen < 0)) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
+ if (!ecParams || !privKey || !privKeyBytes || (privKeyLen < 0) ||
+ !ecParams->name) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
}
/* Initialize an arena for the EC key. */
if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))
- return SECFailure;
+ return SECFailure;
key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey));
if (!key) {
- PORT_FreeArena(arena, PR_TRUE);
- return SECFailure;
+ PORT_FreeArena(arena, PR_TRUE);
+ return SECFailure;
}
/* Set the version number (SEC 1 section C.4 says it should be 1) */
@@ -241,80 +233,98 @@ ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey,
key->ecParams.type = ecParams->type;
key->ecParams.fieldID.size = ecParams->fieldID.size;
key->ecParams.fieldID.type = ecParams->fieldID.type;
- if (ecParams->fieldID.type == ec_field_GFp) {
- CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime,
- &ecParams->fieldID.u.prime));
+ key->ecParams.pointSize = ecParams->pointSize;
+ if (ecParams->fieldID.type == ec_field_GFp ||
+ ecParams->fieldID.type == ec_field_plain) {
+ CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime,
+ &ecParams->fieldID.u.prime));
} else {
- CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.poly,
- &ecParams->fieldID.u.poly));
+ CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.poly,
+ &ecParams->fieldID.u.poly));
}
key->ecParams.fieldID.k1 = ecParams->fieldID.k1;
key->ecParams.fieldID.k2 = ecParams->fieldID.k2;
key->ecParams.fieldID.k3 = ecParams->fieldID.k3;
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a,
- &ecParams->curve.a));
+ &ecParams->curve.a));
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b,
- &ecParams->curve.b));
+ &ecParams->curve.b));
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed,
- &ecParams->curve.seed));
+ &ecParams->curve.seed));
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base,
- &ecParams->base));
+ &ecParams->base));
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order,
- &ecParams->order));
+ &ecParams->order));
key->ecParams.cofactor = ecParams->cofactor;
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding,
- &ecParams->DEREncoding));
+ &ecParams->DEREncoding));
key->ecParams.name = ecParams->name;
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID,
- &ecParams->curveOID));
+ &ecParams->curveOID));
- len = (ecParams->fieldID.size + 7) >> 3;
- SECITEM_AllocItem(arena, &key->publicValue, 2*len + 1);
+ SECITEM_AllocItem(arena, &key->publicValue, ecParams->pointSize);
len = ecParams->order.len;
SECITEM_AllocItem(arena, &key->privateValue, len);
/* Copy private key */
if (privKeyLen >= len) {
- memcpy(key->privateValue.data, privKeyBytes, len);
+ memcpy(key->privateValue.data, privKeyBytes, len);
} else {
- memset(key->privateValue.data, 0, (len - privKeyLen));
- memcpy(key->privateValue.data + (len - privKeyLen), privKeyBytes, privKeyLen);
+ memset(key->privateValue.data, 0, (len - privKeyLen));
+ memcpy(key->privateValue.data + (len - privKeyLen), privKeyBytes, privKeyLen);
}
/* Compute corresponding public key */
- CHECK_MPI_OK( mp_init(&k) );
- CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data,
- (mp_size) len) );
+
+ /* Use curve specific code for point multiplication */
+ if (ecParams->fieldID.type == ec_field_plain) {
+ const ECMethod *method = ec_get_method_from_name(ecParams->name);
+ if (method == NULL || method->mul == NULL) {
+ /* unknown curve */
+ rv = SECFailure;
+ goto cleanup;
+ }
+ rv = method->mul(&key->publicValue, &key->privateValue, NULL);
+ goto done;
+ }
+
+ CHECK_MPI_OK(mp_init(&k));
+ CHECK_MPI_OK(mp_read_unsigned_octets(&k, key->privateValue.data,
+ (mp_size)len));
rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue));
- if (rv != SECSuccess) goto cleanup;
+ if (rv != SECSuccess) {
+ goto cleanup;
+ }
+
+done:
*privKey = key;
cleanup:
mp_clear(&k);
- if (rv)
- PORT_FreeArena(arena, PR_TRUE);
+ if (rv) {
+ PORT_FreeArena(arena, PR_TRUE);
+ }
#if EC_DEBUG
- printf("ec_NewKey returning %s\n",
- (rv == SECSuccess) ? "success" : "failure");
+ printf("ec_NewKey returning %s\n",
+ (rv == SECSuccess) ? "success" : "failure");
#endif
#else
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
#endif /* NSS_DISABLE_ECC */
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
+ * 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)
+SECStatus
+EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey,
+ const unsigned char *seed, int seedlen)
{
SECStatus rv = SECFailure;
#ifndef NSS_DISABLE_ECC
@@ -349,35 +359,36 @@ ec_GenerateRandomPrivateKey(const unsigned char *order, int len)
MP_DIGITS(&privKeyVal) = 0;
MP_DIGITS(&order_1) = 0;
MP_DIGITS(&one) = 0;
- CHECK_MPI_OK( mp_init(&privKeyVal) );
- CHECK_MPI_OK( mp_init(&order_1) );
- CHECK_MPI_OK( mp_init(&one) );
+ CHECK_MPI_OK(mp_init(&privKeyVal));
+ CHECK_MPI_OK(mp_init(&order_1));
+ 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.
*/
- if ((privKeyBytes = PORT_Alloc(2*len)) == NULL) goto cleanup;
- CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) );
- CHECK_MPI_OK( mp_read_unsigned_octets(&privKeyVal, privKeyBytes, 2*len) );
- CHECK_MPI_OK( mp_read_unsigned_octets(&order_1, order, len) );
- CHECK_MPI_OK( mp_set_int(&one, 1) );
- CHECK_MPI_OK( mp_sub(&order_1, &one, &order_1) );
- CHECK_MPI_OK( mp_mod(&privKeyVal, &order_1, &privKeyVal) );
- CHECK_MPI_OK( mp_add(&privKeyVal, &one, &privKeyVal) );
- CHECK_MPI_OK( mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len) );
- memset(privKeyBytes+len, 0, len);
+ if ((privKeyBytes = PORT_Alloc(2 * len)) == NULL)
+ goto cleanup;
+ CHECK_SEC_OK(RNG_GenerateGlobalRandomBytes(privKeyBytes, 2 * len));
+ CHECK_MPI_OK(mp_read_unsigned_octets(&privKeyVal, privKeyBytes, 2 * len));
+ CHECK_MPI_OK(mp_read_unsigned_octets(&order_1, order, len));
+ CHECK_MPI_OK(mp_set_int(&one, 1));
+ CHECK_MPI_OK(mp_sub(&order_1, &one, &order_1));
+ CHECK_MPI_OK(mp_mod(&privKeyVal, &order_1, &privKeyVal));
+ CHECK_MPI_OK(mp_add(&privKeyVal, &one, &privKeyVal));
+ CHECK_MPI_OK(mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len));
+ memset(privKeyBytes + len, 0, len);
cleanup:
mp_clear(&privKeyVal);
mp_clear(&order_1);
mp_clear(&one);
if (err < MP_OKAY) {
- MP_TO_SEC_ERROR(err);
- rv = SECFailure;
+ MP_TO_SEC_ERROR(err);
+ rv = SECFailure;
}
if (rv != SECSuccess && privKeyBytes) {
- PORT_Free(privKeyBytes);
- privKeyBytes = NULL;
+ PORT_ZFree(privKeyBytes, 2 * len);
+ privKeyBytes = NULL;
}
return privKeyBytes;
}
@@ -387,7 +398,7 @@ cleanup:
* the public key is the result of performing a scalar point multiplication
* of that value with the curve's base point.
*/
-SECStatus
+SECStatus
EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey)
{
SECStatus rv = SECFailure;
@@ -396,38 +407,39 @@ EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey)
unsigned char *privKeyBytes = NULL;
if (!ecParams) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
}
len = ecParams->order.len;
privKeyBytes = ec_GenerateRandomPrivateKey(ecParams->order.data, len);
- if (privKeyBytes == NULL) goto cleanup;
+ if (privKeyBytes == NULL)
+ goto cleanup;
/* generate public key */
- CHECK_SEC_OK( ec_NewKey(ecParams, privKey, privKeyBytes, len) );
+ CHECK_SEC_OK(ec_NewKey(ecParams, privKey, privKeyBytes, len));
cleanup:
if (privKeyBytes) {
- PORT_ZFree(privKeyBytes, len);
+ PORT_ZFree(privKeyBytes, len);
}
#if EC_DEBUG
- printf("EC_NewKey returning %s\n",
- (rv == SECSuccess) ? "success" : "failure");
+ printf("EC_NewKey returning %s\n",
+ (rv == SECSuccess) ? "success" : "failure");
#endif
#else
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
#endif /* NSS_DISABLE_ECC */
-
+
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
+ * public key is not valid. These attacks can be prevented by
* validating the public key before using ECDH.
*/
-SECStatus
+SECStatus
EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue)
{
#ifndef NSS_DISABLE_ECC
@@ -437,59 +449,70 @@ EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue)
mp_err err = MP_OKAY;
int len;
- if (!ecParams || !publicValue) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
+ if (!ecParams || !publicValue || !ecParams->name) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* Uses curve specific code for point validation. */
+ if (ecParams->fieldID.type == ec_field_plain) {
+ const ECMethod *method = ec_get_method_from_name(ecParams->name);
+ if (method == NULL || method->validate == NULL) {
+ /* unknown curve */
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ return method->validate(publicValue);
}
-
+
/* NOTE: We only support uncompressed points for now */
len = (ecParams->fieldID.size + 7) >> 3;
if (publicValue->data[0] != EC_POINT_FORM_UNCOMPRESSED) {
- PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
- return SECFailure;
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
+ return SECFailure;
} else if (publicValue->len != (2 * len + 1)) {
- PORT_SetError(SEC_ERROR_BAD_KEY);
- return SECFailure;
+ PORT_SetError(SEC_ERROR_BAD_KEY);
+ return SECFailure;
}
MP_DIGITS(&Px) = 0;
MP_DIGITS(&Py) = 0;
- CHECK_MPI_OK( mp_init(&Px) );
- CHECK_MPI_OK( mp_init(&Py) );
+ CHECK_MPI_OK(mp_init(&Px));
+ CHECK_MPI_OK(mp_init(&Py));
/* Initialize Px and Py */
- CHECK_MPI_OK( mp_read_unsigned_octets(&Px, publicValue->data + 1, (mp_size) len) );
- CHECK_MPI_OK( mp_read_unsigned_octets(&Py, publicValue->data + 1 + len, (mp_size) len) );
+ CHECK_MPI_OK(mp_read_unsigned_octets(&Px, publicValue->data + 1, (mp_size)len));
+ CHECK_MPI_OK(mp_read_unsigned_octets(&Py, publicValue->data + 1 + len, (mp_size)len));
/* construct from named params */
group = ECGroup_fromName(ecParams->name);
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;
+ /*
+ * 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 */
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;
+ if (err == MP_NO) {
+ PORT_SetError(SEC_ERROR_BAD_KEY);
+ rv = SECFailure;
+ err = MP_OKAY; /* don't change the error code */
+ }
+ goto cleanup;
}
rv = SECSuccess;
@@ -499,8 +522,8 @@ cleanup:
mp_clear(&Px);
mp_clear(&Py);
if (err) {
- MP_TO_SEC_ERROR(err);
- rv = SECFailure;
+ MP_TO_SEC_ERROR(err);
+ rv = SECFailure;
}
return rv;
#else
@@ -509,7 +532,7 @@ cleanup:
#endif /* NSS_DISABLE_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
@@ -519,17 +542,17 @@ cleanup:
** produced. It is the caller's responsibility to free the allocated
** buffer containing the derived secret.
*/
-SECStatus
-ECDH_Derive(SECItem *publicValue,
+SECStatus
+ECDH_Derive(SECItem *publicValue,
ECParams *ecParams,
- SECItem *privateValue,
- PRBool withCofactor,
- SECItem *derivedSecret)
+ SECItem *privateValue,
+ PRBool withCofactor,
+ SECItem *derivedSecret)
{
SECStatus rv = SECFailure;
#ifndef NSS_DISABLE_ECC
unsigned int len = 0;
- SECItem pointQ = {siBuffer, NULL, 0};
+ SECItem pointQ = { siBuffer, NULL, 0 };
mp_int k; /* to hold the private value */
mp_int cofactor;
mp_err err = MP_OKAY;
@@ -537,10 +560,32 @@ ECDH_Derive(SECItem *publicValue,
int i;
#endif
- if (!publicValue || !ecParams || !privateValue ||
- !derivedSecret) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
+ if (!publicValue || !ecParams || !privateValue || !derivedSecret ||
+ !ecParams->name) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* Perform curve specific multiplication using ECMethod */
+ if (ecParams->fieldID.type == ec_field_plain) {
+ const ECMethod *method;
+ memset(derivedSecret, 0, sizeof(*derivedSecret));
+ derivedSecret = SECITEM_AllocItem(NULL, derivedSecret, ecParams->pointSize);
+ if (derivedSecret == NULL) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+ method = ec_get_method_from_name(ecParams->name);
+ if (method == NULL || method->validate == NULL ||
+ method->mul == NULL) {
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+ return SECFailure;
+ }
+ if (method->validate(publicValue) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_BAD_KEY);
+ return SECFailure;
+ }
+ return method->mul(derivedSecret, privateValue, publicValue);
}
/*
@@ -548,34 +593,36 @@ ECDH_Derive(SECItem *publicValue,
* this produces predictable results.
*/
if (ec_point_at_infinity(publicValue)) {
- PORT_SetError(SEC_ERROR_BAD_KEY);
- return SECFailure;
+ PORT_SetError(SEC_ERROR_BAD_KEY);
+ return SECFailure;
}
MP_DIGITS(&k) = 0;
memset(derivedSecret, 0, sizeof *derivedSecret);
- len = (ecParams->fieldID.size + 7) >> 3;
- pointQ.len = 2*len + 1;
- if ((pointQ.data = PORT_Alloc(2*len + 1)) == NULL) goto cleanup;
+ len = (ecParams->fieldID.size + 7) >> 3;
+ pointQ.len = ecParams->pointSize;
+ if ((pointQ.data = PORT_Alloc(ecParams->pointSize)) == NULL)
+ goto cleanup;
- CHECK_MPI_OK( mp_init(&k) );
- CHECK_MPI_OK( mp_read_unsigned_octets(&k, privateValue->data,
- (mp_size) privateValue->len) );
+ CHECK_MPI_OK(mp_init(&k));
+ CHECK_MPI_OK(mp_read_unsigned_octets(&k, privateValue->data,
+ (mp_size)privateValue->len));
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 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)
- goto cleanup;
+ if (ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ) != SECSuccess) {
+ goto cleanup;
+ }
if (ec_point_at_infinity(&pointQ)) {
- PORT_SetError(SEC_ERROR_BAD_KEY); /* XXX better error code? */
- goto cleanup;
+ PORT_SetError(SEC_ERROR_BAD_KEY); /* XXX better error code? */
+ goto cleanup;
}
/* Allocate memory for the derived secret and copy
@@ -588,8 +635,8 @@ ECDH_Derive(SECItem *publicValue,
#if EC_DEBUG
printf("derived_secret:\n");
- for (i = 0; i < derivedSecret->len; i++)
- printf("%02x:", derivedSecret->data[i]);
+ for (i = 0; i < derivedSecret->len; i++)
+ printf("%02x:", derivedSecret->data[i]);
printf("\n");
#endif
@@ -597,11 +644,11 @@ cleanup:
mp_clear(&k);
if (err) {
- MP_TO_SEC_ERROR(err);
+ MP_TO_SEC_ERROR(err);
}
if (pointQ.data) {
- PORT_ZFree(pointQ.data, 2*len + 1);
+ PORT_ZFree(pointQ.data, ecParams->pointSize);
}
#else
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
@@ -614,22 +661,24 @@ cleanup:
* 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)
+SECStatus
+ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
+ const SECItem *digest, const unsigned char *kb, const int kblen)
{
SECStatus rv = SECFailure;
#ifndef NSS_DISABLE_ECC
mp_int x1;
- mp_int d, k; /* private key, random integer */
- mp_int r, s; /* tuple (r, s) is the signature */
+ mp_int d, k; /* private key, random integer */
+ mp_int r, s; /* tuple (r, s) is the signature */
+ mp_int t; /* holding tmp values */
mp_int n;
mp_err err = MP_OKAY;
ECParams *ecParams = NULL;
- SECItem kGpoint = { siBuffer, NULL, 0};
- int flen = 0; /* length in bytes of the field size */
- unsigned olen; /* length in bytes of the base point order */
- unsigned obits; /* length in bits of the base point order */
+ SECItem kGpoint = { siBuffer, NULL, 0 };
+ int flen = 0; /* length in bytes of the field size */
+ unsigned olen; /* length in bytes of the base point order */
+ unsigned obits; /* length in bits of the base point order */
+ unsigned char *t2 = NULL;
#if EC_DEBUG
char mpstr[256];
@@ -643,48 +692,49 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
MP_DIGITS(&r) = 0;
MP_DIGITS(&s) = 0;
MP_DIGITS(&n) = 0;
+ MP_DIGITS(&t) = 0;
/* Check args */
if (!key || !signature || !digest || !kb || (kblen < 0)) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- goto cleanup;
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto cleanup;
}
ecParams = &(key->ecParams);
flen = (ecParams->fieldID.size + 7) >> 3;
- olen = ecParams->order.len;
+ olen = ecParams->order.len;
if (signature->data == NULL) {
- /* a call to get the signature length only */
- goto finish;
+ /* a call to get the signature length only */
+ goto finish;
}
- if (signature->len < 2*olen) {
- PORT_SetError(SEC_ERROR_OUTPUT_LEN);
- goto cleanup;
+ if (signature->len < 2 * olen) {
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ goto cleanup;
}
+ CHECK_MPI_OK(mp_init(&x1));
+ CHECK_MPI_OK(mp_init(&d));
+ CHECK_MPI_OK(mp_init(&k));
+ CHECK_MPI_OK(mp_init(&r));
+ CHECK_MPI_OK(mp_init(&s));
+ CHECK_MPI_OK(mp_init(&n));
+ CHECK_MPI_OK(mp_init(&t));
- CHECK_MPI_OK( mp_init(&x1) );
- CHECK_MPI_OK( mp_init(&d) );
- CHECK_MPI_OK( mp_init(&k) );
- CHECK_MPI_OK( mp_init(&r) );
- CHECK_MPI_OK( mp_init(&s) );
- CHECK_MPI_OK( mp_init(&n) );
-
- SECITEM_TO_MPINT( ecParams->order, &n );
- SECITEM_TO_MPINT( key->privateValue, &d );
+ SECITEM_TO_MPINT(ecParams->order, &n);
+ SECITEM_TO_MPINT(key->privateValue, &d);
- CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) );
+ CHECK_MPI_OK(mp_read_unsigned_octets(&k, kb, kblen));
/* Make sure k is in the interval [1, n-1] */
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);
+ printf("k : %s \n", mpstr);
mp_tohex(&n, mpstr);
- printf("n : %s \n", mpstr);
+ printf("n : %s \n", mpstr);
#endif
- PORT_SetError(SEC_ERROR_NEED_RANDOM);
- goto cleanup;
+ PORT_SetError(SEC_ERROR_NEED_RANDOM);
+ goto cleanup;
}
/*
@@ -703,61 +753,60 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
** final value has exactly one more bit than n. Thus, we
** always end up with a value that exactly one more bit than n.
*/
- CHECK_MPI_OK( mp_add(&k, &n, &k) );
+ CHECK_MPI_OK(mp_add(&k, &n, &k));
if (mpl_significant_bits(&k) <= mpl_significant_bits(&n)) {
- CHECK_MPI_OK( mp_add(&k, &n, &k) );
+ CHECK_MPI_OK(mp_add(&k, &n, &k));
}
- /*
+ /*
** ANSI X9.62, Section 5.3.2, Step 2
**
** Compute kG
*/
- kGpoint.len = 2*flen + 1;
- kGpoint.data = PORT_Alloc(2*flen + 1);
+ kGpoint.len = ecParams->pointSize;
+ kGpoint.data = PORT_Alloc(ecParams->pointSize);
if ((kGpoint.data == NULL) ||
- (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint)
- != SECSuccess))
- goto cleanup;
+ (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint) != SECSuccess))
+ goto cleanup;
- /*
+ /*
** ANSI X9.62, Section 5.3.3, Step 1
**
** Extract the x co-ordinate of kG into x1
*/
- CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1,
- (mp_size) flen) );
+ 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
*/
- CHECK_MPI_OK( mp_mod(&x1, &n, &r) );
+ CHECK_MPI_OK(mp_mod(&x1, &n, &r));
/*
** ANSI X9.62, Section 5.3.3, Step 3
**
- ** verify r != 0
+ ** verify r != 0
*/
if (mp_cmp_z(&r) == 0) {
- PORT_SetError(SEC_ERROR_NEED_RANDOM);
- goto cleanup;
+ 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
+ ** s = (k**-1 * (HASH(M) + d*r)) mod n
*/
- SECITEM_TO_MPINT(*digest, &s); /* s = HASH(M) */
+ SECITEM_TO_MPINT(*digest, &s); /* s = HASH(M) */
/* In the definition of EC signing, digests are truncated
- * to the length of n in bits.
+ * to the length of n in bits.
* (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
- CHECK_MPI_OK( (obits = mpl_significant_bits(&n)) );
- if (digest->len*8 > obits) {
- mpl_rsh(&s,&s,digest->len*8 - obits);
+ CHECK_MPI_OK((obits = mpl_significant_bits(&n)));
+ if (digest->len * 8 > obits) {
+ mpl_rsh(&s, &s, digest->len * 8 - obits);
}
#if EC_DEBUG
@@ -775,10 +824,22 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
printf("r : %s\n", mpstr);
#endif
- CHECK_MPI_OK( mp_invmod(&k, &n, &k) ); /* k = k**-1 mod n */
- CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) ); /* d = d * r mod n */
- CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) ); /* s = s + d mod n */
- CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) ); /* s = s * k mod n */
+ if ((t2 = PORT_Alloc(2 * ecParams->order.len)) == NULL) {
+ rv = SECFailure;
+ goto cleanup;
+ }
+ if (RNG_GenerateGlobalRandomBytes(t2, 2 * ecParams->order.len) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_NEED_RANDOM);
+ rv = SECFailure;
+ goto cleanup;
+ }
+ CHECK_MPI_OK(mp_read_unsigned_octets(&t, t2, 2 * ecParams->order.len)); /* t <-$ Zn */
+ CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k)); /* k = k * t mod n */
+ CHECK_MPI_OK(mp_invmod(&k, &n, &k)); /* k = k**-1 mod n */
+ CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k)); /* k = k * t mod n */
+ CHECK_MPI_OK(mp_mulmod(&d, &r, &n, &d)); /* d = d * r mod n */
+ CHECK_MPI_OK(mp_addmod(&s, &d, &n, &s)); /* s = s + d mod n */
+ CHECK_MPI_OK(mp_mulmod(&s, &k, &n, &s)); /* s = s * k mod n */
#if EC_DEBUG
mp_todecimal(&s, mpstr);
@@ -793,18 +854,18 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
** verify s != 0
*/
if (mp_cmp_z(&s) == 0) {
- PORT_SetError(SEC_ERROR_NEED_RANDOM);
- goto cleanup;
+ PORT_SetError(SEC_ERROR_NEED_RANDOM);
+ goto cleanup;
}
- /*
+ /*
**
** Signature is tuple (r, s)
*/
- CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, olen) );
- CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + olen, olen) );
+ CHECK_MPI_OK(mp_to_fixlen_octets(&r, signature->data, olen));
+ CHECK_MPI_OK(mp_to_fixlen_octets(&s, signature->data + olen, olen));
finish:
- signature->len = 2*olen;
+ signature->len = 2 * olen;
rv = SECSuccess;
err = MP_OKAY;
@@ -815,60 +876,66 @@ cleanup:
mp_clear(&r);
mp_clear(&s);
mp_clear(&n);
+ mp_clear(&t);
+
+ if (t2) {
+ PORT_Free(t2);
+ }
if (kGpoint.data) {
- PORT_ZFree(kGpoint.data, 2*flen + 1);
+ PORT_ZFree(kGpoint.data, ecParams->pointSize);
}
if (err) {
- MP_TO_SEC_ERROR(err);
- rv = SECFailure;
+ MP_TO_SEC_ERROR(err);
+ rv = SECFailure;
}
#if EC_DEBUG
printf("ECDSA signing with seed %s\n",
- (rv == SECSuccess) ? "succeeded" : "failed");
+ (rv == SECSuccess) ? "succeeded" : "failed");
#endif
#else
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
#endif /* NSS_DISABLE_ECC */
- return rv;
+ return rv;
}
/*
-** Computes the ECDSA signature on the digest using the given key
+** Computes the ECDSA signature on the digest using the given key
** and a random seed.
*/
-SECStatus
+SECStatus
ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest)
{
SECStatus rv = SECFailure;
#ifndef NSS_DISABLE_ECC
int len;
- unsigned char *kBytes= NULL;
+ unsigned char *kBytes = NULL;
if (!key) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
}
/* Generate random value k */
len = key->ecParams.order.len;
kBytes = ec_GenerateRandomPrivateKey(key->ecParams.order.data, len);
- if (kBytes == NULL) goto cleanup;
+ if (kBytes == NULL)
+ goto cleanup;
/* Generate ECDSA signature with the specified k value */
rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len);
-cleanup:
+cleanup:
if (kBytes) {
- PORT_ZFree(kBytes, len);
+ PORT_ZFree(kBytes, len);
}
#if EC_DEBUG
printf("ECDSA signing %s\n",
- (rv == SECSuccess) ? "succeeded" : "failed");
+ (rv == SECSuccess) ? "succeeded" : "failed");
#endif
#else
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
@@ -885,14 +952,14 @@ cleanup:
** of this function is undefined. In cases where a public key might
** not be valid, use EC_ValidatePublicKey to check.
*/
-SECStatus
-ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
- const SECItem *digest)
+SECStatus
+ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
+ const SECItem *digest)
{
SECStatus rv = SECFailure;
#ifndef NSS_DISABLE_ECC
- mp_int r_, s_; /* tuple (r', s') is received signature) */
- mp_int c, u1, u2, v; /* intermediate values used in verification */
+ 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;
mp_err err = MP_OKAY;
@@ -916,45 +983,45 @@ ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
MP_DIGITS(&u1) = 0;
MP_DIGITS(&u2) = 0;
MP_DIGITS(&x1) = 0;
- MP_DIGITS(&v) = 0;
- MP_DIGITS(&n) = 0;
+ MP_DIGITS(&v) = 0;
+ MP_DIGITS(&n) = 0;
/* Check args */
if (!key || !signature || !digest) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- goto cleanup;
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto cleanup;
}
ecParams = &(key->ecParams);
- flen = (ecParams->fieldID.size + 7) >> 3;
- olen = ecParams->order.len;
- if (signature->len == 0 || signature->len%2 != 0 ||
- signature->len > 2*olen) {
- PORT_SetError(SEC_ERROR_INPUT_LEN);
- goto cleanup;
+ flen = (ecParams->fieldID.size + 7) >> 3;
+ olen = ecParams->order.len;
+ if (signature->len == 0 || signature->len % 2 != 0 ||
+ signature->len > 2 * olen) {
+ PORT_SetError(SEC_ERROR_INPUT_LEN);
+ goto cleanup;
}
- slen = signature->len/2;
+ slen = signature->len / 2;
- SECITEM_AllocItem(NULL, &pointC, 2*flen + 1);
+ SECITEM_AllocItem(NULL, &pointC, ecParams->pointSize);
if (pointC.data == NULL)
- goto cleanup;
+ goto cleanup;
- CHECK_MPI_OK( mp_init(&r_) );
- CHECK_MPI_OK( mp_init(&s_) );
- CHECK_MPI_OK( mp_init(&c) );
- CHECK_MPI_OK( mp_init(&u1) );
- CHECK_MPI_OK( mp_init(&u2) );
- CHECK_MPI_OK( mp_init(&x1) );
- CHECK_MPI_OK( mp_init(&v) );
- CHECK_MPI_OK( mp_init(&n) );
+ CHECK_MPI_OK(mp_init(&r_));
+ CHECK_MPI_OK(mp_init(&s_));
+ CHECK_MPI_OK(mp_init(&c));
+ CHECK_MPI_OK(mp_init(&u1));
+ CHECK_MPI_OK(mp_init(&u2));
+ CHECK_MPI_OK(mp_init(&x1));
+ CHECK_MPI_OK(mp_init(&v));
+ CHECK_MPI_OK(mp_init(&n));
/*
** Convert received signature (r', s') into MPI integers.
*/
- CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, slen) );
- CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + slen, slen) );
-
- /*
+ CHECK_MPI_OK(mp_read_unsigned_octets(&r_, signature->data, slen));
+ 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
@@ -962,8 +1029,8 @@ ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
SECITEM_TO_MPINT(ecParams->order, &n);
if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) {
- PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
- goto cleanup; /* will return rv == SECFailure */
+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+ goto cleanup; /* will return rv == SECFailure */
}
/*
@@ -971,21 +1038,21 @@ ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
**
** c = (s')**-1 mod n
*/
- CHECK_MPI_OK( mp_invmod(&s_, &n, &c) ); /* c = (s')**-1 mod n */
+ 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
*/
- SECITEM_TO_MPINT(*digest, &u1); /* u1 = HASH(M) */
+ SECITEM_TO_MPINT(*digest, &u1); /* u1 = HASH(M) */
/* In the definition of EC signing, digests are truncated
- * to the length of n in bits.
+ * to the length of n in bits.
* (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
- CHECK_MPI_OK( (obits = mpl_significant_bits(&n)) );
- if (digest->len*8 > obits) { /* u1 = HASH(M') */
- mpl_rsh(&u1,&u1,digest->len*8 - obits);
+ CHECK_MPI_OK((obits = mpl_significant_bits(&n)));
+ if (digest->len * 8 > obits) { /* u1 = HASH(M') */
+ mpl_rsh(&u1, &u1, digest->len * 8 - obits);
}
#if EC_DEBUG
@@ -999,14 +1066,14 @@ ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
printf("digest: %s (dec)\n", mpstr);
#endif
- CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) ); /* u1 = u1 * c mod n */
+ 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
*/
- CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) );
+ CHECK_MPI_OK(mp_mulmod(&r_, &c, &n, &u2));
/*
** ANSI X9.62, Section 5.4.3, Step 1
@@ -1015,25 +1082,24 @@ ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
** 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)
- != SECSuccess) {
- rv = SECFailure;
- goto cleanup;
+ if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC) != SECSuccess) {
+ rv = SECFailure;
+ goto cleanup;
}
if (ec_point_at_infinity(&pointC)) {
- PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
- rv = SECFailure;
- goto cleanup;
+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+ rv = SECFailure;
+ goto cleanup;
}
- CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, flen) );
+ 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
*/
- CHECK_MPI_OK( mp_mod(&x1, &n, &v) );
+ CHECK_MPI_OK(mp_mod(&x1, &n, &v));
#if EC_DEBUG
mp_todecimal(&r_, mpstr);
@@ -1048,10 +1114,10 @@ ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
** Verification: v == r'
*/
if (mp_cmp(&v, &r_)) {
- PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
- rv = SECFailure; /* Signature failed to verify. */
+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+ rv = SECFailure; /* Signature failed to verify. */
} else {
- rv = SECSuccess; /* Signature verified. */
+ rv = SECSuccess; /* Signature verified. */
}
#if EC_DEBUG
@@ -1075,15 +1141,16 @@ cleanup:
mp_clear(&v);
mp_clear(&n);
- if (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE);
+ if (pointC.data)
+ SECITEM_ZfreeItem(&pointC, PR_FALSE);
if (err) {
- MP_TO_SEC_ERROR(err);
- rv = SECFailure;
+ MP_TO_SEC_ERROR(err);
+ rv = SECFailure;
}
#if EC_DEBUG
printf("ECDSA verification %s\n",
- (rv == SECSuccess) ? "succeeded" : "failed");
+ (rv == SECSuccess) ? "succeeded" : "failed");
#endif
#else
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
@@ -1091,4 +1158,3 @@ cleanup:
return rv;
}
-