Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/native/sun/security/ec/impl/ec.c
38918 views
/*1* Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.2* Use is subject to license terms.3*4* This library is free software; you can redistribute it and/or5* modify it under the terms of the GNU Lesser General Public6* License as published by the Free Software Foundation; either7* version 2.1 of the License, or (at your option) any later version.8*9* This library is distributed in the hope that it will be useful,10* but WITHOUT ANY WARRANTY; without even the implied warranty of11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU12* Lesser General Public License for more details.13*14* You should have received a copy of the GNU Lesser General Public License15* along with this library; if not, write to the Free Software Foundation,16* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/* *********************************************************************24*25* The Original Code is the Elliptic Curve Cryptography library.26*27* The Initial Developer of the Original Code is28* Sun Microsystems, Inc.29* Portions created by the Initial Developer are Copyright (C) 200330* the Initial Developer. All Rights Reserved.31*32* Contributor(s):33* Dr Vipul Gupta <[email protected]> and34* Douglas Stebila <[email protected]>, Sun Microsystems Laboratories35*36* Last Modified Date from the Original Code: May 201737*********************************************************************** */3839#include "mplogic.h"40#include "ec.h"41#include "ecl.h"4243#include <sys/types.h>44#ifndef _KERNEL45#include <stdlib.h>46#include <string.h>4748#ifndef _WIN3249#include <stdio.h>50#include <strings.h>51#endif /* _WIN32 */5253#endif54#include "ecl-exp.h"55#include "mpi.h"56#include "ecc_impl.h"5758#ifdef _KERNEL59#define PORT_ZFree(p, l) bzero((p), (l)); kmem_free((p), (l))60#else61#ifndef _WIN3262#define PORT_ZFree(p, l) bzero((p), (l)); free((p))63#else64#define PORT_ZFree(p, l) memset((p), 0, (l)); free((p))65#endif /* _WIN32 */66#endif6768/*69* Returns true if pointP is the point at infinity, false otherwise70*/71PRBool72ec_point_at_infinity(SECItem *pointP)73{74unsigned int i;7576for (i = 1; i < pointP->len; i++) {77if (pointP->data[i] != 0x00) return PR_FALSE;78}7980return PR_TRUE;81}8283/*84* Computes scalar point multiplication pointQ = k1 * G + k2 * pointP for85* the curve whose parameters are encoded in params with base point G.86*/87SECStatus88ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2,89const SECItem *pointP, SECItem *pointQ, int kmflag, int timing)90{91mp_int Px, Py, Qx, Qy;92mp_int Gx, Gy, order, irreducible, a, b;93#if 0 /* currently don't support non-named curves */94unsigned int irr_arr[5];95#endif96ECGroup *group = NULL;97SECStatus rv = SECFailure;98mp_err err = MP_OKAY;99unsigned int len;100101#if EC_DEBUG102int i;103char mpstr[256];104105printf("ec_points_mul: params [len=%d]:", params->DEREncoding.len);106for (i = 0; i < params->DEREncoding.len; i++)107printf("%02x:", params->DEREncoding.data[i]);108printf("\n");109110if (k1 != NULL) {111mp_tohex(k1, mpstr);112printf("ec_points_mul: scalar k1: %s\n", mpstr);113mp_todecimal(k1, mpstr);114printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr);115}116117if (k2 != NULL) {118mp_tohex(k2, mpstr);119printf("ec_points_mul: scalar k2: %s\n", mpstr);120mp_todecimal(k2, mpstr);121printf("ec_points_mul: scalar k2: %s (dec)\n", mpstr);122}123124if (pointP != NULL) {125printf("ec_points_mul: pointP [len=%d]:", pointP->len);126for (i = 0; i < pointP->len; i++)127printf("%02x:", pointP->data[i]);128printf("\n");129}130#endif131132/* NOTE: We only support uncompressed points for now */133len = (params->fieldID.size + 7) >> 3;134if (pointP != NULL) {135if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||136(pointP->len != (2 * len + 1))) {137return SECFailure;138};139}140141MP_DIGITS(&Px) = 0;142MP_DIGITS(&Py) = 0;143MP_DIGITS(&Qx) = 0;144MP_DIGITS(&Qy) = 0;145MP_DIGITS(&Gx) = 0;146MP_DIGITS(&Gy) = 0;147MP_DIGITS(&order) = 0;148MP_DIGITS(&irreducible) = 0;149MP_DIGITS(&a) = 0;150MP_DIGITS(&b) = 0;151CHECK_MPI_OK( mp_init(&Px, kmflag) );152CHECK_MPI_OK( mp_init(&Py, kmflag) );153CHECK_MPI_OK( mp_init(&Qx, kmflag) );154CHECK_MPI_OK( mp_init(&Qy, kmflag) );155CHECK_MPI_OK( mp_init(&Gx, kmflag) );156CHECK_MPI_OK( mp_init(&Gy, kmflag) );157CHECK_MPI_OK( mp_init(&order, kmflag) );158CHECK_MPI_OK( mp_init(&irreducible, kmflag) );159CHECK_MPI_OK( mp_init(&a, kmflag) );160CHECK_MPI_OK( mp_init(&b, kmflag) );161162if ((k2 != NULL) && (pointP != NULL)) {163/* Initialize Px and Py */164CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size) len) );165CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) );166}167168/* construct from named params, if possible */169if (params->name != ECCurve_noName) {170group = ECGroup_fromName(params->name, kmflag);171}172173#if 0 /* currently don't support non-named curves */174if (group == NULL) {175/* Set up mp_ints containing the curve coefficients */176CHECK_MPI_OK( mp_read_unsigned_octets(&Gx, params->base.data + 1,177(mp_size) len) );178CHECK_MPI_OK( mp_read_unsigned_octets(&Gy, params->base.data + 1 + len,179(mp_size) len) );180SECITEM_TO_MPINT( params->order, &order );181SECITEM_TO_MPINT( params->curve.a, &a );182SECITEM_TO_MPINT( params->curve.b, &b );183if (params->fieldID.type == ec_field_GFp) {184SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible );185group = ECGroup_consGFp(&irreducible, &a, &b, &Gx, &Gy, &order, params->cofactor);186} else {187SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible );188irr_arr[0] = params->fieldID.size;189irr_arr[1] = params->fieldID.k1;190irr_arr[2] = params->fieldID.k2;191irr_arr[3] = params->fieldID.k3;192irr_arr[4] = 0;193group = ECGroup_consGF2m(&irreducible, irr_arr, &a, &b, &Gx, &Gy, &order, params->cofactor);194}195}196#endif197if (group == NULL)198goto cleanup;199200if ((k2 != NULL) && (pointP != NULL)) {201CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy, timing) );202} else {203CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy, timing) );204}205206/* Construct the SECItem representation of point Q */207pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED;208CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1,209(mp_size) len) );210CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len,211(mp_size) len) );212213rv = SECSuccess;214215#if EC_DEBUG216printf("ec_points_mul: pointQ [len=%d]:", pointQ->len);217for (i = 0; i < pointQ->len; i++)218printf("%02x:", pointQ->data[i]);219printf("\n");220#endif221222cleanup:223ECGroup_free(group);224mp_clear(&Px);225mp_clear(&Py);226mp_clear(&Qx);227mp_clear(&Qy);228mp_clear(&Gx);229mp_clear(&Gy);230mp_clear(&order);231mp_clear(&irreducible);232mp_clear(&a);233mp_clear(&b);234if (err) {235MP_TO_SEC_ERROR(err);236rv = SECFailure;237}238239return rv;240}241242/* Generates a new EC key pair. The private key is a supplied243* value and the public key is the result of performing a scalar244* point multiplication of that value with the curve's base point.245*/246SECStatus247ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey,248const unsigned char *privKeyBytes, int privKeyLen, int kmflag)249{250SECStatus rv = SECFailure;251PRArenaPool *arena;252ECPrivateKey *key;253mp_int k;254mp_err err = MP_OKAY;255int len;256257#if EC_DEBUG258printf("ec_NewKey called\n");259#endif260261if (!ecParams || !privKey || !privKeyBytes || (privKeyLen < 0)) {262PORT_SetError(SEC_ERROR_INVALID_ARGS);263return SECFailure;264}265266/* Initialize an arena for the EC key. */267if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))268return SECFailure;269270key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey),271kmflag);272if (!key) {273PORT_FreeArena(arena, PR_TRUE);274return SECFailure;275}276277/* Set the version number (SEC 1 section C.4 says it should be 1) */278SECITEM_AllocItem(arena, &key->version, 1, kmflag);279key->version.data[0] = 1;280281/* Copy all of the fields from the ECParams argument to the282* ECParams structure within the private key.283*/284key->ecParams.arena = arena;285key->ecParams.type = ecParams->type;286key->ecParams.fieldID.size = ecParams->fieldID.size;287key->ecParams.fieldID.type = ecParams->fieldID.type;288if (ecParams->fieldID.type == ec_field_GFp) {289CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime,290&ecParams->fieldID.u.prime, kmflag));291} else {292CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.poly,293&ecParams->fieldID.u.poly, kmflag));294}295key->ecParams.fieldID.k1 = ecParams->fieldID.k1;296key->ecParams.fieldID.k2 = ecParams->fieldID.k2;297key->ecParams.fieldID.k3 = ecParams->fieldID.k3;298CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a,299&ecParams->curve.a, kmflag));300CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b,301&ecParams->curve.b, kmflag));302CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed,303&ecParams->curve.seed, kmflag));304CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base,305&ecParams->base, kmflag));306CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order,307&ecParams->order, kmflag));308key->ecParams.cofactor = ecParams->cofactor;309CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding,310&ecParams->DEREncoding, kmflag));311key->ecParams.name = ecParams->name;312CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID,313&ecParams->curveOID, kmflag));314315len = (ecParams->fieldID.size + 7) >> 3;316SECITEM_AllocItem(arena, &key->publicValue, 2*len + 1, kmflag);317len = ecParams->order.len;318SECITEM_AllocItem(arena, &key->privateValue, len, kmflag);319320/* Copy private key */321if (privKeyLen >= len) {322memcpy(key->privateValue.data, privKeyBytes, len);323} else {324memset(key->privateValue.data, 0, (len - privKeyLen));325memcpy(key->privateValue.data + (len - privKeyLen), privKeyBytes, privKeyLen);326}327328/* Compute corresponding public key */329MP_DIGITS(&k) = 0;330CHECK_MPI_OK( mp_init(&k, kmflag) );331CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data,332(mp_size) len) );333334/* key generation does not support timing mitigation */335rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue), kmflag, /*timing*/ 0);336if (rv != SECSuccess) goto cleanup;337*privKey = key;338339cleanup:340mp_clear(&k);341if (rv) {342PORT_FreeArena(arena, PR_TRUE);343}344345#if EC_DEBUG346printf("ec_NewKey returning %s\n",347(rv == SECSuccess) ? "success" : "failure");348#endif349350return rv;351352}353354/* Generates a new EC key pair. The private key is a supplied355* random value (in seed) and the public key is the result of356* performing a scalar point multiplication of that value with357* the curve's base point.358*/359SECStatus360EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey,361const unsigned char *seed, int seedlen, int kmflag)362{363SECStatus rv = SECFailure;364rv = ec_NewKey(ecParams, privKey, seed, seedlen, kmflag);365return rv;366}367368/* Generate a random private key using the algorithm A.4.1 of ANSI X9.62,369* modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the370* random number generator.371*372* Parameters373* - order: a buffer that holds the curve's group order374* - len: the length in octets of the order buffer375* - random: a buffer of 2 * len random bytes376* - randomlen: the length in octets of the random buffer377*378* Return Value379* Returns a buffer of len octets that holds the private key. The caller380* is responsible for freeing the buffer with PORT_ZFree.381*/382static unsigned char *383ec_GenerateRandomPrivateKey(const unsigned char *order, int len,384const unsigned char *random, int randomlen, int kmflag)385{386SECStatus rv = SECSuccess;387mp_err err;388unsigned char *privKeyBytes = NULL;389mp_int privKeyVal, order_1, one;390391MP_DIGITS(&privKeyVal) = 0;392MP_DIGITS(&order_1) = 0;393MP_DIGITS(&one) = 0;394CHECK_MPI_OK( mp_init(&privKeyVal, kmflag) );395CHECK_MPI_OK( mp_init(&order_1, kmflag) );396CHECK_MPI_OK( mp_init(&one, kmflag) );397398/*399* Reduces the 2*len buffer of random bytes modulo the group order.400*/401if ((privKeyBytes = PORT_Alloc(2*len, kmflag)) == NULL) goto cleanup;402if (randomlen != 2 * len) {403randomlen = 2 * len;404}405/* No need to generate - random bytes are now supplied */406/* CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) );*/407memcpy(privKeyBytes, random, randomlen);408409CHECK_MPI_OK( mp_read_unsigned_octets(&privKeyVal, privKeyBytes, 2*len) );410CHECK_MPI_OK( mp_read_unsigned_octets(&order_1, order, len) );411CHECK_MPI_OK( mp_set_int(&one, 1) );412CHECK_MPI_OK( mp_sub(&order_1, &one, &order_1) );413CHECK_MPI_OK( mp_mod(&privKeyVal, &order_1, &privKeyVal) );414CHECK_MPI_OK( mp_add(&privKeyVal, &one, &privKeyVal) );415CHECK_MPI_OK( mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len) );416memset(privKeyBytes+len, 0, len);417cleanup:418mp_clear(&privKeyVal);419mp_clear(&order_1);420mp_clear(&one);421if (err < MP_OKAY) {422MP_TO_SEC_ERROR(err);423rv = SECFailure;424}425if (rv != SECSuccess && privKeyBytes) {426#ifdef _KERNEL427kmem_free(privKeyBytes, 2*len);428#else429free(privKeyBytes);430#endif431privKeyBytes = NULL;432}433return privKeyBytes;434}435436/* Generates a new EC key pair. The private key is a random value and437* the public key is the result of performing a scalar point multiplication438* of that value with the curve's base point.439*/440SECStatus441EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey,442const unsigned char* random, int randomlen, int kmflag)443{444SECStatus rv = SECFailure;445int len;446unsigned char *privKeyBytes = NULL;447448if (!ecParams) {449PORT_SetError(SEC_ERROR_INVALID_ARGS);450return SECFailure;451}452453len = ecParams->order.len;454privKeyBytes = ec_GenerateRandomPrivateKey(ecParams->order.data, len,455random, randomlen, kmflag);456if (privKeyBytes == NULL) goto cleanup;457/* generate public key */458CHECK_SEC_OK( ec_NewKey(ecParams, privKey, privKeyBytes, len, kmflag) );459460cleanup:461if (privKeyBytes) {462PORT_ZFree(privKeyBytes, len * 2);463}464#if EC_DEBUG465printf("EC_NewKey returning %s\n",466(rv == SECSuccess) ? "success" : "failure");467#endif468469return rv;470}471472/* Validates an EC public key as described in Section 5.2.2 of473* X9.62. The ECDH primitive when used without the cofactor does474* not address small subgroup attacks, which may occur when the475* public key is not valid. These attacks can be prevented by476* validating the public key before using ECDH.477*/478SECStatus479EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue, int kmflag)480{481mp_int Px, Py;482ECGroup *group = NULL;483SECStatus rv = SECFailure;484mp_err err = MP_OKAY;485unsigned int len;486487if (!ecParams || !publicValue) {488PORT_SetError(SEC_ERROR_INVALID_ARGS);489return SECFailure;490}491492/* NOTE: We only support uncompressed points for now */493len = (ecParams->fieldID.size + 7) >> 3;494if (publicValue->data[0] != EC_POINT_FORM_UNCOMPRESSED) {495PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);496return SECFailure;497} else if (publicValue->len != (2 * len + 1)) {498PORT_SetError(SEC_ERROR_BAD_KEY);499return SECFailure;500}501502MP_DIGITS(&Px) = 0;503MP_DIGITS(&Py) = 0;504CHECK_MPI_OK( mp_init(&Px, kmflag) );505CHECK_MPI_OK( mp_init(&Py, kmflag) );506507/* Initialize Px and Py */508CHECK_MPI_OK( mp_read_unsigned_octets(&Px, publicValue->data + 1, (mp_size) len) );509CHECK_MPI_OK( mp_read_unsigned_octets(&Py, publicValue->data + 1 + len, (mp_size) len) );510511/* construct from named params */512group = ECGroup_fromName(ecParams->name, kmflag);513if (group == NULL) {514/*515* ECGroup_fromName fails if ecParams->name is not a valid516* ECCurveName value, or if we run out of memory, or perhaps517* for other reasons. Unfortunately if ecParams->name is a518* valid ECCurveName value, we don't know what the right error519* code should be because ECGroup_fromName doesn't return an520* error code to the caller. Set err to MP_UNDEF because521* that's what ECGroup_fromName uses internally.522*/523if ((ecParams->name <= ECCurve_noName) ||524(ecParams->name >= ECCurve_pastLastCurve)) {525err = MP_BADARG;526} else {527err = MP_UNDEF;528}529goto cleanup;530}531532/* validate public point */533if ((err = ECPoint_validate(group, &Px, &Py)) < MP_YES) {534if (err == MP_NO) {535PORT_SetError(SEC_ERROR_BAD_KEY);536rv = SECFailure;537err = MP_OKAY; /* don't change the error code */538}539goto cleanup;540}541542rv = SECSuccess;543544cleanup:545ECGroup_free(group);546mp_clear(&Px);547mp_clear(&Py);548if (err) {549MP_TO_SEC_ERROR(err);550rv = SECFailure;551}552return rv;553}554555/*556** Performs an ECDH key derivation by computing the scalar point557** multiplication of privateValue and publicValue (with or without the558** cofactor) and returns the x-coordinate of the resulting elliptic559** curve point in derived secret. If successful, derivedSecret->data560** is set to the address of the newly allocated buffer containing the561** derived secret, and derivedSecret->len is the size of the secret562** produced. It is the caller's responsibility to free the allocated563** buffer containing the derived secret.564*/565SECStatus566ECDH_Derive(SECItem *publicValue,567ECParams *ecParams,568SECItem *privateValue,569PRBool withCofactor,570SECItem *derivedSecret,571int kmflag)572{573SECStatus rv = SECFailure;574unsigned int len = 0;575SECItem pointQ = {siBuffer, NULL, 0};576mp_int k; /* to hold the private value */577mp_int cofactor;578mp_err err = MP_OKAY;579#if EC_DEBUG580int i;581#endif582583if (!publicValue || !ecParams || !privateValue ||584!derivedSecret) {585PORT_SetError(SEC_ERROR_INVALID_ARGS);586return SECFailure;587}588589if (EC_ValidatePublicKey(ecParams, publicValue, kmflag) != SECSuccess) {590return SECFailure;591}592593memset(derivedSecret, 0, sizeof *derivedSecret);594len = (ecParams->fieldID.size + 7) >> 3;595pointQ.len = 2*len + 1;596if ((pointQ.data = PORT_Alloc(2*len + 1, kmflag)) == NULL) goto cleanup;597598MP_DIGITS(&k) = 0;599CHECK_MPI_OK( mp_init(&k, kmflag) );600CHECK_MPI_OK( mp_read_unsigned_octets(&k, privateValue->data,601(mp_size) privateValue->len) );602603if (withCofactor && (ecParams->cofactor != 1)) {604/* multiply k with the cofactor */605MP_DIGITS(&cofactor) = 0;606CHECK_MPI_OK( mp_init(&cofactor, kmflag) );607mp_set(&cofactor, ecParams->cofactor);608CHECK_MPI_OK( mp_mul(&k, &cofactor, &k) );609}610611/* Multiply our private key and peer's public point */612/* ECDH doesn't support timing mitigation */613if ((ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ, kmflag, /*timing*/ 0) != SECSuccess) ||614ec_point_at_infinity(&pointQ))615goto cleanup;616617/* Allocate memory for the derived secret and copy618* the x co-ordinate of pointQ into it.619*/620SECITEM_AllocItem(NULL, derivedSecret, len, kmflag);621memcpy(derivedSecret->data, pointQ.data + 1, len);622623rv = SECSuccess;624625#if EC_DEBUG626printf("derived_secret:\n");627for (i = 0; i < derivedSecret->len; i++)628printf("%02x:", derivedSecret->data[i]);629printf("\n");630#endif631632cleanup:633mp_clear(&k);634635if (pointQ.data) {636PORT_ZFree(pointQ.data, 2*len + 1);637}638639return rv;640}641642/* Computes the ECDSA signature (a concatenation of two values r and s)643* on the digest using the given key and the random value kb (used in644* computing s).645*/646SECStatus647ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,648const SECItem *digest, const unsigned char *kb, const int kblen, int kmflag,649int timing)650{651SECStatus rv = SECFailure;652mp_int x1;653mp_int d, k; /* private key, random integer */654mp_int r, s; /* tuple (r, s) is the signature */655mp_int n;656mp_err err = MP_OKAY;657ECParams *ecParams = NULL;658SECItem kGpoint = { siBuffer, NULL, 0};659int flen = 0; /* length in bytes of the field size */660unsigned olen; /* length in bytes of the base point order */661unsigned int orderBitSize;662663#if EC_DEBUG664char mpstr[256];665#endif666667/* Initialize MPI integers. */668/* must happen before the first potential call to cleanup */669MP_DIGITS(&x1) = 0;670MP_DIGITS(&d) = 0;671MP_DIGITS(&k) = 0;672MP_DIGITS(&r) = 0;673MP_DIGITS(&s) = 0;674MP_DIGITS(&n) = 0;675676/* Check args */677if (!key || !signature || !digest || !kb || (kblen < 0)) {678PORT_SetError(SEC_ERROR_INVALID_ARGS);679goto cleanup;680}681682ecParams = &(key->ecParams);683flen = (ecParams->fieldID.size + 7) >> 3;684olen = ecParams->order.len;685if (signature->data == NULL) {686/* a call to get the signature length only */687goto finish;688}689if (signature->len < 2*olen) {690PORT_SetError(SEC_ERROR_OUTPUT_LEN);691rv = SECBufferTooSmall;692goto cleanup;693}694695696CHECK_MPI_OK( mp_init(&x1, kmflag) );697CHECK_MPI_OK( mp_init(&d, kmflag) );698CHECK_MPI_OK( mp_init(&k, kmflag) );699CHECK_MPI_OK( mp_init(&r, kmflag) );700CHECK_MPI_OK( mp_init(&s, kmflag) );701CHECK_MPI_OK( mp_init(&n, kmflag) );702703SECITEM_TO_MPINT( ecParams->order, &n );704SECITEM_TO_MPINT( key->privateValue, &d );705CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) );706/* Make sure k is in the interval [1, n-1] */707if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) {708#if EC_DEBUG709printf("k is outside [1, n-1]\n");710mp_tohex(&k, mpstr);711printf("k : %s \n", mpstr);712mp_tohex(&n, mpstr);713printf("n : %s \n", mpstr);714#endif715PORT_SetError(SEC_ERROR_NEED_RANDOM);716goto cleanup;717}718719/*720** ANSI X9.62, Section 5.3.2, Step 2721**722** Compute kG723*/724kGpoint.len = 2*flen + 1;725kGpoint.data = PORT_Alloc(2*flen + 1, kmflag);726if ((kGpoint.data == NULL) ||727(ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint, kmflag, timing)728!= SECSuccess))729goto cleanup;730731/*732** ANSI X9.62, Section 5.3.3, Step 1733**734** Extract the x co-ordinate of kG into x1735*/736CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1,737(mp_size) flen) );738739/*740** ANSI X9.62, Section 5.3.3, Step 2741**742** r = x1 mod n NOTE: n is the order of the curve743*/744CHECK_MPI_OK( mp_mod(&x1, &n, &r) );745746/*747** ANSI X9.62, Section 5.3.3, Step 3748**749** verify r != 0750*/751if (mp_cmp_z(&r) == 0) {752PORT_SetError(SEC_ERROR_NEED_RANDOM);753goto cleanup;754}755756/*757** ANSI X9.62, Section 5.3.3, Step 4758**759** s = (k**-1 * (HASH(M) + d*r)) mod n760*/761SECITEM_TO_MPINT(*digest, &s); /* s = HASH(M) */762763/* In the definition of EC signing, digests are truncated764* to the order length765* (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/766orderBitSize = mpl_significant_bits(&n);767if (digest->len*8 > orderBitSize) {768mpl_rsh(&s,&s,digest->len*8 - orderBitSize);769}770771#if EC_DEBUG772mp_todecimal(&n, mpstr);773printf("n : %s (dec)\n", mpstr);774mp_todecimal(&d, mpstr);775printf("d : %s (dec)\n", mpstr);776mp_tohex(&x1, mpstr);777printf("x1: %s\n", mpstr);778mp_todecimal(&s, mpstr);779printf("digest: %s (decimal)\n", mpstr);780mp_todecimal(&r, mpstr);781printf("r : %s (dec)\n", mpstr);782mp_tohex(&r, mpstr);783printf("r : %s\n", mpstr);784#endif785786CHECK_MPI_OK( mp_invmod(&k, &n, &k) ); /* k = k**-1 mod n */787CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) ); /* d = d * r mod n */788CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) ); /* s = s + d mod n */789CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) ); /* s = s * k mod n */790791#if EC_DEBUG792mp_todecimal(&s, mpstr);793printf("s : %s (dec)\n", mpstr);794mp_tohex(&s, mpstr);795printf("s : %s\n", mpstr);796#endif797798/*799** ANSI X9.62, Section 5.3.3, Step 5800**801** verify s != 0802*/803if (mp_cmp_z(&s) == 0) {804PORT_SetError(SEC_ERROR_NEED_RANDOM);805goto cleanup;806}807808/*809**810** Signature is tuple (r, s)811*/812CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, olen) );813CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + olen, olen) );814finish:815signature->len = 2*olen;816817rv = SECSuccess;818err = MP_OKAY;819cleanup:820mp_clear(&x1);821mp_clear(&d);822mp_clear(&k);823mp_clear(&r);824mp_clear(&s);825mp_clear(&n);826827if (kGpoint.data) {828PORT_ZFree(kGpoint.data, 2*flen + 1);829}830831if (err) {832MP_TO_SEC_ERROR(err);833rv = SECFailure;834}835836#if EC_DEBUG837printf("ECDSA signing with seed %s\n",838(rv == SECSuccess) ? "succeeded" : "failed");839#endif840841return rv;842}843844/*845** Computes the ECDSA signature on the digest using the given key846** and a random seed.847*/848SECStatus849ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest,850const unsigned char* random, int randomLen, int kmflag, int timing)851{852SECStatus rv = SECFailure;853int len;854unsigned char *kBytes= NULL;855856if (!key) {857PORT_SetError(SEC_ERROR_INVALID_ARGS);858return SECFailure;859}860861/* Generate random value k */862len = key->ecParams.order.len;863kBytes = ec_GenerateRandomPrivateKey(key->ecParams.order.data, len,864random, randomLen, kmflag);865if (kBytes == NULL) goto cleanup;866867/* Generate ECDSA signature with the specified k value */868rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len, kmflag, timing);869870cleanup:871if (kBytes) {872PORT_ZFree(kBytes, len * 2);873}874875#if EC_DEBUG876printf("ECDSA signing %s\n",877(rv == SECSuccess) ? "succeeded" : "failed");878#endif879880return rv;881}882883/*884** Checks the signature on the given digest using the key provided.885*/886SECStatus887ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,888const SECItem *digest, int kmflag)889{890SECStatus rv = SECFailure;891mp_int r_, s_; /* tuple (r', s') is received signature) */892mp_int c, u1, u2, v; /* intermediate values used in verification */893mp_int x1;894mp_int n;895mp_err err = MP_OKAY;896ECParams *ecParams = NULL;897SECItem pointC = { siBuffer, NULL, 0 };898int slen; /* length in bytes of a half signature (r or s) */899int flen; /* length in bytes of the field size */900unsigned olen; /* length in bytes of the base point order */901unsigned int orderBitSize;902903#if EC_DEBUG904char mpstr[256];905printf("ECDSA verification called\n");906#endif907908/* Initialize MPI integers. */909/* must happen before the first potential call to cleanup */910MP_DIGITS(&r_) = 0;911MP_DIGITS(&s_) = 0;912MP_DIGITS(&c) = 0;913MP_DIGITS(&u1) = 0;914MP_DIGITS(&u2) = 0;915MP_DIGITS(&x1) = 0;916MP_DIGITS(&v) = 0;917MP_DIGITS(&n) = 0;918919/* Check args */920if (!key || !signature || !digest) {921PORT_SetError(SEC_ERROR_INVALID_ARGS);922goto cleanup;923}924925ecParams = &(key->ecParams);926flen = (ecParams->fieldID.size + 7) >> 3;927olen = ecParams->order.len;928if (signature->len == 0 || signature->len%2 != 0 ||929signature->len > 2*olen) {930PORT_SetError(SEC_ERROR_INPUT_LEN);931goto cleanup;932}933slen = signature->len/2;934935SECITEM_AllocItem(NULL, &pointC, 2*flen + 1, kmflag);936if (pointC.data == NULL)937goto cleanup;938939CHECK_MPI_OK( mp_init(&r_, kmflag) );940CHECK_MPI_OK( mp_init(&s_, kmflag) );941CHECK_MPI_OK( mp_init(&c, kmflag) );942CHECK_MPI_OK( mp_init(&u1, kmflag) );943CHECK_MPI_OK( mp_init(&u2, kmflag) );944CHECK_MPI_OK( mp_init(&x1, kmflag) );945CHECK_MPI_OK( mp_init(&v, kmflag) );946CHECK_MPI_OK( mp_init(&n, kmflag) );947948/*949** Convert received signature (r', s') into MPI integers.950*/951CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, slen) );952CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + slen, slen) );953954/*955** ANSI X9.62, Section 5.4.2, Steps 1 and 2956**957** Verify that 0 < r' < n and 0 < s' < n958*/959SECITEM_TO_MPINT(ecParams->order, &n);960if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||961mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) {962PORT_SetError(SEC_ERROR_BAD_SIGNATURE);963goto cleanup; /* will return rv == SECFailure */964}965966/*967** ANSI X9.62, Section 5.4.2, Step 3968**969** c = (s')**-1 mod n970*/971CHECK_MPI_OK( mp_invmod(&s_, &n, &c) ); /* c = (s')**-1 mod n */972973/*974** ANSI X9.62, Section 5.4.2, Step 4975**976** u1 = ((HASH(M')) * c) mod n977*/978SECITEM_TO_MPINT(*digest, &u1); /* u1 = HASH(M) */979980/* In the definition of EC signing, digests are truncated981* to the order length, in bits.982* (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/983/* u1 = HASH(M') */984orderBitSize = mpl_significant_bits(&n);985if (digest->len*8 > orderBitSize) {986mpl_rsh(&u1,&u1,digest->len*8- orderBitSize);987}988989#if EC_DEBUG990mp_todecimal(&r_, mpstr);991printf("r_: %s (dec)\n", mpstr);992mp_todecimal(&s_, mpstr);993printf("s_: %s (dec)\n", mpstr);994mp_todecimal(&c, mpstr);995printf("c : %s (dec)\n", mpstr);996mp_todecimal(&u1, mpstr);997printf("digest: %s (dec)\n", mpstr);998#endif9991000CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) ); /* u1 = u1 * c mod n */10011002/*1003** ANSI X9.62, Section 5.4.2, Step 41004**1005** u2 = ((r') * c) mod n1006*/1007CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) );10081009/*1010** ANSI X9.62, Section 5.4.3, Step 11011**1012** Compute u1*G + u2*Q1013** Here, A = u1.G B = u2.Q and C = A + B1014** If the result, C, is the point at infinity, reject the signature1015*/1016/* verification does not support timing mitigation */1017if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC, kmflag, /*timing*/ 0)1018!= SECSuccess) {1019rv = SECFailure;1020goto cleanup;1021}1022if (ec_point_at_infinity(&pointC)) {1023PORT_SetError(SEC_ERROR_BAD_SIGNATURE);1024rv = SECFailure;1025goto cleanup;1026}10271028CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, flen) );10291030/*1031** ANSI X9.62, Section 5.4.4, Step 21032**1033** v = x1 mod n1034*/1035CHECK_MPI_OK( mp_mod(&x1, &n, &v) );10361037#if EC_DEBUG1038mp_todecimal(&r_, mpstr);1039printf("r_: %s (dec)\n", mpstr);1040mp_todecimal(&v, mpstr);1041printf("v : %s (dec)\n", mpstr);1042#endif10431044/*1045** ANSI X9.62, Section 5.4.4, Step 31046**1047** Verification: v == r'1048*/1049if (mp_cmp(&v, &r_)) {1050PORT_SetError(SEC_ERROR_BAD_SIGNATURE);1051rv = SECFailure; /* Signature failed to verify. */1052} else {1053rv = SECSuccess; /* Signature verified. */1054}10551056#if EC_DEBUG1057mp_todecimal(&u1, mpstr);1058printf("u1: %s (dec)\n", mpstr);1059mp_todecimal(&u2, mpstr);1060printf("u2: %s (dec)\n", mpstr);1061mp_tohex(&x1, mpstr);1062printf("x1: %s\n", mpstr);1063mp_todecimal(&v, mpstr);1064printf("v : %s (dec)\n", mpstr);1065#endif10661067cleanup:1068mp_clear(&r_);1069mp_clear(&s_);1070mp_clear(&c);1071mp_clear(&u1);1072mp_clear(&u2);1073mp_clear(&x1);1074mp_clear(&v);1075mp_clear(&n);10761077if (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE);1078if (err) {1079MP_TO_SEC_ERROR(err);1080rv = SECFailure;1081}10821083#if EC_DEBUG1084printf("ECDSA verification %s\n",1085(rv == SECSuccess) ? "succeeded" : "failed");1086#endif10871088return rv;1089}109010911092