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?
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.
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With