Files
mars-matrixssl/crypto/pubkey/ecc_pub.c
Janne Johansson 69b5f2c6c3 MatrixSSL 4.5.1
2022-07-29 12:30:12 +03:00

328 lines
8.2 KiB
C

/**
* @file ecc_pub.c
* @version $Format:%h%d$
*
* ECDSA public key operations for Matrix Crypto.
*/
/*
* Copyright (c) 2013-2018 Rambus Inc.
* Copyright (c) PeerSec Networks, 2002-2011
* All Rights Reserved
*
* The latest version of this code is available at http://www.matrixssl.org
*
* This software is open source; 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.
*
* This General Public License does NOT permit incorporating this software
* into proprietary programs. If you are unable to comply with the GPL, a
* commercial license for this software may be purchased from Rambus at
* http://www.rambus.com/
*
* This program is distributed in 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* http://www.gnu.org/copyleft/gpl.html
*/
/******************************************************************************/
#include "../cryptoImpl.h"
#ifdef USE_MATRIX_ECC
/* These internal functions are defined in ecc_math.c */
extern psEccPoint_t *eccNewPoint(psPool_t *pool,
short size);
extern void eccFreePoint(psEccPoint_t *p);
extern int32_t eccMulmod(psPool_t *pool,
const pstm_int *k,
const psEccPoint_t *G,
psEccPoint_t *R,
pstm_int *modulus,
uint8_t map,
pstm_int *tmp_int);
extern int32_t eccProjectiveAddPoint(psPool_t *pool,
const psEccPoint_t *P,
const psEccPoint_t *Q,
psEccPoint_t *R,
const pstm_int *modulus,
const pstm_digit *mp,
pstm_int *tmp_int);
extern int32_t eccMap(psPool_t *pool,
psEccPoint_t *P,
const pstm_int *modulus,
const pstm_digit *mp);
/******************************************************************************/
/**
Verify an ECDSA signature.
@param pool Memory pool
@param[in] key Public key to use for signature validation
@param[in] buf Data that is signed by private 'key'
@param[in] buflen Length in bytes of 'buf'
@param[in] sig Signature of 'buf' by the private key pair of 'key'
@param[in] siglen Length in bytes of 'sig'
@param[out] status Result of the signature check. 1 on success, -1 on
non-matching signature.
@param usrData Data used by some hardware crypto. Can be NULL.
@return < 0 on failure. Also 'status'.
*/
int32_t psEccDsaVerify(psPool_t *pool, const psEccKey_t *key,
const unsigned char *buf, psSize_t buflen,
const unsigned char *sig, psSize_t siglen,
int32_t *status, void *usrData)
{
psEccPoint_t *mG, *mQ;
pstm_digit mp;
pstm_int *A = NULL;
pstm_int v, w, u1, u2, e, p, m, r, s;
const unsigned char *c, *end;
int32_t err, radlen;
psSize_t len;
/* default to invalid signature */
*status = -1;
c = sig;
end = c + siglen;
if ((err = getAsnSequence(&c, (uint16_t) (end - c), &len)) < 0)
{
psTraceCrypto("ECDSA subject signature parse failure 1\n");
return err;
}
if ((err = pstm_read_asn(pool, &c, (uint16_t) (end - c), &r)) < 0)
{
psTraceCrypto("ECDSA subject signature parse failure 2\n");
return err;
}
if ((err = pstm_read_asn(pool, &c, (uint16_t) (end - c), &s)) < 0)
{
psTraceCrypto("ECDSA subject signature parse failure 3\n");
pstm_clear(&r);
return err;
}
/* allocate ints */
radlen = key->curve->size * 2;
if (pstm_init_for_read_unsigned_bin(pool, &p, key->curve->size) < 0)
{
pstm_clear(&s);
pstm_clear(&r);
return PS_MEM_FAIL;
}
err = PS_MEM_FAIL;
if (pstm_init_for_read_unsigned_bin(pool, &m, key->curve->size) < 0)
{
goto LBL_P;
}
if (pstm_init_size(pool, &v, key->pubkey.x.alloc) < 0)
{
goto LBL_M;
}
if (pstm_init_size(pool, &w, s.alloc) < 0)
{
goto LBL_V;
}
/* Shouldn't have signed more data than the key length. Truncate if so */
if (buflen > key->curve->size)
{
buflen = key->curve->size;
}
if (pstm_init_for_read_unsigned_bin(pool, &e, buflen) < 0)
{
goto LBL_W;
}
if (pstm_init_size(pool, &u1, e.alloc + w.alloc) < 0)
{
goto LBL_E;
}
if (pstm_init_size(pool, &u2, r.alloc + w.alloc) < 0)
{
goto LBL_U1;
}
/* allocate points */
if ((mG = eccNewPoint(pool, key->pubkey.x.alloc * 2)) == NULL)
{
goto LBL_U2;
}
if ((mQ = eccNewPoint(pool, key->pubkey.x.alloc * 2)) == NULL)
{
goto LBL_MG;
}
/* get the order */
if ((err = pstm_read_radix(pool, &p, key->curve->order, radlen, 16))
!= PS_SUCCESS)
{
goto error;
}
/* get the modulus */
if ((err = pstm_read_radix(pool, &m, key->curve->prime, radlen, 16))
!= PS_SUCCESS)
{
goto error;
}
/* check for zero */
if (pstm_iszero(&r) || pstm_iszero(&s) || pstm_cmp(&r, &p) != PSTM_LT ||
pstm_cmp(&s, &p) != PSTM_LT)
{
err = PS_PARSE_FAIL;
goto error;
}
/* read data */
if ((err = pstm_read_unsigned_bin(&e, buf, buflen)) != PS_SUCCESS)
{
goto error;
}
/* w = s^-1 mod n */
if ((err = pstm_invmod(pool, &s, &p, &w)) != PS_SUCCESS)
{
goto error;
}
/* u1 = ew */
if ((err = pstm_mulmod(pool, &e, &w, &p, &u1)) != PS_SUCCESS)
{
goto error;
}
/* u2 = rw */
if ((err = pstm_mulmod(pool, &r, &w, &p, &u2)) != PS_SUCCESS)
{
goto error;
}
/* find mG and mQ */
if ((err = pstm_read_radix(pool, &mG->x, key->curve->Gx, radlen, 16))
!= PS_SUCCESS)
{
goto error;
}
if ((err = pstm_read_radix(pool, &mG->y, key->curve->Gy, radlen, 16))
!= PS_SUCCESS)
{
goto error;
}
pstm_set(&mG->z, 1);
if ((err = pstm_copy(&key->pubkey.x, &mQ->x)) != PS_SUCCESS)
{
goto error;
}
if ((err = pstm_copy(&key->pubkey.y, &mQ->y)) != PS_SUCCESS)
{
goto error;
}
if ((err = pstm_copy(&key->pubkey.z, &mQ->z)) != PS_SUCCESS)
{
goto error;
}
if (key->curve->isOptimized == 0)
{
if ((A = psMalloc(pool, sizeof(pstm_int))) == NULL)
{
goto error;
}
if (pstm_init_for_read_unsigned_bin(pool, A, key->curve->size) < 0)
{
goto error;
}
if ((err = pstm_read_radix(pool, A, key->curve->A,
key->curve->size * 2, 16))
!= PS_SUCCESS)
{
goto error;
}
}
/* compute u1*mG + u2*mQ = mG */
if ((err = eccMulmod(pool, &u1, mG, mG, &m, 0, A)) != PS_SUCCESS)
{
goto error;
}
if ((err = eccMulmod(pool, &u2, mQ, mQ, &m, 0, A)) != PS_SUCCESS)
{
goto error;
}
/* find the montgomery mp */
if ((err = pstm_montgomery_setup(&m, &mp)) != PS_SUCCESS)
{
goto error;
}
/* add them */
if ((err = eccProjectiveAddPoint(pool, mQ, mG, mG, &m, &mp, A)) != PS_SUCCESS)
{
goto error;
}
/* reduce */
if ((err = eccMap(pool, mG, &m, &mp)) != PS_SUCCESS)
{
goto error;
}
/* v = X_x1 mod n */
if ((err = pstm_mod(pool, &mG->x, &p, &v)) != PS_SUCCESS)
{
goto error;
}
/* does v == r */
if (pstm_cmp(&v, &r) == PSTM_EQ)
{
*status = 1;
}
/* clear up and return */
err = PS_SUCCESS;
error:
if (A)
{
pstm_clear(A);
psFree(A, pool);
}
eccFreePoint(mQ);
LBL_MG:
eccFreePoint(mG);
LBL_U2:
pstm_clear(&u2);
LBL_U1:
pstm_clear(&u1);
LBL_E:
pstm_clear(&e);
LBL_W:
pstm_clear(&w);
LBL_V:
pstm_clear(&v);
LBL_M:
pstm_clear(&m);
LBL_P:
pstm_clear(&p);
pstm_clear(&s);
pstm_clear(&r);
return err;
}
#endif /* USE_MATRIX_ECC */