mirror of https://github.com/wolfSSL/wolfssl.git
2287 lines
67 KiB
C
2287 lines
67 KiB
C
/* eccsi.c
|
|
*
|
|
* Copyright (C) 2006-2023 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfSSL.
|
|
*
|
|
* wolfSSL is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfSSL is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <wolfssl/wolfcrypt/settings.h>
|
|
|
|
#ifdef NO_INLINE
|
|
#include <wolfssl/wolfcrypt/misc.h>
|
|
#else
|
|
#define WOLFSSL_MISC_INCLUDED
|
|
#include <wolfcrypt/src/misc.c>
|
|
#endif
|
|
|
|
#ifdef WOLFCRYPT_HAVE_ECCSI
|
|
|
|
#include <wolfssl/wolfcrypt/error-crypt.h>
|
|
#include <wolfssl/wolfcrypt/eccsi.h>
|
|
#include <wolfssl/wolfcrypt/asn_public.h>
|
|
#ifdef WOLFSSL_HAVE_SP_ECC
|
|
#include <wolfssl/wolfcrypt/sp.h>
|
|
#endif
|
|
|
|
/**
|
|
* Initialize the components of the ECCSI key and use the specified curve.
|
|
*
|
|
* Must be called before performing any operations.
|
|
* Free the ECCSI key with wc_FreeEccsiKey() when no longer needed.
|
|
*
|
|
* @param [in] key ECCSI key to initialize.
|
|
* @param [in] heap Heap hint.
|
|
* @param [in] devId Device identifier.
|
|
* Use INVALID_DEVID when no device used.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key is NULL.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
int wc_InitEccsiKey_ex(EccsiKey* key, int keySz, int curveId, void* heap,
|
|
int devId)
|
|
{
|
|
int err = 0;
|
|
ecc_key* ecc = NULL;
|
|
ecc_key* pubkey = NULL;
|
|
EccsiKeyParams* params = NULL;
|
|
|
|
if (key == NULL) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (err == 0) {
|
|
XMEMSET(key, 0, sizeof(*key));
|
|
key->heap = heap;
|
|
params = &key->params;
|
|
|
|
err = wc_ecc_init_ex(&key->ecc, heap, devId);
|
|
}
|
|
if (err == 0) {
|
|
ecc = &key->ecc;
|
|
err = wc_ecc_init_ex(&key->pubkey, heap, devId);
|
|
}
|
|
if (err == 0) {
|
|
key->pvt = wc_ecc_new_point_h(heap);
|
|
if (key->pvt == NULL) {
|
|
err = MEMORY_E;
|
|
}
|
|
}
|
|
if (err == 0) {
|
|
pubkey = &key->pubkey;
|
|
err = mp_init_multi(¶ms->order,
|
|
#ifdef WOLFCRYPT_ECCSI_CLIENT
|
|
¶ms->a, ¶ms->b, ¶ms->prime, &key->tmp, &key->ssk
|
|
#else
|
|
NULL, NULL, NULL, NULL, NULL
|
|
#endif
|
|
);
|
|
}
|
|
if (err == 0) {
|
|
err = wc_ecc_set_curve(&key->ecc, keySz, curveId);
|
|
}
|
|
if (err == 0) {
|
|
err = wc_ecc_set_curve(&key->pubkey, keySz, curveId);
|
|
}
|
|
|
|
if (err != 0) {
|
|
wc_ecc_free(pubkey);
|
|
wc_ecc_free(ecc);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Initialize the components of the ECCSI key.
|
|
* Default curve used: NIST_P256 (ECC_SECP256R1)
|
|
*
|
|
* Must be called before performing any operations.
|
|
* Free the ECCSI key with wc_FreeEccsiKey() when no longer needed.
|
|
*
|
|
* @param [in] key ECCSI key to initialize.
|
|
* @param [in] heap Heap hint.
|
|
* @param [in] devId Device identifier.
|
|
* Use INVALID_DEVID when no device used.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key is NULL.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
int wc_InitEccsiKey(EccsiKey* key, void* heap, int devId)
|
|
{
|
|
return wc_InitEccsiKey_ex(key, 32, ECC_SECP256R1, heap, devId);
|
|
}
|
|
|
|
/**
|
|
* Frees memory associated with components of the ECCIS key.
|
|
*
|
|
* Must be called when finished with the ECCIS key.
|
|
*
|
|
* @param [in] key ECCIS key.
|
|
*/
|
|
void wc_FreeEccsiKey(EccsiKey* key)
|
|
{
|
|
if (key != NULL) {
|
|
EccsiKeyParams* params = &key->params;
|
|
|
|
wc_ecc_del_point_h(params->base, key->heap);
|
|
#ifdef WOLFCRYPT_ECCSI_CLIENT
|
|
mp_free(&key->ssk);
|
|
mp_free(&key->tmp);
|
|
mp_free(¶ms->prime);
|
|
mp_free(¶ms->b);
|
|
mp_free(¶ms->a);
|
|
#endif
|
|
mp_free(¶ms->order);
|
|
wc_ecc_del_point_h(key->pvt, key->heap);
|
|
wc_ecc_free(&key->pubkey);
|
|
wc_ecc_free(&key->ecc);
|
|
XMEMSET(key, 0, sizeof(*key));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Order, as a hex string in the ECC object, loaded into mp_int in key.
|
|
* Flags that the order is available so it isn't loaded multiple times.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
static int eccsi_load_order(EccsiKey* key)
|
|
{
|
|
int err = 0;
|
|
|
|
if (!key->params.haveOrder) {
|
|
err = mp_read_radix(&key->params.order, key->ecc.dp->order,
|
|
MP_RADIX_HEX);
|
|
if (err == 0) {
|
|
key->params.haveOrder = 1;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
#ifdef WOLFCRYPT_ECCSI_CLIENT
|
|
/*
|
|
* Parameters, as a hex strings in the ECC object, loaded into mp_ints in key.
|
|
*
|
|
* Parameters loaded: order, A, B, prime.
|
|
* Flags that each parameter is available so they aren't loaded multiple times.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
static int eccsi_load_ecc_params(EccsiKey* key)
|
|
{
|
|
int err = 0;
|
|
EccsiKeyParams* params = &key->params;
|
|
|
|
err = eccsi_load_order(key);
|
|
if ((err == 0) && (!params->haveA)) {
|
|
err = mp_read_radix(¶ms->a, key->ecc.dp->Af, MP_RADIX_HEX);
|
|
if (err == 0) {
|
|
params->haveA = 1;
|
|
}
|
|
}
|
|
if ((err == 0) && (!params->haveB)) {
|
|
err = mp_read_radix(¶ms->b, key->ecc.dp->Bf, MP_RADIX_HEX);
|
|
if (err == 0) {
|
|
params->haveB = 1;
|
|
}
|
|
}
|
|
if ((err == 0) && (!params->havePrime)) {
|
|
err = mp_read_radix(¶ms->prime, key->ecc.dp->prime, MP_RADIX_HEX);
|
|
if (err == 0) {
|
|
params->havePrime = 1;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
#endif /* WOLFCRYPT_ECCSI_CLIENT */
|
|
|
|
/*
|
|
* Get the base point, hex encoded in the ECC object, as an ecc_point.
|
|
*
|
|
* Flags that base is available so it isn't loaded multiple times.
|
|
|
|
* @param [in] key ECCSI key.
|
|
* @param [out] base Base point of curve.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
static int eccsi_load_base(EccsiKey* key)
|
|
{
|
|
int err = 0;
|
|
EccsiKeyParams* params = &key->params;
|
|
|
|
if (!params->haveBase) {
|
|
if (params->base == NULL) {
|
|
params->base = wc_ecc_new_point_h(key->heap);
|
|
if (params->base == NULL) {
|
|
err = MEMORY_E;
|
|
}
|
|
}
|
|
if (err == 0) {
|
|
err = mp_read_radix(params->base->x, key->ecc.dp->Gx, MP_RADIX_HEX);
|
|
}
|
|
if (err == 0) {
|
|
err = mp_read_radix(params->base->y, key->ecc.dp->Gy, MP_RADIX_HEX);
|
|
}
|
|
if (err == 0) {
|
|
err = mp_set(params->base->z, 1);
|
|
}
|
|
if (err == 0) {
|
|
params->haveBase = 1;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Encode the base point of the curve.
|
|
*
|
|
* Base point is hex encoded in the ECC object or cached as an ECC point from
|
|
* previous load calls.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [out] data Buffer to encode base point into.
|
|
* @param [out] dataSz Length of base point in bytes.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
static int eccsi_encode_base(EccsiKey* key, byte* data, word32* dataSz)
|
|
{
|
|
int err;
|
|
int idx = wc_ecc_get_curve_idx(key->ecc.dp->id);
|
|
|
|
err = eccsi_load_base(key);
|
|
if (err == 0) {
|
|
err = wc_ecc_export_point_der(idx, key->params.base, data, dataSz);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
#ifndef WOLFSSL_HAVE_SP_ECC
|
|
/*
|
|
* Convert the KPAK to montgomery form.
|
|
*
|
|
* The KPAK is needed in Montgomery form for verification.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @return 0 on success.
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
static int eccsi_kpak_to_mont(EccsiKey* key)
|
|
{
|
|
int err = 0;
|
|
ecc_point* kpak = &key->ecc.pubkey;
|
|
mp_int* mu = &key->tmp;
|
|
mp_int* prime = &key->params.prime;
|
|
|
|
if (!key->kpakMont) {
|
|
err = mp_montgomery_calc_normalization(mu, prime);
|
|
if (err == 0) {
|
|
err = mp_mulmod(kpak->x, mu, prime, kpak->x);
|
|
}
|
|
if (err == 0) {
|
|
err = mp_mulmod(kpak->y, mu, prime, kpak->y);
|
|
}
|
|
if (err == 0) {
|
|
err = mp_mulmod(kpak->z, mu, prime, kpak->z);
|
|
}
|
|
if (err == 0) {
|
|
key->kpakMont = 1;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Convert the KPAK from montgomery form.
|
|
*
|
|
* The KPAK is needed in Montgomery form for verification.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @return 0 on success.
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
static int eccsi_kpak_from_mont(EccsiKey* key)
|
|
{
|
|
int err = 0;
|
|
ecc_point* kpak = &key->ecc.pubkey;
|
|
mp_digit mp;
|
|
mp_int* prime = &key->params.prime;
|
|
|
|
if (key->kpakMont) {
|
|
err = mp_montgomery_setup(prime, &mp);
|
|
if (err == 0) {
|
|
err = mp_montgomery_reduce(kpak->x, prime, mp);
|
|
}
|
|
if (err == 0) {
|
|
err = mp_montgomery_reduce(kpak->y, prime, mp);
|
|
}
|
|
if (err == 0) {
|
|
err = mp_montgomery_reduce(kpak->z, prime, mp);
|
|
}
|
|
if (err == 0) {
|
|
key->kpakMont = 0;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Compute HS = hash( G | KPAK | ID | PVT )
|
|
*
|
|
* Use when making a (SSK,PVT) pair, signing and verifying.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] hashType Type of hash algorithm. e.g. WC_SHA256
|
|
* @param [in] id Identity to create hash from.
|
|
* @param [in] idSz Length of identity in bytes.
|
|
* @param [in] pvt Public Validation Token (PVT) as an ECC point.
|
|
* @param [out] hash Buffer to hold hash data.
|
|
* @param [out] hashSz Length of hash data in bytes.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
static int eccsi_compute_hs(EccsiKey* key, enum wc_HashType hashType,
|
|
const byte* id, word32 idSz, ecc_point* pvt, byte* hash, byte* hashSz)
|
|
{
|
|
int err;
|
|
word32 dataSz = 0;
|
|
int idx = wc_ecc_get_curve_idx(key->ecc.dp->id);
|
|
ecc_point* kpak = &key->ecc.pubkey;
|
|
int hash_inited = 0;
|
|
|
|
/* HS = hash( G | KPAK | ID | PVT ) */
|
|
err = wc_HashInit_ex(&key->hash, hashType, key->heap, INVALID_DEVID);
|
|
if (err == 0) {
|
|
hash_inited = 1;
|
|
/* Base Point - G */
|
|
dataSz = sizeof(key->data);
|
|
err = eccsi_encode_base(key, key->data, &dataSz);
|
|
}
|
|
if (err == 0) {
|
|
err = wc_HashUpdate(&key->hash, hashType, key->data, dataSz);
|
|
}
|
|
if (err == 0) {
|
|
err = eccsi_kpak_from_mont(key);
|
|
}
|
|
if (err == 0) {
|
|
dataSz = sizeof(key->data);
|
|
/* KPAK - public key */
|
|
err = wc_ecc_export_point_der(idx, kpak, key->data, &dataSz);
|
|
}
|
|
if (err == 0) {
|
|
err = wc_HashUpdate(&key->hash, hashType, key->data, dataSz);
|
|
}
|
|
if (err == 0) {
|
|
/* Id - Signer's ID */
|
|
err = wc_HashUpdate(&key->hash, hashType, id, idSz);
|
|
}
|
|
if (err == 0) {
|
|
dataSz = sizeof(key->data);
|
|
/* PVT - Public Validation Token */
|
|
err = wc_ecc_export_point_der(idx, pvt, key->data, &dataSz);
|
|
}
|
|
if (err == 0) {
|
|
/* PVT - Public Validation Token */
|
|
err = wc_HashUpdate(&key->hash, hashType, key->data, dataSz);
|
|
}
|
|
if (err == 0) {
|
|
err = wc_HashFinal(&key->hash, hashType, hash);
|
|
}
|
|
|
|
if (err == 0) {
|
|
*hashSz = (byte)wc_HashGetDigestSize(hashType);
|
|
}
|
|
|
|
if (hash_inited) {
|
|
(void)wc_HashFree(&key->hash, hashType);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
#ifdef WOLFCRYPT_ECCSI_KMS
|
|
/**
|
|
* Generate KMS Secret Auth Key (KSAK) and KMS Public Auth Key (KPAK).
|
|
*
|
|
* RFC 6507, Section 4.2
|
|
*
|
|
* Called when establishing a new KMS.\n
|
|
* KSAK must be kept secret while KPAK is required by clients for signing
|
|
* and verifying.\n
|
|
* Export key using wc_ExportEccsiKey(), once generated, to reuse the key.\n
|
|
* Export KPAK using wc_ExportEccsiPublicKey(), once generate to send to
|
|
* clients.
|
|
*
|
|
* Creates a random private key and multiplies it by the base point to calculate
|
|
* the public key.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] rng Random number generator.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key or rng is NULL.
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
int wc_MakeEccsiKey(EccsiKey* key, WC_RNG* rng)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (rng == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (err == 0) {
|
|
err = wc_ecc_make_key_ex(rng, key->ecc.dp->size, &key->ecc,
|
|
key->ecc.dp->id);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Encode a point into a buffer.
|
|
*
|
|
* X and y ordinate of point concatenated. Each number is zero padded tosize.
|
|
* Descriptor byte (0x04) is prepended when not raw.
|
|
*
|
|
* @param [in] point ECC point to encode.
|
|
* @param [in] size Size of prime in bytes - maximum ordinate length.
|
|
* @param [out] data Buffer to hold encoded data.
|
|
* NULL when needing length of encoded data.
|
|
* @param [in,out] sz In, the size of the buffer in bytes.
|
|
* Out, the size of the encoded data in bytes.
|
|
* @param [in] raw On 0, prepend descriptor byte.
|
|
* On 1, only include ordinates.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key or sz is NULL.
|
|
* @return LENGTH_ONLY_E when data is NULL - sz will hold the size in bytes of
|
|
* the encoded data.
|
|
* @return BUFFER_E when size of buffer is too small.
|
|
*/
|
|
static int eccsi_encode_point(ecc_point* point, word32 size, byte* data,
|
|
word32* sz, int raw)
|
|
{
|
|
int err = 0;
|
|
|
|
if (data == NULL) {
|
|
*sz = size * 2 + !raw;
|
|
err = LENGTH_ONLY_E;
|
|
}
|
|
if ((err == 0) && (*sz < size * 2 + !raw)) {
|
|
err = BUFFER_E;
|
|
}
|
|
|
|
if (err == 0) {
|
|
if (!raw) {
|
|
data[0] = 0x04;
|
|
data++;
|
|
}
|
|
|
|
/* Write out the point's x ordinate into key size bytes. */
|
|
err = mp_to_unsigned_bin_len(point->x, data, size);
|
|
}
|
|
if (err == 0) {
|
|
data += size;
|
|
/* Write out the point's y ordinate into key size bytes. */
|
|
err = mp_to_unsigned_bin_len(point->y, data, size);
|
|
}
|
|
if (err == 0) {
|
|
*sz = size * 2 + !raw;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Decode the data into an ECC point.
|
|
*
|
|
* X and y ordinate of point concatenated. Each number is zero padded to
|
|
* key size. Supports prepended descriptor byte (0x04).
|
|
*
|
|
* @param [out] point ECC point to encode.
|
|
* @param [in] size Size of prime in bytes - maximum ordinate length.
|
|
* @param [in] data Encoded public key.
|
|
* @param [in] sz Size of the encoded public key in bytes.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key or z is NULL.
|
|
* @return BUFFER_E when size of data is not equal to the expected size.
|
|
* @return ASN_PARSE_E when format byte is invalid.
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
static int eccsi_decode_point(ecc_point* point, word32 size, const byte* data,
|
|
word32 sz)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((sz != size * 2) && (sz != size * 2 + 1)) {
|
|
err = BUFFER_E;
|
|
}
|
|
|
|
if ((err == 0) && (sz & 1)) {
|
|
if (data[0] != 0x04) {
|
|
err = ASN_PARSE_E;
|
|
}
|
|
data++;
|
|
}
|
|
|
|
if (err == 0) {
|
|
/* Read the public key point's x value from key size bytes. */
|
|
err = mp_read_unsigned_bin(point->x, data, size);
|
|
}
|
|
if (err == 0) {
|
|
data += size;
|
|
/* Read the public key point's y value from key size bytes. */
|
|
err = mp_read_unsigned_bin(point->y, data, size);
|
|
}
|
|
if (err == 0) {
|
|
err = mp_set(point->z, 1);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Encode the ECCSI key.
|
|
*
|
|
* Encodes the private key as big-endian bytes of fixed length.
|
|
* Encodes the public key x and y ordinates as big-endian bytes of fixed length.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [out] data Buffer to hold encoded ECCSI key.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails (WOLFSSL_SMALL_STACK).
|
|
*/
|
|
static int eccsi_encode_key(EccsiKey* key, byte* data)
|
|
{
|
|
int err;
|
|
word32 sz = (word32)key->ecc.dp->size * 2;
|
|
|
|
/* Write out the secret value into key size bytes. */
|
|
err = mp_to_unsigned_bin_len(&key->ecc.k, data, key->ecc.dp->size);
|
|
if (err == 0) {
|
|
data += key->ecc.dp->size;
|
|
/* Write the public key. */
|
|
err = eccsi_encode_point(&key->ecc.pubkey, (word32)key->ecc.dp->size,
|
|
data, &sz, 1);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Export the ECCSI key as encoded public/private ECC key.
|
|
*
|
|
* Use when saving the KMS key pair.
|
|
*
|
|
* Private key, x ordinate of public key and y ordinate of public key
|
|
* concatenated. Each number is zero padded to key size.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [out] data Buffer to hold encoded ECCSI key.
|
|
* NULL when requesting required length.
|
|
* @param [in,out] sz On in, size of buffer in bytes.
|
|
* On out, size of encoded ECCSI key in bytes.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key or sz is NULL
|
|
* @return BAD_STATE_E when no key to export.
|
|
* @return LENGTH_ONLY_E when data is NULL - sz is set.
|
|
* @return BUFFER_E when the buffer passed in is too small.
|
|
* @return MEMORY_E when dynamic memory allocation fails (WOLFSSL_SMALL_STACK).
|
|
*/
|
|
int wc_ExportEccsiKey(EccsiKey* key, byte* data, word32* sz)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (sz == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY)) {
|
|
err = BAD_STATE_E;
|
|
}
|
|
|
|
if (err == 0) {
|
|
if (data == NULL) {
|
|
*sz = key->ecc.dp->size * 3;
|
|
err = LENGTH_ONLY_E;
|
|
}
|
|
else if (*sz < (word32)key->ecc.dp->size * 3) {
|
|
err = BUFFER_E;
|
|
}
|
|
else {
|
|
*sz = key->ecc.dp->size * 3;
|
|
}
|
|
}
|
|
if (err == 0) {
|
|
err = eccsi_kpak_from_mont(key);
|
|
}
|
|
if (err == 0) {
|
|
/* Encode key */
|
|
err = eccsi_encode_key(key, data);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Import the ECCSI key as encoded public/private ECC key.
|
|
*
|
|
* Decodes the private key as big-endian bytes of fixed length.
|
|
* Decodes the public key x and y ordinates as big-endian bytes of fixed length.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] data Buffer holding encoded ECCSI key.
|
|
* @return 0 on success.
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
static int eccsi_decode_key(EccsiKey* key, const byte* data)
|
|
{
|
|
int err;
|
|
|
|
/* Read the secret value from key size bytes. */
|
|
err = mp_read_unsigned_bin(&key->ecc.k, data, key->ecc.dp->size);
|
|
if (err == 0) {
|
|
data += key->ecc.dp->size;
|
|
/* Read public key. */
|
|
err = eccsi_decode_point(&key->ecc.pubkey, (word32)key->ecc.dp->size,
|
|
data, key->ecc.dp->size * 2);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Import the ECCSI key as encoded public/private ECC key.
|
|
*
|
|
* Use when restoring the KMS key pair.
|
|
*
|
|
* Private key, x ordinate of public key and y ordinate of public key
|
|
* concatenated. Each number is zero padded to key size.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] data Buffer holding encoded ECCSI key.
|
|
* @param [in] sz Size of encoded ECCSI key in bytes.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key or data is NULL.
|
|
* @return BUFFER_E when size of data is not equal to the expected size.
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
int wc_ImportEccsiKey(EccsiKey* key, const byte* data, word32 sz)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (data == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
if ((err == 0) && (sz != (word32)key->ecc.dp->size * 3)) {
|
|
err = BUFFER_E;
|
|
}
|
|
|
|
if (err == 0) {
|
|
key->kpakMont = 0;
|
|
|
|
/* Decode key */
|
|
err = eccsi_decode_key(key, data);
|
|
}
|
|
if (err == 0) {
|
|
key->ecc.type = ECC_PRIVATEKEY;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Export the ECCSI private key.
|
|
*
|
|
* Use when saving the KMS key.
|
|
*
|
|
* Private key is zero padded to key size.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [out] data Buffer to hold encoded ECCSI private key.
|
|
* NULL when requesting required length.
|
|
* @param [in,out] sz On in, size of buffer in bytes.
|
|
* On out, size of encoded ECCSI private key in bytes.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key or sz is NULL
|
|
* @return BAD_STATE_E when no key to export.
|
|
* @return LENGTH_ONLY_E when data is NULL - sz is set.
|
|
* @return BUFFER_E when the buffer passed in is too small.
|
|
* @return MEMORY_E when dynamic memory allocation fails (WOLFSSL_SMALL_STACK).
|
|
*/
|
|
int wc_ExportEccsiPrivateKey(EccsiKey* key, byte* data, word32* sz)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (sz == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY)) {
|
|
err = BAD_STATE_E;
|
|
}
|
|
|
|
if (err == 0) {
|
|
if (data == NULL) {
|
|
*sz = key->ecc.dp->size;
|
|
err = LENGTH_ONLY_E;
|
|
}
|
|
else if (*sz < (word32)key->ecc.dp->size) {
|
|
err = BUFFER_E;
|
|
}
|
|
else {
|
|
*sz = key->ecc.dp->size;
|
|
}
|
|
}
|
|
if (err == 0) {
|
|
err = mp_to_unsigned_bin_len(&key->ecc.k, data, key->ecc.dp->size);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Import the ECCSI private key.
|
|
*
|
|
* Use when restoring the KMS key pair.
|
|
*
|
|
* Private key is zero padded to key size.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] data Buffer holding encoded ECCSI private key.
|
|
* @param [in] sz Size of encoded ECCSI private key in bytes.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key or data is NULL.
|
|
* @return BUFFER_E when size of data is not equal to the expected size.
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
int wc_ImportEccsiPrivateKey(EccsiKey* key, const byte* data, word32 sz)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (data == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
if ((err == 0) && (sz != (word32)key->ecc.dp->size)) {
|
|
err = BUFFER_E;
|
|
}
|
|
|
|
if (err == 0) {
|
|
err = mp_read_unsigned_bin(&key->ecc.k, data, key->ecc.dp->size);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Export the KMS Public Auth Key (KPAK) from the ECCSI object.
|
|
*
|
|
* KPAK is required by all clients in order to perform cryptographic operations.
|
|
*
|
|
* X and y ordinate of public key concatenated. Each number is zero padded to
|
|
* key size.
|
|
* Descriptor byte (0x04) is prepended when not raw.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [out] data Buffer to hold the encoded public key.
|
|
* @param [in,out] sz On in, size of buffer in bytes.
|
|
* On out, length of encoded public key in bytes.
|
|
* @param [in] raw On 0, prepend descriptor byte.
|
|
* On 1, only include ordinates.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key or sz is NULL.
|
|
* @return LENGTH_ONLY_E when data is NULL - sz is set.
|
|
* @return BUFFER_E when the buffer passed in is too small.
|
|
*/
|
|
int wc_ExportEccsiPublicKey(EccsiKey* key, byte* data, word32* sz, int raw)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (sz == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY) &&
|
|
(key->ecc.type != ECC_PUBLICKEY)) {
|
|
err = BAD_STATE_E;
|
|
}
|
|
|
|
if ((err == 0) && (data != NULL)) {
|
|
err = eccsi_kpak_from_mont(key);
|
|
}
|
|
if (err == 0) {
|
|
/* Write out public key. */
|
|
err = eccsi_encode_point(&key->ecc.pubkey, (word32)key->ecc.dp->size,
|
|
data, sz, raw);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Generates an (SSK, PVT) Pair - signing key pair.
|
|
*
|
|
* RFC 6507, Section 5.1.1
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] rng Random number generator.
|
|
* @param [in] hashType Type of hash algorithm. e.g. WC_SHA256
|
|
* @param [in] id Identity to create hash from.
|
|
* @param [in] idSz Length of identity in bytes.
|
|
* @param [out] ssk Secret Signing Key as an MP integer.
|
|
* @param [out] pvt Public Validation Token (PVT) as an ECC point.
|
|
* @return 0 on success.
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
static int eccsi_make_pair(EccsiKey* key, WC_RNG* rng,
|
|
enum wc_HashType hashType, const byte* id, word32 idSz, mp_int* ssk,
|
|
ecc_point* pvt)
|
|
{
|
|
int err = 0;
|
|
byte hashSz = 0;
|
|
int genTryCnt = 0;
|
|
|
|
do {
|
|
/* Don't infinitely make pairs when random number generator fails. */
|
|
if ((++genTryCnt) > ECCSI_MAX_GEN_COUNT) {
|
|
err = RNG_FAILURE_E;
|
|
}
|
|
|
|
if (err == 0) {
|
|
wc_ecc_free(&key->pubkey);
|
|
|
|
/* Step 1 and 2: Generate ephemeral key - v, PVT = [v]G */
|
|
err = wc_ecc_make_key_ex(rng, key->ecc.dp->size, &key->pubkey,
|
|
key->ecc.dp->id);
|
|
}
|
|
if (err == 0) {
|
|
err = wc_ecc_copy_point(&key->pubkey.pubkey, pvt);
|
|
}
|
|
|
|
/* Step 3: Compute HS */
|
|
if (err == 0) {
|
|
hashSz = (byte)sizeof(key->data);
|
|
err = eccsi_compute_hs(key, hashType, id, idSz, pvt, key->data,
|
|
&hashSz);
|
|
}
|
|
|
|
/* Step 4: Compute SSK = ( KSAK + HS * v ) modulo q */
|
|
if (err == 0) {
|
|
err = mp_read_unsigned_bin(ssk, key->data, hashSz);
|
|
}
|
|
if (err == 0) {
|
|
err = mp_mulmod(ssk, &key->pubkey.k, &key->params.order, ssk);
|
|
}
|
|
if (err == 0) {
|
|
err = mp_addmod(ssk, &key->ecc.k, &key->params.order, ssk);
|
|
}
|
|
}
|
|
while ((err == 0) && (mp_iszero(ssk) ||
|
|
(mp_cmp(ssk, &key->ecc.k) == MP_EQ)));
|
|
/* Step 5: ensure SSK and HS are non-zero (code lines above) */
|
|
|
|
/* Step 6: Copy out SSK (done during calc) and PVT. Erase v */
|
|
mp_forcezero(&key->pubkey.k);
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Generates an (SSK, PVT) Pair - signing key pair.
|
|
*
|
|
* RFC 6507, Section 5.1.1
|
|
*
|
|
* ID should include information to indicate a revocation date.\n
|
|
* SSK must be zeroized after sending to client.\n
|
|
* SSK is sent to signing client only.\n
|
|
* PVT is sent to all client types.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] rng Random number generator.
|
|
* @param [in] hashType Type of hash algorithm. e.g. WC_SHA256
|
|
* @param [in] id Identity to create hash from.
|
|
* @param [in] idSz Length of identity in bytes.
|
|
* @param [out] ssk Secret Signing Key as an MP integer.
|
|
* @param [out] pvt Public Validation Token (PVT) as an ECC point.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key, rng, id, ssk or pvt is NULL.
|
|
* @return BAD_STATE_E when curve not set (key not set).
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
int wc_MakeEccsiPair(EccsiKey* key, WC_RNG* rng, enum wc_HashType hashType,
|
|
const byte* id, word32 idSz, mp_int* ssk, ecc_point* pvt)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (rng == NULL) || (id == NULL) || (ssk == NULL) ||
|
|
(pvt == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY)) {
|
|
err = BAD_STATE_E;
|
|
}
|
|
|
|
if (err == 0) {
|
|
err = eccsi_load_order(key);
|
|
}
|
|
if (err == 0) {
|
|
err = eccsi_make_pair(key, rng, hashType, id, idSz, ssk, pvt);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Encode the SSK and PVT into a buffer.
|
|
*
|
|
* SSK and PVT required by client signing messages.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] ssk Secret Signing Key as an MP integer.
|
|
* @param [in] pvt Public Validation Token (PVT) as an ECC point.
|
|
* @param [out] data Buffer to encode key pair into.
|
|
* @param [in,out] sz In, size of buffer in bytes.
|
|
* Out, size of encoded pair data in bytes.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key, ssk, pvt or sz is NULL.
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
* @return LENGTH_ONLY_E when data is NULL - sz is set.
|
|
*/
|
|
int wc_EncodeEccsiPair(const EccsiKey* key, mp_int* ssk, ecc_point* pvt,
|
|
byte* data, word32* sz)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (ssk == NULL) || (pvt == NULL) || (sz == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if ((err == 0) && (data == NULL)) {
|
|
*sz = key->ecc.dp->size * 3;
|
|
err = LENGTH_ONLY_E;
|
|
}
|
|
if ((err == 0) && (*sz < (word32)(key->ecc.dp->size * 3))) {
|
|
err = BUFFER_E;
|
|
}
|
|
|
|
if (err == 0) {
|
|
err = mp_to_unsigned_bin_len(ssk, data, key->ecc.dp->size);
|
|
}
|
|
if (err == 0) {
|
|
data += key->ecc.dp->size;
|
|
/* Write out the PVT's x ordinate into key size bytes. */
|
|
err = mp_to_unsigned_bin_len(pvt->x, data, key->ecc.dp->size);
|
|
}
|
|
if (err == 0) {
|
|
data += key->ecc.dp->size;
|
|
/* Write out the PVT's y ordinate into key size bytes. */
|
|
err = mp_to_unsigned_bin_len(pvt->y, data, key->ecc.dp->size);
|
|
}
|
|
if (err == 0) {
|
|
*sz = key->ecc.dp->size * 3;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Encode the Secret Signing Key (SSK).
|
|
*
|
|
* Use when saving the key pair.
|
|
*
|
|
* SSK is zero padded to key size.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] ssk Secret Signing Key as an MP integer.
|
|
* @param [out] data Buffer to hold encoded SSK.
|
|
* NULL when requesting required length.
|
|
* @param [in,out] sz On in, size of buffer in bytes.
|
|
* On out, size of encoded ECCSI key in bytes.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key, ssk or sz is NULL
|
|
* @return BAD_STATE_E when no key to export.
|
|
* @return LENGTH_ONLY_E when data is NULL - sz is set.
|
|
* @return BUFFER_E when the buffer passed in is too small.
|
|
* @return MEMORY_E when dynamic memory allocation fails (WOLFSSL_SMALL_STACK).
|
|
*/
|
|
int wc_EncodeEccsiSsk(const EccsiKey* key, mp_int* ssk, byte* data, word32* sz)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (ssk == NULL) || (sz == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY)) {
|
|
err = BAD_STATE_E;
|
|
}
|
|
|
|
if (err == 0) {
|
|
if (data == NULL) {
|
|
*sz = key->ecc.dp->size;
|
|
err = LENGTH_ONLY_E;
|
|
}
|
|
else if (*sz < (word32)key->ecc.dp->size) {
|
|
err = BUFFER_E;
|
|
}
|
|
else {
|
|
*sz = key->ecc.dp->size;
|
|
}
|
|
}
|
|
if (err == 0) {
|
|
err = mp_to_unsigned_bin_len(ssk, data, key->ecc.dp->size);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Decode the Secret Signing Key (SSK).
|
|
*
|
|
* Use when restoring the key pair.
|
|
*
|
|
* SSK is zero padded to key size.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] data Buffer holding encoded ECCSI key.
|
|
* @param [in] sz Size of encoded ECCSI key in bytes.
|
|
* @param [out] ssk Secret Signing Key as an MP integer.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key, data or ssk is NULL.
|
|
* @return BUFFER_E when size of data is not equal to the expected size.
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
int wc_DecodeEccsiSsk(const EccsiKey* key, const byte* data, word32 sz,
|
|
mp_int* ssk)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (data == NULL) || (ssk == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
if ((err == 0) && (sz != (word32)key->ecc.dp->size)) {
|
|
err = BUFFER_E;
|
|
}
|
|
|
|
if (err == 0) {
|
|
err = mp_read_unsigned_bin(ssk, data, key->ecc.dp->size);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Encode the PVT into a buffer.
|
|
*
|
|
* PVT required by client verifying messages.
|
|
*
|
|
* X and y ordinate of public key concatenated. Each number is zero padded to
|
|
* key size.
|
|
* Descriptor byte (0x04) is prepended when not raw.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] pvt Public Validation Token (PVT) as an ECC point.
|
|
* @param [out] data Buffer to encode key pair into.
|
|
* @param [in,out] sz In, size of buffer in bytes.
|
|
* Out, size of encoded pair data in bytes.
|
|
* @param [in] raw On 0, prepend descriptor byte.
|
|
* On 1, only include ordinates.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key, pvt or sz is NULL.
|
|
* @return BAD_STATE_E when PVT has not been set.
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
* @return LENGTH_ONLY_E when data is NULL - sz is set.
|
|
*/
|
|
int wc_EncodeEccsiPvt(const EccsiKey* key, ecc_point* pvt, byte* data,
|
|
word32* sz, int raw)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (pvt == NULL) || (sz == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (err == 0) {
|
|
err = eccsi_encode_point(pvt, (word32)key->ecc.dp->size, data, sz, raw);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
#endif /* WOLFCRYPT_ECCSI_KMS */
|
|
|
|
#ifdef WOLFCRYPT_ECCSI_CLIENT
|
|
/**
|
|
* Decode the SSK and PVT data into separate variables.
|
|
*
|
|
* A signing client decodes the data so that it can validate the pair and sign.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] data Buffer holding key pair data.
|
|
* @param [in] sz Size of data in bytes.
|
|
* @param [out] ssk Secret Signing Key as an MP integer.
|
|
* @param [out] pvt Public Validation Token (PVT) as an ECC point.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key, data, ssk or pvt is NULL.
|
|
* @return LENGTH_ONLY_E when data is NULL - sz is set.
|
|
* @return BUFFER_E when size of data is not equal to the expected size.
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
int wc_DecodeEccsiPair(const EccsiKey* key, const byte* data, word32 sz,
|
|
mp_int* ssk, ecc_point* pvt)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (data == NULL) || (ssk == NULL) || (pvt == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
if ((err == 0) && (sz != (word32)(key->ecc.dp->size * 3))) {
|
|
err = BUFFER_E;
|
|
}
|
|
|
|
if (err == 0) {
|
|
/* Read the SSK value from key size bytes. */
|
|
err = mp_read_unsigned_bin(ssk, data, key->ecc.dp->size);
|
|
}
|
|
if (err == 0) {
|
|
data += key->ecc.dp->size;
|
|
/* Read the PVT's x value from key size bytes. */
|
|
err = mp_read_unsigned_bin(pvt->x, data, key->ecc.dp->size);
|
|
}
|
|
if (err == 0) {
|
|
data += key->ecc.dp->size;
|
|
/* Read the PVT's y value from key size bytes. */
|
|
err = mp_read_unsigned_bin(pvt->y, data, key->ecc.dp->size);
|
|
}
|
|
if (err == 0) {
|
|
err = mp_set(pvt->z, 1);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Decode the PVT data into an ECC point.
|
|
*
|
|
* A verifying client decodes the data so that it can verify a message.
|
|
*
|
|
* X and y ordinate of public key concatenated. Each number is zero padded to
|
|
* key size.
|
|
* Descriptor byte (0x04) is prepended when not raw.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] data Buffer holding PVT data.
|
|
* @param [in] sz Size of data in bytes.
|
|
* @param [out] pvt Public Validation Token (PVT) as an ECC point.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key, data, ssk or pvt is NULL.
|
|
* @return BUFFER_E when size of data is not equal to the expected size.
|
|
* @return ASN_PARSE_E when format byte is invalid.
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
int wc_DecodeEccsiPvt(const EccsiKey* key, const byte* data, word32 sz,
|
|
ecc_point* pvt)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (data == NULL) || (pvt == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (err == 0) {
|
|
err = eccsi_decode_point(pvt, (word32)key->ecc.dp->size, data, sz);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Decode the PVT data, from a signature, into an ECC point.
|
|
*
|
|
* A verifying client decodes the data so that it can calculate the identity
|
|
* hash.
|
|
*
|
|
* X and y ordinate of public key concatenated. Each number is zero padded to
|
|
* key size.
|
|
* Descriptor byte (0x04) is prepended when not raw.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] sig Buffer holding signature data.
|
|
* @param [in] sz Size of data in bytes.
|
|
* @param [out] pvt Public Validation Token (PVT) as an ECC point.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key, data, ssk or pvt is NULL.
|
|
* @return BUFFER_E when size of data is not equal to the expected size.
|
|
* @return ASN_PARSE_E when format byte is invalid.
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
int wc_DecodeEccsiPvtFromSig(const EccsiKey* key, const byte* sig, word32 sz,
|
|
ecc_point* pvt)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (sig == NULL) || (pvt == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (err == 0) {
|
|
word32 rSz = key->ecc.dp->size * 2;
|
|
err = eccsi_decode_point(pvt, (word32)key->ecc.dp->size, sig + rSz,
|
|
sz - rSz);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Import the KMS Public Auth Key (KPAK) into the ECCSI object.
|
|
*
|
|
* Clients import the KPAK to perform cryptographic operations.
|
|
*
|
|
* X and y ordinate of public key concatenated. Each number is zero padded to
|
|
* key size.
|
|
* Descriptor byte (0x04) is prepended when not raw.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] data Encoded public key as an array of bytes.
|
|
* @param [in] sz Length of encoded KPAK in bytes.
|
|
* @param [in] trusted 1 when public key is trusted.
|
|
* 0 when validation is required to be performed.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key or data is NULL.
|
|
* @return BUFFER_E when size of data is not equal to the expected size.
|
|
* @return ASN_PARSE_E when format byte is invalid.
|
|
* @return ECC_OUT_OF_RANGE_E when point is invalid.
|
|
* @return ECC_INF_E when point is at infinity and invalid.
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
int wc_ImportEccsiPublicKey(EccsiKey* key, const byte* data, word32 sz,
|
|
int trusted)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (data == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (err == 0) {
|
|
key->kpakMont = 0;
|
|
|
|
/* Read the public key. */
|
|
err = eccsi_decode_point(&key->ecc.pubkey, (word32)key->ecc.dp->size,
|
|
data, sz);
|
|
}
|
|
if (err == 0) {
|
|
key->ecc.type = ECC_PUBLICKEY;
|
|
}
|
|
if ((err == 0) && (!trusted)) {
|
|
err = wc_ecc_check_key(&key->ecc);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Scalar multiply the base point of the curve and add a point.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] n MP integer representing scalar to multiply by.
|
|
* @param [in] a ECC point to add.
|
|
* @param [out] res ECC point representation of the resulting point.
|
|
* @param [in] mp Montgomery reduction multiplier.
|
|
* @param [in] map 0 indicates to leave in projective representation.
|
|
* 1 indicates map projective point to affine.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
static int eccsi_mulmod_base_add(EccsiKey* key, const mp_int* n,
|
|
ecc_point* a, ecc_point* res, mp_digit mp, int map)
|
|
{
|
|
int err = 0;
|
|
|
|
#ifdef WOLFSSL_HAVE_SP_ECC
|
|
#ifndef WOLFSSL_SP_NO_256
|
|
if ((key->ecc.idx != ECC_CUSTOM_IDX) &&
|
|
(ecc_sets[key->ecc.idx].id == ECC_SECP256R1)) {
|
|
err = sp_ecc_mulmod_base_add_256(n, a, 1, res, map, key->heap);
|
|
}
|
|
else
|
|
#endif
|
|
#endif
|
|
#ifndef WOLFSSL_SP_MATH
|
|
{
|
|
EccsiKeyParams* params = &key->params;
|
|
err = wc_ecc_mulmod(n, params->base, params->base, ¶ms->a,
|
|
¶ms->prime, 0);
|
|
key->params.haveBase = 0;
|
|
if (err == 0) {
|
|
err = ecc_projective_add_point(params->base, a, res, ¶ms->a,
|
|
¶ms->prime, mp);
|
|
}
|
|
if ((err == 0) && map) {
|
|
err = ecc_map(res, ¶ms->prime, mp);
|
|
}
|
|
}
|
|
#else
|
|
{
|
|
err = NOT_COMPILED_IN;
|
|
}
|
|
(void)mp;
|
|
#endif
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Scalar multiply a point on the curve.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] n MP integer representing scalar to multiply by.
|
|
* @param [in] point ECC point representation of a point on the curve.
|
|
* @param [out] res ECC point representation of the resulting point.
|
|
* @param [in] map 0 indicates to leave in projective representation.
|
|
* 1 indicates map projective point to affine.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
static int eccsi_mulmod_point(EccsiKey* key, const mp_int* n, ecc_point* point,
|
|
ecc_point* res, int map)
|
|
{
|
|
int err;
|
|
|
|
#ifdef WOLFSSL_HAVE_SP_ECC
|
|
#ifndef WOLFSSL_SP_NO_256
|
|
if ((key->ecc.idx != ECC_CUSTOM_IDX) &&
|
|
(ecc_sets[key->ecc.idx].id == ECC_SECP256R1)) {
|
|
err = sp_ecc_mulmod_256(n, point, res, map, key->heap);
|
|
}
|
|
else
|
|
#endif
|
|
#endif
|
|
{
|
|
EccsiKeyParams* params = &key->params;
|
|
|
|
err = wc_ecc_mulmod(n, point, res, ¶ms->a, ¶ms->prime, map);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Scalar multiply a point on the curve and add a.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] n MP integer representing scalar to multiply by.
|
|
* @param [in] point ECC point representation of a point on the curve.
|
|
* @param [in] a ECC point to add.
|
|
* @param [out] res ECC point representation of the resulting point.
|
|
* @param [in] mp Montgomery reduction multiplier.
|
|
* @param [in] map 0 indicates to leave in projective representation.
|
|
* 1 indicates map projective point to affine.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
static int eccsi_mulmod_point_add(EccsiKey* key, const mp_int* n,
|
|
ecc_point* point, ecc_point* a, ecc_point* res, mp_digit mp, int map)
|
|
{
|
|
#ifdef WOLFSSL_HAVE_SP_ECC
|
|
#ifndef WOLFSSL_SP_NO_256
|
|
int err = NOT_COMPILED_IN;
|
|
|
|
if ((key->ecc.idx != ECC_CUSTOM_IDX) &&
|
|
(ecc_sets[key->ecc.idx].id == ECC_SECP256R1)) {
|
|
err = sp_ecc_mulmod_add_256(n, point, a, 0, res, map, key->heap);
|
|
}
|
|
|
|
(void)mp;
|
|
|
|
return err;
|
|
#endif
|
|
#else
|
|
int err;
|
|
EccsiKeyParams* params = &key->params;
|
|
|
|
err = wc_ecc_mulmod(n, point, res, ¶ms->a, ¶ms->prime, 0);
|
|
if (err == 0) {
|
|
err = ecc_projective_add_point(res, a, res, &key->params.a,
|
|
¶ms->prime, mp);
|
|
}
|
|
if ((err == 0) && map) {
|
|
err = ecc_map(res, ¶ms->prime, mp);
|
|
}
|
|
|
|
return err;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Validate an (SSV, PVT) Pair.
|
|
*
|
|
* RFC 6507, Section 5.1.2
|
|
*
|
|
* A signing client should validate the key pair before first use.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] hashType Type of hash algorithm. e.g. WC_SHA256
|
|
* @param [in] id Identity to create hash from.
|
|
* @param [in] idSz Length of identity in bytes.
|
|
* @param [in] ssk Secret Signing Key as an MP integer.
|
|
* @param [in] pvt Public Validation Token (PVT) as an ECC point.
|
|
* @param [out] valid 1 when pair is valid and 0 otherwise.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key, id, ssk, pvt or valid is NULL.
|
|
* @return BAD_STATE_E when curve not set (key not set).
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
* @return IS_POINT_E when point is not on the curve.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
int wc_ValidateEccsiPair(EccsiKey* key, enum wc_HashType hashType,
|
|
const byte* id, word32 idSz, const mp_int* ssk, ecc_point* pvt,
|
|
int* valid)
|
|
{
|
|
int err = 0;
|
|
ecc_point* res = NULL;
|
|
mp_int* hs = NULL;
|
|
mp_digit mp = 0;
|
|
byte hashSz = 0;
|
|
EccsiKeyParams* params = NULL;
|
|
|
|
if ((key == NULL) || (id == NULL) || (ssk == NULL) || (pvt == NULL) ||
|
|
(valid == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY) &&
|
|
(key->ecc.type != ECC_PUBLICKEY)) {
|
|
err = BAD_STATE_E;
|
|
}
|
|
|
|
if (err != 0)
|
|
return err;
|
|
|
|
SAVE_VECTOR_REGISTERS(return _svr_ret;);
|
|
|
|
params = &key->params;
|
|
hs = &key->tmp;
|
|
res = &key->pubkey.pubkey;
|
|
|
|
err = eccsi_load_base(key);
|
|
|
|
if (err == 0) {
|
|
err = eccsi_load_ecc_params(key);
|
|
}
|
|
if (err == 0) {
|
|
err = mp_montgomery_setup(¶ms->prime, &mp);
|
|
}
|
|
|
|
/* Step 1: Validate PVT is on curve */
|
|
if (err == 0) {
|
|
err = wc_ecc_is_point(pvt, ¶ms->a, ¶ms->b, ¶ms->prime);
|
|
if (err == -1) {
|
|
err = IS_POINT_E;
|
|
}
|
|
}
|
|
|
|
/* Step 2: Compute HS = hash( G | KPAK | ID | PVT ) */
|
|
if (err == 0) {
|
|
hashSz = (byte)sizeof(key->data);
|
|
/* Converts KPAK from mont. */
|
|
err = eccsi_compute_hs(key, hashType, id, idSz, pvt, key->data,
|
|
&hashSz);
|
|
}
|
|
|
|
/* Step 3: Validate that KPAK = [SSK]G - [HS]PVT */
|
|
if (err == 0) {
|
|
err = mp_read_unsigned_bin(hs, key->data, hashSz);
|
|
}
|
|
/* [HS]PVT */
|
|
if (err == 0) {
|
|
err = eccsi_mulmod_point(key, hs, pvt, res, 0);
|
|
}
|
|
/* -[HS]PVT */
|
|
if (err == 0) {
|
|
err = mp_sub(¶ms->prime, res->y, res->y);
|
|
}
|
|
/* [SSK]G + -[HS]PVT */
|
|
if (err == 0) {
|
|
err = eccsi_mulmod_base_add(key, ssk, res, res, mp, 1);
|
|
}
|
|
if (valid != NULL) {
|
|
*valid = (err == 0);
|
|
if (err == 0) {
|
|
ecc_point* kpak = &key->ecc.pubkey;
|
|
/* Compare KPAK and [SSK]G + -[HS]PVT */
|
|
*valid = (wc_ecc_cmp_point(res, kpak) == MP_EQ);
|
|
}
|
|
}
|
|
|
|
RESTORE_VECTOR_REGISTERS();
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Validate Public Validation Token (PVT) is on the curve.
|
|
*
|
|
* RFC 6507, Section 5.1.2, Step 1
|
|
*
|
|
* A verifying client should validate the PVT before first use.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] pvt Public Validation Token (PVT) as an ECC point.
|
|
* @param [out] valid 1 when PVT is valid and 0 otherwise.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key, pvt or valid is NULL.
|
|
* @return BAD_STATE_E when curve not set (key not set).
|
|
* @return MP_MEM or MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
int wc_ValidateEccsiPvt(EccsiKey* key, const ecc_point* pvt, int* valid)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL)| (pvt == NULL) || (valid == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (err == 0) {
|
|
err = wc_ecc_set_curve(&key->pubkey, key->ecc.dp->size,
|
|
key->ecc.dp->id);
|
|
}
|
|
if (err == 0) {
|
|
err = wc_ecc_copy_point(pvt, &key->pubkey.pubkey);
|
|
}
|
|
if (err == 0) {
|
|
*valid = (wc_ecc_check_key(&key->pubkey) == 0);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Creates the Hash of the ID and PVT with the ECCSI key.
|
|
*
|
|
* The hash ID is required as input to the sign and verify operations.\n
|
|
* Signing clients may cache this value.
|
|
*
|
|
* RFC 6507, Section 5.2.1, Step 3
|
|
*
|
|
* Set the calculated hash internally for use.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] hashType Type of hash algorithm. e.g. WC_SHA256
|
|
* @param [in] id Identity to create hash from.
|
|
* @param [in] idSz Length of identity in bytes.
|
|
* @param [in] pvt Public Validation Token (PVT) as an ECC point.
|
|
* @param [out] hash Buffer to hold hash result.
|
|
* @param [out] hashSz Length of hash data in bytes.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key, id, pvt, hash or hashSz is NULL.
|
|
* @return BAD_FUNC_ARG when hash size doesn't match curve size.
|
|
* @return BAD_STATE_E when public key not set.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
int wc_HashEccsiId(EccsiKey* key, enum wc_HashType hashType, const byte* id,
|
|
word32 idSz, ecc_point* pvt, byte* hash, byte* hashSz)
|
|
{
|
|
int err = 0;
|
|
int dgstSz = -1;
|
|
int curveSz = -1;
|
|
|
|
if ((key == NULL) || (id == NULL) || (pvt == NULL) || (hash == NULL) ||
|
|
(hashSz == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY) &&
|
|
(key->ecc.type != ECC_PUBLICKEY)) {
|
|
err = BAD_STATE_E;
|
|
}
|
|
/* Ensure digest output size matches curve size (RFC 6507 4.1). */
|
|
if (err == 0) {
|
|
dgstSz = wc_HashGetDigestSize(hashType);
|
|
if (dgstSz < 0) {
|
|
err = dgstSz;
|
|
}
|
|
}
|
|
if (err == 0) {
|
|
curveSz = wc_ecc_get_curve_size_from_id(key->ecc.dp->id);
|
|
if (curveSz < 0) {
|
|
err = curveSz;
|
|
}
|
|
}
|
|
if ((err == 0) && (dgstSz != curveSz)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
/* Load the curve parameters for operations */
|
|
if (err == 0) {
|
|
err = eccsi_load_ecc_params(key);
|
|
}
|
|
if (err == 0) {
|
|
err = eccsi_compute_hs(key, hashType, id, idSz, pvt, hash, hashSz);
|
|
}
|
|
if (err == 0) {
|
|
XMEMCPY(key->idHash, hash, *hashSz);
|
|
key->idHashSz = *hashSz;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Set the identity hash for use with signing/verification.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] hash Buffer with hash of identity.
|
|
* @param [in] hashSz Length of hash data in bytes.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key or hash is NULL, or hashSz is greater than
|
|
* WC_MAX_DIGEST_SIZE.
|
|
*/
|
|
int wc_SetEccsiHash(EccsiKey* key, const byte* hash, byte hashSz)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (hash == NULL) || (hashSz > WC_MAX_DIGEST_SIZE)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
if (err == 0) {
|
|
XMEMCPY(key->idHash, hash, hashSz);
|
|
key->idHashSz = hashSz;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Set an (SSV, PVT) Pair for signing.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] ssk Secret Signing Key as an MP integer.
|
|
* @param [in] pvt Public Validation Token (PVT) as an ECC point.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key, ssk or pvt is NULL.
|
|
* @return MP math errors when copy fails
|
|
*/
|
|
int wc_SetEccsiPair(EccsiKey* key, const mp_int* ssk, const ecc_point* pvt)
|
|
{
|
|
int err = 0;
|
|
|
|
if ((key == NULL) || (ssk == NULL) || (pvt == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (err == 0) {
|
|
err = mp_copy(ssk, &key->ssk);
|
|
}
|
|
|
|
if (err == 0) {
|
|
err = wc_ecc_copy_point(pvt, key->pvt);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
#ifdef ECCSI_ORDER_MORE_BITS_THAN_PRIME
|
|
/*
|
|
* Fit the number to the maximum number of bytes.
|
|
*
|
|
* If the number is too big then subtract from order.
|
|
* RFC 6507, Section 5.2.1, Note at end.
|
|
* This should only happen when order is larger than prime in bits.
|
|
*
|
|
* @param [in] a MP integer to fix.
|
|
* @param [in] order MP integer representing order of curve.
|
|
* @param [in] m Maximum number of bytes to encode into.
|
|
* @param [out] r MP integer that is the result after fixing.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
static int eccsi_fit_to_octets(const mp_int* a, mp_int* order, int m,
|
|
mp_int* r)
|
|
{
|
|
int err;
|
|
|
|
if (mp_count_bits(a) > m * 8) {
|
|
err = mp_sub(order, (mp_int*)a, r);
|
|
}
|
|
else
|
|
{
|
|
err = mp_copy(a, r);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
#else
|
|
/*
|
|
* Fit the number to the maximum number of bytes.
|
|
*
|
|
* If the number is too big then subtract from order.
|
|
* RFC 6507, Section 5.2.1, Note at end.
|
|
* This should only happen when order is larger than prime in bits.
|
|
*
|
|
* @param [in] a MP integer to fix.
|
|
* @param [in] order MP integer representing order of curve.
|
|
* @param [in] m Maximum number of bytes to encode into.
|
|
* @param [out] r MP integer that is the result after fixing.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
static int eccsi_fit_to_octets(const mp_int* a, const mp_int* order, int m,
|
|
mp_int* r)
|
|
{
|
|
(void)order;
|
|
(void)m;
|
|
|
|
/* Duplicate line to stop static analyzer complaining. */
|
|
return mp_copy(a, r);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Compute the HE = hash( HS | r | M ), hash value of signature.
|
|
*
|
|
* Partial result required for signing and verification.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] hashType Type of hash algorithm. e.g. WC_SHA256
|
|
* @param [in] r MP integer that is the first signature element.
|
|
* @param [in] msg Message of signature.
|
|
* @param [in] msgSz Length of message in bytes.
|
|
* @param [out] he Signature hash.
|
|
* @param [out] heSz Length of signature hash in bytes
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
static int eccsi_compute_he(EccsiKey* key, enum wc_HashType hashType,
|
|
mp_int* r, const byte* msg, word32 msgSz, byte* he, word32* heSz)
|
|
{
|
|
int err = 0;
|
|
word32 dataSz = key->ecc.dp->size;
|
|
int hash_inited = 0;
|
|
|
|
/* HE = hash( HS | r | M ) */
|
|
err = wc_HashInit_ex(&key->hash, hashType, key->heap, INVALID_DEVID);
|
|
if (err == 0) {
|
|
hash_inited = 1;
|
|
/* HS */
|
|
err = wc_HashUpdate(&key->hash, hashType, key->idHash, key->idHashSz);
|
|
}
|
|
if (err == 0) {
|
|
err = mp_to_unsigned_bin_len(r, key->data, dataSz);
|
|
}
|
|
if (err == 0) {
|
|
/* r */
|
|
err = wc_HashUpdate(&key->hash, hashType, key->data, dataSz);
|
|
}
|
|
if (err == 0) {
|
|
/* M */
|
|
err = wc_HashUpdate(&key->hash, hashType, msg, msgSz);
|
|
}
|
|
if (err == 0) {
|
|
err = wc_HashFinal(&key->hash, hashType, he);
|
|
}
|
|
if (err == 0) {
|
|
*heSz = wc_HashGetDigestSize(hashType);
|
|
}
|
|
|
|
if (hash_inited) {
|
|
(void)wc_HashFree(&key->hash, hashType);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Encode the signature = ( r | s | PVT )
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] r MP integer that is the first signature element.
|
|
* @param [in] s MP integer that is the second signature element.
|
|
* @param [in] pvt ECC point representing Public Validation Token.
|
|
* @param [out] sig Signature of message.
|
|
* @param [out] sigSz Length of signature in bytes.
|
|
*/
|
|
static int eccsi_encode_sig(const EccsiKey* key, mp_int* r, mp_int* s,
|
|
byte* sig, word32* sigSz)
|
|
{
|
|
int err;
|
|
word32 sz = key->ecc.dp->size;
|
|
|
|
err = mp_to_unsigned_bin_len(r, sig, sz);
|
|
if (err == 0) {
|
|
err = mp_to_unsigned_bin_len(s, sig + sz, sz);
|
|
}
|
|
if (err == 0) {
|
|
*sigSz = key->ecc.dp->size * 2 + 1;
|
|
err = wc_ecc_export_point_der(wc_ecc_get_curve_idx(key->ecc.dp->id),
|
|
key->pvt, sig + sz * 2, sigSz);
|
|
}
|
|
if (err == 0) {
|
|
*sigSz = sz * 4 + 1;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Sign the ECCSI hash (of ID with the key) to two mp_int objects: r and s.
|
|
*
|
|
* RFC 6507, Section 5.2.1, Steps 1 to 4
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] rng Random number generator.
|
|
* @param [in] hashType Type of hash algorithm. e.g. WC_SHA256
|
|
* @param [in] msg Message to sign.
|
|
* @param [in] msgSz Length of message in bytes.
|
|
* @param [out] r First big number integer part of signature.
|
|
* @param [out] s Second big number integer part of signature.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
static int eccsi_gen_sig(EccsiKey* key, WC_RNG* rng, enum wc_HashType hashType,
|
|
const byte* msg, word32 msgSz, mp_int* r, mp_int* s)
|
|
{
|
|
int err = 0;
|
|
word32 sz = key->ecc.dp->size;
|
|
word32 heSz = 0;
|
|
const mp_int* jx = NULL;
|
|
mp_int* he = &key->tmp;
|
|
int genTryCnt = 0;
|
|
|
|
do {
|
|
/* Don't infinitely gen sigs when random number generator fails. */
|
|
if ((++genTryCnt) > ECCSI_MAX_GEN_COUNT) {
|
|
err = RNG_FAILURE_E;
|
|
}
|
|
|
|
if (err == 0) {
|
|
wc_ecc_free(&key->pubkey);
|
|
|
|
/* Step 1 and 2: Generate ephemeral key - j, J = [j]G, r = Jx */
|
|
err = wc_ecc_make_key_ex(rng, sz, &key->pubkey, key->ecc.dp->id);
|
|
}
|
|
if (err == 0) {
|
|
jx = key->pubkey.pubkey.x;
|
|
err = eccsi_fit_to_octets(jx, &key->params.order, sz, r);
|
|
}
|
|
|
|
/* Step 3: Compute HE = hash( HS | r | M ) */
|
|
if (err == 0) {
|
|
err = eccsi_compute_he(key, hashType, r, msg, msgSz, key->data,
|
|
&heSz);
|
|
}
|
|
|
|
/* Step 4: Verify that HE + r * SSK is non-zero modulo q */
|
|
if (err == 0) {
|
|
err = mp_read_unsigned_bin(he, key->data, heSz);
|
|
}
|
|
/* s' = r * SSK */
|
|
if (err == 0) {
|
|
err = mp_mulmod(r, &key->ssk, &key->params.order, s);
|
|
}
|
|
/* s' = HE + r * SSK */
|
|
if (err == 0) {
|
|
err = mp_addmod(he, s, &key->params.order, s);
|
|
}
|
|
}
|
|
while ((err == 0) && (mp_iszero(s) || (mp_cmp(s, he) == MP_EQ)));
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
/**
|
|
* Sign the ECCSI hash (of ID with the key).
|
|
*
|
|
* RFC 6507, Section 5.2.1
|
|
*
|
|
* Must have imported KPAK using wc_ImportEccsiPublicKey() before calling.\n
|
|
* Use wc_HashEccsiId() to calculate the hash and wc_SetEccsiHash() to set
|
|
* the identity hash to use.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] rng Random number generator.
|
|
* @param [in] hashType Type of hash algorithm. e.g. WC_SHA256
|
|
* @param [in] msg Message to sign.
|
|
* @param [in] msgSz Length of message in bytes.
|
|
* @param [out] sig Signature of message.
|
|
* @param [out] sigSz Length of signature in bytes.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key, rng, msg or sigSz is NULL.
|
|
* @return BAD_STATE_E when the curve or id hash has not been set (no key set).
|
|
* @return LENGTH_ONLY_E when sig is NULL - sigSz is set.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
int wc_SignEccsiHash(EccsiKey* key, WC_RNG* rng, enum wc_HashType hashType,
|
|
const byte* msg, word32 msgSz, byte* sig, word32* sigSz)
|
|
{
|
|
int err = 0;
|
|
mp_int* r = NULL;
|
|
mp_int* s = NULL;
|
|
mp_int* j = NULL;
|
|
word32 sz = 0;
|
|
|
|
if ((key == NULL) || (rng == NULL) || (msg == NULL) || (sigSz == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
if ((err == 0) && (key->ecc.type != ECC_PUBLICKEY) &&
|
|
(key->ecc.type != ECC_PRIVATEKEY)) {
|
|
err = BAD_STATE_E;
|
|
}
|
|
if ((err == 0) && (sig != NULL) && (key->idHashSz == 0)) {
|
|
err = BAD_STATE_E;
|
|
}
|
|
|
|
if (err == 0) {
|
|
sz = key->ecc.dp->size;
|
|
if (sig == NULL) {
|
|
*sigSz = sz * 4 + 1;
|
|
err = LENGTH_ONLY_E;
|
|
}
|
|
}
|
|
if ((err == 0) && (*sigSz < sz * 4 + 1)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (err == 0) {
|
|
r = key->pubkey.pubkey.y;
|
|
s = key->pubkey.pubkey.z;
|
|
|
|
err = eccsi_load_order(key);
|
|
}
|
|
|
|
if (err == 0) {
|
|
/* Steps 1 to 4. */
|
|
err = eccsi_gen_sig(key, rng, hashType, msg, msgSz, r, s);
|
|
}
|
|
|
|
/* Step 5: s' = ( (( HE + r * SSK )^-1) * j ) modulo q, erase j */
|
|
if (err == 0) {
|
|
err = mp_invmod(s, &key->params.order, s);
|
|
}
|
|
if (err == 0) {
|
|
j = &key->pubkey.k;
|
|
err = mp_mulmod(s, j, &key->params.order, s);
|
|
}
|
|
if (err == 0) {
|
|
mp_forcezero(j);
|
|
|
|
/* Step 6: s = s' fitted */
|
|
err = eccsi_fit_to_octets(s, &key->params.order, sz, s);
|
|
}
|
|
|
|
/* Step 7: Output Signature = ( r | s | PVT ) */
|
|
if (err == 0) {
|
|
err = eccsi_encode_sig(key, r, s, sig, sigSz);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Decode the s part of the signature = ( r | s | PVT )
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] sig Signature of message.
|
|
* @param [in] sigSz Length of signature in bytes.
|
|
* @param [out] s MP integer that is the second signature element.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
static int eccsi_decode_sig_s(const EccsiKey* key, const byte* sig,
|
|
word32 sigSz, mp_int* s)
|
|
{
|
|
int err = 0;
|
|
word32 sz = key->ecc.dp->size;
|
|
|
|
if (sigSz != sz * 4 + 1) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (err == 0) {
|
|
err = mp_read_unsigned_bin(s, sig + sz, sz);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Decode the r and pvt part of the signature = ( r | s | PVT )
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] sig Signature of message.
|
|
* @param [in] sigSz Length of signature in bytes.
|
|
* @param [out] r MP integer that is the first signature element.
|
|
* @param [out] pvt ECC point representing Public Validation Token.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other -ve value when an internal operation fails.
|
|
*/
|
|
static int eccsi_decode_sig_r_pvt(const EccsiKey* key, const byte* sig,
|
|
word32 sigSz, mp_int* r, ecc_point* pvt)
|
|
{
|
|
int err = 0;
|
|
word32 sz = key->ecc.dp->size;
|
|
|
|
if (sigSz != sz * 4 + 1) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (err == 0) {
|
|
err = mp_read_unsigned_bin(r, sig, sz);
|
|
}
|
|
if (err == 0) {
|
|
/* must free previous public point otherwise wc_ecc_import_point_der
|
|
* could leak memory */
|
|
mp_clear(pvt->x);
|
|
mp_clear(pvt->y);
|
|
mp_clear(pvt->z);
|
|
|
|
err = wc_ecc_import_point_der(sig + sz * 2, sz * 2 + 1,
|
|
wc_ecc_get_curve_idx(key->ecc.dp->id), pvt);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Calculate Y point as part of verification process.
|
|
*
|
|
* Y = [HS]PVT + KPAK
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] pvt ECC point representing Public Validation Token.
|
|
* @param [in] mp Montgomery reduction multiplier.
|
|
* @param [out] y ECC point representing calculated value Y.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other value when an an internal operation fails.
|
|
*/
|
|
static int eccsi_calc_y(EccsiKey* key, ecc_point* pvt, mp_digit mp,
|
|
ecc_point* y)
|
|
{
|
|
int err;
|
|
mp_int* hs = &key->ssk;
|
|
|
|
err = mp_read_unsigned_bin(hs, key->idHash, key->idHashSz);
|
|
#ifndef WOLFSSL_HAVE_SP_ECC
|
|
/* Need KPAK in montgomery form. */
|
|
if (err == 0) {
|
|
err = eccsi_kpak_to_mont(key);
|
|
}
|
|
#endif
|
|
/* [HS]PVT + KPAK */
|
|
if (err == 0) {
|
|
ecc_point* kpak = &key->ecc.pubkey;
|
|
err = eccsi_mulmod_point_add(key, hs, pvt, kpak, y, mp, 1);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Calculate J point as part of verification process.
|
|
*
|
|
* J = [s]( [HE]G + [r]Y )
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] hem MP int representation of HE = Hash (hs, r and message).
|
|
* @param [in] sig Signature of message.
|
|
* @param [in] sigSz Length of signature in bytes.
|
|
* @param [in] y ECC point representing [r]Y.
|
|
* @param [in] mp Montgomery reduction multiplier.
|
|
* @param [out] j ECC point representing calculated value J.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other value when an an internal operation fails.
|
|
*/
|
|
static int eccsi_calc_j(EccsiKey* key, const mp_int* hem, const byte* sig,
|
|
word32 sigSz, ecc_point* y, mp_digit mp, ecc_point* j)
|
|
{
|
|
int err;
|
|
mp_int* s = &key->tmp;
|
|
|
|
/* [HE]G + [r]Y */
|
|
err = eccsi_mulmod_base_add(key, hem, y, j, mp, 1);
|
|
if (err == 0) {
|
|
err = eccsi_decode_sig_s(key, sig, sigSz, s);
|
|
}
|
|
/* [s]( [HE]G + [r]Y ) */
|
|
if (err == 0) {
|
|
err = eccsi_mulmod_point(key, s, j, j, 1);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Verify the ECCSI hash (of ID with the key).
|
|
*
|
|
* RFC 6507, Section 5.2.2
|
|
*
|
|
* Must have imported KPAK using wc_ImportEccsiPublicKey() before calling.\n
|
|
* Use wc_HashEccsiId() to calculate the hash and wc_SetEccsiHash() to set
|
|
* the identity hash to use.
|
|
*
|
|
* @param [in] key ECCSI key.
|
|
* @param [in] hashType Type of hash algorithm. e.g. WC_SHA256
|
|
* @param [in] msg Message to verify.
|
|
* @param [in] msgSz Length of message in bytes.
|
|
* @param [in] sig Signature of message.
|
|
* @param [in] sigSz Length of signature in bytes.
|
|
* @param [out] verified 1 when the signature was verified and 0 otherwise.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key, hash, msg, sig or ret is NULL.
|
|
* @return BAD_STATE_E when the curve or id hash has not been set (no key set).
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other value when an an internal operation fails.
|
|
*/
|
|
int wc_VerifyEccsiHash(EccsiKey* key, enum wc_HashType hashType,
|
|
const byte* msg, word32 msgSz, const byte* sig, word32 sigSz,
|
|
int* verified)
|
|
{
|
|
int err = 0;
|
|
byte* he = NULL;
|
|
word32 heSz = 0;
|
|
mp_int* r = NULL;
|
|
mp_int* jx = NULL;
|
|
mp_int* hem = NULL;
|
|
ecc_point* pvt = NULL;
|
|
ecc_point* y = NULL;
|
|
ecc_point* j = NULL;
|
|
mp_digit mp = 0;
|
|
EccsiKeyParams* params = NULL;
|
|
|
|
if ((key == NULL) || (msg == NULL) || (sig == NULL) || (verified == NULL)) {
|
|
err = BAD_FUNC_ARG;
|
|
}
|
|
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY) &&
|
|
(key->ecc.type != ECC_PUBLICKEY)) {
|
|
err = BAD_STATE_E;
|
|
}
|
|
if ((err == 0) && (key->idHashSz == 0)) {
|
|
err = BAD_STATE_E;
|
|
}
|
|
|
|
if (err != 0)
|
|
return err;
|
|
|
|
SAVE_VECTOR_REGISTERS(return _svr_ret;);
|
|
|
|
/* Decode the signature into components. */
|
|
r = &key->pubkey.k;
|
|
pvt = &key->pubkey.pubkey;
|
|
err = eccsi_decode_sig_r_pvt(key, sig, sigSz, r, pvt);
|
|
|
|
/* Load the curve parameters for operations */
|
|
if (err == 0) {
|
|
err = eccsi_load_base(key);
|
|
}
|
|
if (err == 0) {
|
|
err = eccsi_load_ecc_params(key);
|
|
}
|
|
if (err == 0) {
|
|
params = &key->params;
|
|
err = mp_montgomery_setup(¶ms->prime, &mp);
|
|
}
|
|
|
|
/* Step 1: Validate PVT is on curve */
|
|
if (err == 0) {
|
|
err = wc_ecc_is_point(pvt, ¶ms->a, ¶ms->b, ¶ms->prime);
|
|
}
|
|
|
|
/* Step 2: Compute HS = hash( G | KPAK | ID | PVT )
|
|
* HS is key->idHash, key->idHashSz */
|
|
|
|
/* Step 3: Compute HE = hash( HS | r | M ) */
|
|
if (err == 0) {
|
|
he = key->data;
|
|
err = eccsi_compute_he(key, hashType, r, msg, msgSz, he, &heSz);
|
|
}
|
|
|
|
/* Step 4: Y = [HS]PVT + KPAK */
|
|
if (err == 0) {
|
|
y = pvt;
|
|
err = eccsi_calc_y(key, pvt, mp, y);
|
|
}
|
|
|
|
/* Step 5: Compute J = [s]( [HE]G + [r]Y ) */
|
|
/* [r]Y */
|
|
if (err == 0) {
|
|
hem = &key->tmp;
|
|
err = mp_read_unsigned_bin(hem, he, heSz);
|
|
}
|
|
if (err == 0) {
|
|
err = eccsi_mulmod_point(key, r, y, y, 0);
|
|
}
|
|
if (err == 0) {
|
|
j = params->base;
|
|
err = eccsi_calc_j(key, hem, sig, sigSz, y, mp, j);
|
|
key->params.haveBase = 0;
|
|
}
|
|
|
|
/* Step 6: Jx fitting, compare with r */
|
|
if (err == 0) {
|
|
jx = &key->tmp;
|
|
err = eccsi_fit_to_octets(j->x, ¶ms->order, key->ecc.dp->size, jx);
|
|
}
|
|
|
|
if (verified != NULL) {
|
|
*verified = ((err == 0) && (mp_cmp(jx, r) == MP_EQ));
|
|
}
|
|
|
|
RESTORE_VECTOR_REGISTERS();
|
|
|
|
return err;
|
|
}
|
|
#endif /* WOLFCRYPT_ECCSI_CLIENT */
|
|
|
|
#endif /* WOLFCRYPT_HAVE_ECCSI */
|
|
|