blob: 1c8f4c0392c48f26a7d4caf60e188b2fadd66863 [file] [log] [blame]
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "blapi.h"
#include "ec.h"
#include "ecl-curve.h"
#include "prprf.h"
#include "basicutil.h"
#include "secder.h"
#include "secitem.h"
#include "nspr.h"
#include <stdio.h>
typedef struct {
ECCurveName curve;
int iterations;
char *privhex;
char *our_pubhex;
char *their_pubhex;
char *common_key;
char *name;
ECFieldType fieldType;
} ECDH_KAT;
typedef struct {
ECCurveName curve;
char *point;
char *name;
ECFieldType fieldType;
} ECDH_BAD;
#include "testvecs.h"
void
printBuf(const SECItem *item)
{
int i;
if (!item || !item->len) {
printf("(null)\n");
return;
}
for (i = 0; i < item->len; i++) {
printf("%02x", item->data[i]);
}
printf("\n");
}
/* Initialise test with basic curve populate with only the necessary things */
SECStatus
init_params(ECParams *ecParams, ECCurveName curve, PLArenaPool **arena,
ECFieldType type)
{
if ((curve < ECCurve_noName) || (curve > ECCurve_pastLastCurve)) {
return SECFailure;
}
*arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!*arena) {
return SECFailure;
}
ecParams->name = curve;
ecParams->type = ec_params_named;
ecParams->curveOID.data = NULL;
ecParams->curveOID.len = 0;
ecParams->curve.seed.data = NULL;
ecParams->curve.seed.len = 0;
ecParams->DEREncoding.data = NULL;
ecParams->DEREncoding.len = 0;
ecParams->arena = *arena;
ecParams->fieldID.size = ecCurve_map[curve]->size;
ecParams->fieldID.type = type;
ecParams->cofactor = ecCurve_map[curve]->cofactor;
return SECSuccess;
}
SECStatus
ectest_ecdh_kat(ECDH_KAT *kat)
{
ECCurveName curve = kat->curve;
ECParams ecParams = { 0 };
ECPrivateKey *ecPriv = NULL;
SECItem theirKey = { siBuffer, NULL, 0 };
SECStatus rv = SECFailure;
PLArenaPool *arena = NULL;
SECItem seed = { siBuffer, NULL, 0 };
SECItem answer = { siBuffer, NULL, 0 };
SECItem answer2 = { siBuffer, NULL, 0 };
SECItem derived = { siBuffer, NULL, 0 };
SECItem ecEncodedParams = { siBuffer, NULL, 0 };
int i;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena) {
return SECFailure;
}
rv = SECU_ecName2params(curve, &ecEncodedParams);
if (rv != SECSuccess) {
goto cleanup;
}
EC_FillParams(arena, &ecEncodedParams, &ecParams);
if (kat->our_pubhex) {
SECU_HexString2SECItem(arena, &answer, kat->our_pubhex);
}
SECU_HexString2SECItem(arena, &seed, kat->privhex);
rv = EC_NewKeyFromSeed(&ecParams, &ecPriv, seed.data, seed.len);
if (rv != SECSuccess) {
rv = SECFailure;
goto cleanup;
}
if (kat->our_pubhex) {
if (SECITEM_CompareItem(&answer, &ecPriv->publicValue) != SECEqual) {
rv = SECFailure;
goto cleanup;
}
}
SECU_HexString2SECItem(arena, &theirKey, kat->their_pubhex);
SECU_HexString2SECItem(arena, &answer2, kat->common_key);
rv = EC_ValidatePublicKey(&ecParams, &theirKey);
if (rv != SECSuccess) {
printf("EC_ValidatePublicKey failed\n");
goto cleanup;
}
for (i = 0; i < kat->iterations; ++i) {
rv = ECDH_Derive(&theirKey, &ecParams, &ecPriv->privateValue, PR_TRUE, &derived);
if (rv != SECSuccess) {
rv = SECFailure;
goto cleanup;
}
rv = SECITEM_CopyItem(ecParams.arena, &theirKey, &ecPriv->privateValue);
if (rv != SECSuccess) {
goto cleanup;
}
rv = SECITEM_CopyItem(ecParams.arena, &ecPriv->privateValue, &derived);
if (rv != SECSuccess) {
goto cleanup;
}
SECITEM_FreeItem(&derived, PR_FALSE);
}
if (SECITEM_CompareItem(&answer2, &ecPriv->privateValue) != SECEqual) {
printf("expected: ");
printBuf(&answer2);
printf("derived: ");
printBuf(&ecPriv->privateValue);
rv = SECFailure;
goto cleanup;
}
cleanup:
SECITEM_FreeItem(&ecEncodedParams, PR_FALSE);
PORT_FreeArena(arena, PR_FALSE);
if (ecPriv) {
PORT_FreeArena(ecPriv->ecParams.arena, PR_FALSE);
}
if (derived.data) {
SECITEM_FreeItem(&derived, PR_FALSE);
}
return rv;
}
SECStatus
ectest_validate_point(ECDH_BAD *bad)
{
ECParams ecParams = { 0 };
SECItem point = { siBuffer, NULL, 0 };
SECStatus rv = SECFailure;
PLArenaPool *arena = NULL;
rv = init_params(&ecParams, bad->curve, &arena, bad->fieldType);
if (rv != SECSuccess) {
return rv;
}
SECU_HexString2SECItem(arena, &point, bad->point);
rv = EC_ValidatePublicKey(&ecParams, &point);
PORT_FreeArena(arena, PR_FALSE);
return rv;
}
void
printUsage(char *prog)
{
printf("Usage: %s [-fp] [-nd]\n"
"\t-n: NIST curves\n"
"\t-d: non-NIST curves\n"
"You have to specify at at least one of n or d.\n"
"By default no tests are executed.\n",
prog);
}
/* Performs tests of elliptic curve cryptography over prime fields If
* tests fail, then it prints an error message, aborts, and returns an
* error code. Otherwise, returns 0. */
int
main(int argv, char **argc)
{
SECStatus rv = SECSuccess;
int numkats = 0;
int i = 0;
int nist = 0;
int nonnist = 0;
for (i = 1; i < argv; i++) {
if (PL_strcasecmp(argc[i], "-n") == 0) {
nist = 1;
} else if (PL_strcasecmp(argc[i], "-d") == 0) {
nonnist = 1;
} else {
printUsage(argc[0]);
return 1;
}
}
if (!nist && !nonnist) {
printUsage(argc[0]);
return 1;
}
rv = SECOID_Init();
if (rv != SECSuccess) {
SECU_PrintError("Error:", "SECOID_Init");
goto cleanup;
}
/* Test P256, P384, P521 */
if (nist) {
while (ecdh_testvecs[numkats].curve != ECCurve_pastLastCurve) {
numkats++;
}
printf("1..%d\n", numkats);
for (i = 0; ecdh_testvecs[i].curve != ECCurve_pastLastCurve; i++) {
if (ectest_ecdh_kat(&ecdh_testvecs[i]) != SECSuccess) {
printf("not okay %d - %s\n", i + 1, ecdh_testvecs[i].name);
rv = SECFailure;
} else {
printf("okay %d - %s\n", i + 1, ecdh_testvecs[i].name);
}
}
}
/* Test KAT for non-NIST curves */
if (nonnist) {
for (i = 0; nonnist_testvecs[i].curve != ECCurve_pastLastCurve; i++) {
if (ectest_ecdh_kat(&nonnist_testvecs[i]) != SECSuccess) {
printf("not okay %d - %s\n", i + 1, nonnist_testvecs[i].name);
rv = SECFailure;
} else {
printf("okay %d - %s\n", i + 1, nonnist_testvecs[i].name);
}
}
for (i = 0; nonnist_testvecs_bad_values[i].curve != ECCurve_pastLastCurve; i++) {
if (ectest_validate_point(&nonnist_testvecs_bad_values[i]) == SECSuccess) {
printf("not okay %d - %s\n", i + 1, nonnist_testvecs_bad_values[i].name);
rv = SECFailure;
} else {
printf("okay %d - %s\n", i + 1, nonnist_testvecs_bad_values[i].name);
}
}
}
cleanup:
rv |= SECOID_Shutdown();
if (rv != SECSuccess) {
printf("Error: exiting with error value\n");
}
return rv;
}