/* 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 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; }