/* * 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 ECGroup *group = NULL; SECStatus rv = SECFailure; 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 */ 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); } } #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) ); } /* 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) ); 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: ECGroup_free(group); mp_clear(&Px); mp_clear(&Py); mp_clear(&Qx); mp_clear(&Qy); mp_clear(&Gx); mp_clear(&Gy); mp_clear(&order); mp_clear(&irreducible); mp_clear(&a); mp_clear(&b); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } 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) { #ifndef NSS_DISABLE_ECC mp_int Px, Py; ECGroup *group = NULL; SECStatus rv = SECFailure; mp_err err = MP_OKAY; int len; if (!ecParams || !publicValue) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* 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; } else if (publicValue->len != (2 * len + 1)) { 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) ); /* 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) ); /* 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; } /* 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; } rv = SECSuccess; cleanup: ECGroup_free(group); mp_clear(&Px); mp_clear(&Py); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; #else PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); return SECFailure; #endif /* NSS_DISABLE_ECC */ }
/* * 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, int kmflag) { mp_int Px, Py, Qx, Qy; mp_int Gx, Gy, order, irreducible, a, b; ECGroup *group = NULL; SECStatus rv = SECFailure; mp_err err = MP_OKAY; int len; #if EC_DEBUG int i; char mpstr[256]; 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 */ len = (params->fieldID.size + 7) >> 3; if (pointP != NULL) { if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) || (pointP->len != (unsigned int)(2 * len + 1))) { 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) ); 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: ECGroup_free(group); mp_clear(&Px); mp_clear(&Py); mp_clear(&Qx); mp_clear(&Qy); mp_clear(&Gx); mp_clear(&Gy); mp_clear(&order); mp_clear(&irreducible); mp_clear(&a); mp_clear(&b); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }