Commit 8402cd5f authored by Shane Lontis's avatar Shane Lontis Committed by Nicola Tuveri
Browse files

added code to validate EC named curve parameters

parent 4660bdea
Loading
Loading
Loading
Loading
+17 −2
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ typedef enum OPTION_choice {
    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
    OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_TEXT, OPT_C,
    OPT_CHECK, OPT_LIST_CURVES, OPT_NO_SEED, OPT_NOOUT, OPT_NAME,
    OPT_CONV_FORM, OPT_PARAM_ENC, OPT_GENKEY, OPT_ENGINE,
    OPT_CONV_FORM, OPT_PARAM_ENC, OPT_GENKEY, OPT_ENGINE, OPT_CHECK_NAMED,
    OPT_R_ENUM
} OPTION_CHOICE;

@@ -43,6 +43,8 @@ const OPTIONS ecparam_options[] = {
    {"text", OPT_TEXT, '-', "Print the ec parameters in text form"},
    {"C", OPT_C, '-', "Print a 'C' function creating the parameters"},
    {"check", OPT_CHECK, '-', "Validate the ec parameters"},
    {"check_named", OPT_CHECK_NAMED, '-',
     "Check that named EC curve parameters have not been modified"},
    {"list_curves", OPT_LIST_CURVES, '-',
     "Prints a list of all curve 'short names'"},
    {"no_seed", OPT_NO_SEED, '-',
@@ -90,7 +92,7 @@ int ecparam_main(int argc, char **argv)
    int informat = FORMAT_PEM, outformat = FORMAT_PEM, noout = 0, C = 0;
    int ret = 1, private = 0;
    int list_curves = 0, no_seed = 0, check = 0, new_form = 0;
    int text = 0, i, genkey = 0;
    int text = 0, i, genkey = 0, check_named = 0;

    prog = opt_init(argc, argv, ecparam_options);
    while ((o = opt_next()) != OPT_EOF) {
@@ -127,6 +129,9 @@ int ecparam_main(int argc, char **argv)
        case OPT_CHECK:
            check = 1;
            break;
        case OPT_CHECK_NAMED:
            check_named = 1;
            break;
        case OPT_LIST_CURVES:
            list_curves = 1;
            break;
@@ -266,6 +271,16 @@ int ecparam_main(int argc, char **argv)
            goto end;
    }

    if (check_named) {
        BIO_printf(bio_err, "validating named elliptic curve parameters: ");
        if (EC_GROUP_check_named_curve(group, 0) <= 0) {
            BIO_printf(bio_err, "failed\n");
            ERR_print_errors(bio_err);
            goto end;
        }
        BIO_printf(bio_err, "ok\n");
    }

    if (check) {
        BIO_printf(bio_err, "checking elliptic curve parameters: ");
        if (!EC_GROUP_check(group, NULL)) {
+16 −1
Original line number Diff line number Diff line
/*
 * Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved.
 * Copyright 2002-2019 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the Apache License 2.0 (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
@@ -10,6 +10,16 @@
#include "ec_lcl.h"
#include <openssl/err.h>

int EC_GROUP_check_named_curve(const EC_GROUP *group, int nist_only)
{
    int nid;

    nid = ec_curve_nid_from_params(group);
    if (nid > 0 && nist_only && EC_curve_nid2nist(nid) == NULL)
        nid = 0;
    return nid;
}

int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx)
{
    int ret = 0;
@@ -17,6 +27,11 @@ int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx)
    BN_CTX *new_ctx = NULL;
    EC_POINT *point = NULL;

    if (group == NULL || group->meth == NULL) {
        ECerr(EC_F_EC_GROUP_CHECK, ERR_R_PASSED_NULL_PARAMETER);
        return 0;
    }

    /* Custom curves assumed to be correct */
    if ((group->meth->flags & EC_FLAGS_CUSTOM_CURVE) != 0)
        return 1;
+122 −1
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <openssl/obj_mac.h>
#include <openssl/opensslconf.h>
#include "internal/nelem.h"
#include "internal/o_str.h"

typedef struct {
    int field_type,             /* either NID_X9_62_prime_field or
@@ -1136,6 +1137,7 @@ static const struct {
    },
    {
        /* no seed */
        /* p */
        0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
@@ -1209,6 +1211,7 @@ static const struct {
    },
    {
        /* no seed */
        /* p */
        0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
@@ -1244,6 +1247,7 @@ static const struct {
    },
    {
        /* no seed */
        /* p */
        0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA1,
@@ -1278,7 +1282,7 @@ static const struct {
        NID_X9_62_characteristic_two_field, 20, 36, 2
    },
    {
        /* no seed */
        /* seed */
        0x77, 0xE2, 0xB0, 0x73, 0x70, 0xEB, 0x0F, 0x83, 0x2A, 0x6D, 0xD5, 0xB6,
        0x2D, 0xFC, 0x88, 0xCD, 0x06, 0xBB, 0x84, 0xBE,
        /* p */
@@ -3197,3 +3201,120 @@ int EC_curve_nist2nid(const char *name)
    }
    return NID_undef;
}

#define NUM_BN_FIELDS 6
/*
 * Validates EC domain parameter data for known named curves.
 * This can be used when a curve is loaded explicitly (without a curve
 * name) or to validate that domain parameters have not been modified.
 *
 * Returns: The nid associated with the found named curve, or NID_undef
 *          if not found. If there was an error it returns -1.
 */
int ec_curve_nid_from_params(const EC_GROUP *group)
{
    int ret = -1, nid, len, field_type, param_len;
    size_t i, seed_len;
    const unsigned char *seed, *params_seed, *params;
    unsigned char *param_bytes = NULL;
    const EC_CURVE_DATA *data;
    const EC_POINT *generator = NULL;
    const EC_METHOD *meth;
    const BIGNUM *cofactor = NULL;
    /* An array of BIGNUMs for (p, a, b, x, y, order) */
    BIGNUM *bn[NUM_BN_FIELDS] = {NULL, NULL, NULL, NULL, NULL, NULL};
    BN_CTX *ctx = NULL;

    meth = EC_GROUP_method_of(group);
    if (meth == NULL)
        return -1;
    /* Use the optional named curve nid as a search field */
    nid = EC_GROUP_get_curve_name(group);
    field_type = EC_METHOD_get_field_type(meth);
    seed_len = EC_GROUP_get_seed_len(group);
    seed = EC_GROUP_get0_seed(group);
    cofactor = EC_GROUP_get0_cofactor(group);

    ctx = BN_CTX_new();
    if (ctx == NULL)
        return -1;
    BN_CTX_start(ctx);

    /*
     * The in built curves contains data fields (p, a, b, x, y, order) that are
     * all zero padded to be the same size. The size of the padding is
     * determined by either the number of bytes in the field modulus (p) or the
     * EC group order, whichever is larger.
     */
    param_len = BN_num_bytes(group->order);
    len = BN_num_bytes(group->field);
    if (len > param_len)
        param_len = len;

    /* Allocate space to store the padded data for (p, a, b, x, y, order)  */
    param_bytes = OPENSSL_malloc(param_len * NUM_BN_FIELDS);
    if (param_bytes == NULL)
        goto end;

    /* Create the bignums */
    for (i = 0; i < NUM_BN_FIELDS; ++i) {
        if ((bn[i] = BN_CTX_get(ctx)) == NULL)
            goto end;
    }
    /*
     * Fill in the bn array with the same values as the internal curves
     * i.e. the values are p, a, b, x, y, order.
     */
    /* Get p, a & b */
    if (!(EC_GROUP_get_curve(group, bn[0], bn[1], bn[2], ctx)
        && ((generator = EC_GROUP_get0_generator(group)) != NULL)
        /* Get x & y */
        && EC_POINT_get_affine_coordinates(group, generator, bn[3], bn[4], ctx)
        /* Get order */
        && EC_GROUP_get_order(group, bn[5], ctx)))
        goto end;

   /*
     * Convert the bignum array to bytes that are joined together to form
     * a single buffer that contains data for all fields.
     * (p, a, b, x, y, order) are all zero padded to be the same size.
     */
    for (i = 0; i < NUM_BN_FIELDS; ++i) {
        if (BN_bn2binpad(bn[i], &param_bytes[i*param_len], param_len) <= 0)
            goto end;
    }

    for (i = 0; i < curve_list_length; i++) {
        const ec_list_element curve = curve_list[i];

        data = curve.data;
        /* Get the raw order byte data */
        params_seed = (const unsigned char *)(data + 1); /* skip header */
        params = params_seed + data->seed_len;

        /* Look for unique fields in the fixed curve data */
        if (data->field_type == field_type
            && param_len == data->param_len
            && (nid <= 0 || nid == curve.nid)
            /* check the optional cofactor (ignore if its zero) */
            && (BN_is_zero(cofactor)
                || BN_is_word(cofactor, (const BN_ULONG)curve.data->cofactor))
            /* Check the optional seed (ignore if its not set) */
            && (data->seed_len == 0 || seed_len == 0
                || ((size_t)data->seed_len == seed_len
                     && OPENSSL_memcmp(params_seed, seed, seed_len) == 0))
            /* Check that the groups params match the inbuilt curve params */
            && OPENSSL_memcmp(param_bytes, params, param_len * NUM_BN_FIELDS)
                              == 0) {
            ret = curve.nid;
            goto end;
        }
    }
    /* Gets here if the group was not found */
    ret = NID_undef;
end:
    OPENSSL_free(param_bytes);
    BN_CTX_end(ctx);
    BN_CTX_free(ctx);
    return ret;
}
+6 −7
Original line number Diff line number Diff line
@@ -309,13 +309,10 @@ struct ec_point_st {
static ossl_inline int ec_point_is_compat(const EC_POINT *point,
                                          const EC_GROUP *group)
{
    if (group->meth != point->meth
        || (group->curve_name != 0
            && point->curve_name != 0
            && group->curve_name != point->curve_name))
        return 0;

    return 1;
    return group->meth == point->meth
           && (group->curve_name == 0
               || point->curve_name == 0
               || group->curve_name == point->curve_name);
}

NISTP224_PRE_COMP *EC_nistp224_pre_comp_dup(NISTP224_PRE_COMP *);
@@ -595,6 +592,8 @@ int ec_key_simple_generate_key(EC_KEY *eckey);
int ec_key_simple_generate_public_key(EC_KEY *eckey);
int ec_key_simple_check_key(const EC_KEY *eckey);

int ec_curve_nid_from_params(const EC_GROUP *group);

/* EC_METHOD definitions */

struct ec_key_method_st {
+30 −16
Original line number Diff line number Diff line
@@ -284,15 +284,17 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
    if (order != NULL) {
        if (!BN_copy(group->order, order))
            return 0;
    } else
    } else {
        BN_zero(group->order);
    }

    /* The cofactor is an optional field, so it should be able to be NULL. */
    if (cofactor != NULL) {
        if (!BN_copy(group->cofactor, cofactor))
            return 0;
    } else
    } else {
        BN_zero(group->cofactor);

    }
    /*
     * Some groups have an order with
     * factors of two, which makes the Montgomery setup fail.
@@ -530,30 +532,42 @@ int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ctx)
        !b->meth->group_get_curve(b, b1, b2, b3, ctx))
        r = 1;

    if (r || BN_cmp(a1, b1) || BN_cmp(a2, b2) || BN_cmp(a3, b3))
    /* return 1 if the curve parameters are different */
    if (r || BN_cmp(a1, b1) != 0 || BN_cmp(a2, b2) != 0 || BN_cmp(a3, b3) != 0)
        r = 1;

    /* XXX EC_POINT_cmp() assumes that the methods are equal */
    /* return 1 if the generators are different */
    if (r || EC_POINT_cmp(a, EC_GROUP_get0_generator(a),
                          EC_GROUP_get0_generator(b), ctx))
                          EC_GROUP_get0_generator(b), ctx) != 0)
        r = 1;

    if (!r) {
        const BIGNUM *ao, *bo, *ac, *bc;
        /* compare the order and cofactor */
        /* compare the order's */
        ao = EC_GROUP_get0_order(a);
        bo = EC_GROUP_get0_order(b);
        ac = EC_GROUP_get0_cofactor(a);
        bc = EC_GROUP_get0_cofactor(b);
        if (ao == NULL || bo == NULL) {
            BN_CTX_end(ctx);
            BN_CTX_free(ctx_new);
            return -1;
            /* return an error if either order is NULL */
            r = -1;
            goto end;
        }
        if (BN_cmp(ao, bo) || BN_cmp(ac, bc))
        if (BN_cmp(ao, bo) != 0) {
            /* return 1 if orders are different */
            r = 1;
            goto end;
        }

        /*
         * It gets here if the curve parameters and generator matched.
         * Now check the optional cofactors (if both are present).
         */
        ac = EC_GROUP_get0_cofactor(a);
        bc = EC_GROUP_get0_cofactor(b);
        /* Returns 1 (mismatch) if both cofactors are specified and different */
        if (!BN_is_zero(ac) && !BN_is_zero(bc) && BN_cmp(ac, bc) != 0)
            r = 1;
        /* Returns 0 if the parameters matched */
    }
end:
    BN_CTX_end(ctx);
    BN_CTX_free(ctx_new);

Loading