Bugzilla Bug 318968: added FIPS ECDSA algorithm test. r=glen.beasley.
Modified file: fipstest.c Added file: ecdsa.sh git-svn-id: svn://10.0.0.236/trunk@186457 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
439ca8b797
commit
1626f81291
29
mozilla/security/nss/cmd/fipstest/ecdsa.sh
Normal file
29
mozilla/security/nss/cmd/fipstest/ecdsa.sh
Normal file
@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# A Bourne shell script for running the NIST ECDSA Validation System
|
||||
#
|
||||
# Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment
|
||||
# variables appropriately so that the fipstest command and the NSPR and NSS
|
||||
# shared libraries/DLLs are on the search path. Then run this script in the
|
||||
# directory where the REQUEST (.req) files reside. The script generates the
|
||||
# RESPONSE (.rsp) files in the same directory.
|
||||
|
||||
request=KeyPair.req
|
||||
response=`echo $request | sed -e "s/req/rsp/"`
|
||||
echo $request $response
|
||||
fipstest ecdsa keypair $request > $response
|
||||
|
||||
request=PKV.req
|
||||
response=`echo $request | sed -e "s/req/rsp/"`
|
||||
echo $request $response
|
||||
fipstest ecdsa pkv $request > $response
|
||||
|
||||
request=SigGen.req
|
||||
response=`echo $request | sed -e "s/req/rsp/"`
|
||||
echo $request $response
|
||||
fipstest ecdsa siggen $request > $response
|
||||
|
||||
request=SigVer.req
|
||||
response=`echo $request | sed -e "s/req/rsp/"`
|
||||
echo $request $response
|
||||
fipstest ecdsa sigver $request > $response
|
||||
@ -41,16 +41,23 @@
|
||||
#include "secitem.h"
|
||||
#include "blapi.h"
|
||||
#include "nss.h"
|
||||
#include "secerr.h"
|
||||
#include "secoidt.h"
|
||||
#include "keythi.h"
|
||||
#include "ec.h"
|
||||
#if 0
|
||||
#include "../../lib/freebl/mpi/mpi.h"
|
||||
#endif
|
||||
|
||||
extern SECStatus
|
||||
EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams);
|
||||
|
||||
#define ENCRYPT 1
|
||||
#define DECRYPT 0
|
||||
#define BYTE unsigned char
|
||||
|
||||
SECStatus
|
||||
hex_from_2char(unsigned char *c2, unsigned char *byteval)
|
||||
hex_from_2char(const unsigned char *c2, unsigned char *byteval)
|
||||
{
|
||||
int i;
|
||||
unsigned char offset;
|
||||
@ -99,12 +106,67 @@ to_hex_str(char *str, const unsigned char *buf, unsigned int len)
|
||||
}
|
||||
|
||||
void
|
||||
to_hex_str_cap(char *str, unsigned char *buf, unsigned int len)
|
||||
to_hex_str_cap(char *str, const unsigned char *buf, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i=0; i<len; i++) {
|
||||
char2_from_hex(buf[i], &str[2*i], 'A');
|
||||
}
|
||||
str[2*len] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a string of hex digits (str) to an array (buf) of len bytes.
|
||||
* Return PR_TRUE if the hex string can fit in the byte array. Return
|
||||
* PR_FALSE if the hex string is empty or is too long.
|
||||
*/
|
||||
PRBool
|
||||
from_hex_str(unsigned char *buf, unsigned int len, const char *str)
|
||||
{
|
||||
unsigned int nxdigit; /* number of hex digits in str */
|
||||
unsigned int i; /* index into buf */
|
||||
unsigned int j; /* index into str */
|
||||
|
||||
/* count the hex digits */
|
||||
nxdigit = 0;
|
||||
for (nxdigit = 0; isxdigit(str[nxdigit]); nxdigit++) {
|
||||
/* empty body */
|
||||
}
|
||||
if (nxdigit == 0) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (nxdigit > 2*len) {
|
||||
/*
|
||||
* The input hex string is too long, but we allow it if the
|
||||
* extra digits are leading 0's.
|
||||
*/
|
||||
for (j = 0; j < nxdigit-2*len; j++) {
|
||||
if (str[j] != '0') {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
/* skip leading 0's */
|
||||
str += nxdigit-2*len;
|
||||
nxdigit = 2*len;
|
||||
}
|
||||
for (i=0, j=0; i< len; i++) {
|
||||
if (2*i < 2*len-nxdigit) {
|
||||
/* Handle a short input as if we padded it with leading 0's. */
|
||||
if (2*i+1 < 2*len-nxdigit) {
|
||||
buf[i] = 0;
|
||||
} else {
|
||||
char tmp[2];
|
||||
tmp[0] = '0';
|
||||
tmp[1] = str[j];
|
||||
hex_from_2char(tmp, &buf[i]);
|
||||
j++;
|
||||
}
|
||||
} else {
|
||||
hex_from_2char(&str[j], &buf[i]);
|
||||
j += 2;
|
||||
}
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
@ -2163,6 +2225,684 @@ do_sigver:
|
||||
fclose(rsp);
|
||||
}
|
||||
|
||||
typedef struct curveNameTagPairStr {
|
||||
char *curveName;
|
||||
SECOidTag curveOidTag;
|
||||
} CurveNameTagPair;
|
||||
|
||||
#define DEFAULT_CURVE_OID_TAG SEC_OID_SECG_EC_SECP192R1
|
||||
/* #define DEFAULT_CURVE_OID_TAG SEC_OID_SECG_EC_SECP160R1 */
|
||||
|
||||
static CurveNameTagPair nameTagPair[] =
|
||||
{
|
||||
{ "sect163k1", SEC_OID_SECG_EC_SECT163K1},
|
||||
{ "nistk163", SEC_OID_SECG_EC_SECT163K1},
|
||||
{ "sect163r1", SEC_OID_SECG_EC_SECT163R1},
|
||||
{ "sect163r2", SEC_OID_SECG_EC_SECT163R2},
|
||||
{ "nistb163", SEC_OID_SECG_EC_SECT163R2},
|
||||
{ "sect193r1", SEC_OID_SECG_EC_SECT193R1},
|
||||
{ "sect193r2", SEC_OID_SECG_EC_SECT193R2},
|
||||
{ "sect233k1", SEC_OID_SECG_EC_SECT233K1},
|
||||
{ "nistk233", SEC_OID_SECG_EC_SECT233K1},
|
||||
{ "sect233r1", SEC_OID_SECG_EC_SECT233R1},
|
||||
{ "nistb233", SEC_OID_SECG_EC_SECT233R1},
|
||||
{ "sect239k1", SEC_OID_SECG_EC_SECT239K1},
|
||||
{ "sect283k1", SEC_OID_SECG_EC_SECT283K1},
|
||||
{ "nistk283", SEC_OID_SECG_EC_SECT283K1},
|
||||
{ "sect283r1", SEC_OID_SECG_EC_SECT283R1},
|
||||
{ "nistb283", SEC_OID_SECG_EC_SECT283R1},
|
||||
{ "sect409k1", SEC_OID_SECG_EC_SECT409K1},
|
||||
{ "nistk409", SEC_OID_SECG_EC_SECT409K1},
|
||||
{ "sect409r1", SEC_OID_SECG_EC_SECT409R1},
|
||||
{ "nistb409", SEC_OID_SECG_EC_SECT409R1},
|
||||
{ "sect571k1", SEC_OID_SECG_EC_SECT571K1},
|
||||
{ "nistk571", SEC_OID_SECG_EC_SECT571K1},
|
||||
{ "sect571r1", SEC_OID_SECG_EC_SECT571R1},
|
||||
{ "nistb571", SEC_OID_SECG_EC_SECT571R1},
|
||||
{ "secp160k1", SEC_OID_SECG_EC_SECP160K1},
|
||||
{ "secp160r1", SEC_OID_SECG_EC_SECP160R1},
|
||||
{ "secp160r2", SEC_OID_SECG_EC_SECP160R2},
|
||||
{ "secp192k1", SEC_OID_SECG_EC_SECP192K1},
|
||||
{ "secp192r1", SEC_OID_SECG_EC_SECP192R1},
|
||||
{ "nistp192", SEC_OID_SECG_EC_SECP192R1},
|
||||
{ "secp224k1", SEC_OID_SECG_EC_SECP224K1},
|
||||
{ "secp224r1", SEC_OID_SECG_EC_SECP224R1},
|
||||
{ "nistp224", SEC_OID_SECG_EC_SECP224R1},
|
||||
{ "secp256k1", SEC_OID_SECG_EC_SECP256K1},
|
||||
{ "secp256r1", SEC_OID_SECG_EC_SECP256R1},
|
||||
{ "nistp256", SEC_OID_SECG_EC_SECP256R1},
|
||||
{ "secp384r1", SEC_OID_SECG_EC_SECP384R1},
|
||||
{ "nistp384", SEC_OID_SECG_EC_SECP384R1},
|
||||
{ "secp521r1", SEC_OID_SECG_EC_SECP521R1},
|
||||
{ "nistp521", SEC_OID_SECG_EC_SECP521R1},
|
||||
|
||||
{ "prime192v1", SEC_OID_ANSIX962_EC_PRIME192V1 },
|
||||
{ "prime192v2", SEC_OID_ANSIX962_EC_PRIME192V2 },
|
||||
{ "prime192v3", SEC_OID_ANSIX962_EC_PRIME192V3 },
|
||||
{ "prime239v1", SEC_OID_ANSIX962_EC_PRIME239V1 },
|
||||
{ "prime239v2", SEC_OID_ANSIX962_EC_PRIME239V2 },
|
||||
{ "prime239v3", SEC_OID_ANSIX962_EC_PRIME239V3 },
|
||||
|
||||
{ "c2pnb163v1", SEC_OID_ANSIX962_EC_C2PNB163V1 },
|
||||
{ "c2pnb163v2", SEC_OID_ANSIX962_EC_C2PNB163V2 },
|
||||
{ "c2pnb163v3", SEC_OID_ANSIX962_EC_C2PNB163V3 },
|
||||
{ "c2pnb176v1", SEC_OID_ANSIX962_EC_C2PNB176V1 },
|
||||
{ "c2tnb191v1", SEC_OID_ANSIX962_EC_C2TNB191V1 },
|
||||
{ "c2tnb191v2", SEC_OID_ANSIX962_EC_C2TNB191V2 },
|
||||
{ "c2tnb191v3", SEC_OID_ANSIX962_EC_C2TNB191V3 },
|
||||
{ "c2onb191v4", SEC_OID_ANSIX962_EC_C2ONB191V4 },
|
||||
{ "c2onb191v5", SEC_OID_ANSIX962_EC_C2ONB191V5 },
|
||||
{ "c2pnb208w1", SEC_OID_ANSIX962_EC_C2PNB208W1 },
|
||||
{ "c2tnb239v1", SEC_OID_ANSIX962_EC_C2TNB239V1 },
|
||||
{ "c2tnb239v2", SEC_OID_ANSIX962_EC_C2TNB239V2 },
|
||||
{ "c2tnb239v3", SEC_OID_ANSIX962_EC_C2TNB239V3 },
|
||||
{ "c2onb239v4", SEC_OID_ANSIX962_EC_C2ONB239V4 },
|
||||
{ "c2onb239v5", SEC_OID_ANSIX962_EC_C2ONB239V5 },
|
||||
{ "c2pnb272w1", SEC_OID_ANSIX962_EC_C2PNB272W1 },
|
||||
{ "c2pnb304w1", SEC_OID_ANSIX962_EC_C2PNB304W1 },
|
||||
{ "c2tnb359v1", SEC_OID_ANSIX962_EC_C2TNB359V1 },
|
||||
{ "c2pnb368w1", SEC_OID_ANSIX962_EC_C2PNB368W1 },
|
||||
{ "c2tnb431r1", SEC_OID_ANSIX962_EC_C2TNB431R1 },
|
||||
|
||||
{ "secp112r1", SEC_OID_SECG_EC_SECP112R1},
|
||||
{ "secp112r2", SEC_OID_SECG_EC_SECP112R2},
|
||||
{ "secp128r1", SEC_OID_SECG_EC_SECP128R1},
|
||||
{ "secp128r2", SEC_OID_SECG_EC_SECP128R2},
|
||||
|
||||
{ "sect113r1", SEC_OID_SECG_EC_SECT113R1},
|
||||
{ "sect113r2", SEC_OID_SECG_EC_SECT113R2},
|
||||
{ "sect131r1", SEC_OID_SECG_EC_SECT131R1},
|
||||
{ "sect131r2", SEC_OID_SECG_EC_SECT131R2},
|
||||
};
|
||||
|
||||
static SECKEYECParams *
|
||||
getECParams(const char *curve)
|
||||
{
|
||||
SECKEYECParams *ecparams;
|
||||
SECOidData *oidData = NULL;
|
||||
SECOidTag curveOidTag = SEC_OID_UNKNOWN; /* default */
|
||||
int i, numCurves;
|
||||
|
||||
if (curve != NULL) {
|
||||
numCurves = sizeof(nameTagPair)/sizeof(CurveNameTagPair);
|
||||
for (i = 0; ((i < numCurves) && (curveOidTag == SEC_OID_UNKNOWN));
|
||||
i++) {
|
||||
if (PL_strcmp(curve, nameTagPair[i].curveName) == 0)
|
||||
curveOidTag = nameTagPair[i].curveOidTag;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return NULL if curve name is not recognized */
|
||||
if ((curveOidTag == SEC_OID_UNKNOWN) ||
|
||||
(oidData = SECOID_FindOIDByTag(curveOidTag)) == NULL) {
|
||||
fprintf(stderr, "Unrecognized elliptic curve %s\n", curve);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ecparams = SECITEM_AllocItem(NULL, NULL, (2 + oidData->oid.len));
|
||||
|
||||
/*
|
||||
* ecparams->data needs to contain the ASN encoding of an object ID (OID)
|
||||
* representing the named curve. The actual OID is in
|
||||
* oidData->oid.data so we simply prepend 0x06 and OID length
|
||||
*/
|
||||
ecparams->data[0] = SEC_ASN1_OBJECT_ID;
|
||||
ecparams->data[1] = oidData->oid.len;
|
||||
memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len);
|
||||
|
||||
return ecparams;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the ECDSA Key Pair Generation Test.
|
||||
*
|
||||
* reqfn is the pathname of the REQUEST file.
|
||||
*
|
||||
* The output RESPONSE file is written to stdout.
|
||||
*/
|
||||
void
|
||||
ecdsa_keypair_test(char *reqfn)
|
||||
{
|
||||
char buf[256]; /* holds one line from the input REQUEST file
|
||||
* or to the output RESPONSE file.
|
||||
* needs to be large enough to hold the longest
|
||||
* line "Qx = <144 hex digits>\n".
|
||||
*/
|
||||
FILE *ecdsareq; /* input stream from the REQUEST file */
|
||||
FILE *ecdsaresp; /* output stream to the RESPONSE file */
|
||||
char curve[16]; /* "nistxddd" */
|
||||
ECParams *ecparams;
|
||||
int N;
|
||||
int i;
|
||||
unsigned int len;
|
||||
|
||||
ecdsareq = fopen(reqfn, "r");
|
||||
ecdsaresp = stdout;
|
||||
strcpy(curve, "nist");
|
||||
while (fgets(buf, sizeof buf, ecdsareq) != NULL) {
|
||||
/* a comment or blank line */
|
||||
if (buf[0] == '#' || buf[0] == '\n') {
|
||||
fputs(buf, ecdsaresp);
|
||||
continue;
|
||||
}
|
||||
/* [X-ddd] */
|
||||
if (buf[0] == '[') {
|
||||
const char *src;
|
||||
char *dst;
|
||||
SECKEYECParams *encodedparams;
|
||||
|
||||
src = &buf[1];
|
||||
dst = &curve[4];
|
||||
*dst++ = tolower(*src);
|
||||
src += 2; /* skip the hyphen */
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst = '\0';
|
||||
encodedparams = getECParams(curve);
|
||||
if (encodedparams == NULL) {
|
||||
goto loser;
|
||||
}
|
||||
if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
SECITEM_FreeItem(encodedparams, PR_TRUE);
|
||||
fputs(buf, ecdsaresp);
|
||||
continue;
|
||||
}
|
||||
/* N = x */
|
||||
if (buf[0] == 'N') {
|
||||
if (sscanf(buf, "N = %d", &N) != 1) {
|
||||
goto loser;
|
||||
}
|
||||
for (i = 0; i < N; i++) {
|
||||
ECPrivateKey *ecpriv;
|
||||
|
||||
if (EC_NewKey(ecparams, &ecpriv) != SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
fputs("d = ", ecdsaresp);
|
||||
to_hex_str(buf, ecpriv->privateValue.data,
|
||||
ecpriv->privateValue.len);
|
||||
fputs(buf, ecdsaresp);
|
||||
fputc('\n', ecdsaresp);
|
||||
if (EC_ValidatePublicKey(ecparams, &ecpriv->publicValue)
|
||||
!= SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
len = ecpriv->publicValue.len;
|
||||
if (len%2 == 0) {
|
||||
goto loser;
|
||||
}
|
||||
len = (len-1)/2;
|
||||
if (ecpriv->publicValue.data[0]
|
||||
!= EC_POINT_FORM_UNCOMPRESSED) {
|
||||
goto loser;
|
||||
}
|
||||
fputs("Qx = ", ecdsaresp);
|
||||
to_hex_str(buf, &ecpriv->publicValue.data[1], len);
|
||||
fputs(buf, ecdsaresp);
|
||||
fputc('\n', ecdsaresp);
|
||||
fputs("Qy = ", ecdsaresp);
|
||||
to_hex_str(buf, &ecpriv->publicValue.data[1+len], len);
|
||||
fputs(buf, ecdsaresp);
|
||||
fputc('\n', ecdsaresp);
|
||||
fputc('\n', ecdsaresp);
|
||||
PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE);
|
||||
}
|
||||
PORT_FreeArena(ecparams->arena, PR_TRUE);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
loser:
|
||||
fclose(ecdsareq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the ECDSA Public Key Validation Test.
|
||||
*
|
||||
* reqfn is the pathname of the REQUEST file.
|
||||
*
|
||||
* The output RESPONSE file is written to stdout.
|
||||
*/
|
||||
void
|
||||
ecdsa_pkv_test(char *reqfn)
|
||||
{
|
||||
char buf[256]; /* holds one line from the input REQUEST file.
|
||||
* needs to be large enough to hold the longest
|
||||
* line "Qx = <144 hex digits>\n".
|
||||
*/
|
||||
FILE *ecdsareq; /* input stream from the REQUEST file */
|
||||
FILE *ecdsaresp; /* output stream to the RESPONSE file */
|
||||
char curve[16]; /* "nistxddd" */
|
||||
ECParams *ecparams = NULL;
|
||||
SECItem pubkey;
|
||||
unsigned int i;
|
||||
unsigned int len;
|
||||
PRBool keyvalid = PR_TRUE;
|
||||
|
||||
ecdsareq = fopen(reqfn, "r");
|
||||
ecdsaresp = stdout;
|
||||
strcpy(curve, "nist");
|
||||
pubkey.data = NULL;
|
||||
while (fgets(buf, sizeof buf, ecdsareq) != NULL) {
|
||||
/* a comment or blank line */
|
||||
if (buf[0] == '#' || buf[0] == '\n') {
|
||||
fputs(buf, ecdsaresp);
|
||||
continue;
|
||||
}
|
||||
/* [X-ddd] */
|
||||
if (buf[0] == '[') {
|
||||
const char *src;
|
||||
char *dst;
|
||||
SECKEYECParams *encodedparams;
|
||||
|
||||
src = &buf[1];
|
||||
dst = &curve[4];
|
||||
*dst++ = tolower(*src);
|
||||
src += 2; /* skip the hyphen */
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst = '\0';
|
||||
if (ecparams != NULL) {
|
||||
PORT_FreeArena(ecparams->arena, PR_TRUE);
|
||||
ecparams = NULL;
|
||||
}
|
||||
encodedparams = getECParams(curve);
|
||||
if (encodedparams == NULL) {
|
||||
goto loser;
|
||||
}
|
||||
if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
SECITEM_FreeItem(encodedparams, PR_TRUE);
|
||||
len = (ecparams->fieldID.size + 7) >> 3;
|
||||
if (pubkey.data != NULL) {
|
||||
PORT_Free(pubkey.data);
|
||||
pubkey.data = NULL;
|
||||
}
|
||||
SECITEM_AllocItem(NULL, &pubkey, 2*len+1);
|
||||
if (pubkey.data == NULL) {
|
||||
goto loser;
|
||||
}
|
||||
pubkey.data[0] = EC_POINT_FORM_UNCOMPRESSED;
|
||||
fputs(buf, ecdsaresp);
|
||||
continue;
|
||||
}
|
||||
/* Qx = ... */
|
||||
if (strncmp(buf, "Qx", 2) == 0) {
|
||||
fputs(buf, ecdsaresp);
|
||||
i = 2;
|
||||
while (isspace(buf[i]) || buf[i] == '=') {
|
||||
i++;
|
||||
}
|
||||
keyvalid = from_hex_str(&pubkey.data[1], len, &buf[i]);
|
||||
continue;
|
||||
}
|
||||
/* Qy = ... */
|
||||
if (strncmp(buf, "Qy", 2) == 0) {
|
||||
fputs(buf, ecdsaresp);
|
||||
if (!keyvalid) {
|
||||
fputs("Result = F\n", ecdsaresp);
|
||||
continue;
|
||||
}
|
||||
i = 2;
|
||||
while (isspace(buf[i]) || buf[i] == '=') {
|
||||
i++;
|
||||
}
|
||||
keyvalid = from_hex_str(&pubkey.data[1+len], len, &buf[i]);
|
||||
if (!keyvalid) {
|
||||
fputs("Result = F\n", ecdsaresp);
|
||||
continue;
|
||||
}
|
||||
if (EC_ValidatePublicKey(ecparams, &pubkey) == SECSuccess) {
|
||||
fputs("Result = P\n", ecdsaresp);
|
||||
} else if (PORT_GetError() == SEC_ERROR_BAD_KEY) {
|
||||
fputs("Result = F\n", ecdsaresp);
|
||||
} else {
|
||||
goto loser;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
loser:
|
||||
if (ecparams != NULL) {
|
||||
PORT_FreeArena(ecparams->arena, PR_TRUE);
|
||||
}
|
||||
if (pubkey.data != NULL) {
|
||||
PORT_Free(pubkey.data);
|
||||
}
|
||||
fclose(ecdsareq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the ECDSA Signature Generation Test.
|
||||
*
|
||||
* reqfn is the pathname of the REQUEST file.
|
||||
*
|
||||
* The output RESPONSE file is written to stdout.
|
||||
*/
|
||||
void
|
||||
ecdsa_siggen_test(char *reqfn)
|
||||
{
|
||||
char buf[1024]; /* holds one line from the input REQUEST file
|
||||
* or to the output RESPONSE file.
|
||||
* needs to be large enough to hold the longest
|
||||
* line "Msg = <256 hex digits>\n".
|
||||
*/
|
||||
FILE *ecdsareq; /* input stream from the REQUEST file */
|
||||
FILE *ecdsaresp; /* output stream to the RESPONSE file */
|
||||
char curve[16]; /* "nistxddd" */
|
||||
ECParams *ecparams = NULL;
|
||||
int i, j;
|
||||
unsigned int len;
|
||||
unsigned char msg[512]; /* message to be signed (<= 128 bytes) */
|
||||
unsigned int msglen;
|
||||
unsigned char sha1[20]; /* SHA-1 hash (160 bits) */
|
||||
unsigned char sig[2*MAX_ECKEY_LEN];
|
||||
SECItem signature, digest;
|
||||
|
||||
ecdsareq = fopen(reqfn, "r");
|
||||
ecdsaresp = stdout;
|
||||
strcpy(curve, "nist");
|
||||
while (fgets(buf, sizeof buf, ecdsareq) != NULL) {
|
||||
/* a comment or blank line */
|
||||
if (buf[0] == '#' || buf[0] == '\n') {
|
||||
fputs(buf, ecdsaresp);
|
||||
continue;
|
||||
}
|
||||
/* [X-ddd] */
|
||||
if (buf[0] == '[') {
|
||||
const char *src;
|
||||
char *dst;
|
||||
SECKEYECParams *encodedparams;
|
||||
|
||||
src = &buf[1];
|
||||
dst = &curve[4];
|
||||
*dst++ = tolower(*src);
|
||||
src += 2; /* skip the hyphen */
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst = '\0';
|
||||
if (ecparams != NULL) {
|
||||
PORT_FreeArena(ecparams->arena, PR_TRUE);
|
||||
ecparams = NULL;
|
||||
}
|
||||
encodedparams = getECParams(curve);
|
||||
if (encodedparams == NULL) {
|
||||
goto loser;
|
||||
}
|
||||
if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
SECITEM_FreeItem(encodedparams, PR_TRUE);
|
||||
fputs(buf, ecdsaresp);
|
||||
continue;
|
||||
}
|
||||
/* Msg = ... */
|
||||
if (strncmp(buf, "Msg", 3) == 0) {
|
||||
ECPrivateKey *ecpriv;
|
||||
|
||||
i = 3;
|
||||
while (isspace(buf[i]) || buf[i] == '=') {
|
||||
i++;
|
||||
}
|
||||
for (j=0; isxdigit(buf[i]); i+=2,j++) {
|
||||
hex_from_2char(&buf[i], &msg[j]);
|
||||
}
|
||||
msglen = j;
|
||||
if (SHA1_HashBuf(sha1, msg, msglen) != SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
fputs(buf, ecdsaresp);
|
||||
|
||||
if (EC_NewKey(ecparams, &ecpriv) != SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
if (EC_ValidatePublicKey(ecparams, &ecpriv->publicValue)
|
||||
!= SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
len = ecpriv->publicValue.len;
|
||||
if (len%2 == 0) {
|
||||
goto loser;
|
||||
}
|
||||
len = (len-1)/2;
|
||||
if (ecpriv->publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) {
|
||||
goto loser;
|
||||
}
|
||||
fputs("Qx = ", ecdsaresp);
|
||||
to_hex_str(buf, &ecpriv->publicValue.data[1], len);
|
||||
fputs(buf, ecdsaresp);
|
||||
fputc('\n', ecdsaresp);
|
||||
fputs("Qy = ", ecdsaresp);
|
||||
to_hex_str(buf, &ecpriv->publicValue.data[1+len], len);
|
||||
fputs(buf, ecdsaresp);
|
||||
fputc('\n', ecdsaresp);
|
||||
|
||||
digest.type = siBuffer;
|
||||
digest.data = sha1;
|
||||
digest.len = sizeof sha1;
|
||||
signature.type = siBuffer;
|
||||
signature.data = sig;
|
||||
signature.len = sizeof sig;
|
||||
if (ECDSA_SignDigest(ecpriv, &signature, &digest) != SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
len = signature.len;
|
||||
if (len%2 != 0) {
|
||||
goto loser;
|
||||
}
|
||||
len = len/2;
|
||||
fputs("R = ", ecdsaresp);
|
||||
to_hex_str(buf, &signature.data[0], len);
|
||||
fputs(buf, ecdsaresp);
|
||||
fputc('\n', ecdsaresp);
|
||||
fputs("S = ", ecdsaresp);
|
||||
to_hex_str(buf, &signature.data[len], len);
|
||||
fputs(buf, ecdsaresp);
|
||||
fputc('\n', ecdsaresp);
|
||||
|
||||
PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
loser:
|
||||
if (ecparams != NULL) {
|
||||
PORT_FreeArena(ecparams->arena, PR_TRUE);
|
||||
}
|
||||
fclose(ecdsareq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the ECDSA Signature Verification Test.
|
||||
*
|
||||
* reqfn is the pathname of the REQUEST file.
|
||||
*
|
||||
* The output RESPONSE file is written to stdout.
|
||||
*/
|
||||
void
|
||||
ecdsa_sigver_test(char *reqfn)
|
||||
{
|
||||
char buf[1024]; /* holds one line from the input REQUEST file.
|
||||
* needs to be large enough to hold the longest
|
||||
* line "Msg = <256 hex digits>\n".
|
||||
*/
|
||||
FILE *ecdsareq; /* input stream from the REQUEST file */
|
||||
FILE *ecdsaresp; /* output stream to the RESPONSE file */
|
||||
char curve[16]; /* "nistxddd" */
|
||||
ECParams *ecparams = NULL;
|
||||
ECPublicKey ecpub;
|
||||
unsigned int i, j;
|
||||
unsigned int flen; /* length in bytes of the field size */
|
||||
unsigned int olen; /* length in bytes of the base point order */
|
||||
unsigned char msg[512]; /* message that was signed (<= 128 bytes) */
|
||||
unsigned int msglen;
|
||||
unsigned char sha1[20]; /* SHA-1 hash (160 bits) */
|
||||
unsigned char sig[2*MAX_ECKEY_LEN];
|
||||
SECItem signature, digest;
|
||||
PRBool keyvalid = PR_TRUE;
|
||||
PRBool sigvalid = PR_TRUE;
|
||||
|
||||
ecdsareq = fopen(reqfn, "r");
|
||||
ecdsaresp = stdout;
|
||||
ecpub.publicValue.type = siBuffer;
|
||||
ecpub.publicValue.data = NULL;
|
||||
ecpub.publicValue.len = 0;
|
||||
strcpy(curve, "nist");
|
||||
while (fgets(buf, sizeof buf, ecdsareq) != NULL) {
|
||||
/* a comment or blank line */
|
||||
if (buf[0] == '#' || buf[0] == '\n') {
|
||||
fputs(buf, ecdsaresp);
|
||||
continue;
|
||||
}
|
||||
/* [X-ddd] */
|
||||
if (buf[0] == '[') {
|
||||
const char *src;
|
||||
char *dst;
|
||||
SECKEYECParams *encodedparams;
|
||||
|
||||
src = &buf[1];
|
||||
dst = &curve[4];
|
||||
*dst++ = tolower(*src);
|
||||
src += 2; /* skip the hyphen */
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst = '\0';
|
||||
if (ecparams != NULL) {
|
||||
PORT_FreeArena(ecparams->arena, PR_TRUE);
|
||||
ecparams = NULL;
|
||||
}
|
||||
encodedparams = getECParams(curve);
|
||||
if (encodedparams == NULL) {
|
||||
goto loser;
|
||||
}
|
||||
if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
SECITEM_FreeItem(encodedparams, PR_TRUE);
|
||||
ecpub.ecParams = *ecparams;
|
||||
flen = (ecparams->fieldID.size + 7) >> 3;
|
||||
olen = ecparams->order.len;
|
||||
if (2*olen > sizeof sig) {
|
||||
goto loser;
|
||||
}
|
||||
if (ecpub.publicValue.data != NULL) {
|
||||
SECITEM_FreeItem(&ecpub.publicValue, PR_FALSE);
|
||||
}
|
||||
SECITEM_AllocItem(NULL, &ecpub.publicValue, 2*flen+1);
|
||||
if (ecpub.publicValue.data == NULL) {
|
||||
goto loser;
|
||||
}
|
||||
ecpub.publicValue.data[0] = EC_POINT_FORM_UNCOMPRESSED;
|
||||
fputs(buf, ecdsaresp);
|
||||
continue;
|
||||
}
|
||||
/* Msg = ... */
|
||||
if (strncmp(buf, "Msg", 3) == 0) {
|
||||
i = 3;
|
||||
while (isspace(buf[i]) || buf[i] == '=') {
|
||||
i++;
|
||||
}
|
||||
for (j=0; isxdigit(buf[i]); i+=2,j++) {
|
||||
hex_from_2char(&buf[i], &msg[j]);
|
||||
}
|
||||
msglen = j;
|
||||
if (SHA1_HashBuf(sha1, msg, msglen) != SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
fputs(buf, ecdsaresp);
|
||||
|
||||
digest.type = siBuffer;
|
||||
digest.data = sha1;
|
||||
digest.len = sizeof sha1;
|
||||
|
||||
continue;
|
||||
}
|
||||
/* Qx = ... */
|
||||
if (strncmp(buf, "Qx", 2) == 0) {
|
||||
fputs(buf, ecdsaresp);
|
||||
i = 2;
|
||||
while (isspace(buf[i]) || buf[i] == '=') {
|
||||
i++;
|
||||
}
|
||||
keyvalid = from_hex_str(&ecpub.publicValue.data[1], flen,
|
||||
&buf[i]);
|
||||
continue;
|
||||
}
|
||||
/* Qy = ... */
|
||||
if (strncmp(buf, "Qy", 2) == 0) {
|
||||
fputs(buf, ecdsaresp);
|
||||
if (!keyvalid) {
|
||||
continue;
|
||||
}
|
||||
i = 2;
|
||||
while (isspace(buf[i]) || buf[i] == '=') {
|
||||
i++;
|
||||
}
|
||||
keyvalid = from_hex_str(&ecpub.publicValue.data[1+flen], flen,
|
||||
&buf[i]);
|
||||
if (!keyvalid) {
|
||||
continue;
|
||||
}
|
||||
if (EC_ValidatePublicKey(ecparams, &ecpub.publicValue)
|
||||
!= SECSuccess) {
|
||||
if (PORT_GetError() == SEC_ERROR_BAD_KEY) {
|
||||
keyvalid = PR_FALSE;
|
||||
} else {
|
||||
goto loser;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* R = ... */
|
||||
if (buf[0] == 'R') {
|
||||
fputs(buf, ecdsaresp);
|
||||
i = 1;
|
||||
while (isspace(buf[i]) || buf[i] == '=') {
|
||||
i++;
|
||||
}
|
||||
sigvalid = from_hex_str(sig, olen, &buf[i]);
|
||||
continue;
|
||||
}
|
||||
/* S = ... */
|
||||
if (buf[0] == 'S') {
|
||||
fputs(buf, ecdsaresp);
|
||||
i = 1;
|
||||
while (isspace(buf[i]) || buf[i] == '=') {
|
||||
i++;
|
||||
}
|
||||
if (sigvalid) {
|
||||
sigvalid = from_hex_str(&sig[olen], olen, &buf[i]);
|
||||
}
|
||||
signature.type = siBuffer;
|
||||
signature.data = sig;
|
||||
signature.len = 2*olen;
|
||||
|
||||
if (!keyvalid || !sigvalid) {
|
||||
fputs("Result = F\n", ecdsaresp);
|
||||
} else if (ECDSA_VerifyDigest(&ecpub, &signature, &digest)
|
||||
== SECSuccess) {
|
||||
fputs("Result = P\n", ecdsaresp);
|
||||
} else {
|
||||
fputs("Result = F\n", ecdsaresp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
loser:
|
||||
if (ecparams != NULL) {
|
||||
PORT_FreeArena(ecparams->arena, PR_TRUE);
|
||||
}
|
||||
if (ecpub.publicValue.data != NULL) {
|
||||
SECITEM_FreeItem(&ecpub.publicValue, PR_FALSE);
|
||||
}
|
||||
fclose(ecdsareq);
|
||||
}
|
||||
|
||||
void do_random()
|
||||
{
|
||||
int i, j, k = 0;
|
||||
@ -2634,6 +3374,24 @@ int main(int argc, char **argv)
|
||||
} else if (strcmp(argv[1], "dss") == 0) {
|
||||
dss_test(argv[2], argv[3]);
|
||||
/*************/
|
||||
/* ECDSA */
|
||||
/*************/
|
||||
} else if (strcmp(argv[1], "ecdsa") == 0) {
|
||||
/* argv[2]=keypair|pkv|siggen|sigver argv[3]=<test name>.req */
|
||||
if ( strcmp(argv[2], "keypair") == 0) {
|
||||
/* Key Pair Generation Test */
|
||||
ecdsa_keypair_test(argv[3]);
|
||||
} else if (strcmp(argv[2], "pkv") == 0) {
|
||||
/* Public Key Validation Test */
|
||||
ecdsa_pkv_test(argv[3]);
|
||||
} else if (strcmp(argv[2], "siggen") == 0) {
|
||||
/* Signature Generation Test */
|
||||
ecdsa_siggen_test(argv[3]);
|
||||
} else if (strcmp(argv[2], "sigver") == 0) {
|
||||
/* Signature Verification Test */
|
||||
ecdsa_sigver_test(argv[3]);
|
||||
}
|
||||
/*************/
|
||||
/* RNG */
|
||||
/*************/
|
||||
} else if (strcmp(argv[1], "rng") == 0) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user