4272N/A/*
4272N/A * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
4272N/A * Use is subject to license terms.
4272N/A *
4272N/A * This library is free software; you can redistribute it and/or
4272N/A * modify it under the terms of the GNU Lesser General Public
4272N/A * License as published by the Free Software Foundation; either
4272N/A * version 2.1 of the License, or (at your option) any later version.
1674N/A *
4272N/A * This library is distributed in the hope that it will be useful,
4272N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of
4272N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4272N/A * Lesser General Public License for more details.
1674N/A *
4272N/A * You should have received a copy of the GNU Lesser General Public License
4272N/A * along with this library; if not, write to the Free Software Foundation,
4272N/A * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1674N/A *
4272N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
4272N/A * or visit www.oracle.com if you need additional information or have any
4272N/A * questions.
4272N/A */
4272N/A
4272N/A/* *********************************************************************
1674N/A *
1674N/A * The Original Code is the Elliptic Curve Cryptography library.
1674N/A *
1674N/A * The Initial Developer of the Original Code is
1674N/A * Sun Microsystems, Inc.
1674N/A * Portions created by the Initial Developer are Copyright (C) 2003
1674N/A * the Initial Developer. All Rights Reserved.
1674N/A *
1674N/A * Contributor(s):
1674N/A * Dr Vipul Gupta <vipul.gupta@sun.com> and
1674N/A * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
1674N/A *
1674N/A *********************************************************************** */
1674N/A
1674N/A#include "mplogic.h"
1674N/A#include "ec.h"
1674N/A#include "ecl.h"
1674N/A
1674N/A#include <sys/types.h>
1674N/A#ifndef _KERNEL
1674N/A#include <stdlib.h>
1674N/A#include <string.h>
1674N/A
1674N/A#ifndef _WIN32
3488N/A#include <stdio.h>
1674N/A#include <strings.h>
1674N/A#endif /* _WIN32 */
1674N/A
1674N/A#endif
1674N/A#include "ecl-exp.h"
1674N/A#include "mpi.h"
1674N/A#include "ecc_impl.h"
1674N/A
1674N/A#ifdef _KERNEL
1674N/A#define PORT_ZFree(p, l) bzero((p), (l)); kmem_free((p), (l))
1674N/A#else
1674N/A#ifndef _WIN32
1674N/A#define PORT_ZFree(p, l) bzero((p), (l)); free((p))
1674N/A#else
1674N/A#define PORT_ZFree(p, l) memset((p), 0, (l)); free((p))
1674N/A#endif /* _WIN32 */
1674N/A#endif
1674N/A
1674N/A/*
1674N/A * Returns true if pointP is the point at infinity, false otherwise
1674N/A */
1674N/APRBool
1674N/Aec_point_at_infinity(SECItem *pointP)
1674N/A{
1674N/A unsigned int i;
1674N/A
1674N/A for (i = 1; i < pointP->len; i++) {
1674N/A if (pointP->data[i] != 0x00) return PR_FALSE;
1674N/A }
1674N/A
1674N/A return PR_TRUE;
1674N/A}
1674N/A
1674N/A/*
1674N/A * Computes scalar point multiplication pointQ = k1 * G + k2 * pointP for
1674N/A * the curve whose parameters are encoded in params with base point G.
1674N/A */
1674N/ASECStatus
1674N/Aec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2,
1674N/A const SECItem *pointP, SECItem *pointQ, int kmflag)
1674N/A{
1674N/A mp_int Px, Py, Qx, Qy;
1674N/A mp_int Gx, Gy, order, irreducible, a, b;
1674N/A#if 0 /* currently don't support non-named curves */
1674N/A unsigned int irr_arr[5];
1674N/A#endif
1674N/A ECGroup *group = NULL;
1674N/A SECStatus rv = SECFailure;
1674N/A mp_err err = MP_OKAY;
3488N/A unsigned int len;
1674N/A
1674N/A#if EC_DEBUG
1674N/A int i;
1674N/A char mpstr[256];
1674N/A
1674N/A printf("ec_points_mul: params [len=%d]:", params->DEREncoding.len);
1674N/A for (i = 0; i < params->DEREncoding.len; i++)
1674N/A printf("%02x:", params->DEREncoding.data[i]);
1674N/A printf("\n");
1674N/A
1674N/A if (k1 != NULL) {
1674N/A mp_tohex(k1, mpstr);
1674N/A printf("ec_points_mul: scalar k1: %s\n", mpstr);
1674N/A mp_todecimal(k1, mpstr);
1674N/A printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr);
1674N/A }
1674N/A
1674N/A if (k2 != NULL) {
1674N/A mp_tohex(k2, mpstr);
1674N/A printf("ec_points_mul: scalar k2: %s\n", mpstr);
1674N/A mp_todecimal(k2, mpstr);
1674N/A printf("ec_points_mul: scalar k2: %s (dec)\n", mpstr);
1674N/A }
1674N/A
1674N/A if (pointP != NULL) {
1674N/A printf("ec_points_mul: pointP [len=%d]:", pointP->len);
1674N/A for (i = 0; i < pointP->len; i++)
1674N/A printf("%02x:", pointP->data[i]);
1674N/A printf("\n");
1674N/A }
1674N/A#endif
1674N/A
1674N/A /* NOTE: We only support uncompressed points for now */
1674N/A len = (params->fieldID.size + 7) >> 3;
1674N/A if (pointP != NULL) {
1674N/A if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
1674N/A (pointP->len != (2 * len + 1))) {
1674N/A return SECFailure;
1674N/A };
1674N/A }
1674N/A
1674N/A MP_DIGITS(&Px) = 0;
1674N/A MP_DIGITS(&Py) = 0;
1674N/A MP_DIGITS(&Qx) = 0;
1674N/A MP_DIGITS(&Qy) = 0;
1674N/A MP_DIGITS(&Gx) = 0;
1674N/A MP_DIGITS(&Gy) = 0;
1674N/A MP_DIGITS(&order) = 0;
1674N/A MP_DIGITS(&irreducible) = 0;
1674N/A MP_DIGITS(&a) = 0;
1674N/A MP_DIGITS(&b) = 0;
1674N/A CHECK_MPI_OK( mp_init(&Px, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&Py, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&Qx, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&Qy, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&Gx, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&Gy, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&order, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&irreducible, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&a, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&b, kmflag) );
1674N/A
1674N/A if ((k2 != NULL) && (pointP != NULL)) {
1674N/A /* Initialize Px and Py */
1674N/A CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size) len) );
1674N/A CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) );
1674N/A }
1674N/A
1674N/A /* construct from named params, if possible */
1674N/A if (params->name != ECCurve_noName) {
1674N/A group = ECGroup_fromName(params->name, kmflag);
1674N/A }
1674N/A
1674N/A#if 0 /* currently don't support non-named curves */
1674N/A if (group == NULL) {
1674N/A /* Set up mp_ints containing the curve coefficients */
1674N/A CHECK_MPI_OK( mp_read_unsigned_octets(&Gx, params->base.data + 1,
1674N/A (mp_size) len) );
1674N/A CHECK_MPI_OK( mp_read_unsigned_octets(&Gy, params->base.data + 1 + len,
1674N/A (mp_size) len) );
1674N/A SECITEM_TO_MPINT( params->order, &order );
1674N/A SECITEM_TO_MPINT( params->curve.a, &a );
1674N/A SECITEM_TO_MPINT( params->curve.b, &b );
1674N/A if (params->fieldID.type == ec_field_GFp) {
1674N/A SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible );
1674N/A group = ECGroup_consGFp(&irreducible, &a, &b, &Gx, &Gy, &order, params->cofactor);
1674N/A } else {
1674N/A SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible );
1674N/A irr_arr[0] = params->fieldID.size;
1674N/A irr_arr[1] = params->fieldID.k1;
1674N/A irr_arr[2] = params->fieldID.k2;
1674N/A irr_arr[3] = params->fieldID.k3;
1674N/A irr_arr[4] = 0;
1674N/A group = ECGroup_consGF2m(&irreducible, irr_arr, &a, &b, &Gx, &Gy, &order, params->cofactor);
1674N/A }
1674N/A }
1674N/A#endif
1674N/A if (group == NULL)
1674N/A goto cleanup;
1674N/A
1674N/A if ((k2 != NULL) && (pointP != NULL)) {
1674N/A CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy) );
1674N/A } else {
1674N/A CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) );
1674N/A }
1674N/A
1674N/A /* Construct the SECItem representation of point Q */
1674N/A pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED;
1674N/A CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1,
1674N/A (mp_size) len) );
1674N/A CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len,
1674N/A (mp_size) len) );
1674N/A
1674N/A rv = SECSuccess;
1674N/A
1674N/A#if EC_DEBUG
1674N/A printf("ec_points_mul: pointQ [len=%d]:", pointQ->len);
1674N/A for (i = 0; i < pointQ->len; i++)
1674N/A printf("%02x:", pointQ->data[i]);
1674N/A printf("\n");
1674N/A#endif
1674N/A
1674N/Acleanup:
1674N/A ECGroup_free(group);
1674N/A mp_clear(&Px);
1674N/A mp_clear(&Py);
1674N/A mp_clear(&Qx);
1674N/A mp_clear(&Qy);
1674N/A mp_clear(&Gx);
1674N/A mp_clear(&Gy);
1674N/A mp_clear(&order);
1674N/A mp_clear(&irreducible);
1674N/A mp_clear(&a);
1674N/A mp_clear(&b);
1674N/A if (err) {
1674N/A MP_TO_SEC_ERROR(err);
1674N/A rv = SECFailure;
1674N/A }
1674N/A
1674N/A return rv;
1674N/A}
1674N/A
1674N/A/* Generates a new EC key pair. The private key is a supplied
1674N/A * value and the public key is the result of performing a scalar
1674N/A * point multiplication of that value with the curve's base point.
1674N/A */
1674N/ASECStatus
1674N/Aec_NewKey(ECParams *ecParams, ECPrivateKey **privKey,
1674N/A const unsigned char *privKeyBytes, int privKeyLen, int kmflag)
1674N/A{
1674N/A SECStatus rv = SECFailure;
1674N/A PRArenaPool *arena;
1674N/A ECPrivateKey *key;
1674N/A mp_int k;
1674N/A mp_err err = MP_OKAY;
1674N/A int len;
1674N/A
1674N/A#if EC_DEBUG
1674N/A printf("ec_NewKey called\n");
1674N/A#endif
1674N/A
1674N/A if (!ecParams || !privKey || !privKeyBytes || (privKeyLen < 0)) {
1674N/A PORT_SetError(SEC_ERROR_INVALID_ARGS);
1674N/A return SECFailure;
1674N/A }
1674N/A
1674N/A /* Initialize an arena for the EC key. */
1674N/A if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))
1674N/A return SECFailure;
1674N/A
1674N/A key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey),
1674N/A kmflag);
1674N/A if (!key) {
1674N/A PORT_FreeArena(arena, PR_TRUE);
1674N/A return SECFailure;
1674N/A }
1674N/A
1674N/A /* Set the version number (SEC 1 section C.4 says it should be 1) */
1674N/A SECITEM_AllocItem(arena, &key->version, 1, kmflag);
1674N/A key->version.data[0] = 1;
1674N/A
1674N/A /* Copy all of the fields from the ECParams argument to the
1674N/A * ECParams structure within the private key.
1674N/A */
1674N/A key->ecParams.arena = arena;
1674N/A key->ecParams.type = ecParams->type;
1674N/A key->ecParams.fieldID.size = ecParams->fieldID.size;
1674N/A key->ecParams.fieldID.type = ecParams->fieldID.type;
1674N/A if (ecParams->fieldID.type == ec_field_GFp) {
1674N/A CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime,
1674N/A &ecParams->fieldID.u.prime, kmflag));
1674N/A } else {
1674N/A CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.poly,
1674N/A &ecParams->fieldID.u.poly, kmflag));
1674N/A }
1674N/A key->ecParams.fieldID.k1 = ecParams->fieldID.k1;
1674N/A key->ecParams.fieldID.k2 = ecParams->fieldID.k2;
1674N/A key->ecParams.fieldID.k3 = ecParams->fieldID.k3;
1674N/A CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a,
1674N/A &ecParams->curve.a, kmflag));
1674N/A CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b,
1674N/A &ecParams->curve.b, kmflag));
1674N/A CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed,
1674N/A &ecParams->curve.seed, kmflag));
1674N/A CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base,
1674N/A &ecParams->base, kmflag));
1674N/A CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order,
1674N/A &ecParams->order, kmflag));
1674N/A key->ecParams.cofactor = ecParams->cofactor;
1674N/A CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding,
1674N/A &ecParams->DEREncoding, kmflag));
1674N/A key->ecParams.name = ecParams->name;
1674N/A CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID,
1674N/A &ecParams->curveOID, kmflag));
1674N/A
1674N/A len = (ecParams->fieldID.size + 7) >> 3;
1674N/A SECITEM_AllocItem(arena, &key->publicValue, 2*len + 1, kmflag);
1674N/A len = ecParams->order.len;
1674N/A SECITEM_AllocItem(arena, &key->privateValue, len, kmflag);
1674N/A
1674N/A /* Copy private key */
1674N/A if (privKeyLen >= len) {
1674N/A memcpy(key->privateValue.data, privKeyBytes, len);
1674N/A } else {
1674N/A memset(key->privateValue.data, 0, (len - privKeyLen));
1674N/A memcpy(key->privateValue.data + (len - privKeyLen), privKeyBytes, privKeyLen);
1674N/A }
1674N/A
1674N/A /* Compute corresponding public key */
1674N/A MP_DIGITS(&k) = 0;
1674N/A CHECK_MPI_OK( mp_init(&k, kmflag) );
1674N/A CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data,
1674N/A (mp_size) len) );
1674N/A
1674N/A rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue), kmflag);
1674N/A if (rv != SECSuccess) goto cleanup;
1674N/A *privKey = key;
1674N/A
1674N/Acleanup:
1674N/A mp_clear(&k);
3488N/A if (rv) {
1674N/A PORT_FreeArena(arena, PR_TRUE);
3488N/A }
1674N/A
1674N/A#if EC_DEBUG
1674N/A printf("ec_NewKey returning %s\n",
1674N/A (rv == SECSuccess) ? "success" : "failure");
1674N/A#endif
1674N/A
1674N/A return rv;
1674N/A
1674N/A}
1674N/A
1674N/A/* Generates a new EC key pair. The private key is a supplied
1674N/A * random value (in seed) and the public key is the result of
1674N/A * performing a scalar point multiplication of that value with
1674N/A * the curve's base point.
1674N/A */
1674N/ASECStatus
1674N/AEC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey,
1674N/A const unsigned char *seed, int seedlen, int kmflag)
1674N/A{
1674N/A SECStatus rv = SECFailure;
1674N/A rv = ec_NewKey(ecParams, privKey, seed, seedlen, kmflag);
1674N/A return rv;
1674N/A}
1674N/A
1674N/A/* Generate a random private key using the algorithm A.4.1 of ANSI X9.62,
1674N/A * modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the
1674N/A * random number generator.
1674N/A *
1674N/A * Parameters
1674N/A * - order: a buffer that holds the curve's group order
1674N/A * - len: the length in octets of the order buffer
1674N/A * - random: a buffer of 2 * len random bytes
1674N/A * - randomlen: the length in octets of the random buffer
1674N/A *
1674N/A * Return Value
1674N/A * Returns a buffer of len octets that holds the private key. The caller
1674N/A * is responsible for freeing the buffer with PORT_ZFree.
1674N/A */
1674N/Astatic unsigned char *
1674N/Aec_GenerateRandomPrivateKey(const unsigned char *order, int len,
1674N/A const unsigned char *random, int randomlen, int kmflag)
1674N/A{
1674N/A SECStatus rv = SECSuccess;
1674N/A mp_err err;
1674N/A unsigned char *privKeyBytes = NULL;
1674N/A mp_int privKeyVal, order_1, one;
1674N/A
1674N/A MP_DIGITS(&privKeyVal) = 0;
1674N/A MP_DIGITS(&order_1) = 0;
1674N/A MP_DIGITS(&one) = 0;
1674N/A CHECK_MPI_OK( mp_init(&privKeyVal, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&order_1, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&one, kmflag) );
1674N/A
1674N/A /*
1674N/A * Reduces the 2*len buffer of random bytes modulo the group order.
1674N/A */
1674N/A if ((privKeyBytes = PORT_Alloc(2*len, kmflag)) == NULL) goto cleanup;
1674N/A if (randomlen != 2 * len) {
1674N/A randomlen = 2 * len;
1674N/A }
1674N/A /* No need to generate - random bytes are now supplied */
1674N/A /* CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) );*/
1674N/A memcpy(privKeyBytes, random, randomlen);
1674N/A
1674N/A CHECK_MPI_OK( mp_read_unsigned_octets(&privKeyVal, privKeyBytes, 2*len) );
1674N/A CHECK_MPI_OK( mp_read_unsigned_octets(&order_1, order, len) );
1674N/A CHECK_MPI_OK( mp_set_int(&one, 1) );
1674N/A CHECK_MPI_OK( mp_sub(&order_1, &one, &order_1) );
1674N/A CHECK_MPI_OK( mp_mod(&privKeyVal, &order_1, &privKeyVal) );
1674N/A CHECK_MPI_OK( mp_add(&privKeyVal, &one, &privKeyVal) );
1674N/A CHECK_MPI_OK( mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len) );
1674N/A memset(privKeyBytes+len, 0, len);
1674N/Acleanup:
1674N/A mp_clear(&privKeyVal);
1674N/A mp_clear(&order_1);
1674N/A mp_clear(&one);
1674N/A if (err < MP_OKAY) {
1674N/A MP_TO_SEC_ERROR(err);
1674N/A rv = SECFailure;
1674N/A }
1674N/A if (rv != SECSuccess && privKeyBytes) {
1674N/A#ifdef _KERNEL
1674N/A kmem_free(privKeyBytes, 2*len);
1674N/A#else
1674N/A free(privKeyBytes);
1674N/A#endif
1674N/A privKeyBytes = NULL;
1674N/A }
1674N/A return privKeyBytes;
1674N/A}
1674N/A
1674N/A/* Generates a new EC key pair. The private key is a random value and
1674N/A * the public key is the result of performing a scalar point multiplication
1674N/A * of that value with the curve's base point.
1674N/A */
1674N/ASECStatus
1674N/AEC_NewKey(ECParams *ecParams, ECPrivateKey **privKey,
1674N/A const unsigned char* random, int randomlen, int kmflag)
1674N/A{
1674N/A SECStatus rv = SECFailure;
1674N/A int len;
1674N/A unsigned char *privKeyBytes = NULL;
1674N/A
1674N/A if (!ecParams) {
1674N/A PORT_SetError(SEC_ERROR_INVALID_ARGS);
1674N/A return SECFailure;
1674N/A }
1674N/A
1674N/A len = ecParams->order.len;
1674N/A privKeyBytes = ec_GenerateRandomPrivateKey(ecParams->order.data, len,
1674N/A random, randomlen, kmflag);
1674N/A if (privKeyBytes == NULL) goto cleanup;
1674N/A /* generate public key */
1674N/A CHECK_SEC_OK( ec_NewKey(ecParams, privKey, privKeyBytes, len, kmflag) );
1674N/A
1674N/Acleanup:
1674N/A if (privKeyBytes) {
1674N/A PORT_ZFree(privKeyBytes, len * 2);
1674N/A }
1674N/A#if EC_DEBUG
1674N/A printf("EC_NewKey returning %s\n",
1674N/A (rv == SECSuccess) ? "success" : "failure");
1674N/A#endif
1674N/A
1674N/A return rv;
1674N/A}
1674N/A
1674N/A/* Validates an EC public key as described in Section 5.2.2 of
1674N/A * X9.62. The ECDH primitive when used without the cofactor does
1674N/A * not address small subgroup attacks, which may occur when the
1674N/A * public key is not valid. These attacks can be prevented by
1674N/A * validating the public key before using ECDH.
1674N/A */
1674N/ASECStatus
1674N/AEC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue, int kmflag)
1674N/A{
1674N/A mp_int Px, Py;
1674N/A ECGroup *group = NULL;
1674N/A SECStatus rv = SECFailure;
1674N/A mp_err err = MP_OKAY;
3488N/A unsigned int len;
1674N/A
1674N/A if (!ecParams || !publicValue) {
1674N/A PORT_SetError(SEC_ERROR_INVALID_ARGS);
1674N/A return SECFailure;
1674N/A }
1674N/A
1674N/A /* NOTE: We only support uncompressed points for now */
1674N/A len = (ecParams->fieldID.size + 7) >> 3;
1674N/A if (publicValue->data[0] != EC_POINT_FORM_UNCOMPRESSED) {
1674N/A PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
1674N/A return SECFailure;
1674N/A } else if (publicValue->len != (2 * len + 1)) {
1674N/A PORT_SetError(SEC_ERROR_BAD_KEY);
1674N/A return SECFailure;
1674N/A }
1674N/A
1674N/A MP_DIGITS(&Px) = 0;
1674N/A MP_DIGITS(&Py) = 0;
1674N/A CHECK_MPI_OK( mp_init(&Px, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&Py, kmflag) );
1674N/A
1674N/A /* Initialize Px and Py */
1674N/A CHECK_MPI_OK( mp_read_unsigned_octets(&Px, publicValue->data + 1, (mp_size) len) );
1674N/A CHECK_MPI_OK( mp_read_unsigned_octets(&Py, publicValue->data + 1 + len, (mp_size) len) );
1674N/A
1674N/A /* construct from named params */
1674N/A group = ECGroup_fromName(ecParams->name, kmflag);
1674N/A if (group == NULL) {
1674N/A /*
1674N/A * ECGroup_fromName fails if ecParams->name is not a valid
1674N/A * ECCurveName value, or if we run out of memory, or perhaps
1674N/A * for other reasons. Unfortunately if ecParams->name is a
1674N/A * valid ECCurveName value, we don't know what the right error
1674N/A * code should be because ECGroup_fromName doesn't return an
1674N/A * error code to the caller. Set err to MP_UNDEF because
1674N/A * that's what ECGroup_fromName uses internally.
1674N/A */
1674N/A if ((ecParams->name <= ECCurve_noName) ||
1674N/A (ecParams->name >= ECCurve_pastLastCurve)) {
1674N/A err = MP_BADARG;
1674N/A } else {
1674N/A err = MP_UNDEF;
1674N/A }
1674N/A goto cleanup;
1674N/A }
1674N/A
1674N/A /* validate public point */
1674N/A if ((err = ECPoint_validate(group, &Px, &Py)) < MP_YES) {
1674N/A if (err == MP_NO) {
1674N/A PORT_SetError(SEC_ERROR_BAD_KEY);
1674N/A rv = SECFailure;
1674N/A err = MP_OKAY; /* don't change the error code */
1674N/A }
1674N/A goto cleanup;
1674N/A }
1674N/A
1674N/A rv = SECSuccess;
1674N/A
1674N/Acleanup:
1674N/A ECGroup_free(group);
1674N/A mp_clear(&Px);
1674N/A mp_clear(&Py);
1674N/A if (err) {
1674N/A MP_TO_SEC_ERROR(err);
1674N/A rv = SECFailure;
1674N/A }
1674N/A return rv;
1674N/A}
1674N/A
1674N/A/*
1674N/A** Performs an ECDH key derivation by computing the scalar point
1674N/A** multiplication of privateValue and publicValue (with or without the
1674N/A** cofactor) and returns the x-coordinate of the resulting elliptic
1674N/A** curve point in derived secret. If successful, derivedSecret->data
1674N/A** is set to the address of the newly allocated buffer containing the
1674N/A** derived secret, and derivedSecret->len is the size of the secret
1674N/A** produced. It is the caller's responsibility to free the allocated
1674N/A** buffer containing the derived secret.
1674N/A*/
1674N/ASECStatus
1674N/AECDH_Derive(SECItem *publicValue,
1674N/A ECParams *ecParams,
1674N/A SECItem *privateValue,
1674N/A PRBool withCofactor,
1674N/A SECItem *derivedSecret,
1674N/A int kmflag)
1674N/A{
1674N/A SECStatus rv = SECFailure;
1674N/A unsigned int len = 0;
1674N/A SECItem pointQ = {siBuffer, NULL, 0};
1674N/A mp_int k; /* to hold the private value */
1674N/A mp_int cofactor;
1674N/A mp_err err = MP_OKAY;
1674N/A#if EC_DEBUG
1674N/A int i;
1674N/A#endif
1674N/A
1674N/A if (!publicValue || !ecParams || !privateValue ||
1674N/A !derivedSecret) {
1674N/A PORT_SetError(SEC_ERROR_INVALID_ARGS);
1674N/A return SECFailure;
1674N/A }
1674N/A
1674N/A memset(derivedSecret, 0, sizeof *derivedSecret);
1674N/A len = (ecParams->fieldID.size + 7) >> 3;
1674N/A pointQ.len = 2*len + 1;
1674N/A if ((pointQ.data = PORT_Alloc(2*len + 1, kmflag)) == NULL) goto cleanup;
1674N/A
1674N/A MP_DIGITS(&k) = 0;
1674N/A CHECK_MPI_OK( mp_init(&k, kmflag) );
1674N/A CHECK_MPI_OK( mp_read_unsigned_octets(&k, privateValue->data,
1674N/A (mp_size) privateValue->len) );
1674N/A
1674N/A if (withCofactor && (ecParams->cofactor != 1)) {
1674N/A /* multiply k with the cofactor */
1674N/A MP_DIGITS(&cofactor) = 0;
1674N/A CHECK_MPI_OK( mp_init(&cofactor, kmflag) );
1674N/A mp_set(&cofactor, ecParams->cofactor);
1674N/A CHECK_MPI_OK( mp_mul(&k, &cofactor, &k) );
1674N/A }
1674N/A
1674N/A /* Multiply our private key and peer's public point */
1674N/A if ((ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ, kmflag) != SECSuccess) ||
1674N/A ec_point_at_infinity(&pointQ))
1674N/A goto cleanup;
1674N/A
1674N/A /* Allocate memory for the derived secret and copy
1674N/A * the x co-ordinate of pointQ into it.
1674N/A */
1674N/A SECITEM_AllocItem(NULL, derivedSecret, len, kmflag);
1674N/A memcpy(derivedSecret->data, pointQ.data + 1, len);
1674N/A
1674N/A rv = SECSuccess;
1674N/A
1674N/A#if EC_DEBUG
1674N/A printf("derived_secret:\n");
1674N/A for (i = 0; i < derivedSecret->len; i++)
1674N/A printf("%02x:", derivedSecret->data[i]);
1674N/A printf("\n");
1674N/A#endif
1674N/A
1674N/Acleanup:
1674N/A mp_clear(&k);
1674N/A
1674N/A if (pointQ.data) {
1674N/A PORT_ZFree(pointQ.data, 2*len + 1);
1674N/A }
1674N/A
1674N/A return rv;
1674N/A}
1674N/A
1674N/A/* Computes the ECDSA signature (a concatenation of two values r and s)
1674N/A * on the digest using the given key and the random value kb (used in
1674N/A * computing s).
1674N/A */
1674N/ASECStatus
1674N/AECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
1674N/A const SECItem *digest, const unsigned char *kb, const int kblen, int kmflag)
1674N/A{
1674N/A SECStatus rv = SECFailure;
1674N/A mp_int x1;
1674N/A mp_int d, k; /* private key, random integer */
1674N/A mp_int r, s; /* tuple (r, s) is the signature */
1674N/A mp_int n;
1674N/A mp_err err = MP_OKAY;
1674N/A ECParams *ecParams = NULL;
1674N/A SECItem kGpoint = { siBuffer, NULL, 0};
1674N/A int flen = 0; /* length in bytes of the field size */
1674N/A unsigned olen; /* length in bytes of the base point order */
1674N/A
1674N/A#if EC_DEBUG
1674N/A char mpstr[256];
1674N/A#endif
1674N/A
1674N/A /* Initialize MPI integers. */
1674N/A /* must happen before the first potential call to cleanup */
1674N/A MP_DIGITS(&x1) = 0;
1674N/A MP_DIGITS(&d) = 0;
1674N/A MP_DIGITS(&k) = 0;
1674N/A MP_DIGITS(&r) = 0;
1674N/A MP_DIGITS(&s) = 0;
1674N/A MP_DIGITS(&n) = 0;
1674N/A
1674N/A /* Check args */
1674N/A if (!key || !signature || !digest || !kb || (kblen < 0)) {
1674N/A PORT_SetError(SEC_ERROR_INVALID_ARGS);
1674N/A goto cleanup;
1674N/A }
1674N/A
1674N/A ecParams = &(key->ecParams);
1674N/A flen = (ecParams->fieldID.size + 7) >> 3;
1674N/A olen = ecParams->order.len;
1674N/A if (signature->data == NULL) {
1674N/A /* a call to get the signature length only */
1674N/A goto finish;
1674N/A }
1674N/A if (signature->len < 2*olen) {
1674N/A PORT_SetError(SEC_ERROR_OUTPUT_LEN);
1674N/A rv = SECBufferTooSmall;
1674N/A goto cleanup;
1674N/A }
1674N/A
1674N/A
1674N/A CHECK_MPI_OK( mp_init(&x1, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&d, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&k, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&r, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&s, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&n, kmflag) );
1674N/A
1674N/A SECITEM_TO_MPINT( ecParams->order, &n );
1674N/A SECITEM_TO_MPINT( key->privateValue, &d );
1674N/A CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) );
1674N/A /* Make sure k is in the interval [1, n-1] */
1674N/A if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) {
1674N/A#if EC_DEBUG
1674N/A printf("k is outside [1, n-1]\n");
1674N/A mp_tohex(&k, mpstr);
1674N/A printf("k : %s \n", mpstr);
1674N/A mp_tohex(&n, mpstr);
1674N/A printf("n : %s \n", mpstr);
1674N/A#endif
1674N/A PORT_SetError(SEC_ERROR_NEED_RANDOM);
1674N/A goto cleanup;
1674N/A }
1674N/A
1674N/A /*
1674N/A ** ANSI X9.62, Section 5.3.2, Step 2
1674N/A **
1674N/A ** Compute kG
1674N/A */
1674N/A kGpoint.len = 2*flen + 1;
1674N/A kGpoint.data = PORT_Alloc(2*flen + 1, kmflag);
1674N/A if ((kGpoint.data == NULL) ||
1674N/A (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint, kmflag)
1674N/A != SECSuccess))
1674N/A goto cleanup;
1674N/A
1674N/A /*
1674N/A ** ANSI X9.62, Section 5.3.3, Step 1
1674N/A **
1674N/A ** Extract the x co-ordinate of kG into x1
1674N/A */
1674N/A CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1,
1674N/A (mp_size) flen) );
1674N/A
1674N/A /*
1674N/A ** ANSI X9.62, Section 5.3.3, Step 2
1674N/A **
1674N/A ** r = x1 mod n NOTE: n is the order of the curve
1674N/A */
1674N/A CHECK_MPI_OK( mp_mod(&x1, &n, &r) );
1674N/A
1674N/A /*
1674N/A ** ANSI X9.62, Section 5.3.3, Step 3
1674N/A **
1674N/A ** verify r != 0
1674N/A */
1674N/A if (mp_cmp_z(&r) == 0) {
1674N/A PORT_SetError(SEC_ERROR_NEED_RANDOM);
1674N/A goto cleanup;
1674N/A }
1674N/A
1674N/A /*
1674N/A ** ANSI X9.62, Section 5.3.3, Step 4
1674N/A **
1674N/A ** s = (k**-1 * (HASH(M) + d*r)) mod n
1674N/A */
1674N/A SECITEM_TO_MPINT(*digest, &s); /* s = HASH(M) */
1674N/A
1674N/A /* In the definition of EC signing, digests are truncated
1674N/A * to the length of n in bits.
1674N/A * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
3488N/A if (digest->len*8 > (unsigned int)ecParams->fieldID.size) {
1674N/A mpl_rsh(&s,&s,digest->len*8 - ecParams->fieldID.size);
1674N/A }
1674N/A
1674N/A#if EC_DEBUG
1674N/A mp_todecimal(&n, mpstr);
1674N/A printf("n : %s (dec)\n", mpstr);
1674N/A mp_todecimal(&d, mpstr);
1674N/A printf("d : %s (dec)\n", mpstr);
1674N/A mp_tohex(&x1, mpstr);
1674N/A printf("x1: %s\n", mpstr);
1674N/A mp_todecimal(&s, mpstr);
1674N/A printf("digest: %s (decimal)\n", mpstr);
1674N/A mp_todecimal(&r, mpstr);
1674N/A printf("r : %s (dec)\n", mpstr);
1674N/A mp_tohex(&r, mpstr);
1674N/A printf("r : %s\n", mpstr);
1674N/A#endif
1674N/A
1674N/A CHECK_MPI_OK( mp_invmod(&k, &n, &k) ); /* k = k**-1 mod n */
1674N/A CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) ); /* d = d * r mod n */
1674N/A CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) ); /* s = s + d mod n */
1674N/A CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) ); /* s = s * k mod n */
1674N/A
1674N/A#if EC_DEBUG
1674N/A mp_todecimal(&s, mpstr);
1674N/A printf("s : %s (dec)\n", mpstr);
1674N/A mp_tohex(&s, mpstr);
1674N/A printf("s : %s\n", mpstr);
1674N/A#endif
1674N/A
1674N/A /*
1674N/A ** ANSI X9.62, Section 5.3.3, Step 5
1674N/A **
1674N/A ** verify s != 0
1674N/A */
1674N/A if (mp_cmp_z(&s) == 0) {
1674N/A PORT_SetError(SEC_ERROR_NEED_RANDOM);
1674N/A goto cleanup;
1674N/A }
1674N/A
1674N/A /*
1674N/A **
1674N/A ** Signature is tuple (r, s)
1674N/A */
1674N/A CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, olen) );
1674N/A CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + olen, olen) );
1674N/Afinish:
1674N/A signature->len = 2*olen;
1674N/A
1674N/A rv = SECSuccess;
1674N/A err = MP_OKAY;
1674N/Acleanup:
1674N/A mp_clear(&x1);
1674N/A mp_clear(&d);
1674N/A mp_clear(&k);
1674N/A mp_clear(&r);
1674N/A mp_clear(&s);
1674N/A mp_clear(&n);
1674N/A
1674N/A if (kGpoint.data) {
1674N/A PORT_ZFree(kGpoint.data, 2*flen + 1);
1674N/A }
1674N/A
1674N/A if (err) {
1674N/A MP_TO_SEC_ERROR(err);
1674N/A rv = SECFailure;
1674N/A }
1674N/A
1674N/A#if EC_DEBUG
1674N/A printf("ECDSA signing with seed %s\n",
1674N/A (rv == SECSuccess) ? "succeeded" : "failed");
1674N/A#endif
1674N/A
1674N/A return rv;
1674N/A}
1674N/A
1674N/A/*
1674N/A** Computes the ECDSA signature on the digest using the given key
1674N/A** and a random seed.
1674N/A*/
1674N/ASECStatus
1674N/AECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest,
1674N/A const unsigned char* random, int randomLen, int kmflag)
1674N/A{
1674N/A SECStatus rv = SECFailure;
1674N/A int len;
1674N/A unsigned char *kBytes= NULL;
1674N/A
1674N/A if (!key) {
1674N/A PORT_SetError(SEC_ERROR_INVALID_ARGS);
1674N/A return SECFailure;
1674N/A }
1674N/A
1674N/A /* Generate random value k */
1674N/A len = key->ecParams.order.len;
1674N/A kBytes = ec_GenerateRandomPrivateKey(key->ecParams.order.data, len,
1674N/A random, randomLen, kmflag);
1674N/A if (kBytes == NULL) goto cleanup;
1674N/A
1674N/A /* Generate ECDSA signature with the specified k value */
1674N/A rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len, kmflag);
1674N/A
1674N/Acleanup:
1674N/A if (kBytes) {
1674N/A PORT_ZFree(kBytes, len * 2);
1674N/A }
1674N/A
1674N/A#if EC_DEBUG
1674N/A printf("ECDSA signing %s\n",
1674N/A (rv == SECSuccess) ? "succeeded" : "failed");
1674N/A#endif
1674N/A
1674N/A return rv;
1674N/A}
1674N/A
1674N/A/*
1674N/A** Checks the signature on the given digest using the key provided.
1674N/A*/
1674N/ASECStatus
1674N/AECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
1674N/A const SECItem *digest, int kmflag)
1674N/A{
1674N/A SECStatus rv = SECFailure;
1674N/A mp_int r_, s_; /* tuple (r', s') is received signature) */
1674N/A mp_int c, u1, u2, v; /* intermediate values used in verification */
1674N/A mp_int x1;
1674N/A mp_int n;
1674N/A mp_err err = MP_OKAY;
1674N/A ECParams *ecParams = NULL;
1674N/A SECItem pointC = { siBuffer, NULL, 0 };
1674N/A int slen; /* length in bytes of a half signature (r or s) */
1674N/A int flen; /* length in bytes of the field size */
1674N/A unsigned olen; /* length in bytes of the base point order */
1674N/A
1674N/A#if EC_DEBUG
1674N/A char mpstr[256];
1674N/A printf("ECDSA verification called\n");
1674N/A#endif
1674N/A
1674N/A /* Initialize MPI integers. */
1674N/A /* must happen before the first potential call to cleanup */
1674N/A MP_DIGITS(&r_) = 0;
1674N/A MP_DIGITS(&s_) = 0;
1674N/A MP_DIGITS(&c) = 0;
1674N/A MP_DIGITS(&u1) = 0;
1674N/A MP_DIGITS(&u2) = 0;
1674N/A MP_DIGITS(&x1) = 0;
1674N/A MP_DIGITS(&v) = 0;
1674N/A MP_DIGITS(&n) = 0;
1674N/A
1674N/A /* Check args */
1674N/A if (!key || !signature || !digest) {
1674N/A PORT_SetError(SEC_ERROR_INVALID_ARGS);
1674N/A goto cleanup;
1674N/A }
1674N/A
1674N/A ecParams = &(key->ecParams);
1674N/A flen = (ecParams->fieldID.size + 7) >> 3;
1674N/A olen = ecParams->order.len;
1674N/A if (signature->len == 0 || signature->len%2 != 0 ||
1674N/A signature->len > 2*olen) {
1674N/A PORT_SetError(SEC_ERROR_INPUT_LEN);
1674N/A goto cleanup;
1674N/A }
1674N/A slen = signature->len/2;
1674N/A
1674N/A SECITEM_AllocItem(NULL, &pointC, 2*flen + 1, kmflag);
1674N/A if (pointC.data == NULL)
1674N/A goto cleanup;
1674N/A
1674N/A CHECK_MPI_OK( mp_init(&r_, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&s_, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&c, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&u1, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&u2, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&x1, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&v, kmflag) );
1674N/A CHECK_MPI_OK( mp_init(&n, kmflag) );
1674N/A
1674N/A /*
1674N/A ** Convert received signature (r', s') into MPI integers.
1674N/A */
1674N/A CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, slen) );
1674N/A CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + slen, slen) );
1674N/A
1674N/A /*
1674N/A ** ANSI X9.62, Section 5.4.2, Steps 1 and 2
1674N/A **
1674N/A ** Verify that 0 < r' < n and 0 < s' < n
1674N/A */
1674N/A SECITEM_TO_MPINT(ecParams->order, &n);
1674N/A if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
1674N/A mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) {
1674N/A PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
1674N/A goto cleanup; /* will return rv == SECFailure */
1674N/A }
1674N/A
1674N/A /*
1674N/A ** ANSI X9.62, Section 5.4.2, Step 3
1674N/A **
1674N/A ** c = (s')**-1 mod n
1674N/A */
1674N/A CHECK_MPI_OK( mp_invmod(&s_, &n, &c) ); /* c = (s')**-1 mod n */
1674N/A
1674N/A /*
1674N/A ** ANSI X9.62, Section 5.4.2, Step 4
1674N/A **
1674N/A ** u1 = ((HASH(M')) * c) mod n
1674N/A */
1674N/A SECITEM_TO_MPINT(*digest, &u1); /* u1 = HASH(M) */
1674N/A
1674N/A /* In the definition of EC signing, digests are truncated
1674N/A * to the length of n in bits.
1674N/A * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
3488N/A /* u1 = HASH(M') */
3488N/A if (digest->len*8 > (unsigned int)ecParams->fieldID.size) {
1674N/A mpl_rsh(&u1,&u1,digest->len*8- ecParams->fieldID.size);
1674N/A }
1674N/A
1674N/A#if EC_DEBUG
1674N/A mp_todecimal(&r_, mpstr);
1674N/A printf("r_: %s (dec)\n", mpstr);
1674N/A mp_todecimal(&s_, mpstr);
1674N/A printf("s_: %s (dec)\n", mpstr);
1674N/A mp_todecimal(&c, mpstr);
1674N/A printf("c : %s (dec)\n", mpstr);
1674N/A mp_todecimal(&u1, mpstr);
1674N/A printf("digest: %s (dec)\n", mpstr);
1674N/A#endif
1674N/A
1674N/A CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) ); /* u1 = u1 * c mod n */
1674N/A
1674N/A /*
1674N/A ** ANSI X9.62, Section 5.4.2, Step 4
1674N/A **
1674N/A ** u2 = ((r') * c) mod n
1674N/A */
1674N/A CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) );
1674N/A
1674N/A /*
1674N/A ** ANSI X9.62, Section 5.4.3, Step 1
1674N/A **
1674N/A ** Compute u1*G + u2*Q
1674N/A ** Here, A = u1.G B = u2.Q and C = A + B
1674N/A ** If the result, C, is the point at infinity, reject the signature
1674N/A */
1674N/A if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC, kmflag)
1674N/A != SECSuccess) {
1674N/A rv = SECFailure;
1674N/A goto cleanup;
1674N/A }
1674N/A if (ec_point_at_infinity(&pointC)) {
1674N/A PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
1674N/A rv = SECFailure;
1674N/A goto cleanup;
1674N/A }
1674N/A
1674N/A CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, flen) );
1674N/A
1674N/A /*
1674N/A ** ANSI X9.62, Section 5.4.4, Step 2
1674N/A **
1674N/A ** v = x1 mod n
1674N/A */
1674N/A CHECK_MPI_OK( mp_mod(&x1, &n, &v) );
1674N/A
1674N/A#if EC_DEBUG
1674N/A mp_todecimal(&r_, mpstr);
1674N/A printf("r_: %s (dec)\n", mpstr);
1674N/A mp_todecimal(&v, mpstr);
1674N/A printf("v : %s (dec)\n", mpstr);
1674N/A#endif
1674N/A
1674N/A /*
1674N/A ** ANSI X9.62, Section 5.4.4, Step 3
1674N/A **
1674N/A ** Verification: v == r'
1674N/A */
1674N/A if (mp_cmp(&v, &r_)) {
1674N/A PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
1674N/A rv = SECFailure; /* Signature failed to verify. */
1674N/A } else {
1674N/A rv = SECSuccess; /* Signature verified. */
1674N/A }
1674N/A
1674N/A#if EC_DEBUG
1674N/A mp_todecimal(&u1, mpstr);
1674N/A printf("u1: %s (dec)\n", mpstr);
1674N/A mp_todecimal(&u2, mpstr);
1674N/A printf("u2: %s (dec)\n", mpstr);
1674N/A mp_tohex(&x1, mpstr);
1674N/A printf("x1: %s\n", mpstr);
1674N/A mp_todecimal(&v, mpstr);
1674N/A printf("v : %s (dec)\n", mpstr);
1674N/A#endif
1674N/A
1674N/Acleanup:
1674N/A mp_clear(&r_);
1674N/A mp_clear(&s_);
1674N/A mp_clear(&c);
1674N/A mp_clear(&u1);
1674N/A mp_clear(&u2);
1674N/A mp_clear(&x1);
1674N/A mp_clear(&v);
1674N/A mp_clear(&n);
1674N/A
1674N/A if (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE);
1674N/A if (err) {
1674N/A MP_TO_SEC_ERROR(err);
1674N/A rv = SECFailure;
1674N/A }
1674N/A
1674N/A#if EC_DEBUG
1674N/A printf("ECDSA verification %s\n",
1674N/A (rv == SECSuccess) ? "succeeded" : "failed");
1674N/A#endif
1674N/A
1674N/A return rv;
1674N/A}