Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Some elliptic curves in openssl give "no shared cipher" errors

Tags:

openssl

Certain curves in generating keypairs seem to not work when using an openssl s_server/s_client combination. I have verified this using the following methodology:

  • create an elliptic curve keypair with openssl ecparam -out ec_$curve.key -name $curve -genkey, foreach $curve in openssl ecparam -list_curves

  • generate self-signed certificates for each ec_$curve.key with openssl req -x509 -new -days 365 -key ec_$curve.key -out ec_$curve.crt -subj $SOME_SUBJ

  • for each ec_$curve.key, do: in one window, openssl s_server -cert ec_$curve.crt -key ec_$curve.key -accept 10000, another openssl s_client -host localhost -port 10000

I get on handshake:

Using default temp DH parameters Using default temp ECDH parameters ACCEPT ERROR 8606155664:error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher:s3_srvr.c:1355: shutting down SSL CONNECTION CLOSED

for only for the keypairs created with the following curves: the c2.* curves (eg., c2pnb163v1), prime192v[23], prime239.* and the sec.1[123].* curves. All the other curves work fine.

This makes no sense to me. s_client ought to be able to talk to s_server, so either this is an OpenSSL bug, or I've configured the client or the server or both wrongly. I've tried adding -named_curve parameters server side, but this doesn't improve things. OpenSSL version is 1.0.1e.

So, someone with more crypto/EC-clue, what the hell is going on here?

like image 374
quack Avatar asked May 02 '13 09:05

quack


Video Answer


2 Answers

TLS standard defines support only for these curves:

    sect163k1 (1), sect163r1 (2), sect163r2 (3),
    sect193r1 (4), sect193r2 (5), sect233k1 (6),
    sect233r1 (7), sect239k1 (8), sect283k1 (9),
    sect283r1 (10), sect409k1 (11), sect409r1 (12),
    sect571k1 (13), sect571r1 (14), secp160k1 (15),
    secp160r1 (16), secp160r2 (17), secp192k1 (18),
    secp192r1 (19), secp224k1 (20), secp224r1 (21),
    secp256k1 (22), secp256r1 (23), secp384r1 (24),
    secp521r1 (25)

And while OpenSSL can generate certificates with other curves, they cannot be used for SSL/TLS. Most likely, this is the reason.

like image 130
Nickolay Olshevsky Avatar answered Oct 21 '22 03:10

Nickolay Olshevsky


According to the section 5.1.1 of RFC 4492 curves with arbitrary params are supported as well (see arbitrary_explicit_prime_curves below). It means that if you find definitions and all EC parameters for each curve that you want to test, you could generate keys through openssl calls such as EC_GROUP_new_curve, EC_KEY_set_group, EC_KEY_get0_private_key and then use them in TLS handshake.

So, the conclusion is that all the keys that you're generating can be supported if instead of using named curves you go with custom ones.

 enum {
        sect163k1 (1), sect163r1 (2), sect163r2 (3),
        sect193r1 (4), sect193r2 (5), sect233k1 (6),
        sect233r1 (7), sect239k1 (8), sect283k1 (9),
        sect283r1 (10), sect409k1 (11), sect409r1 (12),
        sect571k1 (13), sect571r1 (14), secp160k1 (15),
        secp160r1 (16), secp160r2 (17), secp192k1 (18),
        secp192r1 (19), secp224k1 (20), secp224r1 (21),
        secp256k1 (22), secp256r1 (23), secp384r1 (24),
        secp521r1 (25),
        reserved (0xFE00..0xFEFF),
        arbitrary_explicit_prime_curves(0xFF01),
        arbitrary_explicit_char2_curves(0xFF02),
        (0xFFFF)
    } NamedCurve;

There is also -C option in 'openssl ecparam' that allows generating C code for a named curve, e.g.

openssl ecparam  -name prime256v1  -C

will generate code for creating EC_GROUP object that can be used for generating a custom curve's key with parameters that match those of named curve:

static unsigned char ec_p_256[] = {
    0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
    };

static unsigned char ec_a_256[] = {
    0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFC
    };

static unsigned char ec_b_256[] = {
    0x5A,0xC6,0x35,0xD8,0xAA,0x3A,0x93,0xE7,0xB3,0xEB,0xBD,0x55,
    0x76,0x98,0x86,0xBC,0x65,0x1D,0x06,0xB0,0xCC,0x53,0xB0,0xF6,
    0x3B,0xCE,0x3C,0x3E,0x27,0xD2,0x60,0x4B
    };

static unsigned char ec_gen_256[] = {
    0x04,0x6B,0x17,0xD1,0xF2,0xE1,0x2C,0x42,0x47,0xF8,0xBC,0xE6,
    0xE5,0x63,0xA4,0x40,0xF2,0x77,0x03,0x7D,0x81,0x2D,0xEB,0x33,
    0xA0,0xF4,0xA1,0x39,0x45,0xD8,0x98,0xC2,0x96,0x4F,0xE3,0x42,
    0xE2,0xFE,0x1A,0x7F,0x9B,0x8E,0xE7,0xEB,0x4A,0x7C,0x0F,0x9E,
    0x16,0x2B,0xCE,0x33,0x57,0x6B,0x31,0x5E,0xCE,0xCB,0xB6,0x40,
    0x68,0x37,0xBF,0x51,0xF5
    };

static unsigned char ec_order_256[] = {
    0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,
    0xFF,0xFF,0xFF,0xFF,0xBC,0xE6,0xFA,0xAD,0xA7,0x17,0x9E,0x84,
    0xF3,0xB9,0xCA,0xC2,0xFC,0x63,0x25,0x51
    };

static unsigned char ec_cofactor_256[] = {
    0x01
    };



EC_GROUP *get_ec_group_256(void)
    {
    int ok=0;
    EC_GROUP *group = NULL;
    EC_POINT *point = NULL;
    BIGNUM   *tmp_1 = NULL, *tmp_2 = NULL, *tmp_3 = NULL;

    if ((tmp_1 = BN_bin2bn(ec_p_256, sizeof(ec_p_256), NULL)) == NULL)
        goto err;
    if ((tmp_2 = BN_bin2bn(ec_a_256, sizeof(ec_a_256), NULL)) == NULL)
        goto err;
    if ((tmp_3 = BN_bin2bn(ec_b_256, sizeof(ec_b_256), NULL)) == NULL)
        goto err;
    if ((group = EC_GROUP_new_curve_GFp(tmp_1, tmp_2, tmp_3, NULL)) == NULL)
        goto err;

    /* build generator */
    if ((tmp_1 = BN_bin2bn(ec_gen_256, sizeof(ec_gen_256), tmp_1)) == NULL)
        goto err;
    point = EC_POINT_bn2point(group, tmp_1, NULL, NULL);
    if (point == NULL)
        goto err;
    if ((tmp_2 = BN_bin2bn(ec_order_256, sizeof(ec_order_256), tmp_2)) == NULL)
        goto err;
    if ((tmp_3 = BN_bin2bn(ec_cofactor_256, sizeof(ec_cofactor_256), tmp_3)) == NULL)
        goto err;
    if (!EC_GROUP_set_generator(group, point, tmp_2, tmp_3))
        goto err;

    ok=1;
err:
    if (tmp_1)
        BN_free(tmp_1);
    if (tmp_2)
        BN_free(tmp_2);
    if (tmp_3)
        BN_free(tmp_3);
    if (point)
        EC_POINT_free(point);
    if (!ok)
        {
        EC_GROUP_free(group);
        group = NULL;
        }
    return(group);
    }
like image 39
Oleg Gryb Avatar answered Oct 21 '22 03:10

Oleg Gryb