fbectest.c 7.44 KB
Newer Older
1 2 3 4 5 6 7
/* 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"
8 9 10
#include "prprf.h"
#include "basicutil.h"
#include "secder.h"
11 12 13 14 15 16
#include "secitem.h"
#include "nspr.h"
#include <stdio.h>

typedef struct {
    ECCurveName curve;
17
    int iterations;
18 19 20 21 22
    char *privhex;
    char *our_pubhex;
    char *their_pubhex;
    char *common_key;
    char *name;
23
    ECFieldType fieldType;
24 25
} ECDH_KAT;

26 27 28 29 30 31 32
typedef struct {
    ECCurveName curve;
    char *point;
    char *name;
    ECFieldType fieldType;
} ECDH_BAD;

33 34
#include "testvecs.h"

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
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;
71
    ecParams->fieldID.size = ecCurve_map[curve]->size;
72
    ecParams->fieldID.type = type;
73
    ecParams->cofactor = ecCurve_map[curve]->cofactor;
74 75 76 77

    return SECSuccess;
}

78 79 80 81 82 83 84 85
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;
86
    PLArenaPool *arena = NULL;
87 88 89 90
    SECItem seed = { siBuffer, NULL, 0 };
    SECItem answer = { siBuffer, NULL, 0 };
    SECItem answer2 = { siBuffer, NULL, 0 };
    SECItem derived = { siBuffer, NULL, 0 };
91
    SECItem ecEncodedParams = { siBuffer, NULL, 0 };
92
    int i;
93

94 95 96
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    if (!arena) {
        return SECFailure;
97
    }
98

99 100 101 102 103
    rv = SECU_ecName2params(curve, &ecEncodedParams);
    if (rv != SECSuccess) {
        goto cleanup;
    }
    EC_FillParams(arena, &ecEncodedParams, &ecParams);
104

105
    if (kat->our_pubhex) {
106
        SECU_HexString2SECItem(arena, &answer, kat->our_pubhex);
107
    }
108
    SECU_HexString2SECItem(arena, &seed, kat->privhex);
109 110 111 112 113
    rv = EC_NewKeyFromSeed(&ecParams, &ecPriv, seed.data, seed.len);
    if (rv != SECSuccess) {
        rv = SECFailure;
        goto cleanup;
    }
114 115 116 117 118
    if (kat->our_pubhex) {
        if (SECITEM_CompareItem(&answer, &ecPriv->publicValue) != SECEqual) {
            rv = SECFailure;
            goto cleanup;
        }
119 120
    }

121 122
    SECU_HexString2SECItem(arena, &theirKey, kat->their_pubhex);
    SECU_HexString2SECItem(arena, &answer2, kat->common_key);
123 124

    rv = EC_ValidatePublicKey(&ecParams, &theirKey);
125
    if (rv != SECSuccess) {
126
        printf("EC_ValidatePublicKey failed\n");
127 128 129
        goto cleanup;
    }

130 131 132 133 134 135
    for (i = 0; i < kat->iterations; ++i) {
        rv = ECDH_Derive(&theirKey, &ecParams, &ecPriv->privateValue, PR_TRUE, &derived);
        if (rv != SECSuccess) {
            rv = SECFailure;
            goto cleanup;
        }
136 137 138 139 140 141 142 143
        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;
        }
144 145 146 147 148 149 150 151
        SECITEM_FreeItem(&derived, PR_FALSE);
    }

    if (SECITEM_CompareItem(&answer2, &ecPriv->privateValue) != SECEqual) {
        printf("expected: ");
        printBuf(&answer2);
        printf("derived:  ");
        printBuf(&ecPriv->privateValue);
152 153 154
        rv = SECFailure;
        goto cleanup;
    }
155

156
cleanup:
157
    SECITEM_FreeItem(&ecEncodedParams, PR_FALSE);
158
    PORT_FreeArena(arena, PR_FALSE);
159 160 161
    if (ecPriv) {
        PORT_FreeArena(ecPriv->ecParams.arena, PR_FALSE);
    }
162 163 164
    if (derived.data) {
        SECITEM_FreeItem(&derived, PR_FALSE);
    }
165 166 167
    return rv;
}

168 169 170 171 172 173 174 175 176 177 178 179 180
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;
    }

181
    SECU_HexString2SECItem(arena, &point, bad->point);
182 183 184 185 186 187 188 189 190 191 192 193
    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"
194
           "You have to specify at at least one of n or d.\n"
195 196 197 198
           "By default no tests are executed.\n",
           prog);
}

199 200 201 202 203 204 205 206 207
/* 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;
208 209
    int nist = 0;
    int nonnist = 0;
210

211
    for (i = 1; i < argv; i++) {
212
        if (PL_strcasecmp(argc[i], "-n") == 0) {
213 214 215 216 217 218 219 220
            nist = 1;
        } else if (PL_strcasecmp(argc[i], "-d") == 0) {
            nonnist = 1;
        } else {
            printUsage(argc[0]);
            return 1;
        }
    }
221
    if (!nist && !nonnist) {
222 223 224 225
        printUsage(argc[0]);
        return 1;
    }

226
    rv = SECOID_Init();
227
    if (rv != SECSuccess) {
228
        SECU_PrintError("Error:", "SECOID_Init");
229 230 231
        goto cleanup;
    }

232
    /* Test P256, P384, P521 */
233 234 235
    if (nist) {
        while (ecdh_testvecs[numkats].curve != ECCurve_pastLastCurve) {
            numkats++;
236
        }
237 238 239 240 241 242 243
        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);
244 245
            }
        }
246
    }
247

248 249 250 251 252
    /* 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);
253 254
                rv = SECFailure;
            } else {
255
                printf("okay %d - %s\n", i + 1, nonnist_testvecs[i].name);
256 257
            }
        }
258 259 260 261 262 263
        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);
264
            }
265 266 267 268
        }
    }

cleanup:
269
    rv |= SECOID_Shutdown();
270 271 272 273 274 275

    if (rv != SECSuccess) {
        printf("Error: exiting with error value\n");
    }
    return rv;
}