diff options
author | Fredrik Gustafsson <fredrik@erlang.org> | 2013-02-28 09:39:43 +0100 |
---|---|---|
committer | Fredrik Gustafsson <fredrik@erlang.org> | 2013-02-28 09:39:43 +0100 |
commit | db9af15041a88184ffb015b699708017275f8c9e (patch) | |
tree | 0ec0e2f00aea1df6d152fae063b2d79a3a48fa11 /lib | |
parent | 715339824e815e15d7ab396e219ef3135392be23 (diff) | |
parent | fe59c116358d8c79525eff4d5d4e9c76be2bb400 (diff) | |
download | erlang-db9af15041a88184ffb015b699708017275f8c9e.tar.gz |
Merge branch 'as/tls-psk-srp-suites-ECC' into master-pumaster-pu
Diffstat (limited to 'lib')
38 files changed, 5381 insertions, 550 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index e77e5fb8f0..d8d65dff18 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -53,6 +53,11 @@ #include <openssl/rand.h> #include <openssl/evp.h> #include <openssl/hmac.h> +#if !defined(OPENSSL_NO_EC) +#include <openssl/ec.h> +#include <openssl/ecdh.h> +#include <openssl/ecdsa.h> +#endif #include "crypto_callback.h" @@ -136,6 +141,7 @@ static void unload(ErlNifEnv* env, void* priv_data); /* The NIFs: */ static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM md5(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM md5_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM md5_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -207,14 +213,25 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM srp_server_secret(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM ec_key_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM ecdh_compute_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); /* helpers */ +static void init_algorithms_types(void); static void init_digest_types(ErlNifEnv* env); static void hmac_md5(unsigned char *key, int klen, unsigned char *dbuf, int dlen, @@ -247,6 +264,7 @@ static int library_refc = 0; /* number of users of this dynamic library */ static ErlNifFunc nif_funcs[] = { {"info_lib", 0, info_lib}, + {"algorithms", 0, algorithms}, {"md5", 1, md5}, {"md5_init", 0, md5_init}, {"md5_update", 2, md5_update}, @@ -321,11 +339,119 @@ static ErlNifFunc nif_funcs[] = { {"dh_check", 1, dh_check}, {"dh_generate_key_nif", 2, dh_generate_key_nif}, {"dh_compute_key_nif", 3, dh_compute_key_nif}, + {"srp_value_B_nif", 5, srp_value_B_nif}, + {"srp_client_secret_nif", 7, srp_client_secret_nif}, + {"srp_server_secret", 5, srp_server_secret}, {"bf_cfb64_crypt", 4, bf_cfb64_crypt}, {"bf_cbc_crypt", 4, bf_cbc_crypt}, {"bf_ecb_crypt", 3, bf_ecb_crypt}, - {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt} + {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt}, + + {"ec_key_new", 1, ec_key_new}, + {"ec_key_to_term_nif", 1, ec_key_to_term_nif}, + {"term_to_ec_key_nif", 3, term_to_ec_key_nif}, + {"ec_key_generate", 1, ec_key_generate}, + {"ecdsa_sign_nif", 3, ecdsa_sign_nif}, + {"ecdsa_verify_nif", 4, ecdsa_verify_nif}, + {"ecdh_compute_key", 2, ecdh_compute_key} +}; + +#if !defined(OPENSSL_NO_EC) +struct nid_map { + char *name; + int nid; + ERL_NIF_TERM atom; +}; + +static struct nid_map ec_curves[] = { + /* prime field curves */ + /* secg curves */ + { "secp112r1", NID_secp112r1 }, + { "secp112r2", NID_secp112r2 }, + { "secp128r1", NID_secp128r1 }, + { "secp128r2", NID_secp128r2 }, + { "secp160k1", NID_secp160k1 }, + { "secp160r1", NID_secp160r1 }, + { "secp160r2", NID_secp160r2 }, + /* SECG secp192r1 is the same as X9.62 prime192v1 */ + { "secp192r1", NID_X9_62_prime192v1 }, + { "secp192k1", NID_secp192k1 }, + { "secp224k1", NID_secp224k1 }, + { "secp224r1", NID_secp224r1 }, + { "secp256k1", NID_secp256k1 }, + /* SECG secp256r1 is the same as X9.62 prime256v1 */ + { "secp256r1", NID_X9_62_prime256v1 }, + { "secp384r1", NID_secp384r1 }, + { "secp521r1", NID_secp521r1 }, + /* X9.62 curves */ + { "prime192v1", NID_X9_62_prime192v1 }, + { "prime192v2", NID_X9_62_prime192v2 }, + { "prime192v3", NID_X9_62_prime192v3 }, + { "prime239v1", NID_X9_62_prime239v1 }, + { "prime239v2", NID_X9_62_prime239v2 }, + { "prime239v3", NID_X9_62_prime239v3 }, + { "prime256v1", NID_X9_62_prime256v1 }, + /* characteristic two field curves */ + /* NIST/SECG curves */ + { "sect113r1", NID_sect113r1 }, + { "sect113r2", NID_sect113r2 }, + { "sect131r1", NID_sect131r1 }, + { "sect131r2", NID_sect131r2 }, + { "sect163k1", NID_sect163k1 }, + { "sect163r1", NID_sect163r1 }, + { "sect163r2", NID_sect163r2 }, + { "sect193r1", NID_sect193r1 }, + { "sect193r2", NID_sect193r2 }, + { "sect233k1", NID_sect233k1 }, + { "sect233r1", NID_sect233r1 }, + { "sect239k1", NID_sect239k1 }, + { "sect283k1", NID_sect283k1 }, + { "sect283r1", NID_sect283r1 }, + { "sect409k1", NID_sect409k1 }, + { "sect409r1", NID_sect409r1 }, + { "sect571k1", NID_sect571k1 }, + { "sect571r1", NID_sect571r1 }, + /* X9.62 curves */ + { "c2pnb163v1", NID_X9_62_c2pnb163v1 }, + { "c2pnb163v2", NID_X9_62_c2pnb163v2 }, + { "c2pnb163v3", NID_X9_62_c2pnb163v3 }, + { "c2pnb176v1", NID_X9_62_c2pnb176v1 }, + { "c2tnb191v1", NID_X9_62_c2tnb191v1 }, + { "c2tnb191v2", NID_X9_62_c2tnb191v2 }, + { "c2tnb191v3", NID_X9_62_c2tnb191v3 }, + { "c2pnb208w1", NID_X9_62_c2pnb208w1 }, + { "c2tnb239v1", NID_X9_62_c2tnb239v1 }, + { "c2tnb239v2", NID_X9_62_c2tnb239v2 }, + { "c2tnb239v3", NID_X9_62_c2tnb239v3 }, + { "c2pnb272w1", NID_X9_62_c2pnb272w1 }, + { "c2pnb304w1", NID_X9_62_c2pnb304w1 }, + { "c2tnb359v1", NID_X9_62_c2tnb359v1 }, + { "c2pnb368w1", NID_X9_62_c2pnb368w1 }, + { "c2tnb431r1", NID_X9_62_c2tnb431r1 }, + /* the WAP/WTLS curves + * [unlike SECG, spec has its own OIDs for curves from X9.62] */ + { "wtls1", NID_wap_wsg_idm_ecid_wtls1 }, + { "wtls3", NID_wap_wsg_idm_ecid_wtls3 }, + { "wtls4", NID_wap_wsg_idm_ecid_wtls4 }, + { "wtls5", NID_wap_wsg_idm_ecid_wtls5 }, + { "wtls6", NID_wap_wsg_idm_ecid_wtls6 }, + { "wtls7", NID_wap_wsg_idm_ecid_wtls7 }, + { "wtls8", NID_wap_wsg_idm_ecid_wtls8 }, + { "wtls9", NID_wap_wsg_idm_ecid_wtls9 }, + { "wtls10", NID_wap_wsg_idm_ecid_wtls10 }, + { "wtls11", NID_wap_wsg_idm_ecid_wtls11 }, + { "wtls12", NID_wap_wsg_idm_ecid_wtls12 }, + /* IPSec curves */ + { "ipsec3", NID_ipsec3 }, + { "ipsec4", NID_ipsec4 } +}; + +#define EC_CURVES_CNT (sizeof(ec_curves)/sizeof(struct nid_map)) + +struct nif_ec_key { + EC_KEY *key; }; +#endif ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload) @@ -377,6 +503,19 @@ static ERL_NIF_TERM atom_none; static ERL_NIF_TERM atom_notsup; static ERL_NIF_TERM atom_digest; +static ERL_NIF_TERM atom_ec; + +#if !defined(OPENSSL_NO_EC) +static ERL_NIF_TERM atom_prime_field; +static ERL_NIF_TERM atom_characteristic_two_field; +static ERL_NIF_TERM atom_tpbasis; +static ERL_NIF_TERM atom_ppbasis; +static ERL_NIF_TERM atom_onbasis; + +static ErlNifResourceType* res_type_ec_key; +static void ec_key_dtor(ErlNifEnv* env, void* obj); +#endif + /* #define PRINTF_ERR0(FMT) enif_fprintf(stderr, FMT "\n") #define PRINTF_ERR1(FMT, A1) enif_fprintf(stderr, FMT "\n", A1) @@ -406,6 +545,7 @@ static void error_handler(void* null, const char* errstr) static int init(ErlNifEnv* env, ERL_NIF_TERM load_info) { + int i; ErlNifSysInfo sys_info; get_crypto_callbacks_t* funcp; struct crypto_callbacks* ccb; @@ -457,7 +597,24 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info) atom_notsup = enif_make_atom(env,"notsup"); atom_digest = enif_make_atom(env,"digest"); +#if !defined(OPENSSL_NO_EC) + atom_ec = enif_make_atom(env,"ec"); + atom_prime_field = enif_make_atom(env,"prime_field"); + atom_characteristic_two_field = enif_make_atom(env,"characteristic_two_field"); + atom_tpbasis = enif_make_atom(env,"tpbasis"); + atom_ppbasis = enif_make_atom(env,"ppbasis"); + atom_onbasis = enif_make_atom(env,"onbasis"); + + for (i = 0; i < EC_CURVES_CNT; i++) + ec_curves[i].atom = enif_make_atom(env,ec_curves[i].name); + + res_type_ec_key = enif_open_resource_type(env,NULL,"crypto.EC_KEY", + ec_key_dtor, + ERL_NIF_RT_CREATE, NULL); +#endif + init_digest_types(env); + init_algorithms_types(); #ifdef HAVE_DYNAMIC_CRYPTO_LIB { @@ -538,6 +695,38 @@ static void unload(ErlNifEnv* env, void* priv_data) --library_refc; } +static int algos_cnt; +static ERL_NIF_TERM algos[8]; /* increase when extending the list */ + +static void init_algorithms_types(void) +{ + algos_cnt = 0; + + algos[algos_cnt++] = atom_md5; + algos[algos_cnt++] = atom_sha; + algos[algos_cnt++] = atom_ripemd160; +#ifdef HAVE_SHA224 + algos[algos_cnt++] = atom_sha224; +#endif +#ifdef HAVE_SHA256 + algos[algos_cnt++] = atom_sha256; +#endif +#ifdef HAVE_SHA384 + algos[algos_cnt++] = atom_sha384; +#endif +#ifdef HAVE_SHA512 + algos[algos_cnt++] = atom_sha512; +#endif +#if !defined(OPENSSL_NO_EC) + algos[algos_cnt++] = atom_ec; +#endif +} + +static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return enif_make_list_from_array(env, algos, algos_cnt); +} + static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { /* [{<<"OpenSSL">>,9470143,<<"OpenSSL 0.9.8k 25 Mar 2009">>}] */ @@ -1515,6 +1704,17 @@ static int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp) return 1; } +static int get_bn_from_bin(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp) +{ + ErlNifBinary bin; + if (!enif_inspect_binary(env,term,&bin)) { + return 0; + } + ERL_VALGRIND_ASSERT_MEM_DEFINED(bin.data, bin.size); + *bnp = BN_bin2bn(bin.data, bin.size, NULL); + return 1; +} + static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Lo,Hi) */ BIGNUM *bn_from = NULL, *bn_to, *bn_rand; @@ -2344,6 +2544,205 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T return ret; } +static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Multiplier, Verifier, Generator, Exponent, Prime) */ + BIGNUM *bn_verifier = NULL; + BIGNUM *bn_exponent, *bn_generator, *bn_prime, *bn_multiplier, *bn_result; + BN_CTX *bn_ctx; + unsigned char* ptr; + unsigned dlen; + ERL_NIF_TERM ret; + + if (!get_bn_from_mpint(env, argv[0], &bn_multiplier) + || !get_bn_from_bin(env, argv[1], &bn_verifier) + || !get_bn_from_bin(env, argv[2], &bn_generator) + || !get_bn_from_bin(env, argv[3], &bn_exponent) + || !get_bn_from_bin(env, argv[4], &bn_prime)) { + if (bn_multiplier) BN_free(bn_multiplier); + if (bn_verifier) BN_free(bn_verifier); + if (bn_verifier) BN_free(bn_generator); + if (bn_verifier) BN_free(bn_exponent); + if (bn_verifier) BN_free(bn_prime); + return enif_make_badarg(env); + } + + bn_result = BN_new(); + bn_ctx = BN_CTX_new(); + + /* B = k*v + g^b % N */ + + /* k * v */ + BN_mod_mul(bn_multiplier, bn_multiplier, bn_verifier, bn_prime, bn_ctx); + + /* g^b % N */ + BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx); + + /* k*v + g^b % N */ + BN_mod_add(bn_result, bn_result, bn_multiplier, bn_prime, bn_ctx); + + /* check that B % N != 0, reuse bn_multiplier */ + BN_nnmod(bn_multiplier, bn_result, bn_prime, bn_ctx); + if (BN_is_zero(bn_multiplier)) { + ret = atom_error; + } else { + dlen = BN_num_bytes(bn_result); + ptr = enif_make_new_binary(env, dlen, &ret); + BN_bn2bin(bn_result, ptr); + } + BN_free(bn_result); + BN_CTX_free(bn_ctx); + BN_free(bn_prime); + BN_free(bn_generator); + BN_free(bn_multiplier); + BN_free(bn_exponent); + BN_free(bn_verifier); + return ret; +} + +static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (a, u, B, Multiplier, Prime, Exponent, Generator) */ +/* + <premaster secret> = (B - (k * g^x)) ^ (a + (u * x)) % N +*/ + BIGNUM *bn_exponent = NULL, *bn_a = NULL; + BIGNUM *bn_u, *bn_multiplier, *bn_exp2, *bn_base, + *bn_prime, *bn_generator, *bn_B, *bn_result; + BN_CTX *bn_ctx; + unsigned char* ptr; + unsigned dlen; + ERL_NIF_TERM ret; + + if (!get_bn_from_bin(env, argv[0], &bn_a) + || !get_bn_from_bin(env, argv[1], &bn_u) + || !get_bn_from_bin(env, argv[2], &bn_B) + || !get_bn_from_mpint(env, argv[3], &bn_multiplier) + || !get_bn_from_bin(env, argv[4], &bn_generator) + || !get_bn_from_bin(env, argv[5], &bn_exponent) + || !get_bn_from_bin(env, argv[6], &bn_prime)) + { + if (bn_exponent) BN_free(bn_exponent); + if (bn_a) BN_free(bn_a); + if (bn_u) BN_free(bn_u); + if (bn_B) BN_free(bn_B); + if (bn_multiplier) BN_free(bn_multiplier); + if (bn_generator) BN_free(bn_generator); + if (bn_prime) BN_free(bn_prime); + return enif_make_badarg(env); + } + + bn_ctx = BN_CTX_new(); + bn_result = BN_new(); + + /* check that B % N != 0 */ + BN_nnmod(bn_result, bn_B, bn_prime, bn_ctx); + if (BN_is_zero(bn_result)) { + BN_free(bn_exponent); + BN_free(bn_a); + BN_free(bn_generator); + BN_free(bn_prime); + BN_free(bn_u); + BN_free(bn_B); + BN_CTX_free(bn_ctx); + + return atom_error; + } + + /* (B - (k * g^x)) */ + bn_base = BN_new(); + BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx); + BN_mod_mul(bn_result, bn_multiplier, bn_result, bn_prime, bn_ctx); + BN_mod_sub(bn_base, bn_B, bn_result, bn_prime, bn_ctx); + + /* a + (u * x) */ + bn_exp2 = BN_new(); + BN_mod_mul(bn_result, bn_u, bn_exponent, bn_prime, bn_ctx); + BN_mod_add(bn_exp2, bn_a, bn_result, bn_prime, bn_ctx); + + /* (B - (k * g^x)) ^ (a + (u * x)) % N */ + BN_mod_exp(bn_result, bn_base, bn_exp2, bn_prime, bn_ctx); + + dlen = BN_num_bytes(bn_result); + ptr = enif_make_new_binary(env, dlen, &ret); + BN_bn2bin(bn_result, ptr); + BN_free(bn_result); + BN_CTX_free(bn_ctx); + + BN_free(bn_multiplier); + BN_free(bn_exp2); + BN_free(bn_u); + BN_free(bn_exponent); + BN_free(bn_a); + BN_free(bn_B); + BN_free(bn_base); + BN_free(bn_generator); + BN_free(bn_prime); + return ret; +} + +static ERL_NIF_TERM srp_server_secret(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Verifier, b, u, A, Prime) */ +/* + <premaster secret> = (A * v^u) ^ b % N +*/ + BIGNUM *bn_b = NULL, *bn_verifier = NULL; + BIGNUM *bn_prime, *bn_A, *bn_u, *bn_base, *bn_result; + BN_CTX *bn_ctx; + unsigned char* ptr; + unsigned dlen; + ERL_NIF_TERM ret; + + if (!get_bn_from_bin(env, argv[0], &bn_verifier) + || !get_bn_from_bin(env, argv[1], &bn_b) + || !get_bn_from_bin(env, argv[2], &bn_u) + || !get_bn_from_bin(env, argv[3], &bn_A) + || !get_bn_from_bin(env, argv[4], &bn_prime)) + { + if (bn_verifier) BN_free(bn_verifier); + if (bn_b) BN_free(bn_b); + if (bn_u) BN_free(bn_u); + if (bn_A) BN_free(bn_A); + if (bn_prime) BN_free(bn_prime); + return enif_make_badarg(env); + } + + bn_ctx = BN_CTX_new(); + bn_result = BN_new(); + + /* check that A % N != 0 */ + BN_nnmod(bn_result, bn_A, bn_prime, bn_ctx); + if (BN_is_zero(bn_result)) { + BN_free(bn_b); + BN_free(bn_verifier); + BN_free(bn_prime); + BN_free(bn_A); + BN_CTX_free(bn_ctx); + + return atom_error; + } + + /* (A * v^u) */ + bn_base = BN_new(); + BN_mod_exp(bn_base, bn_verifier, bn_u, bn_prime, bn_ctx); + BN_mod_mul(bn_base, bn_A, bn_base, bn_prime, bn_ctx); + + /* (A * v^u) ^ b % N */ + BN_mod_exp(bn_result, bn_base, bn_b, bn_prime, bn_ctx); + + dlen = BN_num_bytes(bn_result); + ptr = enif_make_new_binary(env, dlen, &ret); + BN_bn2bin(bn_result, ptr); + BN_free(bn_result); + BN_CTX_free(bn_ctx); + + BN_free(bn_u); + BN_free(bn_base); + BN_free(bn_verifier); + BN_free(bn_prime); + BN_free(bn_A); + BN_free(bn_b); + return ret; +} + static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key, Ivec, Data, IsEncrypt) */ ErlNifBinary key_bin, ivec_bin, data_bin; @@ -2429,7 +2828,680 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N return ret; } +#if !defined(OPENSSL_NO_EC) +static int term2curve_id(ERL_NIF_TERM nid) +{ + int i; + + for (i = 0; i < EC_CURVES_CNT; i++) + if (ec_curves[i].atom == nid) + return ec_curves[i].nid; + + return 0; +} + +static ERL_NIF_TERM curve_id2term(int nid) +{ + int i; + + for (i = 0; i < EC_CURVES_CNT; i++) + if (ec_curves[i].nid == nid) + return ec_curves[i].atom; + + return atom_undefined; +} +#endif + +static ERL_NIF_TERM ec_key_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#if !defined(OPENSSL_NO_EC) + EC_KEY *key = NULL; + int nid = 0; + + nid = term2curve_id(argv[0]); + if (nid == 0) + return enif_make_badarg(env); + key = EC_KEY_new_by_curve_name(nid); + + if (key) { + ERL_NIF_TERM term; + struct nif_ec_key *obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key)); + if (!obj) + return atom_error; + obj->key = key; + term = enif_make_resource(env, obj); + enif_release_resource(obj); + + return term; + } else + return enif_make_badarg(env); +#else + return atom_notsup; +#endif +} + +#if !defined(OPENSSL_NO_EC) +static ERL_NIF_TERM bn2term(ErlNifEnv* env, const BIGNUM *bn) +{ + unsigned dlen; + unsigned char* ptr; + ERL_NIF_TERM ret; + + if (!bn) + return atom_undefined; + + dlen = BN_num_bytes(bn); + ptr = enif_make_new_binary(env, dlen+4, &ret); + put_int32(ptr, dlen); + BN_bn2bin(bn, ptr+4); + + return ret; +} + +static ERL_NIF_TERM point2term(ErlNifEnv* env, + const EC_GROUP *group, + const EC_POINT *point, + point_conversion_form_t form) +{ + unsigned dlen; + ErlNifBinary bin; + + dlen = EC_POINT_point2oct(group, point, form, NULL, 0, NULL); + if (dlen == 0) + return atom_undefined; + + if (!enif_alloc_binary(dlen, &bin)) + return enif_make_badarg(env); + + if (!EC_POINT_point2oct(group, point, form, bin.data, bin.size, NULL)) { + enif_release_binary(&bin); + return enif_make_badarg(env); + } + + return enif_make_binary(env, &bin); +} +#endif + +static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#if !defined(OPENSSL_NO_EC) + struct nif_ec_key *obj; + const EC_GROUP *group; + const EC_POINT *public_key; + BIGNUM *order=NULL; + const BIGNUM *priv_key = NULL; + ERL_NIF_TERM pub_key = atom_undefined; + ERL_NIF_TERM group_term = atom_undefined; + + if (!enif_get_resource(env, argv[0], res_type_ec_key, (void **)&obj)) + return enif_make_badarg(env); + + group = EC_KEY_get0_group(obj->key); + public_key = EC_KEY_get0_public_key(obj->key); + priv_key = EC_KEY_get0_private_key(obj->key); + + if (group) { + if (EC_GROUP_get_curve_name(group) != 0) { + /* named group */ + group_term = curve_id2term(EC_GROUP_get_curve_name(group)); + } else { + /* export group paramters */ + ERL_NIF_TERM field_term = atom_undefined; + ERL_NIF_TERM prime_term = atom_undefined; + ERL_NIF_TERM seed_term = atom_none; + ERL_NIF_TERM point_term = atom_none; + ERL_NIF_TERM order_term = atom_none; + ERL_NIF_TERM cofactor_term = atom_none; + + int nid = 0; + const EC_POINT *point = NULL; + BIGNUM *tmp = BN_new(); + BIGNUM *tmp_1 = BN_new(); + BIGNUM *tmp_2 = BN_new(); + + nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group)); + if (nid == NID_X9_62_prime_field) { + /* the parameters are specified by the prime number p */ + EC_GROUP_get_curve_GFp(group, tmp, tmp_1, tmp_2, NULL); + + /* {prime_field, Prime} */ + field_term = enif_make_tuple2(env, atom_prime_field, bn2term(env, tmp)); + } else { /* nid == NID_X9_62_characteristic_two_field */ + int field_type; + ERL_NIF_TERM basis_term; + ERL_NIF_TERM m_term; + + EC_GROUP_get_curve_GF2m(group, NULL, tmp_1, tmp_2, NULL); + + m_term = enif_make_long(env, (long)EC_GROUP_get_degree(group)); + + field_type = EC_GROUP_get_basis_type(group); + if (field_type == 0) { + basis_term = atom_undefined; + } else if (field_type == NID_X9_62_tpBasis) { + unsigned int k; + ERL_NIF_TERM k_term = atom_undefined; + + if (EC_GROUP_get_trinomial_basis(group, &k)) + k_term = enif_make_uint(env, k); + + basis_term = enif_make_tuple2(env, atom_tpbasis, k_term); + } else if (field_type == NID_X9_62_ppBasis) { + unsigned int k1, k2, k3; + ERL_NIF_TERM k1_term = atom_undefined; + ERL_NIF_TERM k2_term = atom_undefined; + ERL_NIF_TERM k3_term = atom_undefined; + + if (EC_GROUP_get_pentanomial_basis(group, &k1, &k2, &k3)) { + /* set k? values */ + k1_term = enif_make_uint(env, k1); + k2_term = enif_make_uint(env, k2); + k3_term = enif_make_uint(env, k3); + } + basis_term = enif_make_tuple4(env, atom_ppbasis, k1_term, k2_term, k3_term); + } else { /* field_type == NID_X9_62_onBasis */ + basis_term = atom_onbasis; + } + /* {characteristic_two_field, M, Basis} */ + field_term = enif_make_tuple3(env, atom_characteristic_two_field, m_term, basis_term); + } + + if (EC_GROUP_get0_seed(group)) { + unsigned char* ptr; + + ptr = enif_make_new_binary(env, EC_GROUP_get_seed_len(group), &seed_term); + memcpy(ptr, EC_GROUP_get0_seed(group), EC_GROUP_get_seed_len(group)); + } + + + /* set the base point */ + point = EC_GROUP_get0_generator(group); + if (point) + point_term = point2term(env, group, point, EC_GROUP_get_point_conversion_form(group)); + + /* set the order */ + if (EC_GROUP_get_order(group, tmp, NULL)) + order_term = bn2term(env, tmp); + + /* set the cofactor (optional) */ + if (EC_GROUP_get_cofactor(group, tmp, NULL)) + cofactor_term = bn2term(env, tmp); + + prime_term = enif_make_tuple3(env, bn2term(env, tmp_1), bn2term(env, tmp_2), seed_term); + group_term = enif_make_tuple5(env, field_term, prime_term, point_term, order_term, cofactor_term); + BN_free(tmp); + BN_free(tmp_1); + BN_free(tmp_2); + } + + if (public_key) + pub_key = point2term(env, group, public_key, EC_KEY_get_conv_form(obj->key)); + + if (order) BN_free(order); + } + + return enif_make_tuple3(env, group_term, bn2term(env, priv_key), pub_key); +#else + return atom_notsup; +#endif +} + +#if !defined(OPENSSL_NO_EC) +static int term2point(ErlNifEnv* env, ERL_NIF_TERM term, + EC_GROUP *group, EC_POINT **pptr) +{ + int ret = 0; + ErlNifBinary bin; + EC_POINT *point; + + if (!enif_inspect_binary(env,term,&bin)) { + return 0; + } + + if ((*pptr = point = EC_POINT_new(group)) == NULL) { + return 0; + } + + /* set the point conversion form */ + EC_GROUP_set_point_conversion_form(group, (point_conversion_form_t)(bin.data[0] & ~0x01)); + + /* extract the ec point */ + if (!EC_POINT_oct2point(group, point, bin.data, bin.size, NULL)) { + EC_POINT_free(point); + *pptr = NULL; + } else + ret = 1; + + return ret; +} +#endif + +static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#if !defined(OPENSSL_NO_EC) + ERL_NIF_TERM ret; + EC_KEY *key = NULL; + BIGNUM *priv_key = NULL; + EC_POINT *pub_key = NULL; + struct nif_ec_key *obj; + int c_arity = -1; + const ERL_NIF_TERM* curve; + ErlNifBinary seed; + BIGNUM *p = NULL; + BIGNUM *a = NULL; + BIGNUM *b = NULL; + BIGNUM *bn_order = NULL; + BIGNUM *cofactor = NULL; + EC_GROUP *group = NULL; + EC_POINT *point = NULL; + + if (!(argv[1] == atom_undefined || get_bn_from_mpint(env, argv[1], &priv_key)) + || !(argv[2] == atom_undefined || enif_is_binary(env, argv[2]))) { + printf("#1\n"); + goto out_err; + } + + if (enif_is_atom(env, argv[0])) { + int nid; + + nid = term2curve_id(argv[0]); + if (nid == 0) { + printf("#2\n"); + goto out_err; + } + + key = EC_KEY_new_by_curve_name(nid); + } + else if (enif_is_tuple(env, argv[0]) + && enif_get_tuple(env,argv[0],&c_arity,&curve) + && c_arity == 5 + && get_bn_from_mpint(env, curve[3], &bn_order) + && (curve[4] != atom_none && get_bn_from_mpint(env, curve[4], &cofactor))) { + //* {Field, Prime, Point, Order, CoFactor} = Curve */ + + int f_arity = -1; + const ERL_NIF_TERM* field; + int p_arity = -1; + const ERL_NIF_TERM* prime; + + long field_bits; + + /* {A, B, Seed} = Prime */ + if (!enif_get_tuple(env,curve[1],&p_arity,&prime) + || !get_bn_from_mpint(env, prime[0], &a) + || !get_bn_from_mpint(env, prime[1], &b)) + goto out_err; + + if (!enif_get_tuple(env,curve[0],&f_arity,&field)) + goto out_err; + + if (f_arity == 2 && field[0] == atom_prime_field) { + /* {prime_field, Prime} */ + + if (!get_bn_from_mpint(env, field[1], &p)) + goto out_err; + + if (BN_is_negative(p) || BN_is_zero(p)) + goto out_err; + + field_bits = BN_num_bits(p); + if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS) + goto out_err; + + /* create the EC_GROUP structure */ + group = EC_GROUP_new_curve_GFp(p, a, b, NULL); + + } else if (f_arity == 3 && field[0] == atom_characteristic_two_field) { + /* {characteristic_two_field, M, Basis} */ + + int b_arity = -1; + const ERL_NIF_TERM* basis; + unsigned int k1, k2, k3; + + if ((p = BN_new()) == NULL) + goto out_err; + + if (!enif_get_long(env, field[1], &field_bits) + || field_bits > OPENSSL_ECC_MAX_FIELD_BITS) + goto out_err; + + if (enif_get_tuple(env,field[2],&b_arity,&basis)) { + if (b_arity == 2 + && basis[0] == atom_tpbasis + && enif_get_uint(env, basis[1], &k1)) { + /* {tpbasis, k} = Basis */ + + if (!(field_bits > k1 && k1 > 0)) + goto out_err; + + /* create the polynomial */ + if (!BN_set_bit(p, (int)field_bits) + || !BN_set_bit(p, (int)k1) + || !BN_set_bit(p, 0)) + goto out_err; + + } else if (b_arity == 4 + && basis[0] == atom_ppbasis + && enif_get_uint(env, basis[1], &k1) + && enif_get_uint(env, basis[2], &k2) + && enif_get_uint(env, basis[3], &k3)) { + /* {ppbasis, k1, k2, k3} = Basis */ + + if (!(field_bits > k3 && k3 > k2 && k2 > k1 && k1 > 0)) + goto out_err; + + /* create the polynomial */ + if (!BN_set_bit(p, (int)field_bits) + || !BN_set_bit(p, (int)k1) + || !BN_set_bit(p, (int)k2) + || !BN_set_bit(p, (int)k3) + || !BN_set_bit(p, 0)) + goto out_err; + + } else + goto out_err; + } else if (field[2] == atom_onbasis) { + /* onbasis = Basis */ + /* no parameters */ + goto out_err; + + } else + goto out_err; + + group = EC_GROUP_new_curve_GF2m(p, a, b, NULL); + } else + goto out_err; + + if (enif_inspect_binary(env, prime[2], &seed)) { + EC_GROUP_set_seed(group, seed.data, seed.size); + } + + if (!term2point(env, curve[2], group, &point)) + goto out_err; + + if (BN_is_negative(bn_order) + || BN_is_zero(bn_order) + || BN_num_bits(bn_order) > (int)field_bits + 1) + goto out_err; + + if (!EC_GROUP_set_generator(group, point, bn_order, cofactor)) + goto out_err; + + EC_GROUP_set_asn1_flag(group, 0x0); + + key = EC_KEY_new(); + if (!key) + goto out_err; + EC_KEY_set_group(key, group); + } + else { + printf("#3\n"); + goto out_err; + } + + if (!key) { + printf("#4\n"); + goto out_err; + } + + if (!group) + group = EC_GROUP_dup(EC_KEY_get0_group(key)); + + if (term2point(env, argv[2], group, &pub_key)) { + if (!EC_KEY_set_public_key(key, pub_key)) { + printf("#5\n"); + goto out_err; + } + } + if (argv[1] != atom_undefined + && !BN_is_zero(priv_key)) { + if (!EC_KEY_set_private_key(key, priv_key)) + goto out_err; + + /* calculate public key (if necessary) */ + if (EC_KEY_get0_public_key(key) == NULL) + { + /* the public key was not included in the SEC1 private + * key => calculate the public key */ + pub_key = EC_POINT_new(group); + if (pub_key == NULL + || !EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group)) + || !EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL) + || !EC_KEY_set_public_key(key, pub_key)) + goto out_err; + } + } + + obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key)); + if (!obj) + goto out_err; + + obj->key = key; + ret = enif_make_resource(env, obj); + enif_release_resource(obj); + goto out; + +out_err: + if (key) EC_KEY_free(key); + ret = enif_make_badarg(env); + +out: + /* some OpenSSL structures are mem-dup'ed into the key, + so we have to free our copies here */ + if (priv_key) BN_clear_free(priv_key); + if (pub_key) EC_POINT_free(pub_key); + if (p) BN_free(p); + if (a) BN_free(a); + if (b) BN_free(b); + if (bn_order) BN_free(bn_order); + if (cofactor) BN_free(cofactor); + if (group) EC_GROUP_free(group); + return ret; +#else + return atom_notsup; +#endif +} + +static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#if !defined(OPENSSL_NO_EC) + struct nif_ec_key *obj; + + if (!enif_get_resource(env, argv[0], res_type_ec_key, (void **)&obj)) + return enif_make_badarg(env); + + if (EC_KEY_generate_key(obj->key)) + return atom_ok; + else + return atom_error; +#else + return atom_notsup; +#endif +} + +#if !defined(OPENSSL_NO_EC) +static void ec_key_dtor(ErlNifEnv* env, void* obj) +{ + struct nif_ec_key *key = (struct nif_ec_key*) obj; + EC_KEY_free(key->key); +} +#endif + +static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Type, Data|{digest,Digest}, Key) */ +#if !defined(OPENSSL_NO_EC) + ErlNifBinary data_bin, ret_bin; + unsigned char hmacbuf[SHA_DIGEST_LENGTH]; + unsigned int dsa_s_len; + struct nif_ec_key *obj; + int i; + const ERL_NIF_TERM* tpl_terms; + int tpl_arity; + struct digest_type_t *digp; + unsigned char* digest; + + digp = get_digest_type(argv[0]); + if (!digp) { + return enif_make_badarg(env); + } + if (!digp->len) { + return atom_notsup; + } + + if (!enif_get_resource(env, argv[2], res_type_ec_key, (void **)&obj)) + return enif_make_badarg(env); + + if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { + if (tpl_arity != 2 || tpl_terms[0] != atom_digest + || !enif_inspect_binary(env, tpl_terms[1], &data_bin) + || data_bin.size != digp->len) { + + return enif_make_badarg(env); + } + digest = data_bin.data; + } + else { + if (!inspect_mpint(env,argv[1],&data_bin)) { + return enif_make_badarg(env); + } + digest = hmacbuf; + digp->funcp(data_bin.data+4, data_bin.size-4, digest); + } + + enif_alloc_binary(ECDSA_size(obj->key), &ret_bin); + + i = ECDSA_sign(digp->NID_type, digest, digp->len, + ret_bin.data, &dsa_s_len, obj->key); + if (i) { + if (dsa_s_len != ret_bin.size) { + enif_realloc_binary(&ret_bin, dsa_s_len); + } + return enif_make_binary(env, &ret_bin); + } + else { + enif_release_binary(&ret_bin); + return atom_error; + } +#else + return atom_notsup; +#endif +} + +static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Type, Data|{digest,Digest}, Signature, Key) */ +#if !defined(OPENSSL_NO_EC) + ErlNifBinary data_bin, sign_bin; + unsigned char hmacbuf[SHA512_LEN]; + int i; + struct nif_ec_key *obj; + const ERL_NIF_TERM type = argv[0]; + const ERL_NIF_TERM* tpl_terms; + int tpl_arity; + struct digest_type_t* digp = NULL; + unsigned char* digest = NULL; + + digp = get_digest_type(type); + if (!digp) { + return enif_make_badarg(env); + } + if (!digp->len) { + return atom_notsup; + } + + if (!inspect_mpint(env, argv[2], &sign_bin) + || !enif_get_resource(env, argv[3], res_type_ec_key, (void **)&obj)) + return enif_make_badarg(env); + + if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { + if (tpl_arity != 2 || tpl_terms[0] != atom_digest + || !enif_inspect_binary(env, tpl_terms[1], &data_bin) + || data_bin.size != digp->len) { + + return enif_make_badarg(env); + } + digest = data_bin.data; + } + else if (inspect_mpint(env, argv[1], &data_bin)) { + digest = hmacbuf; + digp->funcp(data_bin.data+4, data_bin.size-4, digest); + } + else { + return enif_make_badarg(env); + } + + i = ECDSA_verify(digp->NID_type, digest, digp->len, + sign_bin.data+4, sign_bin.size-4, obj->key); + + return (i==1 ? atom_true : atom_false); +#else + return atom_notsup; +#endif +} + +/* + (_OthersPublicKey, _MyPrivateKey) + (_OthersPublicKey, _MyEC_Point) +*/ +static ERL_NIF_TERM ecdh_compute_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#if !defined(OPENSSL_NO_EC) + ERL_NIF_TERM ret; + unsigned char *p; + struct nif_ec_key *other_key; + int field_size = 0; + int i; + + EC_GROUP *group; + const BIGNUM *priv_key; + EC_POINT *my_ecpoint; + EC_KEY *other_ecdh = NULL; + + if (!enif_get_resource(env, argv[0], res_type_ec_key, (void **)&other_key)) + return enif_make_badarg(env); + + group = EC_GROUP_dup(EC_KEY_get0_group(other_key->key)); + priv_key = EC_KEY_get0_private_key(other_key->key); + + if (!term2point(env, argv[1], group, &my_ecpoint)) { + struct nif_ec_key *my_key; + + if (!enif_get_resource(env, argv[1], res_type_ec_key, (void **)&my_key)) + goto out_err; + + if ((my_ecpoint = EC_POINT_new(group)) == NULL) + goto out_err; + EC_POINT_copy(my_ecpoint, EC_KEY_get0_public_key(my_key->key)); + } + + if ((other_ecdh = EC_KEY_new()) == NULL + || !EC_KEY_set_group(other_ecdh, group) + || !EC_KEY_set_private_key(other_ecdh, priv_key)) + goto out_err; + + field_size = EC_GROUP_get_degree(group); + if (field_size <= 0) + goto out_err; + + p = enif_make_new_binary(env, (field_size+7)/8, &ret); + i = ECDH_compute_key(p, (field_size+7)/8, my_ecpoint, other_ecdh, NULL); + + if (i < 0) + goto out_err; +out: + if (group) EC_GROUP_free(group); + if (my_ecpoint) EC_POINT_free(my_ecpoint); + if (other_ecdh) EC_KEY_free(other_ecdh); + + return ret; + +out_err: + ret = enif_make_badarg(env); + goto out; +#else + return atom_notsup; +#endif +} /* HMAC */ diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 6b9b2ef207..e0617e33b2 100755..100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -63,6 +63,20 @@ <item> <p>dss: Digital Signature Standard (FIPS 186-2)</p> </item> + <item> + <p>ecdsa: "Public Key Cryptography for the Financial + Services Industry: The Elliptic Curve Digital + Signature Standard (ECDSA)", November, 2005.</p> + </item> + <item> + <p>ec: Standards for Efficient Cryptography Group (SECG), "SEC 1: + Elliptic Curve Cryptography", Version 1.0, September 2000.</p> + </item> + <item> + <p>ecdsa: American National Standards Institute (ANSI), + ANS X9.62-2005: The Elliptic Curve Digital Signature + Algorithm (ECDSA), 2005.</p> + </item> </list> <p>The above publications can be found at <url href="http://csrc.nist.gov/publications">NIST publications</url>, at <url href="http://www.ietf.org">IETF</url>. </p> @@ -99,6 +113,14 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> </desc> </func> <func> + <name>algorithms() -> [atom()]</name> + <fsummary>Provide a list of available crypto algorithms.</fsummary> + <desc> + <p>Provides the available crypto algorithms in terms of a list + of atoms.</p> + </desc> + </func> + <func> <name>info_lib() -> [{Name,VerNum,VerStr}]</name> <fsummary>Provides information about the libraries used by crypto.</fsummary> <type> @@ -1256,6 +1278,205 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> </desc> </func> + <func> + <name>srp_mod_exp(Generator, Exponent, Prime) -> Result</name> + <fsummary>Computes the SRP-SHA function: g^x % N</fsummary> + <type> + <v>Generator, Exponent, Prime = binary()</v> + <v>Result = binary() | error</v> + </type> + <desc> + <p>Computes the SRP-SHA function g^x % N used for the verifier and client public key (RFC-2945, Sect. 3) + </p> + </desc> + </func> + + <func> + <name>srp_value_B(Multiplier, Verifier, Generator, Exponent, Prime) -> ValueB</name> + <fsummary>Computes the SRP function: B = k*v + g^b % N</fsummary> + <type> + <v>Verifier (v), Generator (g), Exponent (b), Prime (N), ValueB (B) = binary()</v> + <v>Multiplier (k) = integer() | binary()</v> + </type> + <desc> + <p>Computes the SRP value B according to RFC-2945, Sect. 3 and RFC-5054, Sect. 2.5.3</p> + <p>B = k*v + g^b % N</p> + </desc> + </func> + + <func> + <name>srp_client_secret(A, U, B, Multiplier, Generator, Exponent, Prime) -> Secret</name> + <fsummary>Computes the SRP client secret</fsummary> + <type> + <v>A (a), U (u), B, Multiplier (k), Generator (g), Exponent (x), Prime (N), Secret = binary()</v> + <v>Multiplier (k) = integer() | binary()</v> + </type> + <desc> + <p>Computes the SRP client secret according to RFC-2945, Sect. 3 and RFC-5054, Sect. 2.6</p> + <p>Secret = (B - (k * g^x)) ^ (a + (u * x)) % N</p> + </desc> + </func> + + <func> + <name>srp_server_secret(Verifier, B, U, A, Prime) -> Secret</name> + <fsummary>Computes the SRP host secret</fsummary> + <type> + <v>Verifier (v), B (b), U (u), A, Prime (N), Secret = binary()</v> + </type> + <desc> + <p>Computes the SRP host secret according to RFC-2945, Sect. 3 and RFC-5054, Sect. 2.6</p> + <p>Secret = (A * v^u) ^ b % N</p> + </desc> + </func> + + <func> + <name>srp3_value_u(B) -> Result</name> + <fsummary>Computes the SRP3-SHA value u</fsummary> + <type> + <v>B = binary()</v> + <v>Result = integer()</v> + </type> + <desc> + <p>Computes the SRP-3 value u according to RFC-2945, Sect. 3 + </p> + </desc> + </func> + + <func> + <name>srp6_value_u(A, B, Prime) -> Result</name> + <fsummary>Computes the SRP6a value u as u = SHA1(PAD(A) | PAD(B))</fsummary> + <type> + <v>A, B, Prime = binary()</v> + <v>Result = integer()</v> + </type> + <desc> + <p>Computes the SRP-6 value u according to RFC-5054, Sect. 2.6 + </p> + </desc> + </func> + + <func> + <name>srp6a_multiplier(Generator, Prime) -> Result</name> + <fsummary>Computes the SRP-SHA function: k = SHA1(N | PAD(g))</fsummary> + <type> + <v>Generator, Prime = binary()</v> + <v>Result = integer()</v> + </type> + <desc> + <p>Computes the SRP-6a function SHA1(N | PAD(g)) as the multiplier + </p> + </desc> + </func> + + <func> + <name>ec_key_new(NamedCurve) -> ECKey</name> + <type> + <v>NamedCurve = atom()</v> + <v>ECKey = EC key resource()</v> + </type> + <desc> + <p>Generate an new EC key from the named curve. The private key + will be initialized with random data. + </p> + </desc> + </func> + + <func> + <name>ec_key_generate(ECKey) -> ok | error</name> + <type> + <v>ECKey = EC key resource()</v> + </type> + <desc> + <p>Fills in the public key if only the private key is known or generates + a new private/public key pair if only the curve parameters are known. + </p> + </desc> + </func> + + <func> + <name>ec_key_to_term(ECKey) -> ECKeyTerm.</name> + <type> + <v>ECKey = EC key resource()</v> + <v>ECKeyTerm = EC key as Erlang term</v> + </type> + <desc> + <p>Convert a EC key from a NIF resource into an Erlang term. + </p> + </desc> + </func> + + <func> + <name>term_to_ec_key(ECKeyTerm) -> ECKey</name> + <type> + <v>ECKeyTerm = EC key as Erlang term</v> + <v>ECKey = EC key resource()</v> + </type> + <desc> + <p>Convert a EC key an Erlang term into a NIF resource. + </p> + </desc> + </func> + + <func> + <name>ecdsa_sign(DataOrDigest, ECKey) -> Signature</name> + <name>ecdsa_sign(DigestType, DataOrDigest, ECKey) -> Signature</name> + <fsummary>Sign the data using ecdsa with the given key.</fsummary> + <type> + <v>DataOrDigest = Data | {digest,Digest}</v> + <v>Data = Mpint</v> + <v>Digest = binary()</v> + <v>ECKey = EC key resource()</v> + <v>DigestType = md5 | sha | sha256 | sha384 | sha512</v> + <d>The default <c>DigestType</c> is sha.</d> + <v>Mpint = binary()</v> + <v>Signature = binary()</v> + </type> + <desc> + <p>Creates a ESDSA signature with the private key <c>Key</c> + of a digest. The digest is either calculated as a + <c>DigestType</c> digest of <c>Data</c> or a precalculated + binary <c>Digest</c>.</p> + </desc> + </func> + + <func> + <name>ecdsa_verify(DataOrDigest, Signature, ECKey) -> Verified</name> + <name>ecdsa_verify(DigestType, DataOrDigest, Signature, ECKey) -> Verified </name> + <fsummary>Verify the digest and signature using ecdsa with given public key.</fsummary> + <type> + <v>Verified = boolean()</v> + <v>DataOrDigest = Data | {digest|Digest}</v> + <v>Data, Signature = Mpint</v> + <v>Digest = binary()</v> + <v>ECKey = EC key resource()</v> + <v>DigestType = md5 | sha | sha256 | sha384 | sha512</v> + <d>The default <c>DigestType</c> is sha.</d> + <v>Mpint = binary()</v> + </type> + <desc> + <p>Verifies that a digest matches the ECDSA signature using the + signer's public key <c>Key</c>. + The digest is either calculated as a <c>DigestType</c> + digest of <c>Data</c> or a precalculated binary <c>Digest</c>.</p> + <p>May throw exception <c>notsup</c> in case the chosen <c>DigestType</c> + is not supported by the underlying OpenSSL implementation.</p> + </desc> + </func> + + <func> + <name>ecdh_compute_key(OthersPublicKey, MyPrivateKey) -> SharedSecret</name> + <name>ecdh_compute_key(OthersPublicKey, MyECPoint) -> SharedSecret</name> + <fsummary>Computes the shared secret</fsummary> + <type> + <v>OthersPublicKey, MyPrivateKey = ECKey()</v> + <v>MyPrivatePoint = binary()</v> + <v>SharedSecret = binary()</v> + </type> + <desc> + <p>Computes the shared secret from the private key and the other party's public key. + </p> + </desc> + </func> <func> <name>exor(Data1, Data2) -> Result</name> @@ -1271,6 +1492,29 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> </funcs> <section> + <title>Elliptic Curve Key</title> + <p>Elliptic Curve keys consist of the curve paramters and a the + private and public keys (points on the curve). Translating the + raw curve paraters into something usable for the underlying + OpenSSL implementation is a complicated process. The main cryptografic + functions therefore expect a NIF resource as input that contains the + key in an internal format. Two functions <b>ec_key_to_term/1</b> + and <b>term_to_ec_key</b> are provided to convert between Erlang + terms and the resource format</p> + <p><em>Key in term form</em></p> + <pre> +ec_named_curve() = atom() +ec_point() = binary() +ec_basis() = {tpbasis, K :: non_neg_integer()} | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | onbasis +ec_field() = {prime_field, Prime :: Mpint()} | {characteristic_two_field, M :: integer(), Basis :: ec_basis()} +ec_prime() = {A :: Mpint(), B :: Mpint(), Seed :: binary()} +ec_curve_spec() = {Field :: ec_field(), Prime :: ec_prime(), Point :: ec_point(), Order :: Mpint(), CoFactor :: none | Mpint()} +ec_curve() = ec_named_curve() | ec_curve_spec() +ec_key() = {Curve :: ec_curve(), PrivKey :: Mpint() | undefined, PubKey :: ec_point() | undefined} + </pre> + </section> + + <section> <title>DES in CBC mode</title> <p>The Data Encryption Standard (DES) defines an algorithm for encrypting and decrypting an 8 byte quantity using an 8 byte key diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 1328a95e87..b7cf8d1de1 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -21,7 +21,7 @@ -module(crypto). --export([start/0, stop/0, info/0, info_lib/0, version/0]). +-export([start/0, stop/0, info/0, info_lib/0, algorithms/0, version/0]). -export([hash/2, hash_init/1, hash_update/2, hash_final/1]). -export([md4/1, md4_init/0, md4_update/2, md4_final/1]). -export([md5/1, md5_init/0, md5_update/2, md5_final/1]). @@ -58,12 +58,18 @@ -export([rand_bytes/1, rand_bytes/3, rand_uniform/2]). -export([strong_rand_bytes/1, strong_rand_mpint/3]). -export([mod_exp/3, mpint/1, erlint/1]). +-export([srp_mod_exp/3, srp_value_B/5]). +-export([srp3_value_u/1, srp6_value_u/3, srp6a_multiplier/2]). +-export([srp_client_secret/7, srp_server_secret/5]). + %% -export([idea_cbc_encrypt/3, idea_cbc_decrypt/3]). -export([aes_cbc_128_encrypt/3, aes_cbc_128_decrypt/3]). -export([aes_cbc_256_encrypt/3, aes_cbc_256_decrypt/3]). -export([aes_cbc_ivec/1]). -export([aes_ctr_encrypt/3, aes_ctr_decrypt/3]). -export([aes_ctr_stream_init/2, aes_ctr_stream_encrypt/2, aes_ctr_stream_decrypt/2]). +-export([ec_key_new/1, ec_key_to_term/1, term_to_ec_key/1, ec_key_generate/1]). +-export([ecdsa_sign/2, ecdsa_sign/3, ecdsa_verify/3, ecdsa_verify/4, ecdh_compute_key/2]). -export([dh_generate_parameters/2, dh_check/1]). %% Testing see below @@ -109,12 +115,28 @@ hash, hash_init, hash_update, hash_final, hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, info, rc2_cbc_encrypt, rc2_cbc_decrypt, - info_lib]). - + srp_mod_exp, srp_value_B, + srp3_value_u, srp6_value_u, srp6a_multiplier, + srp_client_secret, srp_server_secret, + ec_key_new, ec_key_to_term, term_to_ec_key, ec_key_generate, + ecdsa_sign, ecdsa_verify, ecdh_compute_key, + info_lib, algorithms]). + +-type mpint() :: binary(). -type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'. -type dss_digest_type() :: 'none' | 'sha'. +-type ecdsa_digest_type() :: 'md5' | 'sha' | 'sha256' | 'sha384' | 'sha512'. -type data_or_digest() :: binary() | {digest, binary()}. -type crypto_integer() :: binary() | integer(). +-type ec_key_res() :: any(). %% nif resource +-type ec_named_curve() :: atom(). +-type ec_point() :: binary(). +-type ec_basis() :: {tpbasis, K :: non_neg_integer()} | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | onbasis. +-type ec_field() :: {prime_field, Prime :: mpint()} | {characteristic_two_field, M :: integer(), Basis :: ec_basis()}. +-type ec_prime() :: {A :: mpint(), B :: mpint(), Seed :: binary()}. +-type ec_curve_spec() :: {Field :: ec_field(), Prime :: ec_prime(), Point :: ec_point(), Order :: mpint(), CoFactor :: none | mpint()}. +-type ec_curve() :: ec_named_curve() | ec_curve_spec(). +-type ec_key() :: {Curve :: ec_curve(), PrivKey :: mpint() | undefined, PubKey :: ec_point() | undefined}. -define(nif_stub,nif_stub_error(?LINE)). @@ -184,6 +206,8 @@ info() -> info_lib() -> ?nif_stub. +algorithms() -> ?nif_stub. + %% Crypto app version history: %% (no version): Driver implementation %% 2.0 : NIF implementation, requires OTP R14 @@ -1065,9 +1089,160 @@ dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) -> dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub. %% +%% EC +%% +-spec ec_key_new(ec_named_curve()) -> ec_key_res(). +ec_key_new(_Curve) -> ?nif_stub. + +-spec ec_key_generate(ec_key_res()) -> ok | error. +ec_key_generate(_Key) -> ?nif_stub. + +nif_prime_to_term({prime_field, Prime}) -> + {prime_field, erlint(Prime)}; +nif_prime_to_term(PrimeField) -> + PrimeField. +nif_curve_to_term({A, B, Seed}) -> + {erlint(A), erlint(B), Seed}. +nif_curve_parameters_to_term({PrimeField, Curve, BasePoint, Order, CoFactor}) -> + {nif_prime_to_term(PrimeField), nif_curve_to_term(Curve), BasePoint, erlint(Order), erlint(CoFactor)}; +nif_curve_parameters_to_term(Curve) when is_atom(Curve) -> + %% named curve + Curve. + +-spec ec_key_to_term(ec_key_res()) -> ec_key(). +ec_key_to_term(Key) -> + case ec_key_to_term_nif(Key) of + {Curve, PrivKey, PubKey} -> + {nif_curve_parameters_to_term(Curve), erlint(PrivKey), PubKey}; + _ -> + erlang:error(conversion_failed) + end. + +ec_key_to_term_nif(_Key) -> ?nif_stub. + +term_to_nif_prime({prime_field, Prime}) -> + {prime_field, mpint(Prime)}; +term_to_nif_prime(PrimeField) -> + PrimeField. +term_to_nif_curve({A, B, Seed}) -> + {mpint(A), mpint(B), Seed}. +term_to_nif_curve_parameters({PrimeField, Curve, BasePoint, Order, CoFactor}) -> + {term_to_nif_prime(PrimeField), term_to_nif_curve(Curve), BasePoint, mpint(Order), mpint(CoFactor)}; +term_to_nif_curve_parameters(Curve) when is_atom(Curve) -> + %% named curve + Curve. + +-spec term_to_ec_key(ec_key()) -> ec_key_res(). +term_to_ec_key({Curve, undefined, PubKey}) -> + term_to_ec_key_nif(term_to_nif_curve_parameters(Curve), undefined, PubKey); +term_to_ec_key({Curve, PrivKey, PubKey}) -> + term_to_ec_key_nif(term_to_nif_curve_parameters(Curve), mpint(PrivKey), PubKey). + +term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub. + +%% +%% ECDSA - sign +%% +-spec ecdsa_sign(data_or_digest(), ec_key_res()) -> binary(). +-spec ecdsa_sign(ecdsa_digest_type(), data_or_digest(), ec_key_res()) -> binary(). + +ecdsa_sign(DataOrDigest,Key) -> + ecdsa_sign(sha, DataOrDigest, Key). +ecdsa_sign(Type, DataOrDigest, Key) -> + case ecdsa_sign_nif(Type,DataOrDigest,Key) of + error -> erlang:error(badkey, [Type,DataOrDigest,Key]); + Sign -> Sign + end. + +ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub. + +%% +%% ECDSA - verify +%% +-spec ecdsa_verify(data_or_digest(), binary(), ec_key_res()) -> boolean(). +-spec ecdsa_verify(ecdsa_digest_type(), data_or_digest(), binary(), ec_key_res()) -> + boolean(). + +ecdsa_verify(Data,Signature,Key) -> + ecdsa_verify_nif(sha, Data,Signature,Key). +ecdsa_verify(Type, DataOrDigest, Signature, Key) -> + case ecdsa_verify_nif(Type, DataOrDigest, Signature, Key) of + notsup -> erlang:error(notsup); + Bool -> Bool + end. + +ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Key) -> ?nif_stub. + +-spec ecdh_compute_key(ec_key_res(), ec_key_res() | ec_point()) -> binary(). +ecdh_compute_key(_Others, _My) -> ?nif_stub. + +%% +%% SRP functions +%% +-spec srp_mod_exp(binary(), binary(), binary()) -> binary(). +srp_mod_exp(Generator, Exponent, Prime) -> + Verifier = mod_exp_nif(bin2bn(Generator), bin2bn(Exponent), bin2bn(Prime)), + case erlint(Verifier) of + 0 -> error; + _ -> bn2bin(Verifier) + end. + +-spec srp_value_B(binary(), integer(), binary(), binary(), binary()) -> binary(). +srp_value_B(Multiplier, Verifier, Generator, Exponent, Prime) -> + srp_value_B_nif(srp_multiplier(Multiplier), Verifier, Generator, Exponent, Prime). + +srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub. + +-spec srp_client_secret(binary(), binary(), binary(), integer()|binary(), binary(), binary(), binary()) -> binary(). +srp_client_secret(A, U, B, Multiplier, Generator, Exponent, Prime) -> + srp_client_secret_nif(A, U, B, srp_multiplier(Multiplier), Generator, Exponent, Prime). + +srp_client_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub. + +-spec srp_server_secret(binary(), binary(), binary(), binary(), binary()) -> binary(). +srp_server_secret(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub. + +-spec srp6a_multiplier(binary(), binary()) -> binary(). +srp6a_multiplier(Generator, Prime) -> + %% k = SHA1(N | PAD(g)) + C0 = sha_init(), + C1 = sha_update(C0, Prime), + C2 = sha_update(C1, srp_pad_to(erlang:byte_size(Prime), Generator)), + sha_final(C2). + +-spec srp3_value_u(binary()) -> binary(). +srp3_value_u(B) -> + %% The parameter u is a 32-bit unsigned integer which takes its value + %% from the first 32 bits of the SHA1 hash of B, MSB first. + <<U:32/bits, _/binary>> = sha(B), + U. + +-spec srp6_value_u(binary(), binary(), binary()) -> binary(). +srp6_value_u(A, B, Prime) -> + %% SHA1(PAD(A) | PAD(B)) + PadLength = erlang:byte_size(Prime), + C0 = sha_init(), + C1 = sha_update(C0, srp_pad_to(PadLength, A)), + C2 = sha_update(C1, srp_pad_to(PadLength, B)), + sha_final(C2). + +%% %% LOCAL FUNCTIONS %% +srp_pad_length(Width, Length) -> + (Width - Length rem Width) rem Width. + +srp_pad_to(Width, Binary) -> + case srp_pad_length(Width, size(Binary)) of + 0 -> Binary; + N -> << 0:(N*8), Binary/binary>> + end. + +srp_multiplier(Multiplier) when is_binary(Multiplier) -> + bin2bn(Multiplier); +srp_multiplier(Multiplier) when is_integer(Multiplier) -> + mpint(Multiplier). %% large integer in a binary with 32bit length %% MP representaion (SSH2) @@ -1110,4 +1285,13 @@ mpint_pos(X,I,Ds) -> erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) -> Bits= MPIntSize * 8, <<Integer:Bits/integer>> = MPIntValue, - Integer. + Integer; +erlint(undefined) -> + undefined. + +bin2bn(Bin) -> + Len = erlang:byte_size(Bin), + <<?UINT32(Len), Bin/binary>>. + +bn2bin(<<_:32, Bin/binary>>) -> + Bin. diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 6f2df0f07b..c2d843204d 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -39,7 +39,10 @@ hmac_update_md5_io/1, hmac_update_md5_n/1, hmac_rfc2202/1, - hmac_rfc4231/1, + hmac_rfc4231_sha224/1, + hmac_rfc4231_sha256/1, + hmac_rfc4231_sha384/1, + hmac_rfc4231_sha512/1, ripemd160/1, ripemd160_update/1, sha256/1, @@ -72,6 +75,8 @@ dsa_sign_hash_test/1, rsa_encrypt_decrypt/1, dh/1, + srp3/1, srp6/1, srp6a/1, + ec/1, exor_test/1, rc4_test/1, rc4_stream_test/1, @@ -93,14 +98,15 @@ groups() -> sha256, sha256_update, sha512, sha512_update, hmac_update_sha, hmac_update_sha_n, hmac_update_sha256, hmac_update_sha512, hmac_update_md5_n, hmac_update_md5_io, hmac_update_md5, - hmac_rfc2202, hmac_rfc4231, + hmac_rfc2202, hmac_rfc4231_sha224, hmac_rfc4231_sha256, + hmac_rfc4231_sha384, hmac_rfc4231_sha512, des_cbc, aes_cfb, aes_cbc, des_cfb, des_cfb_iter, des3_cbc, des3_cfb, rc2_cbc, aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb, rand_uniform_test, strong_rand_test, rsa_verify_test, dsa_verify_test, rsa_sign_test, rsa_sign_hash_test, dsa_sign_test, dsa_sign_hash_test, - rsa_encrypt_decrypt, dh, exor_test, + rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, ec, exor_test, rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64, smp]}]. @@ -363,8 +369,7 @@ hmac_update_sha256(doc) -> hmac_update_sha256(suite) -> []; hmac_update_sha256(Config) when is_list(Config) -> - if_098(fun() -> hmac_update_sha256_do() end). - + if_supported(sha256, fun() -> hmac_update_sha256_do() end). hmac_update_sha256_do() -> ?line Key = hexstr2bin("00010203101112132021222330313233" @@ -386,7 +391,7 @@ hmac_update_sha512(doc) -> hmac_update_sha512(suite) -> []; hmac_update_sha512(Config) when is_list(Config) -> - if_098(fun() -> hmac_update_sha512_do() end). + if_supported(sha512, fun() -> hmac_update_sha512_do() end). hmac_update_sha512_do() -> ?line Key = hexstr2bin("00010203101112132021222330313233" @@ -582,366 +587,192 @@ hmac_rfc2202_sha() -> ?line m(Case7Exp, Case7Mac_1), ?line m(Case7Exp, Case7Mac_2). -hmac_rfc4231(doc) -> - ["Generate an HMAC using crypto:shaXXX_mac, hmac, and hmac_init, hmac_update, and hmac_final. " +hmac_rfc4231_sha224(doc) -> + ["Generate an HMAC using crypto:sha224_mac, hmac, and hmac_init, hmac_update, and hmac_final. " "Testvectors are take from RFC4231." ]; -hmac_rfc4231(suite) -> +hmac_rfc4231_sha224(suite) -> []; -hmac_rfc4231(Config) when is_list(Config) -> - if_098(fun() -> hmac_rfc4231_do() end). +hmac_rfc4231_sha224(Config) when is_list(Config) -> + if_supported(sha224, fun() -> hmac_rfc4231_sha224_do() end). -hmac_rfc4231_do() -> - %% Test Case 1 - Case1Key = binary:copy(<<16#0b>>, 20), - Case1Data = <<"Hi There">>, - Case1Exp224 = hexstr2bin("896fb1128abbdf196832107cd49df33f" - "47b4b1169912ba4f53684b22"), - Case1Exp256 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b" - "881dc200c9833da726e9376c2e32cff7"), - Case1Exp384 = hexstr2bin("afd03944d84895626b0825f4ab46907f" - "15f9dadbe4101ec682aa034c7cebc59c" - "faea9ea9076ede7f4af152e8b2fa9cb6"), - Case1Exp512 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0" - "2379f4e2ce4ec2787ad0b30545e17cde" - "daa833b7d6b8a702038b274eaea3f4e4" - "be9d914eeb61f1702e696c203a126854"), - - ?line Case1Ctx224 = crypto:hmac_init(sha224, Case1Key), - ?line Case1Ctx224_2 = crypto:hmac_update(Case1Ctx224, Case1Data), - ?line Case1Mac224_1 = crypto:hmac_final(Case1Ctx224_2), - ?line Case1Mac224_2 = crypto:sha224_mac(Case1Key, Case1Data), - ?line Case1Mac224_3 = crypto:hmac(sha224, Case1Key, Case1Data), - ?line m(Case1Exp224, Case1Mac224_1), - ?line m(Case1Exp224, Case1Mac224_2), - ?line m(Case1Exp224, Case1Mac224_3), - - ?line Case1Ctx256 = crypto:hmac_init(sha256, Case1Key), - ?line Case1Ctx256_2 = crypto:hmac_update(Case1Ctx256, Case1Data), - ?line Case1Mac256_1 = crypto:hmac_final(Case1Ctx256_2), - ?line Case1Mac256_2 = crypto:sha256_mac(Case1Key, Case1Data), - ?line Case1Mac256_3 = crypto:hmac(sha256, Case1Key, Case1Data), - ?line m(Case1Exp256, Case1Mac256_1), - ?line m(Case1Exp256, Case1Mac256_2), - ?line m(Case1Exp256, Case1Mac256_3), - - ?line Case1Ctx384 = crypto:hmac_init(sha384, Case1Key), - ?line Case1Ctx384_2 = crypto:hmac_update(Case1Ctx384, Case1Data), - ?line Case1Mac384_1 = crypto:hmac_final(Case1Ctx384_2), - ?line Case1Mac384_2 = crypto:sha384_mac(Case1Key, Case1Data), - ?line Case1Mac384_3 = crypto:hmac(sha384, Case1Key, Case1Data), - ?line m(Case1Exp384, Case1Mac384_1), - ?line m(Case1Exp384, Case1Mac384_2), - ?line m(Case1Exp384, Case1Mac384_3), - - ?line Case1Ctx512 = crypto:hmac_init(sha512, Case1Key), - ?line Case1Ctx512_2 = crypto:hmac_update(Case1Ctx512, Case1Data), - ?line Case1Mac512_1 = crypto:hmac_final(Case1Ctx512_2), - ?line Case1Mac512_2 = crypto:sha512_mac(Case1Key, Case1Data), - ?line Case1Mac512_3 = crypto:hmac(sha512, Case1Key, Case1Data), - ?line m(Case1Exp512, Case1Mac512_1), - ?line m(Case1Exp512, Case1Mac512_2), - ?line m(Case1Exp512, Case1Mac512_3), - - %% Test Case 2 - Case2Key = <<"Jefe">>, - Case2Data = <<"what do ya want for nothing?">>, - Case2Exp224 = hexstr2bin("a30e01098bc6dbbf45690f3a7e9e6d0f" - "8bbea2a39e6148008fd05e44"), - Case2Exp256 = hexstr2bin("5bdcc146bf60754e6a042426089575c7" - "5a003f089d2739839dec58b964ec3843"), - Case2Exp384 = hexstr2bin("af45d2e376484031617f78d2b58a6b1b" - "9c7ef464f5a01b47e42ec3736322445e" - "8e2240ca5e69e2c78b3239ecfab21649"), - Case2Exp512 = hexstr2bin("164b7a7bfcf819e2e395fbe73b56e0a3" - "87bd64222e831fd610270cd7ea250554" - "9758bf75c05a994a6d034f65f8f0e6fd" - "caeab1a34d4a6b4b636e070a38bce737"), - - ?line Case2Ctx224 = crypto:hmac_init(sha224, Case2Key), - ?line Case2Ctx224_2 = crypto:hmac_update(Case2Ctx224, Case2Data), - ?line Case2Mac224_1 = crypto:hmac_final(Case2Ctx224_2), - ?line Case2Mac224_2 = crypto:sha224_mac(Case2Key, Case2Data), - ?line Case2Mac224_3 = crypto:hmac(sha224, Case2Key, Case2Data), - ?line m(Case2Exp224, Case2Mac224_1), - ?line m(Case2Exp224, Case2Mac224_2), - ?line m(Case2Exp224, Case2Mac224_3), - - ?line Case2Ctx256 = crypto:hmac_init(sha256, Case2Key), - ?line Case2Ctx256_2 = crypto:hmac_update(Case2Ctx256, Case2Data), - ?line Case2Mac256_1 = crypto:hmac_final(Case2Ctx256_2), - ?line Case2Mac256_2 = crypto:sha256_mac(Case2Key, Case2Data), - ?line Case2Mac256_3 = crypto:hmac(sha256, Case2Key, Case2Data), - ?line m(Case2Exp256, Case2Mac256_1), - ?line m(Case2Exp256, Case2Mac256_2), - ?line m(Case2Exp256, Case2Mac256_3), - - ?line Case2Ctx384 = crypto:hmac_init(sha384, Case2Key), - ?line Case2Ctx384_2 = crypto:hmac_update(Case2Ctx384, Case2Data), - ?line Case2Mac384_1 = crypto:hmac_final(Case2Ctx384_2), - ?line Case2Mac384_2 = crypto:sha384_mac(Case2Key, Case2Data), - ?line Case2Mac384_3 = crypto:hmac(sha384, Case2Key, Case2Data), - ?line m(Case2Exp384, Case2Mac384_1), - ?line m(Case2Exp384, Case2Mac384_2), - ?line m(Case2Exp384, Case2Mac384_3), - - ?line Case2Ctx512 = crypto:hmac_init(sha512, Case2Key), - ?line Case2Ctx512_2 = crypto:hmac_update(Case2Ctx512, Case2Data), - ?line Case2Mac512_1 = crypto:hmac_final(Case2Ctx512_2), - ?line Case2Mac512_2 = crypto:sha512_mac(Case2Key, Case2Data), - ?line Case2Mac512_3 = crypto:hmac(sha512, Case2Key, Case2Data), - ?line m(Case2Exp512, Case2Mac512_1), - ?line m(Case2Exp512, Case2Mac512_2), - ?line m(Case2Exp512, Case2Mac512_3), - - %% Test Case 3 - Case3Key = binary:copy(<<16#aa>>, 20), - Case3Data = binary:copy(<<16#dd>>, 50), - Case3Exp224 = hexstr2bin("7fb3cb3588c6c1f6ffa9694d7d6ad264" - "9365b0c1f65d69d1ec8333ea"), - Case3Exp256 = hexstr2bin("773ea91e36800e46854db8ebd09181a7" - "2959098b3ef8c122d9635514ced565fe"), - Case3Exp384 = hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f" - "0aa635d947ac9febe83ef4e55966144b" - "2a5ab39dc13814b94e3ab6e101a34f27"), - Case3Exp512 = hexstr2bin("fa73b0089d56a284efb0f0756c890be9" - "b1b5dbdd8ee81a3655f83e33b2279d39" - "bf3e848279a722c806b485a47e67c807" - "b946a337bee8942674278859e13292fb"), - - ?line Case3Ctx224 = crypto:hmac_init(sha224, Case3Key), - ?line Case3Ctx224_2 = crypto:hmac_update(Case3Ctx224, Case3Data), - ?line Case3Mac224_1 = crypto:hmac_final(Case3Ctx224_2), - ?line Case3Mac224_2 = crypto:sha224_mac(Case3Key, Case3Data), - ?line Case3Mac224_3 = crypto:hmac(sha224, Case3Key, Case3Data), - ?line m(Case3Exp224, Case3Mac224_1), - ?line m(Case3Exp224, Case3Mac224_2), - ?line m(Case3Exp224, Case3Mac224_3), - - ?line Case3Ctx256 = crypto:hmac_init(sha256, Case3Key), - ?line Case3Ctx256_2 = crypto:hmac_update(Case3Ctx256, Case3Data), - ?line Case3Mac256_1 = crypto:hmac_final(Case3Ctx256_2), - ?line Case3Mac256_2 = crypto:sha256_mac(Case3Key, Case3Data), - ?line Case3Mac256_3 = crypto:hmac(sha256, Case3Key, Case3Data), - ?line m(Case3Exp256, Case3Mac256_1), - ?line m(Case3Exp256, Case3Mac256_2), - ?line m(Case3Exp256, Case3Mac256_3), - - ?line Case3Ctx384 = crypto:hmac_init(sha384, Case3Key), - ?line Case3Ctx384_2 = crypto:hmac_update(Case3Ctx384, Case3Data), - ?line Case3Mac384_1 = crypto:hmac_final(Case3Ctx384_2), - ?line Case3Mac384_2 = crypto:sha384_mac(Case3Key, Case3Data), - ?line Case3Mac384_3 = crypto:hmac(sha384, Case3Key, Case3Data), - ?line m(Case3Exp384, Case3Mac384_1), - ?line m(Case3Exp384, Case3Mac384_2), - ?line m(Case3Exp384, Case3Mac384_3), - - ?line Case3Ctx512 = crypto:hmac_init(sha512, Case3Key), - ?line Case3Ctx512_2 = crypto:hmac_update(Case3Ctx512, Case3Data), - ?line Case3Mac512_1 = crypto:hmac_final(Case3Ctx512_2), - ?line Case3Mac512_2 = crypto:sha512_mac(Case3Key, Case3Data), - ?line Case3Mac512_3 = crypto:hmac(sha512, Case3Key, Case3Data), - ?line m(Case3Exp512, Case3Mac512_1), - ?line m(Case3Exp512, Case3Mac512_2), - ?line m(Case3Exp512, Case3Mac512_3), - - %% Test Case 4 - Case4Key = list_to_binary(lists:seq(1, 16#19)), - Case4Data = binary:copy(<<16#cd>>, 50), - Case4Exp224 = hexstr2bin("6c11506874013cac6a2abc1bb382627c" - "ec6a90d86efc012de7afec5a"), - Case4Exp256 = hexstr2bin("82558a389a443c0ea4cc819899f2083a" - "85f0faa3e578f8077a2e3ff46729665b"), - Case4Exp384 = hexstr2bin("3e8a69b7783c25851933ab6290af6ca7" - "7a9981480850009cc5577c6e1f573b4e" - "6801dd23c4a7d679ccf8a386c674cffb"), - Case4Exp512 = hexstr2bin("b0ba465637458c6990e5a8c5f61d4af7" - "e576d97ff94b872de76f8050361ee3db" - "a91ca5c11aa25eb4d679275cc5788063" - "a5f19741120c4f2de2adebeb10a298dd"), - - ?line Case4Ctx224 = crypto:hmac_init(sha224, Case4Key), - ?line Case4Ctx224_2 = crypto:hmac_update(Case4Ctx224, Case4Data), - ?line Case4Mac224_1 = crypto:hmac_final(Case4Ctx224_2), - ?line Case4Mac224_2 = crypto:sha224_mac(Case4Key, Case4Data), - ?line Case4Mac224_3 = crypto:hmac(sha224, Case4Key, Case4Data), - ?line m(Case4Exp224, Case4Mac224_1), - ?line m(Case4Exp224, Case4Mac224_2), - ?line m(Case4Exp224, Case4Mac224_3), - - ?line Case4Ctx256 = crypto:hmac_init(sha256, Case4Key), - ?line Case4Ctx256_2 = crypto:hmac_update(Case4Ctx256, Case4Data), - ?line Case4Mac256_1 = crypto:hmac_final(Case4Ctx256_2), - ?line Case4Mac256_2 = crypto:sha256_mac(Case4Key, Case4Data), - ?line Case4Mac256_3 = crypto:hmac(sha256, Case4Key, Case4Data), - ?line m(Case4Exp256, Case4Mac256_1), - ?line m(Case4Exp256, Case4Mac256_2), - ?line m(Case4Exp256, Case4Mac256_3), - - ?line Case4Ctx384 = crypto:hmac_init(sha384, Case4Key), - ?line Case4Ctx384_2 = crypto:hmac_update(Case4Ctx384, Case4Data), - ?line Case4Mac384_1 = crypto:hmac_final(Case4Ctx384_2), - ?line Case4Mac384_2 = crypto:sha384_mac(Case4Key, Case4Data), - ?line Case4Mac384_3 = crypto:hmac(sha384, Case4Key, Case4Data), - ?line m(Case4Exp384, Case4Mac384_1), - ?line m(Case4Exp384, Case4Mac384_2), - ?line m(Case4Exp384, Case4Mac384_3), - - ?line Case4Ctx512 = crypto:hmac_init(sha512, Case4Key), - ?line Case4Ctx512_2 = crypto:hmac_update(Case4Ctx512, Case4Data), - ?line Case4Mac512_1 = crypto:hmac_final(Case4Ctx512_2), - ?line Case4Mac512_2 = crypto:sha512_mac(Case4Key, Case4Data), - ?line Case4Mac512_3 = crypto:hmac(sha512, Case4Key, Case4Data), - ?line m(Case4Exp512, Case4Mac512_1), - ?line m(Case4Exp512, Case4Mac512_2), - ?line m(Case4Exp512, Case4Mac512_3), - - %% Test Case 5 - Case5Key = binary:copy(<<16#0c>>, 20), - Case5Data = <<"Test With Truncation">>, - Case5Exp224 = hexstr2bin("0e2aea68a90c8d37c988bcdb9fca6fa8"), - Case5Exp256 = hexstr2bin("a3b6167473100ee06e0c796c2955552b"), - Case5Exp384 = hexstr2bin("3abf34c3503b2a23a46efc619baef897"), - Case5Exp512 = hexstr2bin("415fad6271580a531d4179bc891d87a6"), - - ?line Case5Ctx224 = crypto:hmac_init(sha224, Case5Key), - ?line Case5Ctx224_2 = crypto:hmac_update(Case5Ctx224, Case5Data), - ?line Case5Mac224_1 = crypto:hmac_final_n(Case5Ctx224_2, 16), - ?line Case5Mac224_2 = crypto:sha224_mac(Case5Key, Case5Data, 16), - ?line Case5Mac224_3 = crypto:hmac(sha224, Case5Key, Case5Data, 16), - ?line m(Case5Exp224, Case5Mac224_1), - ?line m(Case5Exp224, Case5Mac224_2), - ?line m(Case5Exp224, Case5Mac224_3), - - ?line Case5Ctx256 = crypto:hmac_init(sha256, Case5Key), - ?line Case5Ctx256_2 = crypto:hmac_update(Case5Ctx256, Case5Data), - ?line Case5Mac256_1 = crypto:hmac_final_n(Case5Ctx256_2, 16), - ?line Case5Mac256_2 = crypto:sha256_mac(Case5Key, Case5Data, 16), - ?line Case5Mac256_3 = crypto:hmac(sha256, Case5Key, Case5Data, 16), - ?line m(Case5Exp256, Case5Mac256_1), - ?line m(Case5Exp256, Case5Mac256_2), - ?line m(Case5Exp256, Case5Mac256_3), - - ?line Case5Ctx384 = crypto:hmac_init(sha384, Case5Key), - ?line Case5Ctx384_2 = crypto:hmac_update(Case5Ctx384, Case5Data), - ?line Case5Mac384_1 = crypto:hmac_final_n(Case5Ctx384_2, 16), - ?line Case5Mac384_2 = crypto:sha384_mac(Case5Key, Case5Data, 16), - ?line Case5Mac384_3 = crypto:hmac(sha384, Case5Key, Case5Data, 16), - ?line m(Case5Exp384, Case5Mac384_1), - ?line m(Case5Exp384, Case5Mac384_2), - ?line m(Case5Exp384, Case5Mac384_3), - - ?line Case5Ctx512 = crypto:hmac_init(sha512, Case5Key), - ?line Case5Ctx512_2 = crypto:hmac_update(Case5Ctx512, Case5Data), - ?line Case5Mac512_1 = crypto:hmac_final_n(Case5Ctx512_2, 16), - ?line Case5Mac512_2 = crypto:sha512_mac(Case5Key, Case5Data, 16), - ?line Case5Mac512_3 = crypto:hmac(sha512, Case5Key, Case5Data, 16), - ?line m(Case5Exp512, Case5Mac512_1), - ?line m(Case5Exp512, Case5Mac512_2), - ?line m(Case5Exp512, Case5Mac512_3), - - %% Test Case 6 - Case6Key = binary:copy(<<16#aa>>, 131), - Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>, - Case6Exp224 = hexstr2bin("95e9a0db962095adaebe9b2d6f0dbce2" - "d499f112f2d2b7273fa6870e"), - Case6Exp256 = hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f" - "8e0bc6213728c5140546040f0ee37f54"), - Case6Exp384 = hexstr2bin("4ece084485813e9088d2c63a041bc5b4" - "4f9ef1012a2b588f3cd11f05033ac4c6" - "0c2ef6ab4030fe8296248df163f44952"), - Case6Exp512 = hexstr2bin("80b24263c7c1a3ebb71493c1dd7be8b4" - "9b46d1f41b4aeec1121b013783f8f352" - "6b56d037e05f2598bd0fd2215d6a1e52" - "95e64f73f63f0aec8b915a985d786598"), - - ?line Case6Ctx224 = crypto:hmac_init(sha224, Case6Key), - ?line Case6Ctx224_2 = crypto:hmac_update(Case6Ctx224, Case6Data), - ?line Case6Mac224_1 = crypto:hmac_final(Case6Ctx224_2), - ?line Case6Mac224_2 = crypto:sha224_mac(Case6Key, Case6Data), - ?line Case6Mac224_3 = crypto:hmac(sha224, Case6Key, Case6Data), - ?line m(Case6Exp224, Case6Mac224_1), - ?line m(Case6Exp224, Case6Mac224_2), - ?line m(Case6Exp224, Case6Mac224_3), - - ?line Case6Ctx256 = crypto:hmac_init(sha256, Case6Key), - ?line Case6Ctx256_2 = crypto:hmac_update(Case6Ctx256, Case6Data), - ?line Case6Mac256_1 = crypto:hmac_final(Case6Ctx256_2), - ?line Case6Mac256_2 = crypto:sha256_mac(Case6Key, Case6Data), - ?line Case6Mac256_3 = crypto:hmac(sha256, Case6Key, Case6Data), - ?line m(Case6Exp256, Case6Mac256_1), - ?line m(Case6Exp256, Case6Mac256_2), - ?line m(Case6Exp256, Case6Mac256_3), - - ?line Case6Ctx384 = crypto:hmac_init(sha384, Case6Key), - ?line Case6Ctx384_2 = crypto:hmac_update(Case6Ctx384, Case6Data), - ?line Case6Mac384_1 = crypto:hmac_final(Case6Ctx384_2), - ?line Case6Mac384_2 = crypto:sha384_mac(Case6Key, Case6Data), - ?line Case6Mac384_3 = crypto:hmac(sha384, Case6Key, Case6Data), - ?line m(Case6Exp384, Case6Mac384_1), - ?line m(Case6Exp384, Case6Mac384_2), - ?line m(Case6Exp384, Case6Mac384_3), - - ?line Case6Ctx512 = crypto:hmac_init(sha512, Case6Key), - ?line Case6Ctx512_2 = crypto:hmac_update(Case6Ctx512, Case6Data), - ?line Case6Mac512_1 = crypto:hmac_final(Case6Ctx512_2), - ?line Case6Mac512_2 = crypto:sha512_mac(Case6Key, Case6Data), - ?line Case6Mac512_3 = crypto:hmac(sha512, Case6Key, Case6Data), - ?line m(Case6Exp512, Case6Mac512_1), - ?line m(Case6Exp512, Case6Mac512_2), - ?line m(Case6Exp512, Case6Mac512_3), - +hmac_rfc4231_sha256(doc) -> + ["Generate an HMAC using crypto:sha256_mac, hmac, and hmac_init, hmac_update, and hmac_final. " + "Testvectors are take from RFC4231." ]; +hmac_rfc4231_sha256(suite) -> + []; +hmac_rfc4231_sha256(Config) when is_list(Config) -> + if_supported(sha256, fun() -> hmac_rfc4231_sha256_do() end). + +hmac_rfc4231_sha384(doc) -> + ["Generate an HMAC using crypto:sha384_mac, hmac, and hmac_init, hmac_update, and hmac_final. " + "Testvectors are take from RFC4231." ]; +hmac_rfc4231_sha384(suite) -> + []; +hmac_rfc4231_sha384(Config) when is_list(Config) -> + if_supported(sha384, fun() -> hmac_rfc4231_sha384_do() end). + +hmac_rfc4231_sha512(doc) -> + ["Generate an HMAC using crypto:sha512_mac, hmac, and hmac_init, hmac_update, and hmac_final. " + "Testvectors are take from RFC4231." ]; +hmac_rfc4231_sha512(suite) -> + []; +hmac_rfc4231_sha512(Config) when is_list(Config) -> + if_supported(sha512, fun() -> hmac_rfc4231_sha512_do() end). + +hmac_rfc4231_case(Hash, HashFun, case1, Exp) -> + %% Test 1 + Key = binary:copy(<<16#0b>>, 20), + Data = <<"Hi There">>, + hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp); + +hmac_rfc4231_case(Hash, HashFun, case2, Exp) -> + %% Test 2 + Key = <<"Jefe">>, + Data = <<"what do ya want for nothing?">>, + hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp); + +hmac_rfc4231_case(Hash, HashFun, case3, Exp) -> + %% Test 3 + Key = binary:copy(<<16#aa>>, 20), + Data = binary:copy(<<16#dd>>, 50), + hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp); + +hmac_rfc4231_case(Hash, HashFun, case4, Exp) -> + %% Test 4 + Key = list_to_binary(lists:seq(1, 16#19)), + Data = binary:copy(<<16#cd>>, 50), + hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp); + +hmac_rfc4231_case(Hash, HashFun, case5, Exp) -> + %% Test 5 + Key = binary:copy(<<16#0c>>, 20), + Data = <<"Test With Truncation">>, + hmac_rfc4231_case(Hash, HashFun, Key, Data, 16, Exp); + +hmac_rfc4231_case(Hash, HashFun, case6, Exp) -> + %% Test 6 + Key = binary:copy(<<16#aa>>, 131), + Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>, + hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp); + +hmac_rfc4231_case(Hash, HashFun, case7, Exp) -> %% Test Case 7 - Case7Key = binary:copy(<<16#aa>>, 131), - Case7Data = <<"This is a test using a larger than block-size key and a larger t", - "han block-size data. The key needs to be hashed before being use", - "d by the HMAC algorithm.">>, - Case7Exp224 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd" - "946770db9c2b95c9f6f565d1"), - Case7Exp256 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944" - "bfdc63644f0713938a7f51535c3a35e2"), - Case7Exp384 = hexstr2bin("6617178e941f020d351e2f254e8fd32c" - "602420feb0b8fb9adccebb82461e99c5" - "a678cc31e799176d3860e6110c46523e"), - Case7Exp512 = hexstr2bin("e37b6a775dc87dbaa4dfa9f96e5e3ffd" - "debd71f8867289865df5a32d20cdc944" - "b6022cac3c4982b10d5eeb55c3e4de15" - "134676fb6de0446065c97440fa8c6a58"), - - ?line Case7Ctx224 = crypto:hmac_init(sha224, Case7Key), - ?line Case7Ctx224_2 = crypto:hmac_update(Case7Ctx224, Case7Data), - ?line Case7Mac224_1 = crypto:hmac_final(Case7Ctx224_2), - ?line Case7Mac224_2 = crypto:sha224_mac(Case7Key, Case7Data), - ?line Case7Mac224_3 = crypto:hmac(sha224, Case7Key, Case7Data), - ?line m(Case7Exp224, Case7Mac224_1), - ?line m(Case7Exp224, Case7Mac224_2), - ?line m(Case7Exp224, Case7Mac224_3), - - ?line Case7Ctx256 = crypto:hmac_init(sha256, Case7Key), - ?line Case7Ctx256_2 = crypto:hmac_update(Case7Ctx256, Case7Data), - ?line Case7Mac256_1 = crypto:hmac_final(Case7Ctx256_2), - ?line Case7Mac256_2 = crypto:sha256_mac(Case7Key, Case7Data), - ?line Case7Mac256_3 = crypto:hmac(sha256, Case7Key, Case7Data), - ?line m(Case7Exp256, Case7Mac256_1), - ?line m(Case7Exp256, Case7Mac256_2), - ?line m(Case7Exp256, Case7Mac256_3), - - ?line Case7Ctx384 = crypto:hmac_init(sha384, Case7Key), - ?line Case7Ctx384_2 = crypto:hmac_update(Case7Ctx384, Case7Data), - ?line Case7Mac384_1 = crypto:hmac_final(Case7Ctx384_2), - ?line Case7Mac384_2 = crypto:sha384_mac(Case7Key, Case7Data), - ?line Case7Mac384_3 = crypto:hmac(sha384, Case7Key, Case7Data), - ?line m(Case7Exp384, Case7Mac384_1), - ?line m(Case7Exp384, Case7Mac384_2), - ?line m(Case7Exp384, Case7Mac384_3), - - ?line Case7Ctx512 = crypto:hmac_init(sha512, Case7Key), - ?line Case7Ctx512_2 = crypto:hmac_update(Case7Ctx512, Case7Data), - ?line Case7Mac512_1 = crypto:hmac_final(Case7Ctx512_2), - ?line Case7Mac512_2 = crypto:sha512_mac(Case7Key, Case7Data), - ?line Case7Mac512_3 = crypto:hmac(sha512, Case7Key, Case7Data), - ?line m(Case7Exp512, Case7Mac512_1), - ?line m(Case7Exp512, Case7Mac512_2), - ?line m(Case7Exp512, Case7Mac512_3). + Key = binary:copy(<<16#aa>>, 131), + Data = <<"This is a test using a larger than block-size key and a larger t", + "han block-size data. The key needs to be hashed before being use", + "d by the HMAC algorithm.">>, + hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp). + +hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp) -> + ?line Ctx = crypto:hmac_init(Hash, Key), + ?line Ctx2 = crypto:hmac_update(Ctx, Data), + ?line Mac1 = crypto:hmac_final(Ctx2), + ?line Mac2 = crypto:HashFun(Key, Data), + ?line Mac3 = crypto:hmac(Hash, Key, Data), + ?line m(Exp, Mac1), + ?line m(Exp, Mac2), + ?line m(Exp, Mac3). + +hmac_rfc4231_case(Hash, HashFun, Key, Data, Trunc, Exp) -> + ?line Ctx = crypto:hmac_init(Hash, Key), + ?line Ctx2 = crypto:hmac_update(Ctx, Data), + ?line Mac1 = crypto:hmac_final_n(Ctx2, Trunc), + ?line Mac2 = crypto:HashFun(Key, Data, Trunc), + ?line Mac3 = crypto:hmac(Hash, Key, Data, Trunc), + ?line m(Exp, Mac1), + ?line m(Exp, Mac2), + ?line m(Exp, Mac3). + +hmac_rfc4231_sha224_do() -> + Case1 = hexstr2bin("896fb1128abbdf196832107cd49df33f" + "47b4b1169912ba4f53684b22"), + Case2 = hexstr2bin("a30e01098bc6dbbf45690f3a7e9e6d0f" + "8bbea2a39e6148008fd05e44"), + Case3 = hexstr2bin("7fb3cb3588c6c1f6ffa9694d7d6ad264" + "9365b0c1f65d69d1ec8333ea"), + Case4 = hexstr2bin("6c11506874013cac6a2abc1bb382627c" + "ec6a90d86efc012de7afec5a"), + Case5 = hexstr2bin("0e2aea68a90c8d37c988bcdb9fca6fa8"), + Case6 = hexstr2bin("95e9a0db962095adaebe9b2d6f0dbce2" + "d499f112f2d2b7273fa6870e"), + Case7 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd" + "946770db9c2b95c9f6f565d1"), + hmac_rfc4231_cases_do(sha224, sha224_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). + +hmac_rfc4231_sha256_do() -> + Case1 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b" + "881dc200c9833da726e9376c2e32cff7"), + Case2 = hexstr2bin("5bdcc146bf60754e6a042426089575c7" + "5a003f089d2739839dec58b964ec3843"), + Case3 = hexstr2bin("773ea91e36800e46854db8ebd09181a7" + "2959098b3ef8c122d9635514ced565fe"), + Case4 = hexstr2bin("82558a389a443c0ea4cc819899f2083a" + "85f0faa3e578f8077a2e3ff46729665b"), + Case5 = hexstr2bin("a3b6167473100ee06e0c796c2955552b"), + Case6 = hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f" + "8e0bc6213728c5140546040f0ee37f54"), + Case7 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944" + "bfdc63644f0713938a7f51535c3a35e2"), + hmac_rfc4231_cases_do(sha256, sha256_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). + +hmac_rfc4231_sha384_do() -> + Case1 = hexstr2bin("afd03944d84895626b0825f4ab46907f" + "15f9dadbe4101ec682aa034c7cebc59c" + "faea9ea9076ede7f4af152e8b2fa9cb6"), + Case2 = hexstr2bin("af45d2e376484031617f78d2b58a6b1b" + "9c7ef464f5a01b47e42ec3736322445e" + "8e2240ca5e69e2c78b3239ecfab21649"), + Case3 = hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f" + "0aa635d947ac9febe83ef4e55966144b" + "2a5ab39dc13814b94e3ab6e101a34f27"), + Case4 = hexstr2bin("3e8a69b7783c25851933ab6290af6ca7" + "7a9981480850009cc5577c6e1f573b4e" + "6801dd23c4a7d679ccf8a386c674cffb"), + Case5 = hexstr2bin("3abf34c3503b2a23a46efc619baef897"), + Case6 = hexstr2bin("4ece084485813e9088d2c63a041bc5b4" + "4f9ef1012a2b588f3cd11f05033ac4c6" + "0c2ef6ab4030fe8296248df163f44952"), + Case7 = hexstr2bin("6617178e941f020d351e2f254e8fd32c" + "602420feb0b8fb9adccebb82461e99c5" + "a678cc31e799176d3860e6110c46523e"), + hmac_rfc4231_cases_do(sha384, sha384_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). + +hmac_rfc4231_sha512_do() -> + Case1 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0" + "2379f4e2ce4ec2787ad0b30545e17cde" + "daa833b7d6b8a702038b274eaea3f4e4" + "be9d914eeb61f1702e696c203a126854"), + Case2 = hexstr2bin("164b7a7bfcf819e2e395fbe73b56e0a3" + "87bd64222e831fd610270cd7ea250554" + "9758bf75c05a994a6d034f65f8f0e6fd" + "caeab1a34d4a6b4b636e070a38bce737"), + Case3 = hexstr2bin("fa73b0089d56a284efb0f0756c890be9" + "b1b5dbdd8ee81a3655f83e33b2279d39" + "bf3e848279a722c806b485a47e67c807" + "b946a337bee8942674278859e13292fb"), + Case4 = hexstr2bin("b0ba465637458c6990e5a8c5f61d4af7" + "e576d97ff94b872de76f8050361ee3db" + "a91ca5c11aa25eb4d679275cc5788063" + "a5f19741120c4f2de2adebeb10a298dd"), + Case5 = hexstr2bin("415fad6271580a531d4179bc891d87a6"), + Case6 = hexstr2bin("80b24263c7c1a3ebb71493c1dd7be8b4" + "9b46d1f41b4aeec1121b013783f8f352" + "6b56d037e05f2598bd0fd2215d6a1e52" + "95e64f73f63f0aec8b915a985d786598"), + Case7 = hexstr2bin("e37b6a775dc87dbaa4dfa9f96e5e3ffd" + "debd71f8867289865df5a32d20cdc944" + "b6022cac3c4982b10d5eeb55c3e4de15" + "134676fb6de0446065c97440fa8c6a58"), + hmac_rfc4231_cases_do(sha512, sha512_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). + +hmac_rfc4231_cases_do(Hash, HashFun, CasesData) -> + hmac_rfc4231_cases_do(Hash, HashFun, [case1, case2, case3, case4, case5, case6, case7], CasesData). + +hmac_rfc4231_cases_do(_Hash, _HashFun, _, []) -> + ok; +hmac_rfc4231_cases_do(Hash, HashFun, [C|Cases], [D|CasesData]) -> + hmac_rfc4231_case(Hash, HashFun, C, D), + hmac_rfc4231_cases_do(Hash, HashFun, Cases, CasesData). hmac_update_md5_io(doc) -> ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. " @@ -1025,7 +856,7 @@ sha256(doc) -> sha256(suite) -> []; sha256(Config) when is_list(Config) -> - if_098(fun() -> sha256_do() end). + if_supported(sha256, fun() -> sha256_do() end). sha256_do() -> ?line m(crypto:sha256("abc"), @@ -1044,7 +875,7 @@ sha256_update(doc) -> sha256_update(suite) -> []; sha256_update(Config) when is_list(Config) -> - if_098(fun() -> sha256_update_do() end). + if_supported(sha256, fun() -> sha256_update_do() end). sha256_update_do() -> ?line Ctx = crypto:sha256_init(), @@ -1063,7 +894,7 @@ sha512(doc) -> sha512(suite) -> []; sha512(Config) when is_list(Config) -> - if_098(fun() -> sha512_do() end). + if_supported(sha512, fun() -> sha512_do() end). sha512_do() -> ?line m(crypto:sha512("abc"), @@ -1084,7 +915,7 @@ sha512_update(doc) -> sha512_update(suite) -> []; sha512_update(Config) when is_list(Config) -> - if_098(fun() -> sha512_update_do() end). + if_supported(sha512, fun() -> sha512_update_do() end). sha512_update_do() -> ?line Ctx = crypto:sha512_init(), @@ -2017,6 +1848,221 @@ dh(Config) when is_list(Config) -> exit(Pid, kill) end. +ec(doc) -> + ["Test ec (Ecliptic Curve) functions."]; +ec(suite) -> []; +ec(Config) when is_list(Config) -> + if_supported(ec, fun() -> ec_do() end). + +ec_do() -> + %% test for a name curve + L2 = crypto:ec_key_new(sect113r2), + crypto:ec_key_generate(L2), + + D2 = crypto:ec_key_to_term(L2), + T2 = crypto:term_to_ec_key(D2), + ?line D2 = crypto:ec_key_to_term(T2), + + %%TODO: find a published test case for a EC key + + %% test for a full specified curve and public key, + %% taken from csca-germany_013_self_signed_cer.pem + PubKey = <<16#04, 16#4a, 16#94, 16#49, 16#81, 16#77, 16#9d, 16#df, + 16#1d, 16#a5, 16#e7, 16#c5, 16#27, 16#e2, 16#7d, 16#24, + 16#71, 16#a9, 16#28, 16#eb, 16#4d, 16#7b, 16#67, 16#75, + 16#ae, 16#09, 16#0a, 16#51, 16#45, 16#19, 16#9b, 16#d4, + 16#7e, 16#a0, 16#81, 16#e5, 16#5e, 16#d4, 16#a4, 16#3f, + 16#60, 16#7c, 16#6a, 16#50, 16#ee, 16#36, 16#41, 16#8a, + 16#87, 16#ff, 16#cd, 16#a6, 16#10, 16#39, 16#ca, 16#95, + 16#76, 16#7d, 16#ae, 16#ca, 16#c3, 16#44, 16#3f, 16#e3, 16#2c>>, + <<P:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9, + 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d, + 16#72, 16#6e, 16#3b, 16#f6, 16#23, 16#d5, 16#26, 16#20, + 16#28, 16#20, 16#13, 16#48, 16#1d, 16#1f, 16#6e, 16#53, 16#77>>, + <<A:256/integer>> = <<16#7d, 16#5a, 16#09, 16#75, 16#fc, 16#2c, 16#30, 16#57, + 16#ee, 16#f6, 16#75, 16#30, 16#41, 16#7a, 16#ff, 16#e7, + 16#fb, 16#80, 16#55, 16#c1, 16#26, 16#dc, 16#5c, 16#6c, + 16#e9, 16#4a, 16#4b, 16#44, 16#f3, 16#30, 16#b5, 16#d9>>, + <<B:256/integer>> = <<16#26, 16#dc, 16#5c, 16#6c, 16#e9, 16#4a, 16#4b, 16#44, + 16#f3, 16#30, 16#b5, 16#d9, 16#bb, 16#d7, 16#7c, 16#bf, + 16#95, 16#84, 16#16, 16#29, 16#5c, 16#f7, 16#e1, 16#ce, + 16#6b, 16#cc, 16#dc, 16#18, 16#ff, 16#8c, 16#07, 16#b6>>, + BasePoint = <<16#04, 16#8b, 16#d2, 16#ae, 16#b9, 16#cb, 16#7e, 16#57, + 16#cb, 16#2c, 16#4b, 16#48, 16#2f, 16#fc, 16#81, 16#b7, + 16#af, 16#b9, 16#de, 16#27, 16#e1, 16#e3, 16#bd, 16#23, + 16#c2, 16#3a, 16#44, 16#53, 16#bd, 16#9a, 16#ce, 16#32, + 16#62, 16#54, 16#7e, 16#f8, 16#35, 16#c3, 16#da, 16#c4, + 16#fd, 16#97, 16#f8, 16#46, 16#1a, 16#14, 16#61, 16#1d, + 16#c9, 16#c2, 16#77, 16#45, 16#13, 16#2d, 16#ed, 16#8e, + 16#54, 16#5c, 16#1d, 16#54, 16#c7, 16#2f, 16#04, 16#69, 16#97>>, + <<Order:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9, + 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d, + 16#71, 16#8c, 16#39, 16#7a, 16#a3, 16#b5, 16#61, 16#a6, + 16#f7, 16#90, 16#1e, 16#0e, 16#82, 16#97, 16#48, 16#56, 16#a7>>, + CoFactor = 1, + Curve = {{prime_field,P},{A,B,none},BasePoint, Order,CoFactor}, + CsCaKey = {Curve, undefined, PubKey}, + T3 = crypto:term_to_ec_key(CsCaKey), + ?line CsCaKey = crypto:ec_key_to_term(T3), + + Msg = <<99,234,6,64,190,237,201,99,80,248,58,40,70,45,149,218,5,246,242,63>>, + Sign = crypto:ecdsa_sign(sha, sized_binary(Msg), L2), + ?line true = crypto:ecdsa_verify(sha, sized_binary(Msg), sized_binary(Sign), L2), + ?line false = crypto:ecdsa_verify(sha, sized_binary(Msg), sized_binary(<<10,20>>), L2), + + ok. + +srp3(doc) -> + ["SRP-3 test vectors generated by http://srp.stanford.edu/demo/demo.html"]; +srp3(suite) -> []; +srp3(Config) when is_list(Config) -> + Username = <<"alice">>, + Password = <<"password123">>, + Salt = hexstr2bin("2857827A19266A1F2BC6"), + Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C" + "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4" + "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29" + "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A" + "FD5138FE8376435B9FC61D2FC0EB06E3"), + Generator = <<2>>, + Multiplier = 1, + %% X = hexstr2bin("96E54AB0CD4C5123EDCFA4A1502918AAD3C9E2A8"), + Verifier = hexstr2bin("96EB5F13621D911AA1CA405DE9C64217D4108EEEECAFFE500034FE0E" + "C031E42C8714667C161BCE0E7996F7DDE1B63824C130D2D7286C08C0" + "49758420735961347112AE102A3F23B3F687F8FEE0DF2BFAF933C608" + "D6FE5B5EEE3116FE54016E065BF8E8C9FDBBC08719231AC215149140" + "519E8FDD9AA4F410C28A58AF42974D2D"), + ClntPriv = hexstr2bin("6411DE75538BED8170677D577D0608F39112BC95B503C447EB6AC945" + "49C75C7B"), + SrvrPriv = hexstr2bin("85E44A6F694DBE676145DB245A045CD37C99F05C562C7840A31F270D" + "9AADCF8B"), + ClntPub = hexstr2bin("B22B1FFA2244B8CB94F3A9080F419CAEAB0DBA93EA1965B5E84587EE" + "55C79E7A118865DC59B9D0353362C2A8261E7C1B0D221A0E233C2AD1" + "640DACBB8664CBC9733EAC392DA7800142860380C3FC573C3C064329" + "CF54063FD114C7210E9CB3A611EA8002B1844B698F930D95D143899B" + "948A090E0C25938E5F84067D1883DC63"), + SrvrPub = hexstr2bin("93A8C4D8B7F7395ADCFD4ABA37B015124513D3F37B3E85EB23064BE5" + "F53C0AE32FFB9D8C0AA0DCFFA74D632DD67DEBB5C35AAE9812286CC8" + "C43CC176ECBC6D3F447594D9554E995B2509127BF88FADDDA4982D03" + "8EC3001320712D3B1269308CE70F319B2295FA57674F03A2D993CFB1" + "F84C35B7D0C012FA73CD4C8F7D5A71C7"), + U = hexstr2bin("02E2476A"), + + PremasterSecret = hexstr2bin("C29A986C4D521BBC66428ED11D994CD7431574A6184B83CDCC345092" + "791E75748A1D38CAC4BD14760F0D2694B711236419240FF2F172454C" + "46ABF4FF39498DAFDD2C82924F7D7BD76CDFCE688C77D93F18A65409" + "9176A9192615DC0277AE7C12F1F6A7F6563FCA11675D809AF578BDE5" + "2B51E05D440B63099A017A0B45044801"), + UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), + m(crypto:srp_mod_exp(Generator, UserPassHash, Prime), Verifier), + m(crypto:srp_mod_exp(Generator, ClntPriv, Prime), ClntPub), + m(crypto:srp3_value_u(SrvrPub), U), + m(crypto:srp_value_B(Multiplier, Verifier, Generator, SrvrPriv, Prime), SrvrPub), + m(crypto:srp_client_secret(ClntPriv, U, SrvrPub, Multiplier, Generator, UserPassHash, Prime), PremasterSecret), + m(crypto:srp_server_secret(Verifier, SrvrPriv, U, ClntPub, Prime), PremasterSecret), + ok. + +srp6(doc) -> + ["SRP-6 test vectors generated by http://srp.stanford.edu/demo/demo.html"]; +srp6(suite) -> []; +srp6(Config) when is_list(Config) -> + Username = <<"alice">>, + Password = <<"password123">>, + Salt = hexstr2bin("2857827A19266A1F2BC6"), + Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C" + "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4" + "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29" + "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A" + "FD5138FE8376435B9FC61D2FC0EB06E3"), + Generator = <<2>>, + Multiplier = 3, + %% X = hexstr2bin("96E54AB0CD4C5123EDCFA4A1502918AAD3C9E2A8"), + Verifier = hexstr2bin("96EB5F13621D911AA1CA405DE9C64217D4108EEEECAFFE500034FE0E" + "C031E42C8714667C161BCE0E7996F7DDE1B63824C130D2D7286C08C0" + "49758420735961347112AE102A3F23B3F687F8FEE0DF2BFAF933C608" + "D6FE5B5EEE3116FE54016E065BF8E8C9FDBBC08719231AC215149140" + "519E8FDD9AA4F410C28A58AF42974D2D"), + ClntPriv = hexstr2bin("6411DE75538BED8170677D577D0608F39112BC95B503C447EB6AC945" + "49C75C7B"), + SrvrPriv = hexstr2bin("85E44A6F694DBE676145DB245A045CD37C99F05C562C7840A31F270D" + "9AADCF8B"), + ClntPub = hexstr2bin("B22B1FFA2244B8CB94F3A9080F419CAEAB0DBA93EA1965B5E84587EE" + "55C79E7A118865DC59B9D0353362C2A8261E7C1B0D221A0E233C2AD1" + "640DACBB8664CBC9733EAC392DA7800142860380C3FC573C3C064329" + "CF54063FD114C7210E9CB3A611EA8002B1844B698F930D95D143899B" + "948A090E0C25938E5F84067D1883DC63"), + SrvrPub = hexstr2bin("D2D07845CE7ECDB9845DD36B10ACD3598CC29049DE9F467F84CE16B6" + "D97A6DC567AF8B0F9FEDF74962400AD5C357951E64E67B641246F264" + "C8DE6D9A72E554D6C8D3194548780A0C438A0FCC509CA88A14AA1DEB" + "C0F09E4B37A965D1545DB4AD361346F3189B0EA569C06D326C4E4797" + "9E381C748293B7C0591BE0BE419E053E"), + U = hexstr2bin("0A2534C0BF52A0DA9001EEC62CF2A546AB0908A7"), + + PremasterSecret = hexstr2bin("19D22C19612874EBF1F2581F8EFCFDC44C6FDA3B87B0A73823D7E962" + "554295D4E48D3A336523ADBDDD0EC8FB0F02687109E97E01C17C93CC" + "7216F9CD8A4AC39F0429857D8D1023066614BDFCBCB89F59A0FEB81C" + "72E992AAD89095A84B6A5FADA152369AB1E350A03693BEF044DF3EDF" + "0C34741F4696C30E9F675D09F58ACBEB"), + UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), + m(crypto:srp_mod_exp(Generator, UserPassHash, Prime), Verifier), + m(crypto:srp_mod_exp(Generator, ClntPriv, Prime), ClntPub), + m(crypto:srp6_value_u(ClntPub, SrvrPub, Prime), U), + m(crypto:srp_value_B(Multiplier, Verifier, Generator, SrvrPriv, Prime), SrvrPub), + m(crypto:srp_client_secret(ClntPriv, U, SrvrPub, Multiplier, Generator, UserPassHash, Prime), PremasterSecret), + m(crypto:srp_server_secret(Verifier, SrvrPriv, U, ClntPub, Prime), PremasterSecret), + ok. + +srp6a(doc) -> + ["SRP-6a test vectors from RFC5054."]; +srp6a(suite) -> []; +srp6a(Config) when is_list(Config) -> + Username = <<"alice">>, + Password = <<"password123">>, + Salt = hexstr2bin("BEB25379D1A8581EB5A727673A2441EE"), + Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C" + "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4" + "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29" + "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A" + "FD5138FE8376435B9FC61D2FC0EB06E3"), + Generator = <<2>>, + Multiplier = hexstr2bin("7556AA045AEF2CDD07ABAF0F665C3E818913186F"), + %% X = hexstr2bin("94B7555AABE9127CC58CCF4993DB6CF84D16C124"), + Verifier = hexstr2bin("7E273DE8696FFC4F4E337D05B4B375BEB0DDE1569E8FA00A9886D812" + "9BADA1F1822223CA1A605B530E379BA4729FDC59F105B4787E5186F5" + "C671085A1447B52A48CF1970B4FB6F8400BBF4CEBFBB168152E08AB5" + "EA53D15C1AFF87B2B9DA6E04E058AD51CC72BFC9033B564E26480D78" + "E955A5E29E7AB245DB2BE315E2099AFB"), + ClntPriv = hexstr2bin("60975527035CF2AD1989806F0407210BC81EDC04E2762A56AFD529DD" + "DA2D4393"), + SrvrPriv = hexstr2bin("E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D1" + "05284D20"), + ClntPub = hexstr2bin("61D5E490F6F1B79547B0704C436F523DD0E560F0C64115BB72557EC4" + "4352E8903211C04692272D8B2D1A5358A2CF1B6E0BFCF99F921530EC" + "8E39356179EAE45E42BA92AEACED825171E1E8B9AF6D9C03E1327F44" + "BE087EF06530E69F66615261EEF54073CA11CF5858F0EDFDFE15EFEA" + "B349EF5D76988A3672FAC47B0769447B"), + SrvrPub = hexstr2bin("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011" + "BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC99" + "6C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA" + "37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAE" + "EB4012B7D7665238A8E3FB004B117B58"), + U = hexstr2bin("CE38B9593487DA98554ED47D70A7AE5F462EF019"), + + PremasterSecret = hexstr2bin("B0DC82BABCF30674AE450C0287745E7990A3381F63B387AAF271A10D" + "233861E359B48220F7C4693C9AE12B0A6F67809F0876E2D013800D6C" + "41BB59B6D5979B5C00A172B4A2A5903A0BDCAF8A709585EB2AFAFA8F" + "3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D" + "C346D7E474B29EDE8A469FFECA686E5A"), + UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), + m(crypto:srp_mod_exp(Generator, UserPassHash, Prime), Verifier), + m(crypto:srp_mod_exp(Generator, ClntPriv, Prime), ClntPub), + m(crypto:srp6a_multiplier(Generator, Prime), Multiplier), + m(crypto:srp6_value_u(ClntPub, SrvrPub, Prime), U), + m(crypto:srp_value_B(Multiplier, Verifier, Generator, SrvrPriv, Prime), SrvrPub), + m(crypto:srp_client_secret(ClntPriv, U, SrvrPub, Multiplier, Generator, UserPassHash, Prime), PremasterSecret), + m(crypto:srp_server_secret(Verifier, SrvrPriv, U, ClntPub, Prime), PremasterSecret), + ok. + %% %% exor_test(doc) -> @@ -2120,8 +2166,8 @@ worker_loop(N, Config) -> aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, strong_rand_test, rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test, hmac_update_md5, hmac_update_sha, hmac_update_sha256, hmac_update_sha512, - hmac_rfc2202, hmac_rfc4231, - aes_ctr_stream }, + hmac_rfc2202, hmac_rfc4231_sha224, hmac_rfc4231_sha256, hmac_rfc4231_sha384, + hmac_rfc4231_sha512, aes_ctr_stream }, F = element(random:uniform(size(Funcs)),Funcs), %%io:format("worker ~p calling ~p\n",[self(),F]), @@ -2256,10 +2302,10 @@ openssl_version() -> undefined end. -if_098(Fun) -> - case openssl_version() of - V when V < 16#908000 -> - {skipped,"OpenSSL version too old"}; +if_supported(Algorithm, Fun) -> + case proplists:get_bool(Algorithm, crypto:algorithms()) of + true -> + Fun(); _ -> - Fun() + {skipped, io:format("~s not spupported", [Algorithm])} end. diff --git a/lib/public_key/asn1/ECPrivateKey.asn1 b/lib/public_key/asn1/ECPrivateKey.asn1 new file mode 100644 index 0000000000..e8607c4f7b --- /dev/null +++ b/lib/public_key/asn1/ECPrivateKey.asn1 @@ -0,0 +1,24 @@ +ECPrivateKey { iso(1) identified-organization(3) dod(6) + internet(1) security(5) mechanisms(5) pkix(7) id-mod(0) + id-mod-ecprivateKey(65) } + +DEFINITIONS EXPLICIT TAGS ::= + +BEGIN + +-- EXPORTS ALL; + +IMPORTS + +-- FROM New PKIX ASN.1 [RFC5912] + +OTPEcpkParameters FROM OTP-PKIX; + +ECPrivateKey ::= SEQUENCE { + version INTEGER, + privateKey OCTET STRING, + parameters [0] OTPEcpkParameters OPTIONAL, + publicKey [1] BIT STRING OPTIONAL +} + +END
\ No newline at end of file diff --git a/lib/public_key/asn1/OTP-PKIX.asn1 b/lib/public_key/asn1/OTP-PKIX.asn1 index 4f20208bce..8b553fc0d5 100644 --- a/lib/public_key/asn1/OTP-PKIX.asn1 +++ b/lib/public_key/asn1/OTP-PKIX.asn1 @@ -105,7 +105,8 @@ IMPORTS rsaEncryption, RSAPublicKey, dhpublicnumber, DomainParameters, DHPublicKey, id-keyExchangeAlgorithm, KEA-Parms-Id, --KEA-PublicKey, - ecdsa-with-SHA1, + ecdsa-with-SHA1, ecdsa-with-SHA224, + ecdsa-with-SHA256, ecdsa-with-SHA384, ecdsa-with-SHA512, prime-field, Prime-p, characteristic-two-field, --Characteristic-two, gnBasis, @@ -322,7 +323,11 @@ SupportedSignatureAlgorithms SIGNATURE-ALGORITHM-CLASS ::= { sha256-with-rsa-encryption | sha384-with-rsa-encryption | sha512-with-rsa-encryption | - ecdsa-with-sha1 } + ecdsa-with-sha1 | + ecdsa-with-sha224 | + ecdsa-with-sha256 | + ecdsa-with-sha384 | + ecdsa-with-sha512 } SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= { dsa | rsa-encryption | dh | kea | ec-public-key } @@ -431,6 +436,22 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= { ID ecdsa-with-SHA1 TYPE NULL } -- XXX Must be empty and not NULL + ecdsa-with-sha224 SIGNATURE-ALGORITHM-CLASS ::= { + ID ecdsa-with-SHA224 + TYPE NULL } -- XXX Must be empty and not NULL + + ecdsa-with-sha256 SIGNATURE-ALGORITHM-CLASS ::= { + ID ecdsa-with-SHA256 + TYPE NULL } -- XXX Must be empty and not NULL + + ecdsa-with-sha384 SIGNATURE-ALGORITHM-CLASS ::= { + ID ecdsa-with-SHA384 + TYPE NULL } -- XXX Must be empty and not NULL + + ecdsa-with-sha512 SIGNATURE-ALGORITHM-CLASS ::= { + ID ecdsa-with-SHA512 + TYPE NULL } -- XXX Must be empty and not NULL + FIELD-ID-CLASS ::= CLASS { &id OBJECT IDENTIFIER UNIQUE, &Type } @@ -481,6 +502,23 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= { ID ppBasis TYPE Pentanomial } + -- Elliptic Curve parameters may be specified explicitly, + -- specified implicitly through a "named curve", or + -- inherited from the CA + + OTPEcpkParameters ::= CHOICE { + ecParameters OTPECParameters, + namedCurve OBJECT IDENTIFIER, + implicitlyCA NULL } + + OTPECParameters ::= SEQUENCE { -- Elliptic curve parameters + version ECPVer, + fieldID OTPFieldID, + curve Curve, + base ECPoint, -- Base point G + order INTEGER, -- Order n of the base point + cofactor INTEGER OPTIONAL } -- The integer h = #E(Fq)/n + -- SubjectPublicKeyInfo.algorithm ec-public-key PUBLIC-KEY-ALGORITHM-CLASS ::= { diff --git a/lib/public_key/asn1/OTP-PUB-KEY.set.asn b/lib/public_key/asn1/OTP-PUB-KEY.set.asn index f8fb318c93..e94f428e4b 100644 --- a/lib/public_key/asn1/OTP-PUB-KEY.set.asn +++ b/lib/public_key/asn1/OTP-PUB-KEY.set.asn @@ -6,5 +6,6 @@ PKIX1Algorithms88.asn1 PKCS-1.asn1 PKCS-3.asn1 DSS.asn1 +ECPrivateKey.asn1 PKCS-7.asn1 PKCS-10.asn1 diff --git a/lib/public_key/asn1/PKCS-1.asn1 b/lib/public_key/asn1/PKCS-1.asn1 index c83289e779..3b21befdff 100644 --- a/lib/public_key/asn1/PKCS-1.asn1 +++ b/lib/public_key/asn1/PKCS-1.asn1 @@ -50,8 +50,40 @@ id-md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5 } +id-hmacWithSHA224 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 8 +} + +id-hmacWithSHA256 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 9 +} + +id-hmacWithSHA384 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 10 +} + +id-hmacWithSHA512 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 11 +} + id-mgf1 OBJECT IDENTIFIER ::= { pkcs-1 8 } +id-sha224 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) + country(16) us(840) organization(1) gov(101) csor(3) + nistalgorithm(4) hashalgs(2) 4 } + +id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) + country(16) us(840) organization(1) gov(101) csor(3) + nistalgorithm(4) hashalgs(2) 1 } + +id-sha384 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) + country(16) us(840) organization(1) gov(101) csor(3) + nistalgorithm(4) hashalgs(2) 2 } + +id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) + country(16) us(840) organization(1) gov(101) csor(3) + nistalgorithm(4) hashalgs(2) 3 } + RSAPublicKey ::= SEQUENCE { modulus INTEGER, -- n diff --git a/lib/public_key/asn1/PKIX1Algorithms88.asn1 b/lib/public_key/asn1/PKIX1Algorithms88.asn1 index f895b6d0cd..e58305dcb0 100644 --- a/lib/public_key/asn1/PKIX1Algorithms88.asn1 +++ b/lib/public_key/asn1/PKIX1Algorithms88.asn1 @@ -95,6 +95,11 @@ -- OID for ECDSA signatures with SHA-1 ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { id-ecSigType 1 } + ecdsa-with-SHA2 OBJECT IDENTIFIER ::= { id-ecSigType 3 } + ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 1 } + ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 2 } + ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 3 } + ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 4 } -- OID for an elliptic curve signature -- format for the value of an ECDSA signature value @@ -196,40 +201,83 @@ -- Named Elliptic Curves in ANSI X9.62. - ellipticCurve OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) } - - c-TwoCurve OBJECT IDENTIFIER ::= { - ellipticCurve characteristicTwo(0) } - - c2pnb163v1 OBJECT IDENTIFIER ::= { c-TwoCurve 1 } - c2pnb163v2 OBJECT IDENTIFIER ::= { c-TwoCurve 2 } - c2pnb163v3 OBJECT IDENTIFIER ::= { c-TwoCurve 3 } - c2pnb176w1 OBJECT IDENTIFIER ::= { c-TwoCurve 4 } - c2tnb191v1 OBJECT IDENTIFIER ::= { c-TwoCurve 5 } - c2tnb191v2 OBJECT IDENTIFIER ::= { c-TwoCurve 6 } - c2tnb191v3 OBJECT IDENTIFIER ::= { c-TwoCurve 7 } - c2onb191v4 OBJECT IDENTIFIER ::= { c-TwoCurve 8 } - c2onb191v5 OBJECT IDENTIFIER ::= { c-TwoCurve 9 } - c2pnb208w1 OBJECT IDENTIFIER ::= { c-TwoCurve 10 } - c2tnb239v1 OBJECT IDENTIFIER ::= { c-TwoCurve 11 } - c2tnb239v2 OBJECT IDENTIFIER ::= { c-TwoCurve 12 } - c2tnb239v3 OBJECT IDENTIFIER ::= { c-TwoCurve 13 } - c2onb239v4 OBJECT IDENTIFIER ::= { c-TwoCurve 14 } - c2onb239v5 OBJECT IDENTIFIER ::= { c-TwoCurve 15 } - c2pnb272w1 OBJECT IDENTIFIER ::= { c-TwoCurve 16 } - c2pnb304w1 OBJECT IDENTIFIER ::= { c-TwoCurve 17 } - c2tnb359v1 OBJECT IDENTIFIER ::= { c-TwoCurve 18 } - c2pnb368w1 OBJECT IDENTIFIER ::= { c-TwoCurve 19 } - c2tnb431r1 OBJECT IDENTIFIER ::= { c-TwoCurve 20 } - - primeCurve OBJECT IDENTIFIER ::= { ellipticCurve prime(1) } - - prime192v1 OBJECT IDENTIFIER ::= { primeCurve 1 } - prime192v2 OBJECT IDENTIFIER ::= { primeCurve 2 } - prime192v3 OBJECT IDENTIFIER ::= { primeCurve 3 } - prime239v1 OBJECT IDENTIFIER ::= { primeCurve 4 } - prime239v2 OBJECT IDENTIFIER ::= { primeCurve 5 } - prime239v3 OBJECT IDENTIFIER ::= { primeCurve 6 } - prime256v1 OBJECT IDENTIFIER ::= { primeCurve 7 } + -- ellipticCurve OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) } + + -- c-TwoCurve OBJECT IDENTIFIER ::= { + -- ansi-ellipticCurve characteristicTwo(0) } + + -- c2pnb163v1 OBJECT IDENTIFIER ::= { c-TwoCurve 1 } + -- c2pnb163v2 OBJECT IDENTIFIER ::= { c-TwoCurve 2 } + -- c2pnb163v3 OBJECT IDENTIFIER ::= { c-TwoCurve 3 } + -- c2pnb176w1 OBJECT IDENTIFIER ::= { c-TwoCurve 4 } + -- c2tnb191v1 OBJECT IDENTIFIER ::= { c-TwoCurve 5 } + -- c2tnb191v2 OBJECT IDENTIFIER ::= { c-TwoCurve 6 } + -- c2tnb191v3 OBJECT IDENTIFIER ::= { c-TwoCurve 7 } + -- c2onb191v4 OBJECT IDENTIFIER ::= { c-TwoCurve 8 } + -- c2onb191v5 OBJECT IDENTIFIER ::= { c-TwoCurve 9 } + -- c2pnb208w1 OBJECT IDENTIFIER ::= { c-TwoCurve 10 } + -- c2tnb239v1 OBJECT IDENTIFIER ::= { c-TwoCurve 11 } + -- c2tnb239v2 OBJECT IDENTIFIER ::= { c-TwoCurve 12 } + -- c2tnb239v3 OBJECT IDENTIFIER ::= { c-TwoCurve 13 } + -- c2onb239v4 OBJECT IDENTIFIER ::= { c-TwoCurve 14 } + -- c2onb239v5 OBJECT IDENTIFIER ::= { c-TwoCurve 15 } + -- c2pnb272w1 OBJECT IDENTIFIER ::= { c-TwoCurve 16 } + -- c2pnb304w1 OBJECT IDENTIFIER ::= { c-TwoCurve 17 } + -- c2tnb359v1 OBJECT IDENTIFIER ::= { c-TwoCurve 18 } + -- c2pnb368w1 OBJECT IDENTIFIER ::= { c-TwoCurve 19 } + -- c2tnb431r1 OBJECT IDENTIFIER ::= { c-TwoCurve 20 } + + -- primeCurve OBJECT IDENTIFIER ::= { ansi-ellipticCurve prime(1) } + + -- prime192v1 OBJECT IDENTIFIER ::= { primeCurve 1 } + -- prime192v2 OBJECT IDENTIFIER ::= { primeCurve 2 } + -- prime192v3 OBJECT IDENTIFIER ::= { primeCurve 3 } + -- prime239v1 OBJECT IDENTIFIER ::= { primeCurve 4 } + -- prime239v2 OBJECT IDENTIFIER ::= { primeCurve 5 } + -- prime239v3 OBJECT IDENTIFIER ::= { primeCurve 6 } + -- prime256v1 OBJECT IDENTIFIER ::= { primeCurve 7 } + + certicom-arc OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) + } + + ellipticCurve OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) curve(0) + } + + secp192r1 OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) prime(1) 1 } + secp256r1 OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) prime(1) 7 } + + sect163k1 OBJECT IDENTIFIER ::= { ellipticCurve 1 } + sect163r1 OBJECT IDENTIFIER ::= { ellipticCurve 2 } + sect239k1 OBJECT IDENTIFIER ::= { ellipticCurve 3 } + sect113r1 OBJECT IDENTIFIER ::= { ellipticCurve 4 } + sect113r2 OBJECT IDENTIFIER ::= { ellipticCurve 5 } + secp112r1 OBJECT IDENTIFIER ::= { ellipticCurve 6 } + secp112r2 OBJECT IDENTIFIER ::= { ellipticCurve 7 } + secp160r1 OBJECT IDENTIFIER ::= { ellipticCurve 8 } + secp160k1 OBJECT IDENTIFIER ::= { ellipticCurve 9 } + secp256k1 OBJECT IDENTIFIER ::= { ellipticCurve 10 } + sect163r2 OBJECT IDENTIFIER ::= { ellipticCurve 15 } + sect283k1 OBJECT IDENTIFIER ::= { ellipticCurve 16 } + sect283r1 OBJECT IDENTIFIER ::= { ellipticCurve 17 } + sect131r1 OBJECT IDENTIFIER ::= { ellipticCurve 22 } + sect131r2 OBJECT IDENTIFIER ::= { ellipticCurve 23 } + sect193r1 OBJECT IDENTIFIER ::= { ellipticCurve 24 } + sect193r2 OBJECT IDENTIFIER ::= { ellipticCurve 25 } + sect233k1 OBJECT IDENTIFIER ::= { ellipticCurve 26 } + sect233r1 OBJECT IDENTIFIER ::= { ellipticCurve 27 } + secp128r1 OBJECT IDENTIFIER ::= { ellipticCurve 28 } + secp128r2 OBJECT IDENTIFIER ::= { ellipticCurve 29 } + secp160r2 OBJECT IDENTIFIER ::= { ellipticCurve 30 } + secp192k1 OBJECT IDENTIFIER ::= { ellipticCurve 31 } + secp224k1 OBJECT IDENTIFIER ::= { ellipticCurve 32 } + secp224r1 OBJECT IDENTIFIER ::= { ellipticCurve 33 } + secp384r1 OBJECT IDENTIFIER ::= { ellipticCurve 34 } + secp521r1 OBJECT IDENTIFIER ::= { ellipticCurve 35 } + sect409k1 OBJECT IDENTIFIER ::= { ellipticCurve 36 } + sect409r1 OBJECT IDENTIFIER ::= { ellipticCurve 37 } + sect571k1 OBJECT IDENTIFIER ::= { ellipticCurve 38 } + sect571r1 OBJECT IDENTIFIER ::= { ellipticCurve 39 } END diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 5864de2d57..5c97bb816c 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -82,7 +82,8 @@ <p><code>pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey' | 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo' | - 'PrivateKeyInfo' | 'CertificationRequest'</code></p> + 'PrivateKeyInfo' | 'CertificationRequest' | 'ECPrivateKey'| + 'OTPEcpkParameters'</code></p> <p><code>pem_entry () = {pki_asn1_type(), binary(), %% DER or encrypted DER not_encrypted | cipher_info()} </code></p> @@ -98,6 +99,8 @@ <p><code>dsa_private_key() = #'DSAPrivateKey'{}</code></p> + <p><code>ec_key() = {'ECKey', Key}</code></p> + <p><code> public_crypt_options() = [{rsa_pad, rsa_padding()}]. </code></p> <p><code> rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' @@ -107,6 +110,8 @@ <p><code> dss_digest_type() = 'sha' </code></p> + <p><code> ecdsa_digest_type() = 'sha' </code></p> + <p><code> crl_reason() = unspecified | keyCompromise | cACompromise | affiliationChanged | superseded | cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise </code></p> @@ -511,8 +516,8 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | <d>The msg is either the binary "plain text" data to be signed or it is the hashed value of "plain text" i.e. the digest.</d> - <v>DigestType = rsa_digest_type() | dss_digest_type()</v> - <v>Key = rsa_private_key() | dsa_private_key()</v> + <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v> + <v>Key = rsa_private_key() | dsa_private_key() | ec_key()</v> </type> <desc> <p> Creates a digital signature.</p> @@ -575,9 +580,9 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | <v>Msg = binary() | {digest,binary()}</v> <d>The msg is either the binary "plain text" data or it is the hashed value of "plain text" i.e. the digest.</d> - <v>DigestType = rsa_digest_type() | dss_digest_type()</v> + <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v> <v>Signature = binary()</v> - <v>Key = rsa_public_key() | dsa_public_key()</v> + <v>Key = rsa_public_key() | dsa_public_key() | ec_key()</v> </type> <desc> <p>Verifies a digital signature</p> diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl index 4d1d510f29..976104fe6c 100644 --- a/lib/public_key/include/public_key.hrl +++ b/lib/public_key/include/public_key.hrl @@ -72,6 +72,10 @@ valid_ext }). +-record('ECPoint', { + point + }). + -define(unspecified, 0). -define(keyCompromise, 1). diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl index f53c94b334..d6dbaba701 100644 --- a/lib/public_key/src/pubkey_cert.erl +++ b/lib/public_key/src/pubkey_cert.erl @@ -464,7 +464,15 @@ digest_type(?sha512WithRSAEncryption) -> digest_type(?md5WithRSAEncryption) -> md5; digest_type(?'id-dsa-with-sha1') -> - sha. + sha; +digest_type(?'ecdsa-with-SHA1') -> + sha; +digest_type(?'ecdsa-with-SHA512') -> + sha512; +digest_type(?'ecdsa-with-SHA384') -> + sha384; +digest_type(?'ecdsa-with-SHA256') -> + sha256. public_key_info(PublicKeyInfo, #path_validation_state{working_public_key_algorithm = diff --git a/lib/public_key/src/pubkey_cert_records.erl b/lib/public_key/src/pubkey_cert_records.erl index 98004c71a3..0449129809 100644 --- a/lib/public_key/src/pubkey_cert_records.erl +++ b/lib/public_key/src/pubkey_cert_records.erl @@ -23,7 +23,8 @@ -include("public_key.hrl"). --export([decode_cert/1, transform/2, supportedPublicKeyAlgorithms/1]). +-export([decode_cert/1, transform/2, supportedPublicKeyAlgorithms/1, + supportedCurvesTypes/1, namedCurves/1]). %%==================================================================== %% Internal application API @@ -101,6 +102,77 @@ supportedPublicKeyAlgorithms(?'dhpublicnumber') -> 'DHPublicKey'; supportedPublicKeyAlgorithms(?'id-keyExchangeAlgorithm') -> 'KEA-PublicKey'; supportedPublicKeyAlgorithms(?'id-ecPublicKey') -> 'ECPoint'. +supportedCurvesTypes(?'characteristic-two-field') -> characteristic_two_field; +supportedCurvesTypes(?'prime-field') -> prime_field. + +namedCurves(?'sect571r1') -> sect571r1; +namedCurves(?'sect571k1') -> sect571k1; +namedCurves(?'sect409r1') -> sect409r1; +namedCurves(?'sect409k1') -> sect409k1; +namedCurves(?'secp521r1') -> secp521r1; +namedCurves(?'secp384r1') -> secp384r1; +namedCurves(?'secp224r1') -> secp224r1; +namedCurves(?'secp224k1') -> secp224k1; +namedCurves(?'secp192k1') -> secp192k1; +namedCurves(?'secp160r2') -> secp160r2; +namedCurves(?'secp128r2') -> secp128r2; +namedCurves(?'secp128r1') -> secp128r1; +namedCurves(?'sect233r1') -> sect233r1; +namedCurves(?'sect233k1') -> sect233k1; +namedCurves(?'sect193r2') -> sect193r2; +namedCurves(?'sect193r1') -> sect193r1; +namedCurves(?'sect131r2') -> sect131r2; +namedCurves(?'sect131r1') -> sect131r1; +namedCurves(?'sect283r1') -> sect283r1; +namedCurves(?'sect283k1') -> sect283k1; +namedCurves(?'sect163r2') -> sect163r2; +namedCurves(?'secp256k1') -> secp256k1; +namedCurves(?'secp160k1') -> secp160k1; +namedCurves(?'secp160r1') -> secp160r1; +namedCurves(?'secp112r2') -> secp112r2; +namedCurves(?'secp112r1') -> secp112r1; +namedCurves(?'sect113r2') -> sect113r2; +namedCurves(?'sect113r1') -> sect113r1; +namedCurves(?'sect239k1') -> sect239k1; +namedCurves(?'sect163r1') -> sect163r1; +namedCurves(?'sect163k1') -> sect163k1; +namedCurves(?'secp256r1') -> secp256r1; +namedCurves(?'secp192r1') -> secp192r1; + +namedCurves(sect571r1) -> ?'sect571r1'; +namedCurves(sect571k1) -> ?'sect571k1'; +namedCurves(sect409r1) -> ?'sect409r1'; +namedCurves(sect409k1) -> ?'sect409k1'; +namedCurves(secp521r1) -> ?'secp521r1'; +namedCurves(secp384r1) -> ?'secp384r1'; +namedCurves(secp224r1) -> ?'secp224r1'; +namedCurves(secp224k1) -> ?'secp224k1'; +namedCurves(secp192k1) -> ?'secp192k1'; +namedCurves(secp160r2) -> ?'secp160r2'; +namedCurves(secp128r2) -> ?'secp128r2'; +namedCurves(secp128r1) -> ?'secp128r1'; +namedCurves(sect233r1) -> ?'sect233r1'; +namedCurves(sect233k1) -> ?'sect233k1'; +namedCurves(sect193r2) -> ?'sect193r2'; +namedCurves(sect193r1) -> ?'sect193r1'; +namedCurves(sect131r2) -> ?'sect131r2'; +namedCurves(sect131r1) -> ?'sect131r1'; +namedCurves(sect283r1) -> ?'sect283r1'; +namedCurves(sect283k1) -> ?'sect283k1'; +namedCurves(sect163r2) -> ?'sect163r2'; +namedCurves(secp256k1) -> ?'secp256k1'; +namedCurves(secp160k1) -> ?'secp160k1'; +namedCurves(secp160r1) -> ?'secp160r1'; +namedCurves(secp112r2) -> ?'secp112r2'; +namedCurves(secp112r1) -> ?'secp112r1'; +namedCurves(sect113r2) -> ?'sect113r2'; +namedCurves(sect113r1) -> ?'sect113r1'; +namedCurves(sect239k1) -> ?'sect239k1'; +namedCurves(sect163r1) -> ?'sect163r1'; +namedCurves(sect163k1) -> ?'sect163k1'; +namedCurves(secp256r1) -> ?'secp256r1'; +namedCurves(secp192r1) -> ?'secp192r1'. + %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -111,14 +183,24 @@ decode_supportedPublicKey(#'OTPSubjectPublicKeyInfo'{algorithm= PA = #'PublicKeyAlgorithm'{algorithm=Algo}, subjectPublicKey = {0,SPK0}}) -> Type = supportedPublicKeyAlgorithms(Algo), - {ok, SPK} = 'OTP-PUB-KEY':decode(Type, SPK0), + SPK = case Type of + 'ECPoint' -> #'ECPoint'{point = SPK0}; + _ -> {ok, SPK1} = 'OTP-PUB-KEY':decode(Type, SPK0), + SPK1 + end, #'OTPSubjectPublicKeyInfo'{subjectPublicKey = SPK, algorithm=PA}. encode_supportedPublicKey(#'OTPSubjectPublicKeyInfo'{algorithm= PA = #'PublicKeyAlgorithm'{algorithm=Algo}, subjectPublicKey = SPK0}) -> Type = supportedPublicKeyAlgorithms(Algo), - {ok, SPK} = 'OTP-PUB-KEY':encode(Type, SPK0), + SPK = case Type of + 'ECPoint' -> + SPK0#'ECPoint'.point; + _ -> + {ok, SPK1} = 'OTP-PUB-KEY':encode(Type, SPK0), + SPK1 + end, #'OTPSubjectPublicKeyInfo'{subjectPublicKey = {0,SPK}, algorithm=PA}. %%% Extensions diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl index 6bdc35fb79..746d142ec3 100644 --- a/lib/public_key/src/pubkey_pem.erl +++ b/lib/public_key/src/pubkey_pem.erl @@ -202,7 +202,11 @@ pem_start('CertificationRequest') -> pem_start('ContentInfo') -> <<"-----BEGIN PKCS7-----">>; pem_start('CertificateList') -> - <<"-----BEGIN X509 CRL-----">>. + <<"-----BEGIN X509 CRL-----">>; +pem_start('OTPEcpkParameters') -> + <<"-----BEGIN EC PARAMETERS-----">>; +pem_start('ECPrivateKey') -> + <<"-----BEGIN EC PRIVATE KEY-----">>. pem_end(<<"-----BEGIN CERTIFICATE-----">>) -> <<"-----END CERTIFICATE-----">>; @@ -226,6 +230,10 @@ pem_end(<<"-----BEGIN PKCS7-----">>) -> <<"-----END PKCS7-----">>; pem_end(<<"-----BEGIN X509 CRL-----">>) -> <<"-----END X509 CRL-----">>; +pem_end(<<"-----BEGIN EC PARAMETERS-----">>) -> + <<"-----END EC PARAMETERS-----">>; +pem_end(<<"-----BEGIN EC PRIVATE KEY-----">>) -> + <<"-----END EC PRIVATE KEY-----">>; pem_end(_) -> undefined. @@ -250,7 +258,11 @@ asn1_type(<<"-----BEGIN CERTIFICATE REQUEST-----">>) -> asn1_type(<<"-----BEGIN PKCS7-----">>) -> 'ContentInfo'; asn1_type(<<"-----BEGIN X509 CRL-----">>) -> - 'CertificateList'. + 'CertificateList'; +asn1_type(<<"-----BEGIN EC PARAMETERS-----">>) -> + 'OTPEcpkParameters'; +asn1_type(<<"-----BEGIN EC PRIVATE KEY-----">>) -> + 'ECPrivateKey'. pem_decrypt() -> <<"Proc-Type: 4,ENCRYPTED">>. diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index e753cf3867..e432a1f14f 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -92,7 +92,9 @@ pem_entry_decode({'SubjectPublicKeyInfo', Der, _}) -> der_decode(KeyType, Key0); 'DSAPublicKey' -> {params, DssParams} = der_decode('DSAParams', Params), - {der_decode(KeyType, Key0), DssParams} + {der_decode(KeyType, Key0), DssParams}; + 'ECPrivateKey' -> + der_decode(KeyType, Key0) end; pem_entry_decode({Asn1Type, Der, not_encrypted}) when is_atom(Asn1Type), is_binary(Der) -> @@ -334,6 +336,40 @@ format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, privateExponent = D}) -> [crypto:mpint(K) || K <- [E, N, D]]. +%% +%% Description: convert a ECPrivate key into resource Key +%%-------------------------------------------------------------------- +list2int(L) -> + S = length(L) * 8, + <<R:S/integer>> = erlang:iolist_to_binary(L), + R. + +ec_private_key_to_eckey(#'ECPrivateKey'{privateKey = PrivKey, + parameters = Param, + publicKey = _PubKey}) -> + ECCurve = case Param of + #'OTPECParameters'{ fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor } -> + Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'OTPFieldID'.fieldType), FieldId#'OTPFieldID'.parameters}, + Curve = {list2int(PCurve#'Curve'.a), list2int(PCurve#'Curve'.b), none}, + {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor}; + {namedCurve, OID} -> + pubkey_cert_records:namedCurves(OID) + end, + Key = {ECCurve, list2int(PrivKey), undefined}, + {'ECKey', crypto:term_to_ec_key(Key)}. + +ec_public_key_to_eckey({#'ECPoint'{point = ECPoint}, Param}) -> + ECCurve = case Param of + #'OTPECParameters'{ fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor } -> + Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'OTPFieldID'.fieldType), FieldId#'OTPFieldID'.parameters}, + Curve = {list2int(PCurve#'Curve'.a), list2int(PCurve#'Curve'.b), none}, + {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor}; + {namedCurve, OID} -> + pubkey_cert_records:namedCurves(OID) + end, + Key = {ECCurve, undefined, ECPoint}, + {'ECKey', crypto:term_to_ec_key(Key)}. + %%-------------------------------------------------------------------- -spec sign(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type(), rsa_private_key() | @@ -356,6 +392,18 @@ sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) -> [crypto:mpint(P), crypto:mpint(Q), crypto:mpint(G), crypto:mpint(X)]); +sign(Digest, DigestType, Key = {?'id-ecPublicKey', _, _}) -> + sign(Digest, DigestType, ec_public_key_to_eckey(Key)); + +sign(Digest, DigestType, Key = #'ECPrivateKey'{}) -> + sign(Digest, DigestType, ec_private_key_to_eckey(Key)); + +sign({digest,_}=Digest, DigestType, {'ECKey', Key}) -> + crypto:ecdsa_sign(DigestType, Digest, Key); + +sign(PlainText, DigestType, {'ECKey', Key}) -> + crypto:ecdsa_sign(DigestType, sized_binary(PlainText), Key); + %% Backwards compatible sign(Digest, none, #'DSAPrivateKey'{} = Key) -> sign({digest,Digest}, sha, Key). @@ -384,6 +432,24 @@ verify({digest,_}=Digest, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = crypto:dss_verify(Digest, sized_binary(Signature), [crypto:mpint(P), crypto:mpint(Q), crypto:mpint(G), crypto:mpint(Key)]); + +verify({digest,_}=Digest, DigestType, Signature, {'ECKey', Key}) -> + crypto:ecdsa_verify(DigestType, Digest, + sized_binary(Signature), + Key); + +verify(PlainText, DigestType, Signature, Key = #'ECPrivateKey'{}) -> + verify(PlainText, DigestType, Signature, ec_private_key_to_eckey(Key)); + +verify(PlainText, DigestType, Signature, Key = {#'ECPoint'{}, _}) -> + verify(PlainText, DigestType, Signature, ec_public_key_to_eckey(Key)); + +verify(PlainText, DigestType, Signature, {'ECKey', Key}) -> + crypto:ecdsa_verify(DigestType, + sized_binary(PlainText), + sized_binary(Signature), + Key); + %% Backwards compatibility verify(Digest, none, Signature, {_, #'Dss-Parms'{}} = Key ) -> verify({digest,Digest}, sha, Signature, Key); @@ -428,7 +494,17 @@ pkix_verify(DerCert, {Key, #'Dss-Parms'{}} = DSAKey) pkix_verify(DerCert, #'RSAPublicKey'{} = RSAKey) when is_binary(DerCert) -> {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert), - verify(PlainText, DigestType, Signature, RSAKey). + verify(PlainText, DigestType, Signature, RSAKey); + +pkix_verify(DerCert, #'ECPrivateKey'{} = ECKey) + when is_binary(DerCert) -> + {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert), + verify(PlainText, DigestType, Signature, ECKey); + +pkix_verify(DerCert, Key = {'ECKey', _}) + when is_binary(DerCert) -> + {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert), + verify(PlainText, DigestType, Signature, Key). %%-------------------------------------------------------------------- -spec pkix_is_issuer(Cert :: der_encoded()| #'OTPCertificate'{} | #'CertificateList'{}, diff --git a/lib/public_key/test/erl_make_certs.erl b/lib/public_key/test/erl_make_certs.erl index 95e288cd71..0bd4f995bf 100644 --- a/lib/public_key/test/erl_make_certs.erl +++ b/lib/public_key/test/erl_make_certs.erl @@ -45,7 +45,7 @@ %% {dnQualifer, DnQ} %% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created) %% (obs IssuerKey migth be {Key, Password} -%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key +%% key = KeyFile|KeyBin|rsa|dsa|ec Subject PublicKey rsa, dsa or ec generates key %% %% %% (OBS: The generated keys are for testing only) @@ -91,6 +91,16 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) -> {Key, encode_key(Key)}. %%-------------------------------------------------------------------- +%% @doc Creates a ec key (OBS: for testing only) +%% the sizes are in bytes +%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()} +%% @end +%%-------------------------------------------------------------------- +gen_ec(Curve) when is_atom(Curve) -> + Key = gen_ec2(Curve), + {Key, encode_key(Key)}. + +%%-------------------------------------------------------------------- %% @doc Verifies cert signatures %% @spec (::binary(), ::tuple()) -> ::boolean() %% @end @@ -102,7 +112,10 @@ verify_signature(DerEncodedCert, DerKey, _KeyParams) -> public_key:pkix_verify(DerEncodedCert, #'RSAPublicKey'{modulus=Mod, publicExponent=Exp}); #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} -> - public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}) + public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}); + #'ECPrivateKey'{version = _Version, privateKey = _PrivKey, + parameters = _Params, publicKey = _PubKey} -> + public_key:pkix_verify(DerEncodedCert, Key) end. %%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -112,6 +125,7 @@ get_key(Opts) -> undefined -> make_key(rsa, Opts); rsa -> make_key(rsa, Opts); dsa -> make_key(dsa, Opts); + ec -> make_key(ec, Opts); Key -> Password = proplists:get_value(password, Opts, no_passwd), decode_key(Key, Password) @@ -129,6 +143,8 @@ decode_key(#'RSAPrivateKey'{} = Key,_) -> Key; decode_key(#'DSAPrivateKey'{} = Key,_) -> Key; +decode_key(#'ECPrivateKey'{} = Key,_) -> + Key; decode_key(PemEntry = {_,_,_}, Pw) -> public_key:pem_entry_decode(PemEntry, Pw); decode_key(PemBin, Pw) -> @@ -140,7 +156,10 @@ encode_key(Key = #'RSAPrivateKey'{}) -> {'RSAPrivateKey', Der, not_encrypted}; encode_key(Key = #'DSAPrivateKey'{}) -> {ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key), - {'DSAPrivateKey', Der, not_encrypted}. + {'DSAPrivateKey', Der, not_encrypted}; +encode_key(Key = #'ECPrivateKey'{}) -> + {ok, Der} = 'OTP-PUB-KEY':encode('ECPrivateKey', Key), + {'ECPrivateKey', Der, not_encrypted}. make_tbs(SubjectKey, Opts) -> Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))), @@ -282,7 +301,14 @@ publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) -> publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) -> Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa', parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}}, - #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}. + #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}; +publickey(#'ECPrivateKey'{version = _Version, + privateKey = _PrivKey, + parameters = Params, + publicKey = {0, PubKey}}) -> + Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-ecPublicKey', parameters=Params}, + #'OTPSubjectPublicKeyInfo'{algorithm = Algo, + subjectPublicKey = #'ECPoint'{point = PubKey}}. validity(Opts) -> DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1), @@ -303,13 +329,24 @@ sign_algorithm(#'RSAPrivateKey'{}, Opts) -> end, {Type, 'NULL'}; sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) -> - {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}. + {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}; +sign_algorithm(#'ECPrivateKey'{}, Opts) -> + Type = case proplists:get_value(digest, Opts, sha1) of + sha1 -> ?'ecdsa-with-SHA1'; + sha512 -> ?'ecdsa-with-SHA512'; + sha384 -> ?'ecdsa-with-SHA384'; + sha256 -> ?'ecdsa-with-SHA256' + end, + {Type, 'NULL'}. make_key(rsa, _Opts) -> %% (OBS: for testing only) gen_rsa2(64); make_key(dsa, _Opts) -> - gen_dsa2(128, 20). %% Bytes i.e. {1024, 160} + gen_dsa2(128, 20); %% Bytes i.e. {1024, 160} +make_key(ec, _Opts) -> + %% (OBS: for testing only) + gen_ec2(secp256k1). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% RSA key generation (OBS: for testing only) @@ -368,6 +405,24 @@ gen_dsa2(LSize, NSize) -> #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X} end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EC key generation (OBS: for testing only) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +int2list(I) -> + L = (length(integer_to_list(I, 16)) + 1) div 2, + binary_to_list(<<I:(L*8)>>). + +gen_ec2(CurveId) -> + Key = crypto:ec_key_new(CurveId), + crypto:ec_key_generate(Key), + {_Curve, PrivKey, PubKey} = crypto:ec_key_to_term(Key), + + #'ECPrivateKey'{version = 1, + privateKey = int2list(PrivKey), + parameters = {namedCurve, pubkey_cert_records:namedCurves(CurveId)}, + publicKey = {0, PubKey}}. + %% See fips_186-3.pdf dsa_search(T, P0, Q, Iter) when Iter > 0 -> P = 2*T*Q*P0 + 1, diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index 6979fb5b5e..fd0780efa3 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -37,10 +37,13 @@ <list type="bulleted"> <item>ssl requires the crypto and public_key applications.</item> <item>Supported SSL/TLS-versions are SSL-3.0, TLS-1.0, - TLS-1.1 and TLS-1.2 (no support for elliptic curve cipher suites yet).</item> + TLS-1.1 and TLS-1.2.</item> <item>For security reasons sslv2 is not supported.</item> <item>Ephemeral Diffie-Hellman cipher suites are supported but not Diffie Hellman Certificates cipher suites.</item> + <item>Elliptic Curve cipher suites are supported on + systems with a OpenSSL library that has EC support + compiled in.</item> <item>Export cipher suites are not supported as the U.S. lifted its export restrictions in early 2000.</item> <item>IDEA cipher suites are not supported as they have @@ -75,10 +78,11 @@ {fail_if_no_peer_cert, boolean()} {depth, integer()} | {cert, der_encoded()}| {certfile, path()} | - {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'PrivateKeyInfo', der_encoded()}} | + {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' |'PrivateKeyInfo', der_encoded()}} | {keyfile, path()} | {password, string()} | {cacerts, [der_encoded()]} | {cacertfile, path()} | |{dh, der_encoded()} | {dhfile, path()} | {ciphers, ciphers()} | + {user_lookup_fun, {fun(), term()}}, {psk_identity, string()}, {srp_identity, {string(), string()}} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()} {next_protocols_advertised, list(binary()} | {client_preferred_next_protocols, binary(), client | server, list(binary())} @@ -123,6 +127,8 @@ {key_exchange(), cipher(), hash()}</c></p> <p><c>key_exchange() = rsa | dhe_dss | dhe_rsa | dh_anon + | psk | dhe_psk | rsa_psk | srp_anon | srp_dss | srp_rsa + | ecdh_anon | ecdh_ecdsa | ecdhe_ecdsa | ecdh_rsa | ecdhe_rsa </c></p> <p><c>cipher() = rc4_128 | des_cbc | '3des_ede_cbc' @@ -134,6 +140,9 @@ <p><c>prf_random() = client_random | server_random </c></p> + <p><c>srp_param_type() = srp_1024 | srp_1536 | srp_2048 | srp_3072 + | srp_4096 | srp_6144 | srp_8192</c></p> + </section> <section> @@ -152,7 +161,7 @@ <tag>{certfile, path()}</tag> <item>Path to a file containing the user's certificate.</item> - <tag>{key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'PrivateKeyInfo', der_encoded()}}</tag> + <tag>{key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' |'PrivateKeyInfo', der_encoded()}}</tag> <item> The DER encoded users private key. If this option is supplied it will override the keyfile option.</item> @@ -183,11 +192,14 @@ ciphers. Additionally some anonymous cipher suites ({dh_anon, rc4_128, md5}, {dh_anon, des_cbc, sha}, {dh_anon, '3des_ede_cbc', sha}, {dh_anon, aes_128_cbc, sha}, {dh_anon, - aes_256_cbc, sha}) are supported for testing purposes and will - only work if explicitly enabled by this option and they are supported/enabled - by the peer also. + aes_256_cbc, sha}, {ecdh_anon, null, sha}, {ecdh_anon, rc4_128, + sha}, {ecdh_anon, '3des_ede_cbc', sha}, {ecdh_anon, aes_128_cbc, + sha}, {ecdh_anon, aes_256_cbc, sha}) are supported for testing + purposes and will only work if explicitly enabled by this + option and they are supported/enabled by the peer also. </item> + <tag>{ssl_imp, new | old}</tag> <item>No longer has any meaning as the old implementation has been removed, it will be ignored. @@ -292,6 +304,35 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | <c>undefined</c> is specified (this is the default), the process will never go into hibernation. </item> + + <tag>{user_lookup_fun, {Lookupfun :: fun(), UserState :: term()}}</tag> + <item> + <p>The lookup fun should be defined as:</p> + <code> +fun(psk, PSKIdentity, UserState :: term()) -> + {ok, SharedSecret :: binary()} | error; +fun(srp, Username, UserState :: term()) -> + {ok, {SRPParams :: srp_param_type(), Salt :: binary(), UserPassHash :: binary()}} | error. + </code> + + <p>For PSK cipher suites, the lookup fun will be called in the client and server the find + the shared secret. On the client, PSKIdentity will be set to hint presented by the server + or undefined. On the server, PSKIdentity is the identity presented by the client. + For SRP cipher suites, the fun will only be used by the server to find the SRP values. + </p> + + <p>For SRP, the required values on a server will usually be precalculated and kept in a passwd + like file. A sample SRP lookup fun that calculates the values on the fly for a single user entry + with a static password could be:</p> + <code><![CDATA[ +user_lookup(srp, Username, _UserState) -> + Salt = ssl:random_bytes(16), + UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, <<"secret">>])]), + {ok, {srp_1024, Salt, UserPassHash}}. + ]]></code> + + </item> + </taglist> </section> @@ -334,6 +375,14 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | server does not support next protocol renegotiation the connection will be aborted if no default protocol is supplied.</p> </item> + + <tag>{psk_identity, string()}</tag> + <item>Specifies the identity the client presents to the server. The matching secret is + found by calling the user_look_fun. + </item> + <tag>{srp_identity, {Username :: string(), Password :: string()}</tag> + <item>Specifies the Username and Password to use to authenticate to the server. + </item> </taglist> </section> @@ -396,6 +445,10 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | using <c>negotiated_next_protocol/1</c> method. </item> + <tag>{psk_identity, string()}</tag> + <item>Specifies the server identity hint the server presents to the client. + </item> + </taglist> </section> diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile index e61f415c84..d3ba76d34e 100644 --- a/lib/ssl/src/Makefile +++ b/lib/ssl/src/Makefile @@ -50,6 +50,7 @@ MODULES= \ ssl_certificate\ ssl_certificate_db\ ssl_cipher \ + ssl_srp_primes \ ssl_connection \ ssl_connection_sup \ ssl_handshake \ @@ -65,7 +66,7 @@ MODULES= \ INTERNAL_HRL_FILES = \ ssl_alert.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_internal.hrl \ - ssl_record.hrl + ssl_record.hrl ssl_srp.hrl ssl_srp_primes.hrl ERL_FILES= \ $(MODULES:%=%.erl) \ diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src index 897a097f73..5c34de905e 100644 --- a/lib/ssl/src/ssl.app.src +++ b/lib/ssl/src/ssl.app.src @@ -20,6 +20,7 @@ ssl_connection_sup, ssl_connection, ssl_cipher, + ssl_srp_primes, ssl_certificate_db, ssl_certificate, ssl_alert diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 0ba59cede2..8ba58c39a3 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -37,6 +37,7 @@ -include("ssl_record.hrl"). -include("ssl_cipher.hrl"). -include("ssl_handshake.hrl"). +-include("ssl_srp_primes.hrl"). -include_lib("public_key/include/public_key.hrl"). @@ -65,6 +66,9 @@ {cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} | {keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} | {cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} | + {user_lookup_fun, {fun(), InitialUserState::term()}} | + {psk_identity, string()} | + {srp_identity, {string(), string()}} | {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()} | {hibernate_after, integer()|undefined} | {next_protocols_advertised, list(binary())} | @@ -360,11 +364,11 @@ cipher_suites() -> cipher_suites(erlang) -> Version = ssl_record:highest_protocol_version([]), - [suite_definition(S) || S <- ssl_cipher:suites(Version)]; + [suite_definition(S) || S <- cipher_suites(Version, [])]; cipher_suites(openssl) -> Version = ssl_record:highest_protocol_version([]), - [ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)]. + [ssl_cipher:openssl_suite_name(S) || S <- cipher_suites(Version, [])]. %%-------------------------------------------------------------------- -spec getopts(#sslsocket{}, [gen_tcp:option_name()]) -> @@ -628,6 +632,9 @@ handle_options(Opts0, _Role) -> cacertfile = handle_option(cacertfile, Opts, CaCertDefault), dh = handle_option(dh, Opts, undefined), dhfile = handle_option(dhfile, Opts, undefined), + user_lookup_fun = handle_option(user_lookup_fun, Opts, undefined), + psk_identity = handle_option(psk_identity, Opts, undefined), + srp_identity = handle_option(srp_identity, Opts, undefined), ciphers = handle_option(ciphers, Opts, []), %% Server side option reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun), @@ -647,7 +654,8 @@ handle_options(Opts0, _Role) -> SslOptions = [versions, verify, verify_fun, fail_if_no_peer_cert, verify_client_once, depth, cert, certfile, key, keyfile, - password, cacerts, cacertfile, dh, dhfile, ciphers, + password, cacerts, cacertfile, dh, dhfile, + user_lookup_fun, psk_identity, srp_identity, ciphers, reuse_session, reuse_sessions, ssl_imp, cb_info, renegotiate_at, secure_renegotiate, hibernate_after, erl_dist, next_protocols_advertised, @@ -717,6 +725,7 @@ validate_option(key, {KeyType, Value}) when is_binary(Value), KeyType == dsa; %% Backwards compatibility KeyType == 'RSAPrivateKey'; KeyType == 'DSAPrivateKey'; + KeyType == 'ECPrivateKey'; KeyType == 'PrivateKeyInfo' -> {KeyType, Value}; @@ -749,6 +758,20 @@ validate_option(dhfile, Value) when is_binary(Value) -> Value; validate_option(dhfile, Value) when is_list(Value), Value =/= "" -> list_to_binary(Value); +validate_option(psk_identity, undefined) -> + undefined; +validate_option(psk_identity, Identity) + when is_list(Identity), Identity =/= "", length(Identity) =< 65535 -> + list_to_binary(Identity); +validate_option(user_lookup_fun, undefined) -> + undefined; +validate_option(user_lookup_fun, {Fun, _} = Value) when is_function(Fun, 3) -> + Value; +validate_option(srp_identity, undefined) -> + undefined; +validate_option(srp_identity, {Username, Password}) + when is_list(Username), is_list(Password), Username =/= "", length(Username) =< 255 -> + {list_to_binary(Username), list_to_binary(Password)}; validate_option(ciphers, Value) when is_list(Value) -> Version = ssl_record:highest_protocol_version([]), try cipher_suites(Version, Value) @@ -911,18 +934,22 @@ emulated_options([], Inet,Emulated) -> {Inet, Emulated}. cipher_suites(Version, []) -> - ssl_cipher:suites(Version); + ssl_cipher:filter_suites(ssl_cipher:suites(Version)); cipher_suites(Version, [{_,_,_,_}| _] = Ciphers0) -> %% Backwards compatibility Ciphers = [{KeyExchange, Cipher, Hash} || {KeyExchange, Cipher, Hash, _} <- Ciphers0], - cipher_suites(Version, Ciphers); + ssl_cipher:filter_suites(cipher_suites(Version, Ciphers)); cipher_suites(Version, [{_,_,_}| _] = Ciphers0) -> Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0], - cipher_suites(Version, Ciphers); + ssl_cipher:filter_suites(cipher_suites(Version, Ciphers)); cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) -> - Supported = ssl_cipher:suites(Version) ++ ssl_cipher:anonymous_suites(), - case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported)] of + Supported0 = ssl_cipher:suites(Version) + ++ ssl_cipher:anonymous_suites() + ++ ssl_cipher:psk_suites(Version) + ++ ssl_cipher:srp_suites(), + Supported1 = ssl_cipher:filter_suites(Supported0), + case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported1)] of [] -> - Supported; + Supported1; Ciphers -> Ciphers end; diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl index 94e95d3cd3..1810043dfb 100644 --- a/lib/ssl/src/ssl_alert.erl +++ b/lib/ssl/src/ssl_alert.erl @@ -112,4 +112,6 @@ description_txt(?INTERNAL_ERROR) -> description_txt(?USER_CANCELED) -> "user canceled"; description_txt(?NO_RENEGOTIATION) -> - "no renegotiation". + "no renegotiation"; +description_txt(?UNKNOWN_PSK_IDENTITY) -> + "unknown psk identity". diff --git a/lib/ssl/src/ssl_alert.hrl b/lib/ssl/src/ssl_alert.hrl index 92548edab7..2a8a91aefa 100644 --- a/lib/ssl/src/ssl_alert.hrl +++ b/lib/ssl/src/ssl_alert.hrl @@ -60,6 +60,7 @@ %% internal_error(80), %% user_canceled(90), %% no_renegotiation(100), +%% unknown_psk_identity(115), %% (255) %% } AlertDescription; @@ -87,6 +88,7 @@ -define(INTERNAL_ERROR, 80). -define(USER_CANCELED, 90). -define(NO_RENEGOTIATION, 100). +-define(UNKNOWN_PSK_IDENTITY, 115). -define(ALERT_REC(Level,Desc), #alert{level=Level,description=Desc,where={?FILE, ?LINE}}). diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index 86f5617b54..41ca81e277 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -38,7 +38,8 @@ is_valid_key_usage/2, select_extension/2, extensions_list/1, - signature_type/1 + signature_type/1, + public_key_type/1 ]). %%==================================================================== @@ -167,7 +168,7 @@ extensions_list(Extensions) -> Extensions. %%-------------------------------------------------------------------- --spec signature_type(term()) -> rsa | dsa . +-spec signature_type(term()) -> rsa | dsa | ecdsa. %% %% Description: %%-------------------------------------------------------------------- @@ -180,7 +181,26 @@ signature_type(RSA) when RSA == ?sha1WithRSAEncryption; -> rsa; signature_type(?'id-dsa-with-sha1') -> - dsa. + dsa; +signature_type(EC) when EC == ?'ecdsa-with-SHA1'; + EC == ?'ecdsa-with-SHA2'; + EC == ?'ecdsa-with-SHA224'; + EC == ?'ecdsa-with-SHA256'; + EC == ?'ecdsa-with-SHA384'; + EC == ?'ecdsa-with-SHA512' -> + ecdsa. + +%%-------------------------------------------------------------------- +-spec public_key_type(term()) -> rsa | dsa | ec. +%% +%% Description: +%%-------------------------------------------------------------------- +public_key_type(?'rsaEncryption') -> + rsa; +public_key_type(?'id-dsa') -> + dsa; +public_key_type(?'id-ecPublicKey') -> + ec. %%-------------------------------------------------------------------- %%% Internal functions diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 567690a413..7e2277ec72 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -34,8 +34,8 @@ -export([security_parameters/3, suite_definition/1, decipher/5, cipher/5, - suite/1, suites/1, anonymous_suites/0, - openssl_suite/1, openssl_suite_name/1, filter/2, + suite/1, suites/1, anonymous_suites/0, psk_suites/1, srp_suites/0, + openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1, hash_algorithm/1, sign_algorithm/1]). -compile(inline). @@ -212,7 +212,61 @@ anonymous_suites() -> ?TLS_DH_anon_WITH_AES_128_CBC_SHA, ?TLS_DH_anon_WITH_AES_256_CBC_SHA, ?TLS_DH_anon_WITH_AES_128_CBC_SHA256, - ?TLS_DH_anon_WITH_AES_256_CBC_SHA256]. + ?TLS_DH_anon_WITH_AES_256_CBC_SHA256, + ?TLS_ECDH_anon_WITH_RC4_128_SHA, + ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, + ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA, + ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA]. + +%%-------------------------------------------------------------------- +-spec psk_suites(tls_version()) -> [cipher_suite()]. +%% +%% Description: Returns a list of the PSK cipher suites, only supported +%% if explicitly set by user. +%%-------------------------------------------------------------------- +psk_suites({3, N}) -> + psk_suites(N); + +psk_suites(N) + when N >= 3 -> + psk_suites(0) ++ + [?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, + ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, + ?TLS_PSK_WITH_AES_256_CBC_SHA384, + ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, + ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, + ?TLS_PSK_WITH_AES_128_CBC_SHA256]; + +psk_suites(_) -> + [?TLS_DHE_PSK_WITH_AES_256_CBC_SHA, + ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA, + ?TLS_PSK_WITH_AES_256_CBC_SHA, + ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA, + ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA, + ?TLS_PSK_WITH_AES_128_CBC_SHA, + ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, + ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, + ?TLS_PSK_WITH_3DES_EDE_CBC_SHA, + ?TLS_DHE_PSK_WITH_RC4_128_SHA, + ?TLS_RSA_PSK_WITH_RC4_128_SHA, + ?TLS_PSK_WITH_RC4_128_SHA]. + +%%-------------------------------------------------------------------- +-spec srp_suites() -> [cipher_suite()]. +%% +%% Description: Returns a list of the SRP cipher suites, only supported +%% if explicitly set by user. +%%-------------------------------------------------------------------- +srp_suites() -> + [?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, + ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, + ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, + ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA, + ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, + ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, + ?TLS_SRP_SHA_WITH_AES_256_CBC_SHA, + ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, + ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA]. %%-------------------------------------------------------------------- -spec suite_definition(cipher_suite()) -> int_cipher_suite(). @@ -297,7 +351,157 @@ suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) -> suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA256) -> {dh_anon, aes_128_cbc, sha256, default_prf}; suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA256) -> - {dh_anon, aes_256_cbc, sha256, default_prf}. + {dh_anon, aes_256_cbc, sha256, default_prf}; + +%%% PSK Cipher Suites RFC 4279 + +suite_definition(?TLS_PSK_WITH_RC4_128_SHA) -> + {psk, rc4_128, sha, default_prf}; +suite_definition(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) -> + {psk, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA) -> + {psk, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA) -> + {psk, aes_256_cbc, sha, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_RC4_128_SHA) -> + {dhe_psk, rc4_128, sha, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA) -> + {dhe_psk, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA) -> + {dhe_psk, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA) -> + {dhe_psk, aes_256_cbc, sha, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_RC4_128_SHA) -> + {rsa_psk, rc4_128, sha, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA) -> + {rsa_psk, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA) -> + {rsa_psk, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA) -> + {rsa_psk, aes_256_cbc, sha, default_prf}; + +%%% TLS 1.2 PSK Cipher Suites RFC 5487 + +suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA256) -> + {psk, aes_128_cbc, sha256, default_prf}; +suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA384) -> + {psk, aes_256_cbc, sha384, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256) -> + {dhe_psk, aes_128_cbc, sha256, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384) -> + {dhe_psk, aes_256_cbc, sha384, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256) -> + {rsa_psk, aes_128_cbc, sha256, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384) -> + {rsa_psk, aes_256_cbc, sha384, default_prf}; + +suite_definition(?TLS_PSK_WITH_NULL_SHA256) -> + {psk, null, sha256, default_prf}; +suite_definition(?TLS_PSK_WITH_NULL_SHA384) -> + {psk, null, sha384, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA256) -> + {dhe_psk, null, sha256, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA384) -> + {dhe_psk, null, sha384, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA256) -> + {rsa_psk, null, sha256, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA384) -> + {rsa_psk, null, sha384, default_prf}; + +%%% SRP Cipher Suites RFC 5054 + +suite_definition(?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA) -> + {srp_anon, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) -> + {srp_rsa, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) -> + {srp_dss, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_SRP_SHA_WITH_AES_128_CBC_SHA) -> + {srp_anon, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) -> + {srp_rsa, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) -> + {srp_dss, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) -> + {srp_anon, aes_256_cbc, sha, default_prf}; +suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) -> + {srp_rsa, aes_256_cbc, sha, default_prf}; +suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) -> + {srp_dss, aes_256_cbc, sha, default_prf}; + +%% RFC 4492 EC TLS suites +suite_definition(?TLS_ECDH_ECDSA_WITH_NULL_SHA) -> + {ecdh_ecdsa, null, sha, default_prf}; +suite_definition(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) -> + {ecdh_ecdsa, rc4_128, sha, default_prf}; +suite_definition(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) -> + {ecdh_ecdsa, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) -> + {ecdh_ecdsa, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) -> + {ecdh_ecdsa, aes_256_cbc, sha, default_prf}; + +suite_definition(?TLS_ECDHE_ECDSA_WITH_NULL_SHA) -> + {ecdhe_ecdsa, null, sha, default_prf}; +suite_definition(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) -> + {ecdhe_ecdsa, rc4_128, sha, default_prf}; +suite_definition(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) -> + {ecdhe_ecdsa, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) -> + {ecdhe_ecdsa, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) -> + {ecdhe_ecdsa, aes_256_cbc, sha, default_prf}; + +suite_definition(?TLS_ECDH_RSA_WITH_NULL_SHA) -> + {ecdh_rsa, null, sha, default_prf}; +suite_definition(?TLS_ECDH_RSA_WITH_RC4_128_SHA) -> + {ecdh_rsa, rc4_128, sha, default_prf}; +suite_definition(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) -> + {ecdh_rsa, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) -> + {ecdh_rsa, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) -> + {ecdh_rsa, aes_256_cbc, sha, default_prf}; + +suite_definition(?TLS_ECDHE_RSA_WITH_NULL_SHA) -> + {ecdhe_rsa, null, sha, default_prf}; +suite_definition(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) -> + {ecdhe_rsa, rc4_128, sha, default_prf}; +suite_definition(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) -> + {ecdhe_rsa, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) -> + {ecdhe_rsa, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) -> + {ecdhe_rsa, aes_256_cbc, sha, default_prf}; + +suite_definition(?TLS_ECDH_anon_WITH_NULL_SHA) -> + {ecdh_anon, null, sha, default_prf}; +suite_definition(?TLS_ECDH_anon_WITH_RC4_128_SHA) -> + {ecdh_anon, rc4_128, sha, default_prf}; +suite_definition(?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA) -> + {ecdh_anon, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_ECDH_anon_WITH_AES_128_CBC_SHA) -> + {ecdh_anon, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_ECDH_anon_WITH_AES_256_CBC_SHA) -> + {ecdh_anon, aes_256_cbc, sha, default_prf}; + +%% RFC 5289 EC TLS suites +suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) -> + {ecdhe_ecdsa, aes_128_cbc, sha256, sha256}; +suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) -> + {ecdhe_ecdsa, aes_256_cbc, sha384, sha384}; +suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) -> + {ecdh_ecdsa, aes_128_cbc, sha256, sha256}; +suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) -> + {ecdh_ecdsa, aes_256_cbc, sha384, sha384}; +suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) -> + {ecdhe_rsa, aes_128_cbc, sha256, sha256}; +suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) -> + {ecdhe_rsa, aes_256_cbc, sha384, sha384}; +suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) -> + {ecdh_rsa, aes_128_cbc, sha256, sha256}; +suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) -> + {ecdh_rsa, aes_256_cbc, sha384, sha384}. %%-------------------------------------------------------------------- -spec suite(erl_cipher_suite()) -> cipher_suite(). @@ -370,7 +574,157 @@ suite({dhe_rsa, aes_256_cbc, sha256}) -> suite({dh_anon, aes_128_cbc, sha256}) -> ?TLS_DH_anon_WITH_AES_128_CBC_SHA256; suite({dh_anon, aes_256_cbc, sha256}) -> - ?TLS_DH_anon_WITH_AES_256_CBC_SHA256. + ?TLS_DH_anon_WITH_AES_256_CBC_SHA256; + +%%% PSK Cipher Suites RFC 4279 + +suite({psk, rc4_128,sha}) -> + ?TLS_PSK_WITH_RC4_128_SHA; +suite({psk, '3des_ede_cbc',sha}) -> + ?TLS_PSK_WITH_3DES_EDE_CBC_SHA; +suite({psk, aes_128_cbc,sha}) -> + ?TLS_PSK_WITH_AES_128_CBC_SHA; +suite({psk, aes_256_cbc,sha}) -> + ?TLS_PSK_WITH_AES_256_CBC_SHA; +suite({dhe_psk, rc4_128,sha}) -> + ?TLS_DHE_PSK_WITH_RC4_128_SHA; +suite({dhe_psk, '3des_ede_cbc',sha}) -> + ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA; +suite({dhe_psk, aes_128_cbc,sha}) -> + ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA; +suite({dhe_psk, aes_256_cbc,sha}) -> + ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA; +suite({rsa_psk, rc4_128,sha}) -> + ?TLS_RSA_PSK_WITH_RC4_128_SHA; +suite({rsa_psk, '3des_ede_cbc',sha}) -> + ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA; +suite({rsa_psk, aes_128_cbc,sha}) -> + ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA; +suite({rsa_psk, aes_256_cbc,sha}) -> + ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA; + +%%% TLS 1.2 PSK Cipher Suites RFC 5487 + +suite({psk, aes_128_cbc, sha256}) -> + ?TLS_PSK_WITH_AES_128_CBC_SHA256; +suite({psk, aes_256_cbc, sha384}) -> + ?TLS_PSK_WITH_AES_256_CBC_SHA384; +suite({dhe_psk, aes_128_cbc, sha256}) -> + ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256; +suite({dhe_psk, aes_256_cbc, sha384}) -> + ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384; +suite({rsa_psk, aes_128_cbc, sha256}) -> + ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256; +suite({rsa_psk, aes_256_cbc, sha384}) -> + ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384; + +suite({psk, null, sha256}) -> + ?TLS_PSK_WITH_NULL_SHA256; +suite({psk, null, sha384}) -> + ?TLS_PSK_WITH_NULL_SHA384; +suite({dhe_psk, null, sha256}) -> + ?TLS_DHE_PSK_WITH_NULL_SHA256; +suite({dhe_psk, null, sha384}) -> + ?TLS_DHE_PSK_WITH_NULL_SHA384; +suite({rsa_psk, null, sha256}) -> + ?TLS_RSA_PSK_WITH_NULL_SHA256; +suite({rsa_psk, null, sha384}) -> + ?TLS_RSA_PSK_WITH_NULL_SHA384; + +%%% SRP Cipher Suites RFC 5054 + +suite({srp_anon, '3des_ede_cbc', sha}) -> + ?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA; +suite({srp_rsa, '3des_ede_cbc', sha}) -> + ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA; +suite({srp_dss, '3des_ede_cbc', sha}) -> + ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA; +suite({srp_anon, aes_128_cbc, sha}) -> + ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA; +suite({srp_rsa, aes_128_cbc, sha}) -> + ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA; +suite({srp_dss, aes_128_cbc, sha}) -> + ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA; +suite({srp_anon, aes_256_cbc, sha}) -> + ?TLS_SRP_SHA_WITH_AES_256_CBC_SHA; +suite({srp_rsa, aes_256_cbc, sha}) -> + ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA; +suite({srp_dss, aes_256_cbc, sha}) -> + ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA; + +%%% RFC 4492 EC TLS suites +suite({ecdh_ecdsa, null, sha}) -> + ?TLS_ECDH_ECDSA_WITH_NULL_SHA; +suite({ecdh_ecdsa, rc4_128, sha}) -> + ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA; +suite({ecdh_ecdsa, '3des_ede_cbc', sha}) -> + ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA; +suite({ecdh_ecdsa, aes_128_cbc, sha}) -> + ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA; +suite({ecdh_ecdsa, aes_256_cbc, sha}) -> + ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA; + +suite({ecdhe_ecdsa, null, sha}) -> + ?TLS_ECDHE_ECDSA_WITH_NULL_SHA; +suite({ecdhe_ecdsa, rc4_128, sha}) -> + ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA; +suite({ecdhe_ecdsa, '3des_ede_cbc', sha}) -> + ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA; +suite({ecdhe_ecdsa, aes_128_cbc, sha}) -> + ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA; +suite({ecdhe_ecdsa, aes_256_cbc, sha}) -> + ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA; + +suite({ecdh_rsa, null, sha}) -> + ?TLS_ECDH_RSA_WITH_NULL_SHA; +suite({ecdh_rsa, rc4_128, sha}) -> + ?TLS_ECDH_RSA_WITH_RC4_128_SHA; +suite({ecdh_rsa, '3des_ede_cbc', sha}) -> + ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA; +suite({ecdh_rsa, aes_128_cbc, sha}) -> + ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA; +suite({ecdh_rsa, aes_256_cbc, sha}) -> + ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA; + +suite({ecdhe_rsa, null, sha}) -> + ?TLS_ECDHE_RSA_WITH_NULL_SHA; +suite({ecdhe_rsa, rc4_128, sha}) -> + ?TLS_ECDHE_RSA_WITH_RC4_128_SHA; +suite({ecdhe_rsa, '3des_ede_cbc', sha}) -> + ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA; +suite({ecdhe_rsa, aes_128_cbc, sha}) -> + ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA; +suite({ecdhe_rsa, aes_256_cbc, sha}) -> + ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA; + +suite({ecdh_anon, null, sha}) -> + ?TLS_ECDH_anon_WITH_NULL_SHA; +suite({ecdh_anon, rc4_128, sha}) -> + ?TLS_ECDH_anon_WITH_RC4_128_SHA; +suite({ecdh_anon, '3des_ede_cbc', sha}) -> + ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA; +suite({ecdh_anon, aes_128_cbc, sha}) -> + ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA; +suite({ecdh_anon, aes_256_cbc, sha}) -> + ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA; + +%%% RFC 5289 EC TLS suites +suite({ecdhe_ecdsa, aes_128_cbc, sha256}) -> + ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; +suite({ecdhe_ecdsa, aes_256_cbc, sha384}) -> + ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384; +suite({ecdh_ecdsa, aes_128_cbc, sha256}) -> + ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256; +suite({ecdh_ecdsa, aes_256_cbc, sha384}) -> + ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384; +suite({ecdhe_rsa, aes_128_cbc, sha256}) -> + ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256; +suite({ecdhe_rsa, aes_256_cbc, sha384}) -> + ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384; +suite({ecdh_rsa, aes_128_cbc, sha256}) -> + ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256; +suite({ecdh_rsa, aes_256_cbc, sha384}) -> + ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384. %%-------------------------------------------------------------------- -spec openssl_suite(openssl_cipher_suite()) -> cipher_suite(). @@ -415,7 +769,78 @@ openssl_suite("RC4-MD5") -> openssl_suite("EDH-RSA-DES-CBC-SHA") -> ?TLS_DHE_RSA_WITH_DES_CBC_SHA; openssl_suite("DES-CBC-SHA") -> - ?TLS_RSA_WITH_DES_CBC_SHA. + ?TLS_RSA_WITH_DES_CBC_SHA; + +%%% SRP Cipher Suites RFC 5054 + +openssl_suite("SRP-DSS-AES-256-CBC-SHA") -> + ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA; +openssl_suite("SRP-RSA-AES-256-CBC-SHA") -> + ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA; +openssl_suite("SRP-DSS-3DES-EDE-CBC-SHA") -> + ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA; +openssl_suite("SRP-RSA-3DES-EDE-CBC-SHA") -> + ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA; +openssl_suite("SRP-DSS-AES-128-CBC-SHA") -> + ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA; +openssl_suite("SRP-RSA-AES-128-CBC-SHA") -> + ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA; + +%% RFC 4492 EC TLS suites +openssl_suite("ECDH-ECDSA-RC4-SHA") -> + ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA; +openssl_suite("ECDH-ECDSA-DES-CBC3-SHA") -> + ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA; +openssl_suite("ECDH-ECDSA-AES128-SHA") -> + ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA; +openssl_suite("ECDH-ECDSA-AES256-SHA") -> + ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA; + +openssl_suite("ECDHE-ECDSA-RC4-SHA") -> + ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA; +openssl_suite("ECDHE-ECDSA-DES-CBC3-SHA") -> + ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA; +openssl_suite("ECDHE-ECDSA-AES128-SHA") -> + ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA; +openssl_suite("ECDHE-ECDSA-AES256-SHA") -> + ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA; + +openssl_suite("ECDHE-RSA-RC4-SHA") -> + ?TLS_ECDHE_RSA_WITH_RC4_128_SHA; +openssl_suite("ECDHE-RSA-DES-CBC3-SHA") -> + ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA; +openssl_suite("ECDHE-RSA-AES128-SHA") -> + ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA; +openssl_suite("ECDHE-RSA-AES256-SHA") -> + ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA; + +openssl_suite("ECDH-RSA-RC4-SHA") -> + ?TLS_ECDH_RSA_WITH_RC4_128_SHA; +openssl_suite("ECDH-RSA-DES-CBC3-SHA") -> + ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA; +openssl_suite("ECDH-RSA-AES128-SHA") -> + ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA; +openssl_suite("ECDH-RSA-AES256-SHA") -> + ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA; + +%% RFC 5289 EC TLS suites +openssl_suite("ECDHE-ECDSA-AES128-SHA256") -> + ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; +openssl_suite("ECDHE-ECDSA-AES256-SHA384") -> + ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384; +openssl_suite("ECDH-ECDSA-AES128-SHA256") -> + ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256; +openssl_suite("ECDH-ECDSA-AES256-SHA384") -> + ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384; +openssl_suite("ECDHE-RSA-AES128-SHA256") -> + ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256; +openssl_suite("ECDHE-RSA-AES256-SHA384") -> + ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384; +openssl_suite("ECDH-RSA-AES128-SHA256") -> + ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256; +openssl_suite("ECDH-RSA-AES256-SHA384") -> + ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384. + %%-------------------------------------------------------------------- -spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite(). %% @@ -469,6 +894,88 @@ openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) -> "DHE-DSS-AES256-SHA256"; openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) -> "DHE-RSA-AES256-SHA256"; + +%%% PSK Cipher Suites RFC 4279 + +openssl_suite_name(?TLS_PSK_WITH_AES_256_CBC_SHA) -> + "PSK-AES256-CBC-SHA"; +openssl_suite_name(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) -> + "PSK-3DES-EDE-CBC-SHA"; +openssl_suite_name(?TLS_PSK_WITH_AES_128_CBC_SHA) -> + "PSK-AES128-CBC-SHA"; +openssl_suite_name(?TLS_PSK_WITH_RC4_128_SHA) -> + "PSK-RC4-SHA"; + +%%% SRP Cipher Suites RFC 5054 + +openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) -> + "SRP-RSA-3DES-EDE-CBC-SHA"; +openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) -> + "SRP-DSS-3DES-EDE-CBC-SHA"; +openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) -> + "SRP-RSA-AES-128-CBC-SHA"; +openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) -> + "SRP-DSS-AES-128-CBC-SHA"; +openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) -> + "SRP-RSA-AES-256-CBC-SHA"; +openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) -> + "SRP-DSS-AES-256-CBC-SHA"; + +%% RFC 4492 EC TLS suites +openssl_suite_name(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) -> + "ECDH-ECDSA-RC4-SHA"; +openssl_suite_name(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) -> + "ECDH-ECDSA-DES-CBC3-SHA"; +openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) -> + "ECDH-ECDSA-AES128-SHA"; +openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) -> + "ECDH-ECDSA-AES256-SHA"; + +openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) -> + "ECDHE-ECDSA-RC4-SHA"; +openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) -> + "ECDHE-ECDSA-DES-CBC3-SHA"; +openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) -> + "ECDHE-ECDSA-AES128-SHA"; +openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) -> + "ECDHE-ECDSA-AES256-SHA"; + +openssl_suite_name(?TLS_ECDH_RSA_WITH_RC4_128_SHA) -> + "ECDH-RSA-RC4-SHA"; +openssl_suite_name(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) -> + "ECDH-RSA-DES-CBC3-SHA"; +openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) -> + "ECDH-RSA-AES128-SHA"; +openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) -> + "ECDH-RSA-AES256-SHA"; + +openssl_suite_name(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) -> + "ECDHE-RSA-RC4-SHA"; +openssl_suite_name(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) -> + "ECDHE-RSA-DES-CBC3-SHA"; +openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) -> + "ECDHE-RSA-AES128-SHA"; +openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) -> + "ECDHE-RSA-AES256-SHA"; + +%% RFC 5289 EC TLS suites +openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) -> + "ECDHE-ECDSA-AES128-SHA256"; +openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) -> + "ECDHE-ECDSA-AES256-SHA384"; +openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) -> + "ECDH-ECDSA-AES128-SHA256"; +openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) -> + "ECDH-ECDSA-AES256-SHA384"; +openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) -> + "ECDHE-RSA-AES128-SHA256"; +openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) -> + "ECDHE-RSA-AES256-SHA384"; +openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) -> + "ECDH-RSA-AES128-SHA256"; +openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) -> + "ECDH-RSA-AES256-SHA384"; + %% No oppenssl name openssl_suite_name(Cipher) -> suite_definition(Cipher). @@ -483,14 +990,80 @@ filter(undefined, Ciphers) -> filter(DerCert, Ciphers) -> OtpCert = public_key:pkix_decode_cert(DerCert, otp), SigAlg = OtpCert#'OTPCertificate'.signatureAlgorithm, + PubKeyInfo = OtpCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subjectPublicKeyInfo, + PubKeyAlg = PubKeyInfo#'OTPSubjectPublicKeyInfo'.algorithm, + + Ciphers1 = + case ssl_certificate:public_key_type(PubKeyAlg#'PublicKeyAlgorithm'.algorithm) of + rsa -> + filter_keyuse(OtpCert, (Ciphers -- dsa_signed_suites()) -- ecdh_suites(), + rsa_suites(), dhe_rsa_suites() ++ ecdhe_rsa_suites()); + dsa -> + (Ciphers -- rsa_signed_suites()) -- ecdsa_signed_suites(); + ec -> + filter_keyuse(OtpCert, (Ciphers -- rsa_keyed_suites()) -- dsa_signed_suites(), + [], ecdhe_ecdsa_suites()) + end, case ssl_certificate:signature_type(SigAlg#'SignatureAlgorithm'.algorithm) of - rsa -> - filter_rsa(OtpCert, Ciphers -- dsa_signed_suites()); - dsa -> - Ciphers -- rsa_signed_suites() - end. + rsa -> Ciphers1 -- ecdsa_signed_suites(); + dsa -> Ciphers1; + ecdsa -> Ciphers1 -- rsa_signed_suites() + end. %%-------------------------------------------------------------------- +-spec filter_suites([cipher_suite()]) -> [cipher_suite()]. +%% +%% Description: filter suites for algorithms +%%------------------------------------------------------------------- +filter_suites(Suites = [{_,_,_}|_]) -> + Algos = crypto:algorithms(), + lists:filter(fun({KeyExchange, Cipher, Hash}) -> + is_acceptable_keyexchange(KeyExchange, Algos) andalso + is_acceptable_cipher(Cipher, Algos) andalso + is_acceptable_hash(Hash, Algos) + end, Suites); + +filter_suites(Suites = [{_,_,_,_}|_]) -> + Algos = crypto:algorithms(), + lists:filter(fun({KeyExchange, Cipher, Hash, Prf}) -> + is_acceptable_keyexchange(KeyExchange, Algos) andalso + is_acceptable_cipher(Cipher, Algos) andalso + is_acceptable_hash(Hash, Algos) andalso + is_acceptable_prf(Prf, Algos) + end, Suites); + +filter_suites(Suites) -> + Algos = crypto:algorithms(), + lists:filter(fun(Suite) -> + {KeyExchange, Cipher, Hash, Prf} = ssl_cipher:suite_definition(Suite), + is_acceptable_keyexchange(KeyExchange, Algos) andalso + is_acceptable_cipher(Cipher, Algos) andalso + is_acceptable_hash(Hash, Algos) andalso + is_acceptable_prf(Prf, Algos) + end, Suites). + +is_acceptable_keyexchange(KeyExchange, Algos) + when KeyExchange == ecdh_ecdsa; + KeyExchange == ecdhe_ecdsa; + KeyExchange == ecdh_rsa; + KeyExchange == ecdhe_rsa; + KeyExchange == ecdh_anon -> + proplists:get_bool(ec, Algos); +is_acceptable_keyexchange(_, _) -> + true. + +is_acceptable_cipher(_, _) -> + true. + +is_acceptable_hash(Hash, Algos) -> + proplists:get_bool(Hash, Algos). + +is_acceptable_prf(default_prf, _) -> + true; +is_acceptable_prf(Prf, Algos) -> + proplists:get_bool(Prf, Algos). + +%%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -605,14 +1178,14 @@ hash_size(md5) -> 16; hash_size(sha) -> 20; +hash_size(sha224) -> + 28; hash_size(sha256) -> - 32. -%% Currently no supported cipher suites defaults to sha384 or sha512 -%% so these clauses are not needed at the moment. -%% hash_size(sha384) -> -%% 48; -%% hash_size(sha512) -> -%% 64. + 32; +hash_size(sha384) -> + 48; +hash_size(sha512) -> + 64. %% RFC 5246: 6.2.3.2. CBC Block Cipher %% @@ -702,7 +1275,13 @@ next_iv(Bin, IV) -> NextIV. rsa_signed_suites() -> - dhe_rsa_suites() ++ rsa_suites(). + dhe_rsa_suites() ++ rsa_suites() ++ + psk_rsa_suites() ++ srp_rsa_suites() ++ + ecdh_rsa_suites() ++ ecdhe_rsa_suites(). + +rsa_keyed_suites() -> + dhe_rsa_suites() ++ rsa_suites() ++ + psk_rsa_suites() ++ srp_rsa_suites(). dhe_rsa_suites() -> [?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, @@ -712,6 +1291,19 @@ dhe_rsa_suites() -> ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA, ?TLS_DHE_RSA_WITH_DES_CBC_SHA]. +psk_rsa_suites() -> + [?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, + ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, + ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA, + ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA, + ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, + ?TLS_RSA_PSK_WITH_RC4_128_SHA]. + +srp_rsa_suites() -> + [?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, + ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, + ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA]. + rsa_suites() -> [?TLS_RSA_WITH_AES_256_CBC_SHA256, ?TLS_RSA_WITH_AES_256_CBC_SHA, @@ -721,9 +1313,27 @@ rsa_suites() -> ?TLS_RSA_WITH_RC4_128_SHA, ?TLS_RSA_WITH_RC4_128_MD5, ?TLS_RSA_WITH_DES_CBC_SHA]. - + +ecdh_rsa_suites() -> + [?TLS_ECDH_RSA_WITH_NULL_SHA, + ?TLS_ECDH_RSA_WITH_RC4_128_SHA, + ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384]. + +ecdhe_rsa_suites() -> + [?TLS_ECDHE_RSA_WITH_NULL_SHA, + ?TLS_ECDHE_RSA_WITH_RC4_128_SHA, + ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384]. + dsa_signed_suites() -> - dhe_dss_suites(). + dhe_dss_suites() ++ srp_dss_suites(). dhe_dss_suites() -> [?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, @@ -733,24 +1343,53 @@ dhe_dss_suites() -> ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA]. -filter_rsa(OtpCert, RsaCiphers) -> +srp_dss_suites() -> + [?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, + ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, + ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA]. + +ecdsa_signed_suites() -> + ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites(). + +ecdh_suites() -> + ecdh_rsa_suites() ++ ecdh_ecdsa_suites(). + +ecdh_ecdsa_suites() -> + [?TLS_ECDH_ECDSA_WITH_NULL_SHA, + ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA, + ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384]. + +ecdhe_ecdsa_suites() -> + [?TLS_ECDHE_ECDSA_WITH_NULL_SHA, + ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384]. + +filter_keyuse(OtpCert, Ciphers, Suites, SignSuites) -> TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, TBSExtensions = TBSCert#'OTPTBSCertificate'.extensions, Extensions = ssl_certificate:extensions_list(TBSExtensions), case ssl_certificate:select_extension(?'id-ce-keyUsage', Extensions) of undefined -> - RsaCiphers; + Ciphers; #'Extension'{extnValue = KeyUse} -> - Result = filter_rsa_suites(keyEncipherment, - KeyUse, RsaCiphers, rsa_suites()), - filter_rsa_suites(digitalSignature, - KeyUse, Result, dhe_rsa_suites()) + Result = filter_keyuse_suites(keyEncipherment, + KeyUse, Ciphers, Suites), + filter_keyuse_suites(digitalSignature, + KeyUse, Result, SignSuites) end. -filter_rsa_suites(Use, KeyUse, CipherSuits, RsaSuites) -> +filter_keyuse_suites(Use, KeyUse, CipherSuits, Suites) -> case ssl_certificate:is_valid_key_usage(KeyUse, Use) of true -> CipherSuits; false -> - CipherSuits -- RsaSuites + CipherSuits -- Suites end. diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl index 0f439f8ed5..d06fb104ba 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -219,6 +219,120 @@ %% TLS_DH_anon_WITH_AES_256_CBC_SHA256 = { 0x00,0x6D }; -define(TLS_DH_anon_WITH_AES_256_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#6D)>>). +%% RFC 4492 EC TLS suites + +%% ECDH_ECDSA + +%% TLS_ECDH_ECDSA_WITH_NULL_SHA = { 0xC0, 0x01 } +-define(TLS_ECDH_ECDSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#01)>>). + +%% TLS_ECDH_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x02 } +-define(TLS_ECDH_ECDSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#02)>>). + +%% TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x03 } +-define(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#03)>>). + +%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x04 } +-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#04)>>). + +%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x05 } +-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#05)>>). + +%% ECDHE_ECDSA + +%% TLS_ECDHE_ECDSA_WITH_NULL_SHA = { 0xC0, 0x06 } +-define(TLS_ECDHE_ECDSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#06)>>). + +%% TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x07 } +-define(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#07)>>). + +%% TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x08 } +-define(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#08)>>). + +%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x09 } +-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#09)>>). + +%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0A } +-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0A)>>). + +%% ECDH_RSA + +%% TLS_ECDH_RSA_WITH_NULL_SHA = { 0xC0, 0x0B } +-define(TLS_ECDH_RSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#0B)>>). + +%% TLS_ECDH_RSA_WITH_RC4_128_SHA = { 0xC0, 0x0C } +-define(TLS_ECDH_RSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#0C)>>). + +%% TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x0D } +-define(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0D)>>). + +%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x0E } +-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0E)>>). + +%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0F } +-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0F)>>). + +%% ECDHE_RSA + +%% TLS_ECDHE_RSA_WITH_NULL_SHA = { 0xC0, 0x10 } +-define(TLS_ECDHE_RSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#10)>>). + +%% TLS_ECDHE_RSA_WITH_RC4_128_SHA = { 0xC0, 0x11 } +-define(TLS_ECDHE_RSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#11)>>). + +%% TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x12 } +-define(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#12)>>). + +%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x13 } +-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#13)>>). + +%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x14 } +-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#14)>>). + +%% ECDH_anon + +%% TLS_ECDH_anon_WITH_NULL_SHA = { 0xC0, 0x15 } +-define(TLS_ECDH_anon_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#15)>>). + +%% TLS_ECDH_anon_WITH_RC4_128_SHA = { 0xC0, 0x16 } +-define(TLS_ECDH_anon_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#16)>>). + +%% TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x17 } +-define(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#17)>>). + +%% TLS_ECDH_anon_WITH_AES_128_CBC_SHA = { 0xC0, 0x18 } +-define(TLS_ECDH_anon_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#18)>>). + +%% TLS_ECDH_anon_WITH_AES_256_CBC_SHA = { 0xC0, 0x19 } +-define(TLS_ECDH_anon_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#19)>>). + + +%% RFC 5289 EC TLS suites + +%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x23}; +-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#23)>>). + +%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x24}; +-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#24)>>). + +%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x25}; +-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#25)>>). + +%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x26}; +-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#26)>>). + +%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x27}; +-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#27)>>). + +%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x28}; +-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#28)>>). + +%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x29}; +-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#29)>>). + +%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x2A}; +-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#2A)>>). + %%% Kerberos Cipher Suites %% TLS_KRB5_WITH_DES_CBC_SHA = { 0x00,0x1E }; @@ -250,4 +364,109 @@ %% hello extension data as they should. -define(TLS_EMPTY_RENEGOTIATION_INFO_SCSV, <<?BYTE(16#00), ?BYTE(16#FF)>>). +%%% PSK Cipher Suites RFC 4279 + +%% TLS_PSK_WITH_RC4_128_SHA = { 0x00, 0x8A }; +-define(TLS_PSK_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#8A)>>). + +%% TLS_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x8B }; +-define(TLS_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8B)>>). + +%% TLS_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x8C }; +-define(TLS_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8C)>>). + +%% TLS_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x8D }; +-define(TLS_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8D)>>). + +%% TLS_DHE_PSK_WITH_RC4_128_SHA = { 0x00, 0x8E }; +-define(TLS_DHE_PSK_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#8E)>>). + +%% TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x8F }; +-define(TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8F)>>). + +%% TLS_DHE_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x90 }; +-define(TLS_DHE_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#90)>>). + +%% TLS_DHE_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x91 }; +-define(TLS_DHE_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#91)>>). + +%% TLS_RSA_PSK_WITH_RC4_128_SHA = { 0x00, 0x92 }; +-define(TLS_RSA_PSK_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#92)>>). + +%% TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x93 }; +-define(TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#93)>>). + +%% TLS_RSA_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x94 }; +-define(TLS_RSA_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#94)>>). + +%% TLS_RSA_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x95 }; +-define(TLS_RSA_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#95)>>). + +%%% TLS 1.2 PSK Cipher Suites RFC 5487 + +%% TLS_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xAE}; +-define(TLS_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#AE)>>). + +%% TLS_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xAF}; +-define(TLS_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#00), ?BYTE(16#AF)>>). + +%% TLS_PSK_WITH_NULL_SHA256 = {0x00,0xB0}; +-define(TLS_PSK_WITH_NULL_SHA256, <<?BYTE(16#00), ?BYTE(16#B0)>>). + +%% TLS_PSK_WITH_NULL_SHA384 = {0x00,0xB1}; +-define(TLS_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B1)>>). + +%% TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xB2}; +-define(TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#B2)>>). + +%% TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xB3}; +-define(TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#00), ?BYTE(16#B3)>>). + +%% TLS_DHE_PSK_WITH_NULL_SHA256 = {0x00,0xB4}; +-define(TLS_DHE_PSK_WITH_NULL_SHA256, <<?BYTE(16#00), ?BYTE(16#B4)>>). + +%% TLS_DHE_PSK_WITH_NULL_SHA384 = {0x00,0xB5}; +-define(TLS_DHE_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B5)>>). + +%% TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xB6}; +-define(TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#B6)>>). + +%% TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xB7}; +-define(TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#00), ?BYTE(16#B7)>>). + +%% TLS_RSA_PSK_WITH_NULL_SHA256 = {0x00,0xB8}; +-define(TLS_RSA_PSK_WITH_NULL_SHA256, <<?BYTE(16#00), ?BYTE(16#B8)>>). + +%% TLS_RSA_PSK_WITH_NULL_SHA384 = {0x00,0xB9}; +-define(TLS_RSA_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B9)>>). + +%%% SRP Cipher Suites RFC 5054 + +%% TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1A }; +-define(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1A)>>). + +%% TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1B }; +-define(TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1B)>>). + +%% TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1C }; +-define(TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1C)>>). + +%% TLS_SRP_SHA_WITH_AES_128_CBC_SHA = { 0xC0,0x1D }; +-define(TLS_SRP_SHA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1D)>>). + +%% TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = { 0xC0,0x1E }; +-define(TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1E)>>). + +%% TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = { 0xC0,0x1F }; +-define(TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1F)>>). + +%% TLS_SRP_SHA_WITH_AES_256_CBC_SHA = { 0xC0,0x20 }; +-define(TLS_SRP_SHA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#20)>>). + +%% TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = { 0xC0,0x21 }; +-define(TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#21)>>). + +%% TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = { 0xC0,0x22 }; +-define(TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#22)>>). + -endif. % -ifdef(ssl_cipher). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 8f4fd88d42..16232e629a 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -34,6 +34,8 @@ -include("ssl_record.hrl"). -include("ssl_cipher.hrl"). -include("ssl_internal.hrl"). +-include("ssl_srp.hrl"). +-include("ssl_srp_primes.hrl"). -include_lib("public_key/include/public_key.hrl"). %% Internal application API @@ -81,6 +83,9 @@ private_key, % PKIX: #'RSAPrivateKey'{} diffie_hellman_params, % PKIX: #'DHParameter'{} relevant for server side diffie_hellman_keys, % {PublicKey, PrivateKey} + psk_identity, % binary() - server psk identity hint + srp_params, % #srp_user{} + srp_keys, % {PublicKey, PrivateKey} premaster_secret, % file_ref_db, % ets() cert_db_ref, % ref() @@ -522,7 +527,11 @@ certify(#certificate{} = Cert, certify(#server_key_exchange{} = KeyExchangeMsg, #state{role = client, negotiated_version = Version, key_algorithm = Alg} = State0) - when Alg == dhe_dss; Alg == dhe_rsa; Alg == dh_anon -> + when Alg == dhe_dss; Alg == dhe_rsa; + Alg == ecdhe_rsa; Alg == ecdhe_ecdsa; + Alg == dh_anon; Alg == ecdh_anon; + Alg == psk; Alg == dhe_psk; Alg == rsa_psk; + Alg == srp_dss; Alg == srp_rsa; Alg == srp_anon -> case handle_server_key(KeyExchangeMsg, State0) of #state{} = State1 -> {Record, State} = next_record(State1), @@ -539,6 +548,45 @@ certify(#certificate_request{}, State0) -> {Record, State} = next_record(State0#state{client_certificate_requested = true}), next_state(certify, certify, Record, State); +%% PSK and RSA_PSK might bypass the Server-Key-Exchange +certify(#server_hello_done{}, + #state{session = #session{master_secret = undefined}, + negotiated_version = Version, + psk_identity = PSKIdentity, + premaster_secret = undefined, + role = client, + key_algorithm = Alg} = State0) + when Alg == psk -> + case server_psk_master_secret(PSKIdentity, State0) of + #state{} = State -> + client_certify_and_key_exchange(State); + #alert{} = Alert -> + handle_own_alert(Alert, Version, certify, State0) + end; + +certify(#server_hello_done{}, + #state{session = #session{master_secret = undefined}, + ssl_options = SslOpts, + negotiated_version = Version, + psk_identity = PSKIdentity, + premaster_secret = undefined, + role = client, + key_algorithm = Alg} = State0) + when Alg == rsa_psk -> + case handle_psk_identity(PSKIdentity, SslOpts#ssl_options.user_lookup_fun) of + {ok, PSK} when is_binary(PSK) -> + PremasterSecret = make_premaster_secret(Version, rsa), + Len = byte_size(PSK), + RealPMS = <<?UINT16(48), PremasterSecret/binary, ?UINT16(Len), PSK/binary>>, + State1 = State0#state{premaster_secret = PremasterSecret}, + State = master_from_premaster_secret(RealPMS, State1), + client_certify_and_key_exchange(State); + #alert{} = Alert -> + Alert; + _ -> + ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER) + end; + %% Master secret was determined with help of server-key exchange msg certify(#server_hello_done{}, #state{session = #session{master_secret = MasterSecret} = Session, @@ -625,6 +673,71 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl next_state(certify, cipher, Record, State); #alert{} = Alert -> handle_own_alert(Alert, Version, certify, State0) + end; + +certify_client_key_exchange(#client_ec_diffie_hellman_public{dh_public = ClientPublicEcDhPoint}, + #state{negotiated_version = Version, + diffie_hellman_keys = {'ECKey', ECDHKey}} = State0) -> + case ec_dh_master_secret(ECDHKey, ClientPublicEcDhPoint, State0) of + #state{} = State1 -> + {Record, State} = next_record(State1), + next_state(certify, cipher, Record, State); + #alert{} = Alert -> + handle_own_alert(Alert, Version, certify, State0) + end; + +certify_client_key_exchange(#client_psk_identity{identity = ClientPSKIdentity}, + #state{negotiated_version = Version} = State0) -> + case server_psk_master_secret(ClientPSKIdentity, State0) of + #state{} = State1 -> + {Record, State} = next_record(State1), + next_state(certify, cipher, Record, State); + #alert{} = Alert -> + handle_own_alert(Alert, Version, certify, State0) + end; + +certify_client_key_exchange(#client_dhe_psk_identity{ + identity = ClientPSKIdentity, + dh_public = ClientPublicDhKey}, + #state{negotiated_version = Version, + diffie_hellman_params = #'DHParameter'{prime = P, + base = G}, + diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) -> + case dhe_psk_master_secret(ClientPSKIdentity, crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of + #state{} = State1 -> + {Record, State} = next_record(State1), + next_state(certify, cipher, Record, State); + #alert{} = Alert -> + handle_own_alert(Alert, Version, certify, State0) + end; + +certify_client_key_exchange(#client_rsa_psk_identity{ + identity = PskIdentity, + exchange_keys = + #encrypted_premaster_secret{premaster_secret= EncPMS}}, + #state{negotiated_version = Version, + private_key = Key} = State0) -> + PremasterSecret = ssl_handshake:decrypt_premaster_secret(EncPMS, Key), + case server_rsa_psk_master_secret(PskIdentity, PremasterSecret, State0) of + #state{} = State1 -> + {Record, State} = next_record(State1), + next_state(certify, cipher, Record, State); + #alert{} = Alert -> + handle_own_alert(Alert, Version, certify, State0) + end; + +certify_client_key_exchange(#client_srp_public{srp_a = ClientPublicKey}, + #state{negotiated_version = Version, + srp_params = + #srp_user{prime = Prime, + verifier = Verifier} + } = State0) -> + case server_srp_master_secret(Verifier, Prime, ClientPublicKey, State0) of + #state{} = State1 -> + {Record, State} = next_record(State1), + next_state(certify, cipher, Record, State); + #alert{} = Alert -> + handle_own_alert(Alert, Version, certify, State0) end. %%-------------------------------------------------------------------- @@ -1171,6 +1284,7 @@ init_private_key(DbHandle, undefined, KeyFile, Password, _) -> [PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List, PKey =:= 'RSAPrivateKey' orelse PKey =:= 'DSAPrivateKey' orelse + PKey =:= 'ECPrivateKey' orelse PKey =:= 'PrivateKeyInfo' ], private_key(public_key:pem_entry_decode(PemEntry, Password)) @@ -1184,6 +1298,8 @@ init_private_key(_,{rsa, PrivateKey}, _, _,_) -> init_private_key('RSAPrivateKey', PrivateKey); init_private_key(_,{dsa, PrivateKey},_,_,_) -> init_private_key('DSAPrivateKey', PrivateKey); +init_private_key(_,{ec, PrivateKey},_,_,_) -> + init_private_key('ECPrivateKey', PrivateKey); init_private_key(_,{Asn1Type, PrivateKey},_,_,_) -> private_key(init_private_key(Asn1Type, PrivateKey)). @@ -1199,9 +1315,29 @@ private_key(#'PrivateKeyInfo'{privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-dsa'}, privateKey = Key}) -> public_key:der_decode('DSAPrivateKey', iolist_to_binary(Key)); + +private_key(#'ECPrivateKey'{privateKey = PrivKey, + parameters = Param, + publicKey = _PubKey}) -> + ECCurve = case Param of + #'OTPECParameters'{ fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor } -> + Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'OTPFieldID'.fieldType), FieldId#'OTPFieldID'.parameters}, + Curve = {list2int(PCurve#'Curve'.a), list2int(PCurve#'Curve'.b), none}, + {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor}; + {namedCurve, OID} -> + pubkey_cert_records:namedCurves(OID) + end, + Key = {ECCurve, list2int(PrivKey), undefined}, + {'ECKey', crypto:term_to_ec_key(Key)}; + private_key(Key) -> Key. +list2int(L) -> + S = length(L) * 8, + <<R:S/integer>> = erlang:iolist_to_binary(L), + R. + -spec(file_error(_,_) -> no_return()). file_error(File, Throw) -> case Throw of @@ -1250,7 +1386,25 @@ handle_peer_cert(PeerCert, PublicKeyInfo, State1 = State0#state{session = Session#session{peer_certificate = PeerCert}, public_key_info = PublicKeyInfo}, - {Record, State} = next_record(State1), + State2 = case PublicKeyInfo of + {?'id-ecPublicKey', {'ECPoint', PublicKey}, PublicKeyParams} -> + ECCurve = case PublicKeyParams of + #'OTPECParameters'{ fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor } -> + Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'OTPFieldID'.fieldType), FieldId#'OTPFieldID'.parameters}, + Curve = {list2int(PCurve#'Curve'.a), list2int(PCurve#'Curve'.b), none}, + {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor}; + {namedCurve, OID} -> + pubkey_cert_records:namedCurves(OID) + end, + %% Generate Client ECDH Key + ECClntKey = crypto:ec_key_new(ECCurve), + crypto:ec_key_generate(ECClntKey), + State3 = State1#state{diffie_hellman_keys = {'ECKey', ECClntKey}}, + ec_dh_master_secret(ECClntKey, PublicKey, State3); + + _ -> State1 + end, + {Record, State} = next_record(State2), next_state(certify, certify, Record, State). certify_client(#state{client_certificate_requested = true, role = client, @@ -1439,7 +1593,8 @@ server_hello_done(#state{transport_cb = Transport, State#state{connection_states = ConnectionStates, tls_handshake_history = Handshake}. -certify_server(#state{key_algorithm = dh_anon} = State) -> +certify_server(#state{key_algorithm = Algo} = State) + when Algo == dh_anon; Algo == ecdh_anon; Algo == psk; Algo == dhe_psk -> State; certify_server(#state{transport_cb = Transport, @@ -1494,6 +1649,165 @@ key_exchange(#state{role = server, key_algorithm = Algo, diffie_hellman_keys = Keys, tls_handshake_history = Handshake}; +key_exchange(#state{role = server, private_key = Key, key_algorithm = Algo} = State) + when Algo == ecdh_ecdsa; Algo == ecdh_rsa -> + State#state{diffie_hellman_keys = Key}; +key_exchange(#state{role = server, key_algorithm = Algo, + hashsign_algorithm = HashSignAlgo, + private_key = PrivateKey, + connection_states = ConnectionStates0, + negotiated_version = Version, + tls_handshake_history = Handshake0, + socket = Socket, + transport_cb = Transport + } = State) + when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa; + Algo == ecdh_anon -> + %%TODO: select prefered curve from extension + + %% Generate Server ECDH Key + ECDHKey = crypto:ec_key_new(secp256k1), + crypto:ec_key_generate(ECDHKey), + Keys = {'ECKey', ECDHKey}, + + ConnectionState = + ssl_record:pending_connection_state(ConnectionStates0, read), + SecParams = ConnectionState#connection_state.security_parameters, + #security_parameters{client_random = ClientRandom, + server_random = ServerRandom} = SecParams, + Msg = ssl_handshake:key_exchange(server, Version, {ecdh, Keys, + HashSignAlgo, ClientRandom, + ServerRandom, + PrivateKey}), + {BinMsg, ConnectionStates, Handshake1} = + encode_handshake(Msg, Version, ConnectionStates0, Handshake0), + Transport:send(Socket, BinMsg), + State#state{connection_states = ConnectionStates, + diffie_hellman_keys = Keys, + tls_handshake_history = Handshake1}; + +key_exchange(#state{role = server, key_algorithm = psk, + ssl_options = #ssl_options{psk_identity = undefined}} = State) -> + State; +key_exchange(#state{role = server, key_algorithm = psk, + ssl_options = #ssl_options{psk_identity = PskIdentityHint}, + hashsign_algorithm = HashSignAlgo, + private_key = PrivateKey, + connection_states = ConnectionStates0, + negotiated_version = Version, + tls_handshake_history = Handshake0, + socket = Socket, + transport_cb = Transport + } = State) -> + ConnectionState = + ssl_record:pending_connection_state(ConnectionStates0, read), + SecParams = ConnectionState#connection_state.security_parameters, + #security_parameters{client_random = ClientRandom, + server_random = ServerRandom} = SecParams, + Msg = ssl_handshake:key_exchange(server, Version, {psk, PskIdentityHint, + HashSignAlgo, ClientRandom, + ServerRandom, + PrivateKey}), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Msg, Version, ConnectionStates0, Handshake0), + Transport:send(Socket, BinMsg), + State#state{connection_states = ConnectionStates, + tls_handshake_history = Handshake}; + +key_exchange(#state{role = server, key_algorithm = dhe_psk, + ssl_options = #ssl_options{psk_identity = PskIdentityHint}, + hashsign_algorithm = HashSignAlgo, + diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params, + private_key = PrivateKey, + connection_states = ConnectionStates0, + negotiated_version = Version, + tls_handshake_history = Handshake0, + socket = Socket, + transport_cb = Transport + } = State) -> + Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]), + ConnectionState = + ssl_record:pending_connection_state(ConnectionStates0, read), + SecParams = ConnectionState#connection_state.security_parameters, + #security_parameters{client_random = ClientRandom, + server_random = ServerRandom} = SecParams, + Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, Keys, Params, + HashSignAlgo, ClientRandom, + ServerRandom, + PrivateKey}), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Msg, Version, ConnectionStates0, Handshake0), + Transport:send(Socket, BinMsg), + State#state{connection_states = ConnectionStates, + diffie_hellman_keys = Keys, + tls_handshake_history = Handshake}; + +key_exchange(#state{role = server, key_algorithm = rsa_psk, + ssl_options = #ssl_options{psk_identity = undefined}} = State) -> + State; +key_exchange(#state{role = server, key_algorithm = rsa_psk, + ssl_options = #ssl_options{psk_identity = PskIdentityHint}, + hashsign_algorithm = HashSignAlgo, + private_key = PrivateKey, + connection_states = ConnectionStates0, + negotiated_version = Version, + tls_handshake_history = Handshake0, + socket = Socket, + transport_cb = Transport + } = State) -> + ConnectionState = + ssl_record:pending_connection_state(ConnectionStates0, read), + SecParams = ConnectionState#connection_state.security_parameters, + #security_parameters{client_random = ClientRandom, + server_random = ServerRandom} = SecParams, + Msg = ssl_handshake:key_exchange(server, Version, {psk, PskIdentityHint, + HashSignAlgo, ClientRandom, + ServerRandom, + PrivateKey}), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Msg, Version, ConnectionStates0, Handshake0), + Transport:send(Socket, BinMsg), + State#state{connection_states = ConnectionStates, + tls_handshake_history = Handshake}; + +key_exchange(#state{role = server, key_algorithm = Algo, + ssl_options = #ssl_options{user_lookup_fun = LookupFun}, + hashsign_algorithm = HashSignAlgo, + session = #session{srp_username = Username}, + private_key = PrivateKey, + connection_states = ConnectionStates0, + negotiated_version = Version, + tls_handshake_history = Handshake0, + socket = Socket, + transport_cb = Transport + } = State) + when Algo == srp_dss; + Algo == srp_rsa; + Algo == srp_anon -> + SrpParams = handle_srp_identity(Username, LookupFun), + Keys = case generate_srp_server_keys(SrpParams, 0) of + Alert = #alert{} -> + throw(Alert); + Keys0 = {_,_} -> + Keys0 + end, + ConnectionState = + ssl_record:pending_connection_state(ConnectionStates0, read), + SecParams = ConnectionState#connection_state.security_parameters, + #security_parameters{client_random = ClientRandom, + server_random = ServerRandom} = SecParams, + Msg = ssl_handshake:key_exchange(server, Version, {srp, Keys, SrpParams, + HashSignAlgo, ClientRandom, + ServerRandom, + PrivateKey}), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Msg, Version, ConnectionStates0, Handshake0), + Transport:send(Socket, BinMsg), + State#state{connection_states = ConnectionStates, + srp_params = SrpParams, + srp_keys = Keys, + tls_handshake_history = Handshake}; + key_exchange(#state{role = client, connection_states = ConnectionStates0, key_algorithm = rsa, @@ -1523,6 +1837,85 @@ key_exchange(#state{role = client, encode_handshake(Msg, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), State#state{connection_states = ConnectionStates, + tls_handshake_history = Handshake}; + +key_exchange(#state{role = client, + connection_states = ConnectionStates0, + key_algorithm = Algorithm, + negotiated_version = Version, + diffie_hellman_keys = Keys, + socket = Socket, transport_cb = Transport, + tls_handshake_history = Handshake0} = State) + when Algorithm == ecdhe_ecdsa; Algorithm == ecdhe_rsa; + Algorithm == ecdh_ecdsa; Algorithm == ecdh_rsa; + Algorithm == ecdh_anon -> + Msg = ssl_handshake:key_exchange(client, Version, {ecdh, Keys}), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Msg, Version, ConnectionStates0, Handshake0), + Transport:send(Socket, BinMsg), + State#state{connection_states = ConnectionStates, + tls_handshake_history = Handshake}; + +key_exchange(#state{role = client, + ssl_options = SslOpts, + connection_states = ConnectionStates0, + key_algorithm = psk, + negotiated_version = Version, + socket = Socket, transport_cb = Transport, + tls_handshake_history = Handshake0} = State) -> + Msg = ssl_handshake:key_exchange(client, Version, {psk, SslOpts#ssl_options.psk_identity}), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Msg, Version, ConnectionStates0, Handshake0), + Transport:send(Socket, BinMsg), + State#state{connection_states = ConnectionStates, + tls_handshake_history = Handshake}; + +key_exchange(#state{role = client, + ssl_options = SslOpts, + connection_states = ConnectionStates0, + key_algorithm = dhe_psk, + negotiated_version = Version, + diffie_hellman_keys = {DhPubKey, _}, + socket = Socket, transport_cb = Transport, + tls_handshake_history = Handshake0} = State) -> + Msg = ssl_handshake:key_exchange(client, Version, {dhe_psk, SslOpts#ssl_options.psk_identity, DhPubKey}), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Msg, Version, ConnectionStates0, Handshake0), + Transport:send(Socket, BinMsg), + State#state{connection_states = ConnectionStates, + tls_handshake_history = Handshake}; + +key_exchange(#state{role = client, + ssl_options = SslOpts, + connection_states = ConnectionStates0, + key_algorithm = rsa_psk, + public_key_info = PublicKeyInfo, + negotiated_version = Version, + premaster_secret = PremasterSecret, + socket = Socket, transport_cb = Transport, + tls_handshake_history = Handshake0} = State) -> + Msg = rsa_psk_key_exchange(Version, SslOpts#ssl_options.psk_identity, PremasterSecret, PublicKeyInfo), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Msg, Version, ConnectionStates0, Handshake0), + Transport:send(Socket, BinMsg), + State#state{connection_states = ConnectionStates, + tls_handshake_history = Handshake}; + +key_exchange(#state{role = client, + connection_states = ConnectionStates0, + key_algorithm = Algorithm, + negotiated_version = Version, + srp_keys = {ClntPubKey, _}, + socket = Socket, transport_cb = Transport, + tls_handshake_history = Handshake0} = State) + when Algorithm == srp_dss; + Algorithm == srp_rsa; + Algorithm == srp_anon -> + Msg = ssl_handshake:key_exchange(client, Version, {srp, ClntPubKey}), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Msg, Version, ConnectionStates0, Handshake0), + Transport:send(Socket, BinMsg), + State#state{connection_states = ConnectionStates, tls_handshake_history = Handshake}. rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _}) @@ -1541,6 +1934,22 @@ rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _}) rsa_key_exchange(_, _, _) -> throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE)). +rsa_psk_key_exchange(Version, PskIdentity, PremasterSecret, PublicKeyInfo = {Algorithm, _, _}) + when Algorithm == ?rsaEncryption; + Algorithm == ?md2WithRSAEncryption; + Algorithm == ?md5WithRSAEncryption; + Algorithm == ?sha1WithRSAEncryption; + Algorithm == ?sha224WithRSAEncryption; + Algorithm == ?sha256WithRSAEncryption; + Algorithm == ?sha384WithRSAEncryption; + Algorithm == ?sha512WithRSAEncryption + -> + ssl_handshake:key_exchange(client, Version, + {psk_premaster_secret, PskIdentity, PremasterSecret, + PublicKeyInfo}); +rsa_psk_key_exchange(_, _, _, _) -> + throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE)). + request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer}, connection_states = ConnectionStates0, cert_db = CertDbHandle, @@ -1628,7 +2037,7 @@ handle_server_key(#server_key_exchange{exchange_keys = Keys}, Params = ssl_handshake:decode_server_key(Keys, KeyAlg, Version), HashSign = connection_hashsign(Params#server_key_params.hashsign, State), case HashSign of - {_, anon} -> + {_, SignAlgo} when SignAlgo == anon; SignAlgo == ecdh_anon -> server_master_secret(Params#server_key_params.params, State); _ -> verify_server_key(Params, HashSign, State) @@ -1659,7 +2068,32 @@ verify_server_key(#server_key_params{params = Params, server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDhKey}, State) -> - dh_master_secret(P, G, ServerPublicDhKey, undefined, State). + dh_master_secret(P, G, ServerPublicDhKey, undefined, State); + +server_master_secret(#server_ecdh_params{curve = ECCurve, public = ECServerPubKey}, + State) -> + %% Generate Client ECDH Key + ECClntKey = crypto:ec_key_new(ECCurve), + crypto:ec_key_generate(ECClntKey), + State1 = State#state{diffie_hellman_keys = {'ECKey', ECClntKey}}, + + ec_dh_master_secret(ECClntKey, ECServerPubKey, State1); + +server_master_secret(#server_psk_params{ + hint = IdentityHint}, + State) -> + %% store for later use + State#state{psk_identity = IdentityHint}; + +server_master_secret(#server_dhe_psk_params{ + hint = IdentityHint, + dh_params = #server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDhKey}}, + State) -> + dhe_psk_master_secret(IdentityHint, P, G, ServerPublicDhKey, undefined, State); + +server_master_secret(#server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B}, + State) -> + client_srp_master_secret(G, N, S, B, undefined, State). master_from_premaster_secret(PremasterSecret, #state{session = Session, @@ -1689,6 +2123,141 @@ dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) -> [PMpint, GMpint]), master_from_premaster_secret(PremasterSecret, State). +ec_dh_master_secret(ECKey, ECPoint, State) -> + PremasterSecret = + crypto:ecdh_compute_key(ECKey, ECPoint), + master_from_premaster_secret(PremasterSecret, State). + +handle_psk_identity(_PSKIdentity, LookupFun) + when LookupFun == undefined -> + error; +handle_psk_identity(PSKIdentity, {Fun, UserState}) -> + Fun(psk, PSKIdentity, UserState). + +server_psk_master_secret(ClientPSKIdentity, + #state{ssl_options = SslOpts} = State) -> + case handle_psk_identity(ClientPSKIdentity, SslOpts#ssl_options.user_lookup_fun) of + {ok, PSK} when is_binary(PSK) -> + Len = byte_size(PSK), + PremasterSecret = <<?UINT16(Len), 0:(Len*8), ?UINT16(Len), PSK/binary>>, + master_from_premaster_secret(PremasterSecret, State); + #alert{} = Alert -> + Alert; + _ -> + ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER) + end. + +dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, undefined, State) -> + PMpint = mpint_binary(Prime), + GMpint = mpint_binary(Base), + Keys = {_, PrivateDhKey} = + crypto:dh_generate_key([PMpint,GMpint]), + dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey, + State#state{diffie_hellman_keys = Keys}); + +dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey, + #state{ssl_options = SslOpts} = State) -> + case handle_psk_identity(PSKIdentity, SslOpts#ssl_options.user_lookup_fun) of + {ok, PSK} when is_binary(PSK) -> + DHSecret = + crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey, + [PMpint, GMpint]), + DHLen = erlang:byte_size(DHSecret), + Len = erlang:byte_size(PSK), + PremasterSecret = <<?UINT16(DHLen), DHSecret/binary, ?UINT16(Len), PSK/binary>>, + master_from_premaster_secret(PremasterSecret, State); + #alert{} = Alert -> + Alert; + _ -> + ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER) + end. + +server_rsa_psk_master_secret(PskIdentity, PremasterSecret, + #state{ssl_options = SslOpts} = State) -> + case handle_psk_identity(PskIdentity, SslOpts#ssl_options.user_lookup_fun) of + {ok, PSK} when is_binary(PSK) -> + Len = byte_size(PSK), + RealPMS = <<?UINT16(48), PremasterSecret/binary, ?UINT16(Len), PSK/binary>>, + master_from_premaster_secret(RealPMS, State); + #alert{} = Alert -> + Alert; + _ -> + ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER) + end. + +generate_srp_server_keys(_SrpParams, 10) -> + ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); +generate_srp_server_keys(SrpParams = + #srp_user{generator = Generator, prime = Prime, + verifier = Verifier}, N) -> + Private = ssl:random_bytes(32), + Multiplier = crypto:srp6a_multiplier(Generator, Prime), + case crypto:srp_value_B(Multiplier, Verifier, Generator, Private, Prime) of + error -> + generate_srp_server_keys(SrpParams, N+1); + Public -> {Public, Private} + end. + +generate_srp_client_keys(_Generator, _Prime, 10) -> + ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); +generate_srp_client_keys(Generator, Prime, N) -> + Private = ssl:random_bytes(32), + case crypto:srp_mod_exp(Generator, Private, Prime) of + error -> + generate_srp_client_keys(Generator, Prime, N+1); + Public -> {Public, Private} + end. + +handle_srp_identity(Username, {Fun, UserState}) -> + case Fun(srp, Username, UserState) of + {ok, {SRPParams, Salt, UserPassHash}} + when is_atom(SRPParams), is_binary(Salt), is_binary(UserPassHash) -> + {Generator, Prime} = ssl_srp_primes:get_srp_params(SRPParams), + Verifier = crypto:srp_mod_exp(Generator, UserPassHash, Prime), + #srp_user{generator = Generator, prime = Prime, + salt = Salt, verifier = Verifier}; + #alert{} = Alert -> + throw(Alert); + _ -> + throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)) + end. + +server_srp_master_secret(Verifier, Prime, ClntPub, State = #state{srp_keys = {SrvrPub, SrvrPriv}}) -> + U = crypto:srp6_value_u(ClntPub, SrvrPub, Prime), + case crypto:srp_server_secret(Verifier, SrvrPriv, U, ClntPub, Prime) of + error -> + ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); + PremasterSecret -> + master_from_premaster_secret(PremasterSecret, State) + end. + +client_srp_master_secret(_Generator, _Prime, _Salt, _SrvrPub, #alert{} = Alert, _State) -> + Alert; +client_srp_master_secret(Generator, Prime, Salt, SrvrPub, undefined, State) -> + Keys = generate_srp_client_keys(Generator, Prime, 0), + client_srp_master_secret(Generator, Prime, Salt, SrvrPub, Keys, State#state{srp_keys = Keys}); + +client_srp_master_secret(Generator, Prime, Salt, SrvrPub, {ClntPub, ClntPriv}, + #state{ssl_options = SslOpts} = State) -> + case ssl_srp_primes:check_srp_params(Generator, Prime) of + ok -> + {Username, Password} = SslOpts#ssl_options.srp_identity, + UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), + + Multiplier = crypto:srp6a_multiplier(Generator, Prime), + U = crypto:srp6_value_u(ClntPub, SrvrPub, Prime), + case crypto:srp_client_secret(ClntPriv, U, SrvrPub, Multiplier, + Generator, UserPassHash, Prime) of + error -> + ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); + PremasterSecret -> + + master_from_premaster_secret(PremasterSecret, State) + end; + _ -> + ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER) + end. + cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) -> ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0), next_state_connection(cipher, ack_connection(State#state{session = Session, @@ -2488,19 +3057,34 @@ default_hashsign(_Version = {Major, Minor}, KeyExchange) when Major == 3 andalso Minor >= 3 andalso (KeyExchange == rsa orelse KeyExchange == dhe_rsa orelse - KeyExchange == dh_rsa) -> + KeyExchange == dh_rsa orelse + KeyExchange == ecdhe_rsa orelse + KeyExchange == srp_rsa) -> {sha, rsa}; default_hashsign(_Version, KeyExchange) when KeyExchange == rsa; KeyExchange == dhe_rsa; - KeyExchange == dh_rsa -> + KeyExchange == dh_rsa; + KeyExchange == ecdhe_rsa; + KeyExchange == srp_rsa -> {md5sha, rsa}; default_hashsign(_Version, KeyExchange) + when KeyExchange == ecdhe_ecdsa; + KeyExchange == ecdh_ecdsa; + KeyExchange == ecdh_rsa -> + {sha, ecdsa}; +default_hashsign(_Version, KeyExchange) when KeyExchange == dhe_dss; - KeyExchange == dh_dss -> + KeyExchange == dh_dss; + KeyExchange == srp_dss -> {sha, dsa}; default_hashsign(_Version, KeyExchange) - when KeyExchange == dh_anon -> + when KeyExchange == dh_anon; + KeyExchange == ecdh_anon; + KeyExchange == psk; + KeyExchange == dhe_psk; + KeyExchange == rsa_psk; + KeyExchange == srp_anon -> {null, anon}. start_or_recv_cancel_timer(infinity, _RecvFrom) -> diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 1929370991..2758676113 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -28,6 +28,7 @@ -include("ssl_cipher.hrl"). -include("ssl_alert.hrl"). -include("ssl_internal.hrl"). +-include("ssl_srp.hrl"). -include_lib("public_key/include/public_key.hrl"). -export([master_secret/4, client_hello/8, server_hello/5, hello/4, @@ -46,6 +47,8 @@ #client_key_exchange{} | #finished{} | #certificate_verify{} | #hello_request{} | #next_protocol{}. +-define(NAMED_CURVE_TYPE, 3). + %%==================================================================== %% Internal application API %%==================================================================== @@ -69,6 +72,7 @@ client_hello(Host, Port, ConnectionStates, Pending = ssl_record:pending_connection_state(ConnectionStates, read), SecParams = Pending#connection_state.security_parameters, Ciphers = available_suites(UserSuites, Version), + SRP = srp_user(SslOpts), Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert), @@ -80,7 +84,9 @@ client_hello(Host, Port, ConnectionStates, renegotiation_info = renegotiation_info(client, ConnectionStates, Renegotiation), + srp = SRP, hash_signs = default_hash_signs(), + elliptic_curves = #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)}, next_protocol_negotiation = encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector, Renegotiation) }. @@ -165,7 +171,8 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version, hello(#client_hello{client_version = ClientVersion, random = Random, cipher_suites = CipherSuites, - renegotiation_info = Info} = Hello, + renegotiation_info = Info, + srp = SRP} = Hello, #ssl_options{versions = Versions, secure_renegotiate = SecureRenegotation} = SslOpts, {Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) -> @@ -174,13 +181,14 @@ hello(#client_hello{client_version = ClientVersion, random = Random, case ssl_record:is_acceptable_version(Version) of true -> {Type, #session{cipher_suite = CipherSuite, - compression_method = Compression} = Session} + compression_method = Compression} = Session1} = select_session(Hello, Port, Session0, Version, SslOpts, Cache, CacheCb, Cert), case CipherSuite of no_suite -> ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY); _ -> + Session = handle_srp_info(SRP, Session1), case handle_renegotiation_info(server, Info, ConnectionStates0, Renegotiation, SecureRenegotation, CipherSuites) of @@ -348,9 +356,10 @@ verify_signature(_Version, Hash, _HashAlgo, Signature, {?rsaEncryption, PubKey, _ -> false end; verify_signature(_Version, Hash, {HashAlgo, dsa}, Signature, {?'id-dsa', PublicKey, PublicKeyParams}) -> + public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams}); +verify_signature(_Version, Hash, {HashAlgo, ecdsa}, Signature, {?'id-ecPublicKey', PublicKey, PublicKeyParams}) -> public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams}). - %%-------------------------------------------------------------------- -spec certificate_request(#connection_states{}, db_handle(), certdb_ref()) -> #certificate_request{}. @@ -375,6 +384,12 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) -> {premaster_secret, binary(), public_key_info()} | {dh, binary()} | {dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()}, + binary(), binary(), private_key()} | + {ecdh, {'ECKey', any()}, {HashAlgo::atom(), SignAlgo::atom()}, + binary(), binary(), private_key()} | + {psk, binary()} | + {dhe_psk, binary(), binary()} | + {srp, {binary(), binary()}, #srp_user{}, {HashAlgo::atom(), SignAlgo::atom()}, binary(), binary(), private_key()}) -> #client_key_exchange{} | #server_key_exchange{}. %% @@ -391,6 +406,40 @@ key_exchange(client, _Version, {dh, <<?UINT32(Len), PublicKey:Len/binary>>}) -> dh_public = PublicKey} }; +key_exchange(client, _Version, {ecdh, {'ECKey', ECDHKey}}) -> + {_, _, ECPublicKey} = crypto:ec_key_to_term(ECDHKey), + #client_key_exchange{ + exchange_keys = #client_ec_diffie_hellman_public{ + dh_public = ECPublicKey} + }; + +key_exchange(client, _Version, {psk, Identity}) -> + #client_key_exchange{ + exchange_keys = #client_psk_identity{ + identity = Identity} + }; + +key_exchange(client, _Version, {dhe_psk, Identity, <<?UINT32(Len), PublicKey:Len/binary>>}) -> + #client_key_exchange{ + exchange_keys = #client_dhe_psk_identity{ + identity = Identity, + dh_public = PublicKey} + }; + +key_exchange(client, _Version, {psk_premaster_secret, PskIdentity, Secret, {_, PublicKey, _}}) -> + EncPremasterSecret = + encrypted_premaster_secret(Secret, PublicKey), + #client_key_exchange{ + exchange_keys = #client_rsa_psk_identity{ + identity = PskIdentity, + exchange_keys = EncPremasterSecret}}; + +key_exchange(client, _Version, {srp, PublicKey}) -> + #client_key_exchange{ + exchange_keys = #client_srp_public{ + srp_a = PublicKey} + }; + key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _}, #'DHParameter'{prime = P, base = G}, HashSign, ClientRandom, ServerRandom, PrivateKey}) -> @@ -399,6 +448,41 @@ key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _}, ServerDHParams = #server_dh_params{dh_p = PBin, dh_g = GBin, dh_y = PublicKey}, enc_server_key_exchange(Version, ServerDHParams, HashSign, + ClientRandom, ServerRandom, PrivateKey); + +key_exchange(server, Version, {ecdh, {'ECKey', ECKey}, HashSign, ClientRandom, ServerRandom, + PrivateKey}) -> + {ECCurve, _ECPrivKey, ECPubKey} = crypto:ec_key_to_term(ECKey), + ServerECParams = #server_ecdh_params{curve = ECCurve, public = ECPubKey}, + enc_server_key_exchange(Version, ServerECParams, HashSign, + ClientRandom, ServerRandom, PrivateKey); + +key_exchange(server, Version, {psk, PskIdentityHint, + HashSign, ClientRandom, ServerRandom, PrivateKey}) -> + ServerPSKParams = #server_psk_params{hint = PskIdentityHint}, + enc_server_key_exchange(Version, ServerPSKParams, HashSign, + ClientRandom, ServerRandom, PrivateKey); + +key_exchange(server, Version, {dhe_psk, PskIdentityHint, {<<?UINT32(Len), PublicKey:Len/binary>>, _}, + #'DHParameter'{prime = P, base = G}, + HashSign, ClientRandom, ServerRandom, PrivateKey}) -> + <<?UINT32(_), PBin/binary>> = crypto:mpint(P), + <<?UINT32(_), GBin/binary>> = crypto:mpint(G), + ServerEDHPSKParams = #server_dhe_psk_params{ + hint = PskIdentityHint, + dh_params = #server_dh_params{dh_p = PBin, + dh_g = GBin, dh_y = PublicKey} + }, + enc_server_key_exchange(Version, ServerEDHPSKParams, + HashSign, ClientRandom, ServerRandom, PrivateKey); + +key_exchange(server, Version, {srp, {PublicKey, _}, + #srp_user{generator = Generator, prime = Prime, + salt = Salt}, + HashSign, ClientRandom, ServerRandom, PrivateKey}) -> + ServerSRPParams = #server_srp_params{srp_n = Prime, srp_g = Generator, + srp_s = Salt, srp_b = PublicKey}, + enc_server_key_exchange(Version, ServerSRPParams, HashSign, ClientRandom, ServerRandom, PrivateKey). enc_server_key_exchange(Version, Params, {HashAlgo, SignAlgo}, @@ -528,7 +612,12 @@ get_tls_handshake(Version, Data, Buffer) -> %%-------------------------------------------------------------------- -spec decode_client_key(binary(), key_algo(), tls_version()) -> - #encrypted_premaster_secret{} | #client_diffie_hellman_public{}. + #encrypted_premaster_secret{} + | #client_diffie_hellman_public{} + | #client_psk_identity{} + | #client_dhe_psk_identity{} + | #client_rsa_psk_identity{} + | #client_srp_public{}. %% %% Description: Decode client_key data and return appropriate type %%-------------------------------------------------------------------- @@ -680,6 +769,11 @@ cipher_suites(Suites, false) -> cipher_suites(Suites, true) -> Suites. +srp_user(#ssl_options{srp_identity = {UserName, _}}) -> + #srp{username = UserName}; +srp_user(_) -> + undefined. + renegotiation_info(client, _, false) -> #renegotiation_info{renegotiated_connection = undefined}; renegotiation_info(server, ConnectionStates, false) -> @@ -762,6 +856,11 @@ select_next_protocol(Protocols, NextProtocolSelector) -> Protocol end. +handle_srp_info(undefined, Session) -> + Session; +handle_srp_info(#srp{username = Username}, Session) -> + Session#session{srp_username = Username}. + handle_renegotiation_info(_, #renegotiation_info{renegotiated_connection = ?byte(0)}, ConnectionStates, false, _, _) -> {ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)}; @@ -948,7 +1047,10 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, DecodedExtensions = dec_hello_extensions(Extensions), RenegotiationInfo = proplists:get_value(renegotiation_info, DecodedExtensions, undefined), + SRP = proplists:get_value(srp, DecodedExtensions, undefined), HashSigns = proplists:get_value(hash_signs, DecodedExtensions, undefined), + EllipticCurves = proplists:get_value(elliptic_curves, DecodedExtensions, + undefined), NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, DecodedExtensions, undefined), #client_hello{ @@ -958,7 +1060,9 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, cipher_suites = from_2bytes(CipherSuites), compression_methods = Comp_methods, renegotiation_info = RenegotiationInfo, + srp = SRP, hash_signs = HashSigns, + elliptic_curves = EllipticCurves, next_protocol_negotiation = NextProtocolNegotiation }; @@ -972,7 +1076,8 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, cipher_suite = Cipher_suite, compression_method = Comp_method, renegotiation_info = undefined, - hash_signs = undefined}; + hash_signs = undefined, + elliptic_curves = undefined}; dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, ?BYTE(SID_length), Session_ID:SID_length/binary, @@ -984,6 +1089,8 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, undefined), HashSigns = proplists:get_value(hash_signs, HelloExtensions, undefined), + EllipticCurves = proplists:get_value(elliptic_curves, HelloExtensions, + undefined), NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, HelloExtensions, undefined), #server_hello{ @@ -994,6 +1101,7 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, compression_method = Comp_method, renegotiation_info = RenegotiationInfo, hash_signs = HashSigns, + elliptic_curves = EllipticCurves, next_protocol_negotiation = NextProtocolNegotiation}; dec_hs(_Version, ?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>) -> #certificate{asn1_certificates = certs_to_list(ASN1Certs)}; @@ -1036,7 +1144,28 @@ dec_client_key(<<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) -> throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE)); dec_client_key(<<?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) -> - #client_diffie_hellman_public{dh_public = DH_Y}. + #client_diffie_hellman_public{dh_public = DH_Y}; +dec_client_key(<<>>, ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) -> + throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE)); +dec_client_key(<<?BYTE(DH_YLen), DH_Y:DH_YLen/binary>>, + ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) -> + #client_ec_diffie_hellman_public{dh_public = DH_Y}; +dec_client_key(<<?UINT16(Len), Id:Len/binary>>, + ?KEY_EXCHANGE_PSK, _) -> + #client_psk_identity{identity = Id}; +dec_client_key(<<?UINT16(Len), Id:Len/binary, + ?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>, + ?KEY_EXCHANGE_DHE_PSK, _) -> + #client_dhe_psk_identity{identity = Id, dh_public = DH_Y}; +dec_client_key(<<?UINT16(Len), Id:Len/binary, PKEPMS/binary>>, + ?KEY_EXCHANGE_RSA_PSK, {3, 0}) -> + #client_rsa_psk_identity{identity = Id, exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}}; +dec_client_key(<<?UINT16(Len), Id:Len/binary, ?UINT16(_), PKEPMS/binary>>, + ?KEY_EXCHANGE_RSA_PSK, _) -> + #client_rsa_psk_identity{identity = Id, exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}}; +dec_client_key(<<?UINT16(ALen), A:ALen/binary>>, + ?KEY_EXCHANGE_SRP, _) -> + #client_srp_public{srp_a = A}. dec_ske_params(Len, Keys, Version) -> <<Params:Len/bytes, Signature/binary>> = Keys, @@ -1071,6 +1200,54 @@ dec_server_key(<<?UINT16(PLen), P:PLen/binary, params_bin = BinMsg, hashsign = HashSign, signature = Signature}; +%% ECParameters with named_curve +%% TODO: explicit curve +dec_server_key(<<?BYTE(?NAMED_CURVE), ?UINT16(CurveID), + ?BYTE(PointLen), ECPoint:PointLen/binary, + _/binary>> = KeyStruct, + ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, Version) -> + Params = #server_ecdh_params{curve = ssl_tls1:ec_curve_id2nid(CurveID), + public = ECPoint}, + {BinMsg, HashSign, Signature} = dec_ske_params(PointLen + 4, KeyStruct, Version), + #server_key_params{params = Params, + params_bin = BinMsg, + hashsign = HashSign, + signature = Signature}; +dec_server_key(<<?UINT16(Len), PskIdentityHint:Len/binary>> = KeyStruct, + KeyExchange, Version) + when KeyExchange == ?KEY_EXCHANGE_PSK; KeyExchange == ?KEY_EXCHANGE_RSA_PSK -> + Params = #server_psk_params{ + hint = PskIdentityHint}, + {BinMsg, HashSign, Signature} = dec_ske_params(Len + 2, KeyStruct, Version), + #server_key_params{params = Params, + params_bin = BinMsg, + hashsign = HashSign, + signature = Signature}; +dec_server_key(<<?UINT16(Len), IdentityHint:Len/binary, + ?UINT16(PLen), P:PLen/binary, + ?UINT16(GLen), G:GLen/binary, + ?UINT16(YLen), Y:YLen/binary, _/binary>> = KeyStruct, + ?KEY_EXCHANGE_DHE_PSK, Version) -> + DHParams = #server_dh_params{dh_p = P, dh_g = G, dh_y = Y}, + Params = #server_dhe_psk_params{ + hint = IdentityHint, + dh_params = DHParams}, + {BinMsg, HashSign, Signature} = dec_ske_params(Len + PLen + GLen + YLen + 8, KeyStruct, Version), + #server_key_params{params = Params, + params_bin = BinMsg, + hashsign = HashSign, + signature = Signature}; +dec_server_key(<<?UINT16(NLen), N:NLen/binary, + ?UINT16(GLen), G:GLen/binary, + ?BYTE(SLen), S:SLen/binary, + ?UINT16(BLen), B:BLen/binary, _/binary>> = KeyStruct, + ?KEY_EXCHANGE_SRP, Version) -> + Params = #server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B}, + {BinMsg, HashSign, Signature} = dec_ske_params(NLen + GLen + SLen + BLen + 7, KeyStruct, Version), + #server_key_params{params = Params, + params_bin = BinMsg, + hashsign = HashSign, + signature = Signature}; dec_server_key(_, _, _) -> throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)). @@ -1098,6 +1275,11 @@ dec_hello_extensions(<<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info:Len/binar dec_hello_extensions(Rest, [{renegotiation_info, #renegotiation_info{renegotiated_connection = RenegotiateInfo}} | Acc]); +dec_hello_extensions(<<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), SRP:SRPLen/binary, Rest/binary>>, Acc) + when Len == SRPLen + 2 -> + dec_hello_extensions(Rest, [{srp, + #srp{username = SRP}} | Acc]); + dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len), ExtData:Len/binary, Rest/binary>>, Acc) -> SignAlgoListLen = Len - 2, @@ -1107,6 +1289,22 @@ dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len), dec_hello_extensions(Rest, [{hash_signs, #hash_sign_algos{hash_sign_algos = HashSignAlgos}} | Acc]); +dec_hello_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len), + ExtData:Len/binary, Rest/binary>>, Acc) -> + EllipticCurveListLen = Len - 2, + <<?UINT16(EllipticCurveListLen), EllipticCurveList/binary>> = ExtData, + EllipticCurves = [ssl_tls1:ec_curve_id2nid(X) || <<X:16>> <= EllipticCurveList], + dec_hello_extensions(Rest, [{elliptic_curves, + #elliptic_curves{elliptic_curve_list = EllipticCurves}} | Acc]); + +dec_hello_extensions(<<?UINT16(?EC_POINT_FORMATS_EXT), ?UINT16(Len), + ExtData:Len/binary, Rest/binary>>, Acc) -> + ECPointFormatListLen = Len - 1, + <<?BYTE(ECPointFormatListLen), ECPointFormatList/binary>> = ExtData, + ECPointFormats = binary_to_list(ECPointFormatList), + dec_hello_extensions(Rest, [{ec_point_formats, + #ec_point_formats{ec_point_format_list = ECPointFormats}} | Acc]); + %% Ignore data following the ClientHello (i.e., %% extensions) if not understood. @@ -1155,14 +1353,18 @@ enc_hs(#client_hello{client_version = {Major, Minor}, cipher_suites = CipherSuites, compression_methods = CompMethods, renegotiation_info = RenegotiationInfo, + srp = SRP, hash_signs = HashSigns, + elliptic_curves = EllipticCurves, next_protocol_negotiation = NextProtocolNegotiation}, _Version) -> SIDLength = byte_size(SessionID), BinCompMethods = list_to_binary(CompMethods), CmLength = byte_size(BinCompMethods), BinCipherSuites = list_to_binary(CipherSuites), CsLength = byte_size(BinCipherSuites), - Extensions0 = hello_extensions(RenegotiationInfo, NextProtocolNegotiation), + Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation) + ++ hello_extensions(EllipticCurves) + ++ hello_extensions(#ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]}), Extensions1 = if Major == 3, Minor >=3 -> Extensions0 ++ hello_extensions(HashSigns); true -> Extensions0 @@ -1182,7 +1384,8 @@ enc_hs(#server_hello{server_version = {Major, Minor}, renegotiation_info = RenegotiationInfo, next_protocol_negotiation = NextProtocolNegotiation}, _Version) -> SID_length = byte_size(Session_ID), - Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation), + Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation) + ++ hello_extensions(#ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]}), ExtensionsBin = enc_hello_extensions(Extensions), {?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, ?BYTE(SID_length), Session_ID/binary, @@ -1238,13 +1441,64 @@ enc_cke(#encrypted_premaster_secret{premaster_secret = PKEPMS}, _) -> <<?UINT16(PKEPMSLen), PKEPMS/binary>>; enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) -> Len = byte_size(DHPublic), - <<?UINT16(Len), DHPublic/binary>>. + <<?UINT16(Len), DHPublic/binary>>; +enc_cke(#client_ec_diffie_hellman_public{dh_public = DHPublic}, _) -> + Len = byte_size(DHPublic), + <<?BYTE(Len), DHPublic/binary>>; +enc_cke(#client_psk_identity{identity = undefined}, _) -> + Id = <<"psk_identity">>, + Len = byte_size(Id), + <<?UINT16(Len), Id/binary>>; +enc_cke(#client_psk_identity{identity = Id}, _) -> + Len = byte_size(Id), + <<?UINT16(Len), Id/binary>>; +enc_cke(Identity = #client_dhe_psk_identity{identity = undefined}, Version) -> + enc_cke(Identity#client_dhe_psk_identity{identity = <<"psk_identity">>}, Version); +enc_cke(#client_dhe_psk_identity{identity = Id, dh_public = DHPublic}, _) -> + Len = byte_size(Id), + DHLen = byte_size(DHPublic), + <<?UINT16(Len), Id/binary, ?UINT16(DHLen), DHPublic/binary>>; +enc_cke(Identity = #client_rsa_psk_identity{identity = undefined}, Version) -> + enc_cke(Identity#client_rsa_psk_identity{identity = <<"psk_identity">>}, Version); +enc_cke(#client_rsa_psk_identity{identity = Id, exchange_keys = ExchangeKeys}, Version) -> + EncPMS = enc_cke(ExchangeKeys, Version), + Len = byte_size(Id), + <<?UINT16(Len), Id/binary, EncPMS/binary>>; +enc_cke(#client_srp_public{srp_a = A}, _) -> + Len = byte_size(A), + <<?UINT16(Len), A/binary>>. enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) -> PLen = byte_size(P), GLen = byte_size(G), YLen = byte_size(Y), - <<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>. + <<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>; +enc_server_key(#server_ecdh_params{curve = ECCurve, public = ECPubKey}) -> + %%TODO: support arbitrary keys + KLen = size(ECPubKey), + <<?BYTE(?NAMED_CURVE_TYPE), ?UINT16((ssl_tls1:ec_nid2curve_id(ECCurve))), + ?BYTE(KLen), ECPubKey/binary>>; +enc_server_key(#server_psk_params{hint = PskIdentityHint}) -> + Len = byte_size(PskIdentityHint), + <<?UINT16(Len), PskIdentityHint/binary>>; +enc_server_key(Params = #server_dhe_psk_params{hint = undefined}) -> + enc_server_key(Params#server_dhe_psk_params{hint = <<>>}); +enc_server_key(#server_dhe_psk_params{ + hint = PskIdentityHint, + dh_params = #server_dh_params{dh_p = P, dh_g = G, dh_y = Y}}) -> + Len = byte_size(PskIdentityHint), + PLen = byte_size(P), + GLen = byte_size(G), + YLen = byte_size(Y), + <<?UINT16(Len), PskIdentityHint/binary, + ?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>; +enc_server_key(#server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B}) -> + NLen = byte_size(N), + GLen = byte_size(G), + SLen = byte_size(S), + BLen = byte_size(B), + <<?UINT16(NLen), N/binary, ?UINT16(GLen), G/binary, + ?BYTE(SLen), S/binary, ?UINT16(BLen), B/binary>>. enc_sign({_, anon}, _Sign, _Version) -> <<>>; @@ -1260,13 +1514,26 @@ enc_sign(_HashSign, Sign, _Version) -> hello_extensions(RenegotiationInfo, NextProtocolNegotiation) -> hello_extensions(RenegotiationInfo) ++ next_protocol_extension(NextProtocolNegotiation). +hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation) -> + hello_extensions(RenegotiationInfo) + ++ hello_extensions(SRP) + ++ next_protocol_extension(NextProtocolNegotiation). + %% Renegotiation info hello_extensions(#renegotiation_info{renegotiated_connection = undefined}) -> []; hello_extensions(#renegotiation_info{} = Info) -> [Info]; +hello_extensions(#elliptic_curves{} = Info) -> + [Info]; +hello_extensions(#ec_point_formats{} = Info) -> + [Info]; +hello_extensions(#srp{} = Info) -> + [Info]; hello_extensions(#hash_sign_algos{} = Info) -> - [Info]. + [Info]; +hello_extensions(undefined) -> + []. next_protocol_extension(undefined) -> []; @@ -1292,7 +1559,22 @@ enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest InfoLen = byte_size(Info), Len = InfoLen +1, enc_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen), Info/binary, Acc/binary>>); - +enc_hello_extensions([#elliptic_curves{elliptic_curve_list = EllipticCurves} | Rest], Acc) -> + EllipticCurveList = << <<(ssl_tls1:ec_nid2curve_id(X)):16>> || X <- EllipticCurves>>, + ListLen = byte_size(EllipticCurveList), + Len = ListLen + 2, + enc_hello_extensions(Rest, <<?UINT16(?ELLIPTIC_CURVES_EXT), + ?UINT16(Len), ?UINT16(ListLen), EllipticCurveList/binary, Acc/binary>>); +enc_hello_extensions([#ec_point_formats{ec_point_format_list = ECPointFormats} | Rest], Acc) -> + ECPointFormatList = list_to_binary(ECPointFormats), + ListLen = byte_size(ECPointFormatList), + Len = ListLen + 1, + enc_hello_extensions(Rest, <<?UINT16(?EC_POINT_FORMATS_EXT), + ?UINT16(Len), ?BYTE(ListLen), ECPointFormatList/binary, Acc/binary>>); +enc_hello_extensions([#srp{username = UserName} | Rest], Acc) -> + SRPLen = byte_size(UserName), + Len = SRPLen + 2, + enc_hello_extensions(Rest, <<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), UserName/binary, Acc/binary>>); enc_hello_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Rest], Acc) -> SignAlgoList = << <<(ssl_cipher:hash_algorithm(Hash)):8, (ssl_cipher:sign_algorithm(Sign)):8>> || {Hash, Sign} <- HashSignAlgos >>, @@ -1327,9 +1609,15 @@ from_2bytes(<<?UINT16(N), Rest/binary>>, Acc) -> certificate_types({KeyExchange, _, _, _}) when KeyExchange == rsa; KeyExchange == dhe_dss; - KeyExchange == dhe_rsa -> + KeyExchange == dhe_rsa; + KeyExchange == ecdhe_rsa -> <<?BYTE(?RSA_SIGN), ?BYTE(?DSS_SIGN)>>; +certificate_types({KeyExchange, _, _, _}) + when KeyExchange == dh_ecdsa; + KeyExchange == dhe_ecdsa -> + <<?BYTE(?ECDSA_SIGN)>>; + certificate_types(_) -> <<?BYTE(?RSA_SIGN)>>. @@ -1369,7 +1657,9 @@ digitally_signed(_Version, Hash, HashAlgo, #'DSAPrivateKey'{} = Key) -> public_key:sign({digest, Hash}, HashAlgo, Key); digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) -> public_key:encrypt_private(Hash, Key, - [{rsa_pad, rsa_pkcs1_padding}]). + [{rsa_pad, rsa_pkcs1_padding}]); +digitally_signed(_Version, Hash, HashAlgo, {'ECKey', _} = Key) -> + public_key:sign({digest, Hash}, HashAlgo, Key). calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) -> ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom); @@ -1402,6 +1692,19 @@ key_exchange_alg(rsa) -> key_exchange_alg(Alg) when Alg == dhe_rsa; Alg == dhe_dss; Alg == dh_dss; Alg == dh_rsa; Alg == dh_anon -> ?KEY_EXCHANGE_DIFFIE_HELLMAN; +key_exchange_alg(Alg) when Alg == ecdhe_rsa; Alg == ecdh_rsa; + Alg == ecdhe_ecdsa; Alg == ecdh_ecdsa; + Alg == ecdh_anon -> + ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN; +key_exchange_alg(psk) -> + ?KEY_EXCHANGE_PSK; +key_exchange_alg(dhe_psk) -> + ?KEY_EXCHANGE_DHE_PSK; +key_exchange_alg(rsa_psk) -> + ?KEY_EXCHANGE_RSA_PSK; +key_exchange_alg(Alg) + when Alg == srp_rsa; Alg == srp_dss; Alg == srp_anon -> + ?KEY_EXCHANGE_SRP; key_exchange_alg(_) -> ?NULL. @@ -1417,8 +1720,9 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) -> -define(TLSEXT_SIGALG_RSA(MD), {MD, rsa}). -define(TLSEXT_SIGALG_DSA(MD), {MD, dsa}). +-define(TLSEXT_SIGALG_ECDSA(MD), {MD, ecdsa}). --define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_RSA(MD)). +-define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_RSA(MD), ?TLSEXT_SIGALG_ECDSA(MD)). default_hash_signs() -> #hash_sign_algos{hash_sign_algos = diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index 2414d5b666..b9b2d1f91d 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -48,6 +48,7 @@ compression_method, cipher_suite, master_secret, + srp_username, is_resumable, time_stamp }). @@ -99,7 +100,9 @@ cipher_suites, % cipher_suites<2..2^16-1> compression_methods, % compression_methods<1..2^8-1>, renegotiation_info, + srp, % srp username to send hash_signs, % supported combinations of hashes/signature algos + elliptic_curves, % supported elliptic curver next_protocol_negotiation = undefined % [binary()] }). @@ -111,6 +114,7 @@ compression_method, % compression_method renegotiation_info, hash_signs, % supported combinations of hashes/signature algos + elliptic_curves, % supported elliptic curver next_protocol_negotiation = undefined % [binary()] }). @@ -128,6 +132,11 @@ -define(KEY_EXCHANGE_RSA, 0). -define(KEY_EXCHANGE_DIFFIE_HELLMAN, 1). +-define(KEY_EXCHANGE_EC_DIFFIE_HELLMAN, 6). +-define(KEY_EXCHANGE_PSK, 2). +-define(KEY_EXCHANGE_DHE_PSK, 3). +-define(KEY_EXCHANGE_RSA_PSK, 4). +-define(KEY_EXCHANGE_SRP, 5). -record(server_rsa_params, { rsa_modulus, %% opaque RSA_modulus<1..2^16-1> @@ -139,7 +148,28 @@ dh_g, %% opaque DH_g<1..2^16-1> dh_y %% opaque DH_Ys<1..2^16-1> }). - + +-record(server_ecdh_params, { + curve, + public %% opaque encoded ECpoint + }). + +-record(server_psk_params, { + hint + }). + +-record(server_dhe_psk_params, { + hint, + dh_params + }). + +-record(server_srp_params, { + srp_n, %% opaque srp_N<1..2^16-1> + srp_g, %% opaque srp_g<1..2^16-1> + srp_s, %% opaque srp_s<1..2^8-1> + srp_b %% opaque srp_B<1..2^16-1> + }). + -record(server_key_exchange, { exchange_keys }). @@ -173,6 +203,9 @@ -define(DSS_SIGN, 2). -define(RSA_FIXED_DH, 3). -define(DSS_FIXED_DH, 4). +-define(ECDSA_SIGN, 64). +-define(RSA_FIXED_ECDH, 65). +-define(ECDSA_FIXED_ECDH, 66). % opaque DistinguishedName<1..2^16-1>; @@ -209,6 +242,28 @@ dh_public }). +-record(client_ec_diffie_hellman_public, { + dh_public + }). + +-record(client_psk_identity, { + identity + }). + +-record(client_dhe_psk_identity, { + identity, + dh_public + }). + +-record(client_rsa_psk_identity, { + identity, + exchange_keys + }). + +-record(client_srp_public, { + srp_a + }). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Certificate verify - RFC 4346 section 7.4.8 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -235,6 +290,15 @@ }). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% SRP RFC 5054 section 2.8.1. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-define(SRP_EXT, 12). + +-record(srp, { + username + }). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Signature Algorithms RFC 5746 section 7.4.1.4.1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -define(SIGNATURE_ALGORITHMS_EXT, 13). @@ -255,6 +319,33 @@ -record(next_protocol, {selected_protocol}). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% ECC Extensions RFC 4492 section 4 and 5 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-define(ELLIPTIC_CURVES_EXT, 10). +-define(EC_POINT_FORMATS_EXT, 11). + +-record(elliptic_curves, { + elliptic_curve_list + }). + +-record(ec_point_formats, { + ec_point_format_list + }). + +-define(ECPOINT_UNCOMPRESSED, 0). +-define(ECPOINT_ANSIX962_COMPRESSED_PRIME, 1). +-define(ECPOINT_ANSIX962_COMPRESSED_CHAR2, 2). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% ECC RFC 4492 Handshake Messages, Section 5 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-define(EXPLICIT_PRIME, 1). +-define(EXPLICIT_CHAR2, 2). +-define(NAMED_CURVE, 3). + -endif. % -ifdef(ssl_handshake). diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index ed0dc34adf..96a1c8e1ce 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -90,6 +90,9 @@ cacertfile, % file() dh, % der_encoded() dhfile, % file() + user_lookup_fun, % server option, fun to lookup the user + psk_identity, % binary + srp_identity, % client option {User, Password} ciphers, % %% Local policy for the server if it want's to reuse the session %% or not. Defaluts to allways returning true. diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index 173b9611c6..5101beeac8 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -704,12 +704,4 @@ mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) Length, Fragment). sufficient_tlsv1_2_crypto_support() -> - Data = "Sampl", - Data2 = "e #1", - Key = <<0,1,2,3,16,17,18,19,32,33,34,35,48,49,50,51,4,5,6,7,20,21,22,23,36,37,38,39, - 52,53,54,55,8,9,10,11,24,25,26,27,40,41,42,43,56,57,58,59>>, - try - crypto:sha256_mac(Key, lists:flatten([Data, Data2])), - true - catch _:_ -> false - end. + proplists:get_bool(sha256, crypto:algorithms()). diff --git a/lib/ssl/src/ssl_srp.hrl b/lib/ssl/src/ssl_srp.hrl new file mode 100644 index 0000000000..ab2be33ab2 --- /dev/null +++ b/lib/ssl/src/ssl_srp.hrl @@ -0,0 +1,31 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Record definition for the TLS SRP protocol +%% see RFC 5054 +%%---------------------------------------------------------------------- + +-record(srp_user, { + generator :: binary(), + prime :: binary(), + salt :: binary(), + verifier :: binary() + }). diff --git a/lib/ssl/src/ssl_srp_primes.erl b/lib/ssl/src/ssl_srp_primes.erl new file mode 100644 index 0000000000..ca20a8d673 --- /dev/null +++ b/lib/ssl/src/ssl_srp_primes.erl @@ -0,0 +1,506 @@ +-module(ssl_srp_primes). + +-export([get_srp_params/1, check_srp_params/2]). + +-define(PRIME_1024, <<16#EE, 16#AF, 16#0A, 16#B9, 16#AD, 16#B3, 16#8D, + 16#D6, 16#9C, 16#33, 16#F8, 16#0A, 16#FA, 16#8F, + 16#C5, 16#E8, 16#60, 16#72, 16#61, 16#87, 16#75, + 16#FF, 16#3C, 16#0B, 16#9E, 16#A2, 16#31, 16#4C, + 16#9C, 16#25, 16#65, 16#76, 16#D6, 16#74, 16#DF, + 16#74, 16#96, 16#EA, 16#81, 16#D3, 16#38, 16#3B, + 16#48, 16#13, 16#D6, 16#92, 16#C6, 16#E0, 16#E0, + 16#D5, 16#D8, 16#E2, 16#50, 16#B9, 16#8B, 16#E4, + 16#8E, 16#49, 16#5C, 16#1D, 16#60, 16#89, 16#DA, + 16#D1, 16#5D, 16#C7, 16#D7, 16#B4, 16#61, 16#54, + 16#D6, 16#B6, 16#CE, 16#8E, 16#F4, 16#AD, 16#69, + 16#B1, 16#5D, 16#49, 16#82, 16#55, 16#9B, 16#29, + 16#7B, 16#CF, 16#18, 16#85, 16#C5, 16#29, 16#F5, + 16#66, 16#66, 16#0E, 16#57, 16#EC, 16#68, 16#ED, + 16#BC, 16#3C, 16#05, 16#72, 16#6C, 16#C0, 16#2F, + 16#D4, 16#CB, 16#F4, 16#97, 16#6E, 16#AA, 16#9A, + 16#FD, 16#51, 16#38, 16#FE, 16#83, 16#76, 16#43, + 16#5B, 16#9F, 16#C6, 16#1D, 16#2F, 16#C0, 16#EB, + 16#06, 16#E3>>). +-define(GENERATOR_1024, <<2>>). + + +-define(PRIME_1536, <<16#9D, 16#EF, 16#3C, 16#AF, 16#B9, 16#39, 16#27, + 16#7A, 16#B1, 16#F1, 16#2A, 16#86, 16#17, 16#A4, + 16#7B, 16#BB, 16#DB, 16#A5, 16#1D, 16#F4, 16#99, + 16#AC, 16#4C, 16#80, 16#BE, 16#EE, 16#A9, 16#61, + 16#4B, 16#19, 16#CC, 16#4D, 16#5F, 16#4F, 16#5F, + 16#55, 16#6E, 16#27, 16#CB, 16#DE, 16#51, 16#C6, + 16#A9, 16#4B, 16#E4, 16#60, 16#7A, 16#29, 16#15, + 16#58, 16#90, 16#3B, 16#A0, 16#D0, 16#F8, 16#43, + 16#80, 16#B6, 16#55, 16#BB, 16#9A, 16#22, 16#E8, + 16#DC, 16#DF, 16#02, 16#8A, 16#7C, 16#EC, 16#67, + 16#F0, 16#D0, 16#81, 16#34, 16#B1, 16#C8, 16#B9, + 16#79, 16#89, 16#14, 16#9B, 16#60, 16#9E, 16#0B, + 16#E3, 16#BA, 16#B6, 16#3D, 16#47, 16#54, 16#83, + 16#81, 16#DB, 16#C5, 16#B1, 16#FC, 16#76, 16#4E, + 16#3F, 16#4B, 16#53, 16#DD, 16#9D, 16#A1, 16#15, + 16#8B, 16#FD, 16#3E, 16#2B, 16#9C, 16#8C, 16#F5, + 16#6E, 16#DF, 16#01, 16#95, 16#39, 16#34, 16#96, + 16#27, 16#DB, 16#2F, 16#D5, 16#3D, 16#24, 16#B7, + 16#C4, 16#86, 16#65, 16#77, 16#2E, 16#43, 16#7D, + 16#6C, 16#7F, 16#8C, 16#E4, 16#42, 16#73, 16#4A, + 16#F7, 16#CC, 16#B7, 16#AE, 16#83, 16#7C, 16#26, + 16#4A, 16#E3, 16#A9, 16#BE, 16#B8, 16#7F, 16#8A, + 16#2F, 16#E9, 16#B8, 16#B5, 16#29, 16#2E, 16#5A, + 16#02, 16#1F, 16#FF, 16#5E, 16#91, 16#47, 16#9E, + 16#8C, 16#E7, 16#A2, 16#8C, 16#24, 16#42, 16#C6, + 16#F3, 16#15, 16#18, 16#0F, 16#93, 16#49, 16#9A, + 16#23, 16#4D, 16#CF, 16#76, 16#E3, 16#FE, 16#D1, + 16#35, 16#F9, 16#BB>>). +-define(GENERATOR_1536, <<2>>). + +-define(PRIME_2048, <<16#AC, 16#6B, 16#DB, 16#41, 16#32, 16#4A, 16#9A, + 16#9B, 16#F1, 16#66, 16#DE, 16#5E, 16#13, 16#89, + 16#58, 16#2F, 16#AF, 16#72, 16#B6, 16#65, 16#19, + 16#87, 16#EE, 16#07, 16#FC, 16#31, 16#92, 16#94, + 16#3D, 16#B5, 16#60, 16#50, 16#A3, 16#73, 16#29, + 16#CB, 16#B4, 16#A0, 16#99, 16#ED, 16#81, 16#93, + 16#E0, 16#75, 16#77, 16#67, 16#A1, 16#3D, 16#D5, + 16#23, 16#12, 16#AB, 16#4B, 16#03, 16#31, 16#0D, + 16#CD, 16#7F, 16#48, 16#A9, 16#DA, 16#04, 16#FD, + 16#50, 16#E8, 16#08, 16#39, 16#69, 16#ED, 16#B7, + 16#67, 16#B0, 16#CF, 16#60, 16#95, 16#17, 16#9A, + 16#16, 16#3A, 16#B3, 16#66, 16#1A, 16#05, 16#FB, + 16#D5, 16#FA, 16#AA, 16#E8, 16#29, 16#18, 16#A9, + 16#96, 16#2F, 16#0B, 16#93, 16#B8, 16#55, 16#F9, + 16#79, 16#93, 16#EC, 16#97, 16#5E, 16#EA, 16#A8, + 16#0D, 16#74, 16#0A, 16#DB, 16#F4, 16#FF, 16#74, + 16#73, 16#59, 16#D0, 16#41, 16#D5, 16#C3, 16#3E, + 16#A7, 16#1D, 16#28, 16#1E, 16#44, 16#6B, 16#14, + 16#77, 16#3B, 16#CA, 16#97, 16#B4, 16#3A, 16#23, + 16#FB, 16#80, 16#16, 16#76, 16#BD, 16#20, 16#7A, + 16#43, 16#6C, 16#64, 16#81, 16#F1, 16#D2, 16#B9, + 16#07, 16#87, 16#17, 16#46, 16#1A, 16#5B, 16#9D, + 16#32, 16#E6, 16#88, 16#F8, 16#77, 16#48, 16#54, + 16#45, 16#23, 16#B5, 16#24, 16#B0, 16#D5, 16#7D, + 16#5E, 16#A7, 16#7A, 16#27, 16#75, 16#D2, 16#EC, + 16#FA, 16#03, 16#2C, 16#FB, 16#DB, 16#F5, 16#2F, + 16#B3, 16#78, 16#61, 16#60, 16#27, 16#90, 16#04, + 16#E5, 16#7A, 16#E6, 16#AF, 16#87, 16#4E, 16#73, + 16#03, 16#CE, 16#53, 16#29, 16#9C, 16#CC, 16#04, + 16#1C, 16#7B, 16#C3, 16#08, 16#D8, 16#2A, 16#56, + 16#98, 16#F3, 16#A8, 16#D0, 16#C3, 16#82, 16#71, + 16#AE, 16#35, 16#F8, 16#E9, 16#DB, 16#FB, 16#B6, + 16#94, 16#B5, 16#C8, 16#03, 16#D8, 16#9F, 16#7A, + 16#E4, 16#35, 16#DE, 16#23, 16#6D, 16#52, 16#5F, + 16#54, 16#75, 16#9B, 16#65, 16#E3, 16#72, 16#FC, + 16#D6, 16#8E, 16#F2, 16#0F, 16#A7, 16#11, 16#1F, + 16#9E, 16#4A, 16#FF, 16#73>>). +-define(GENERATOR_2048, <<2>>). + +-define(PRIME_3072, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, + 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68, + 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80, + 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08, + 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE, + 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A, + 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF, + 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B, + 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14, + 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51, + 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62, + 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9, + 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C, + 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38, + 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE, + 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6, + 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B, + 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63, + 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C, + 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8, + 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D, + 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62, + 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E, + 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D, + 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98, + 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18, + 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E, + 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C, + 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83, + 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5, + 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE, + 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18, + 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A, + 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA, + 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A, + 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D, + 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21, + 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB, + 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A, + 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D, + 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4, + 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09, + 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A, + 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26, + 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA, + 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76, + 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52, + 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C, + 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D, + 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9, + 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74, + 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC, + 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1, + 16#20, 16#A9, 16#3A, 16#D2, 16#CA, 16#FF, 16#FF, + 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF>>). +-define(GENERATOR_3072, <<5>>). + +-define(PRIME_4096, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, + 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68, + 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80, + 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08, + 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE, + 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A, + 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF, + 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B, + 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14, + 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51, + 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62, + 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9, + 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C, + 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38, + 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE, + 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6, + 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B, + 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63, + 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C, + 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8, + 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D, + 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62, + 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E, + 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D, + 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98, + 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18, + 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E, + 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C, + 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83, + 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5, + 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE, + 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18, + 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A, + 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA, + 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A, + 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D, + 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21, + 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB, + 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A, + 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D, + 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4, + 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09, + 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A, + 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26, + 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA, + 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76, + 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52, + 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C, + 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D, + 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9, + 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74, + 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC, + 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1, + 16#20, 16#A9, 16#21, 16#08, 16#01, 16#1A, 16#72, + 16#3C, 16#12, 16#A7, 16#87, 16#E6, 16#D7, 16#88, + 16#71, 16#9A, 16#10, 16#BD, 16#BA, 16#5B, 16#26, + 16#99, 16#C3, 16#27, 16#18, 16#6A, 16#F4, 16#E2, + 16#3C, 16#1A, 16#94, 16#68, 16#34, 16#B6, 16#15, + 16#0B, 16#DA, 16#25, 16#83, 16#E9, 16#CA, 16#2A, + 16#D4, 16#4C, 16#E8, 16#DB, 16#BB, 16#C2, 16#DB, + 16#04, 16#DE, 16#8E, 16#F9, 16#2E, 16#8E, 16#FC, + 16#14, 16#1F, 16#BE, 16#CA, 16#A6, 16#28, 16#7C, + 16#59, 16#47, 16#4E, 16#6B, 16#C0, 16#5D, 16#99, + 16#B2, 16#96, 16#4F, 16#A0, 16#90, 16#C3, 16#A2, + 16#23, 16#3B, 16#A1, 16#86, 16#51, 16#5B, 16#E7, + 16#ED, 16#1F, 16#61, 16#29, 16#70, 16#CE, 16#E2, + 16#D7, 16#AF, 16#B8, 16#1B, 16#DD, 16#76, 16#21, + 16#70, 16#48, 16#1C, 16#D0, 16#06, 16#91, 16#27, + 16#D5, 16#B0, 16#5A, 16#A9, 16#93, 16#B4, 16#EA, + 16#98, 16#8D, 16#8F, 16#DD, 16#C1, 16#86, 16#FF, + 16#B7, 16#DC, 16#90, 16#A6, 16#C0, 16#8F, 16#4D, + 16#F4, 16#35, 16#C9, 16#34, 16#06, 16#31, 16#99, + 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, + 16#FF>>). +-define(GENERATOR_4096, <<5>>). + +-define(PRIME_6144, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, + 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68, + 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80, + 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08, + 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE, + 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A, + 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF, + 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B, + 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14, + 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51, + 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62, + 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9, + 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C, + 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38, + 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE, + 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6, + 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B, + 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63, + 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C, + 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8, + 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D, + 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62, + 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E, + 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D, + 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98, + 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18, + 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E, + 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C, + 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83, + 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5, + 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE, + 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18, + 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A, + 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA, + 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A, + 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D, + 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21, + 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB, + 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A, + 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D, + 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4, + 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09, + 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A, + 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26, + 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA, + 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76, + 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52, + 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C, + 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D, + 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9, + 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74, + 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC, + 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1, + 16#20, 16#A9, 16#21, 16#08, 16#01, 16#1A, 16#72, + 16#3C, 16#12, 16#A7, 16#87, 16#E6, 16#D7, 16#88, + 16#71, 16#9A, 16#10, 16#BD, 16#BA, 16#5B, 16#26, + 16#99, 16#C3, 16#27, 16#18, 16#6A, 16#F4, 16#E2, + 16#3C, 16#1A, 16#94, 16#68, 16#34, 16#B6, 16#15, + 16#0B, 16#DA, 16#25, 16#83, 16#E9, 16#CA, 16#2A, + 16#D4, 16#4C, 16#E8, 16#DB, 16#BB, 16#C2, 16#DB, + 16#04, 16#DE, 16#8E, 16#F9, 16#2E, 16#8E, 16#FC, + 16#14, 16#1F, 16#BE, 16#CA, 16#A6, 16#28, 16#7C, + 16#59, 16#47, 16#4E, 16#6B, 16#C0, 16#5D, 16#99, + 16#B2, 16#96, 16#4F, 16#A0, 16#90, 16#C3, 16#A2, + 16#23, 16#3B, 16#A1, 16#86, 16#51, 16#5B, 16#E7, + 16#ED, 16#1F, 16#61, 16#29, 16#70, 16#CE, 16#E2, + 16#D7, 16#AF, 16#B8, 16#1B, 16#DD, 16#76, 16#21, + 16#70, 16#48, 16#1C, 16#D0, 16#06, 16#91, 16#27, + 16#D5, 16#B0, 16#5A, 16#A9, 16#93, 16#B4, 16#EA, + 16#98, 16#8D, 16#8F, 16#DD, 16#C1, 16#86, 16#FF, + 16#B7, 16#DC, 16#90, 16#A6, 16#C0, 16#8F, 16#4D, + 16#F4, 16#35, 16#C9, 16#34, 16#02, 16#84, 16#92, + 16#36, 16#C3, 16#FA, 16#B4, 16#D2, 16#7C, 16#70, + 16#26, 16#C1, 16#D4, 16#DC, 16#B2, 16#60, 16#26, + 16#46, 16#DE, 16#C9, 16#75, 16#1E, 16#76, 16#3D, + 16#BA, 16#37, 16#BD, 16#F8, 16#FF, 16#94, 16#06, + 16#AD, 16#9E, 16#53, 16#0E, 16#E5, 16#DB, 16#38, + 16#2F, 16#41, 16#30, 16#01, 16#AE, 16#B0, 16#6A, + 16#53, 16#ED, 16#90, 16#27, 16#D8, 16#31, 16#17, + 16#97, 16#27, 16#B0, 16#86, 16#5A, 16#89, 16#18, + 16#DA, 16#3E, 16#DB, 16#EB, 16#CF, 16#9B, 16#14, + 16#ED, 16#44, 16#CE, 16#6C, 16#BA, 16#CE, 16#D4, + 16#BB, 16#1B, 16#DB, 16#7F, 16#14, 16#47, 16#E6, + 16#CC, 16#25, 16#4B, 16#33, 16#20, 16#51, 16#51, + 16#2B, 16#D7, 16#AF, 16#42, 16#6F, 16#B8, 16#F4, + 16#01, 16#37, 16#8C, 16#D2, 16#BF, 16#59, 16#83, + 16#CA, 16#01, 16#C6, 16#4B, 16#92, 16#EC, 16#F0, + 16#32, 16#EA, 16#15, 16#D1, 16#72, 16#1D, 16#03, + 16#F4, 16#82, 16#D7, 16#CE, 16#6E, 16#74, 16#FE, + 16#F6, 16#D5, 16#5E, 16#70, 16#2F, 16#46, 16#98, + 16#0C, 16#82, 16#B5, 16#A8, 16#40, 16#31, 16#90, + 16#0B, 16#1C, 16#9E, 16#59, 16#E7, 16#C9, 16#7F, + 16#BE, 16#C7, 16#E8, 16#F3, 16#23, 16#A9, 16#7A, + 16#7E, 16#36, 16#CC, 16#88, 16#BE, 16#0F, 16#1D, + 16#45, 16#B7, 16#FF, 16#58, 16#5A, 16#C5, 16#4B, + 16#D4, 16#07, 16#B2, 16#2B, 16#41, 16#54, 16#AA, + 16#CC, 16#8F, 16#6D, 16#7E, 16#BF, 16#48, 16#E1, + 16#D8, 16#14, 16#CC, 16#5E, 16#D2, 16#0F, 16#80, + 16#37, 16#E0, 16#A7, 16#97, 16#15, 16#EE, 16#F2, + 16#9B, 16#E3, 16#28, 16#06, 16#A1, 16#D5, 16#8B, + 16#B7, 16#C5, 16#DA, 16#76, 16#F5, 16#50, 16#AA, + 16#3D, 16#8A, 16#1F, 16#BF, 16#F0, 16#EB, 16#19, + 16#CC, 16#B1, 16#A3, 16#13, 16#D5, 16#5C, 16#DA, + 16#56, 16#C9, 16#EC, 16#2E, 16#F2, 16#96, 16#32, + 16#38, 16#7F, 16#E8, 16#D7, 16#6E, 16#3C, 16#04, + 16#68, 16#04, 16#3E, 16#8F, 16#66, 16#3F, 16#48, + 16#60, 16#EE, 16#12, 16#BF, 16#2D, 16#5B, 16#0B, + 16#74, 16#74, 16#D6, 16#E6, 16#94, 16#F9, 16#1E, + 16#6D, 16#CC, 16#40, 16#24, 16#FF, 16#FF, 16#FF, + 16#FF, 16#FF, 16#FF, 16#FF, 16#FF>>). +-define(GENERATOR_6144, <<5>>). + +-define(PRIME_8192, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, + 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68, + 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80, + 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08, + 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE, + 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A, + 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF, + 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B, + 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14, + 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51, + 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62, + 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9, + 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C, + 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38, + 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE, + 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6, + 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B, + 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63, + 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C, + 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8, + 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D, + 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62, + 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E, + 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D, + 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98, + 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18, + 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E, + 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C, + 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83, + 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5, + 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE, + 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18, + 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A, + 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA, + 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A, + 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D, + 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21, + 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB, + 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A, + 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D, + 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4, + 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09, + 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A, + 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26, + 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA, + 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76, + 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52, + 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C, + 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D, + 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9, + 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74, + 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC, + 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1, + 16#20, 16#A9, 16#21, 16#08, 16#01, 16#1A, 16#72, + 16#3C, 16#12, 16#A7, 16#87, 16#E6, 16#D7, 16#88, + 16#71, 16#9A, 16#10, 16#BD, 16#BA, 16#5B, 16#26, + 16#99, 16#C3, 16#27, 16#18, 16#6A, 16#F4, 16#E2, + 16#3C, 16#1A, 16#94, 16#68, 16#34, 16#B6, 16#15, + 16#0B, 16#DA, 16#25, 16#83, 16#E9, 16#CA, 16#2A, + 16#D4, 16#4C, 16#E8, 16#DB, 16#BB, 16#C2, 16#DB, + 16#04, 16#DE, 16#8E, 16#F9, 16#2E, 16#8E, 16#FC, + 16#14, 16#1F, 16#BE, 16#CA, 16#A6, 16#28, 16#7C, + 16#59, 16#47, 16#4E, 16#6B, 16#C0, 16#5D, 16#99, + 16#B2, 16#96, 16#4F, 16#A0, 16#90, 16#C3, 16#A2, + 16#23, 16#3B, 16#A1, 16#86, 16#51, 16#5B, 16#E7, + 16#ED, 16#1F, 16#61, 16#29, 16#70, 16#CE, 16#E2, + 16#D7, 16#AF, 16#B8, 16#1B, 16#DD, 16#76, 16#21, + 16#70, 16#48, 16#1C, 16#D0, 16#06, 16#91, 16#27, + 16#D5, 16#B0, 16#5A, 16#A9, 16#93, 16#B4, 16#EA, + 16#98, 16#8D, 16#8F, 16#DD, 16#C1, 16#86, 16#FF, + 16#B7, 16#DC, 16#90, 16#A6, 16#C0, 16#8F, 16#4D, + 16#F4, 16#35, 16#C9, 16#34, 16#02, 16#84, 16#92, + 16#36, 16#C3, 16#FA, 16#B4, 16#D2, 16#7C, 16#70, + 16#26, 16#C1, 16#D4, 16#DC, 16#B2, 16#60, 16#26, + 16#46, 16#DE, 16#C9, 16#75, 16#1E, 16#76, 16#3D, + 16#BA, 16#37, 16#BD, 16#F8, 16#FF, 16#94, 16#06, + 16#AD, 16#9E, 16#53, 16#0E, 16#E5, 16#DB, 16#38, + 16#2F, 16#41, 16#30, 16#01, 16#AE, 16#B0, 16#6A, + 16#53, 16#ED, 16#90, 16#27, 16#D8, 16#31, 16#17, + 16#97, 16#27, 16#B0, 16#86, 16#5A, 16#89, 16#18, + 16#DA, 16#3E, 16#DB, 16#EB, 16#CF, 16#9B, 16#14, + 16#ED, 16#44, 16#CE, 16#6C, 16#BA, 16#CE, 16#D4, + 16#BB, 16#1B, 16#DB, 16#7F, 16#14, 16#47, 16#E6, + 16#CC, 16#25, 16#4B, 16#33, 16#20, 16#51, 16#51, + 16#2B, 16#D7, 16#AF, 16#42, 16#6F, 16#B8, 16#F4, + 16#01, 16#37, 16#8C, 16#D2, 16#BF, 16#59, 16#83, + 16#CA, 16#01, 16#C6, 16#4B, 16#92, 16#EC, 16#F0, + 16#32, 16#EA, 16#15, 16#D1, 16#72, 16#1D, 16#03, + 16#F4, 16#82, 16#D7, 16#CE, 16#6E, 16#74, 16#FE, + 16#F6, 16#D5, 16#5E, 16#70, 16#2F, 16#46, 16#98, + 16#0C, 16#82, 16#B5, 16#A8, 16#40, 16#31, 16#90, + 16#0B, 16#1C, 16#9E, 16#59, 16#E7, 16#C9, 16#7F, + 16#BE, 16#C7, 16#E8, 16#F3, 16#23, 16#A9, 16#7A, + 16#7E, 16#36, 16#CC, 16#88, 16#BE, 16#0F, 16#1D, + 16#45, 16#B7, 16#FF, 16#58, 16#5A, 16#C5, 16#4B, + 16#D4, 16#07, 16#B2, 16#2B, 16#41, 16#54, 16#AA, + 16#CC, 16#8F, 16#6D, 16#7E, 16#BF, 16#48, 16#E1, + 16#D8, 16#14, 16#CC, 16#5E, 16#D2, 16#0F, 16#80, + 16#37, 16#E0, 16#A7, 16#97, 16#15, 16#EE, 16#F2, + 16#9B, 16#E3, 16#28, 16#06, 16#A1, 16#D5, 16#8B, + 16#B7, 16#C5, 16#DA, 16#76, 16#F5, 16#50, 16#AA, + 16#3D, 16#8A, 16#1F, 16#BF, 16#F0, 16#EB, 16#19, + 16#CC, 16#B1, 16#A3, 16#13, 16#D5, 16#5C, 16#DA, + 16#56, 16#C9, 16#EC, 16#2E, 16#F2, 16#96, 16#32, + 16#38, 16#7F, 16#E8, 16#D7, 16#6E, 16#3C, 16#04, + 16#68, 16#04, 16#3E, 16#8F, 16#66, 16#3F, 16#48, + 16#60, 16#EE, 16#12, 16#BF, 16#2D, 16#5B, 16#0B, + 16#74, 16#74, 16#D6, 16#E6, 16#94, 16#F9, 16#1E, + 16#6D, 16#BE, 16#11, 16#59, 16#74, 16#A3, 16#92, + 16#6F, 16#12, 16#FE, 16#E5, 16#E4, 16#38, 16#77, + 16#7C, 16#B6, 16#A9, 16#32, 16#DF, 16#8C, 16#D8, + 16#BE, 16#C4, 16#D0, 16#73, 16#B9, 16#31, 16#BA, + 16#3B, 16#C8, 16#32, 16#B6, 16#8D, 16#9D, 16#D3, + 16#00, 16#74, 16#1F, 16#A7, 16#BF, 16#8A, 16#FC, + 16#47, 16#ED, 16#25, 16#76, 16#F6, 16#93, 16#6B, + 16#A4, 16#24, 16#66, 16#3A, 16#AB, 16#63, 16#9C, + 16#5A, 16#E4, 16#F5, 16#68, 16#34, 16#23, 16#B4, + 16#74, 16#2B, 16#F1, 16#C9, 16#78, 16#23, 16#8F, + 16#16, 16#CB, 16#E3, 16#9D, 16#65, 16#2D, 16#E3, + 16#FD, 16#B8, 16#BE, 16#FC, 16#84, 16#8A, 16#D9, + 16#22, 16#22, 16#2E, 16#04, 16#A4, 16#03, 16#7C, + 16#07, 16#13, 16#EB, 16#57, 16#A8, 16#1A, 16#23, + 16#F0, 16#C7, 16#34, 16#73, 16#FC, 16#64, 16#6C, + 16#EA, 16#30, 16#6B, 16#4B, 16#CB, 16#C8, 16#86, + 16#2F, 16#83, 16#85, 16#DD, 16#FA, 16#9D, 16#4B, + 16#7F, 16#A2, 16#C0, 16#87, 16#E8, 16#79, 16#68, + 16#33, 16#03, 16#ED, 16#5B, 16#DD, 16#3A, 16#06, + 16#2B, 16#3C, 16#F5, 16#B3, 16#A2, 16#78, 16#A6, + 16#6D, 16#2A, 16#13, 16#F8, 16#3F, 16#44, 16#F8, + 16#2D, 16#DF, 16#31, 16#0E, 16#E0, 16#74, 16#AB, + 16#6A, 16#36, 16#45, 16#97, 16#E8, 16#99, 16#A0, + 16#25, 16#5D, 16#C1, 16#64, 16#F3, 16#1C, 16#C5, + 16#08, 16#46, 16#85, 16#1D, 16#F9, 16#AB, 16#48, + 16#19, 16#5D, 16#ED, 16#7E, 16#A1, 16#B1, 16#D5, + 16#10, 16#BD, 16#7E, 16#E7, 16#4D, 16#73, 16#FA, + 16#F3, 16#6B, 16#C3, 16#1E, 16#CF, 16#A2, 16#68, + 16#35, 16#90, 16#46, 16#F4, 16#EB, 16#87, 16#9F, + 16#92, 16#40, 16#09, 16#43, 16#8B, 16#48, 16#1C, + 16#6C, 16#D7, 16#88, 16#9A, 16#00, 16#2E, 16#D5, + 16#EE, 16#38, 16#2B, 16#C9, 16#19, 16#0D, 16#A6, + 16#FC, 16#02, 16#6E, 16#47, 16#95, 16#58, 16#E4, + 16#47, 16#56, 16#77, 16#E9, 16#AA, 16#9E, 16#30, + 16#50, 16#E2, 16#76, 16#56, 16#94, 16#DF, 16#C8, + 16#1F, 16#56, 16#E8, 16#80, 16#B9, 16#6E, 16#71, + 16#60, 16#C9, 16#80, 16#DD, 16#98, 16#ED, 16#D3, + 16#DF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, + 16#FF, 16#FF>>). +-define(GENERATOR_8192, <<19>>). + +get_srp_params(srp_1024) -> {?GENERATOR_1024, ?PRIME_1024}; +get_srp_params(srp_1536) -> {?GENERATOR_1536, ?PRIME_1536}; +get_srp_params(srp_2048) -> {?GENERATOR_2048, ?PRIME_2048}; +get_srp_params(srp_3072) -> {?GENERATOR_3072, ?PRIME_3072}; +get_srp_params(srp_4096) -> {?GENERATOR_4096, ?PRIME_4096}; +get_srp_params(srp_6144) -> {?GENERATOR_6144, ?PRIME_6144}; +get_srp_params(srp_8192) -> {?GENERATOR_8192, ?PRIME_8192}. + +check_srp_params(?GENERATOR_1024, ?PRIME_1024) -> ok; +check_srp_params(?GENERATOR_1536, ?PRIME_1536) -> ok; +check_srp_params(?GENERATOR_2048, ?PRIME_2048) -> ok; +check_srp_params(?GENERATOR_3072, ?PRIME_3072) -> ok; +check_srp_params(?GENERATOR_4096, ?PRIME_4096) -> ok; +check_srp_params(?GENERATOR_6144, ?PRIME_6144) -> ok; +check_srp_params(?GENERATOR_8192, ?PRIME_8192) -> ok; +check_srp_params(_Generator, _Prime) -> + not_accepted. diff --git a/lib/ssl/src/ssl_srp_primes.hrl b/lib/ssl/src/ssl_srp_primes.hrl new file mode 100644 index 0000000000..4bd534efbf --- /dev/null +++ b/lib/ssl/src/ssl_srp_primes.hrl @@ -0,0 +1 @@ +-type srp_parameters() :: srp_1024 | srp_1536 | srp_2048 | srp_3072 | srp_4096 | srp_6144 | srp_8192. diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index 41dc1bf0dc..8a8dfca8c2 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -29,7 +29,8 @@ -include("ssl_record.hrl"). -export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7, - setup_keys/8, suites/1, prf/5]). + setup_keys/8, suites/1, prf/5, + ecc_curves/1, ec_nid2curve_id/1, ec_curve_id2nid/1]). %%==================================================================== %% Internal application API @@ -184,27 +185,56 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor}, suites(Minor) when Minor == 1; Minor == 2-> [ + ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA, ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA, + ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, ?TLS_RSA_WITH_AES_256_CBC_SHA, + + ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, + ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, ?TLS_RSA_WITH_3DES_EDE_CBC_SHA, + + ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA, ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, ?TLS_RSA_WITH_AES_128_CBC_SHA, %%?TLS_RSA_WITH_IDEA_CBC_SHA, + ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + ?TLS_ECDHE_RSA_WITH_RC4_128_SHA, ?TLS_RSA_WITH_RC4_128_SHA, ?TLS_RSA_WITH_RC4_128_MD5, ?TLS_DHE_RSA_WITH_DES_CBC_SHA, + ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA, + ?TLS_ECDH_RSA_WITH_RC4_128_SHA, ?TLS_RSA_WITH_DES_CBC_SHA ]; suites(Minor) when Minor == 3 -> [ + ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, + ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, + ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, ?TLS_RSA_WITH_AES_256_CBC_SHA256, + + ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, ?TLS_RSA_WITH_AES_128_CBC_SHA256 @@ -303,3 +333,64 @@ finished_label(client) -> <<"client finished">>; finished_label(server) -> <<"server finished">>. + +%% list ECC curves in prefered order +ecc_curves(_Minor) -> + [sect571r1,sect571k1,secp521r1,sect409k1,sect409r1, + secp384r1,sect283k1,sect283r1,secp256k1,secp256r1, + sect239k1,sect233k1,sect233r1,secp224k1,secp224r1, + sect193r1,sect193r2,secp192k1,secp192r1,sect163k1, + sect163r1,sect163r2,secp160k1,secp160r1,secp160r2]. + +%% ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) +ec_nid2curve_id(sect163k1) -> 1; +ec_nid2curve_id(sect163r1) -> 2; +ec_nid2curve_id(sect163r2) -> 3; +ec_nid2curve_id(sect193r1) -> 4; +ec_nid2curve_id(sect193r2) -> 5; +ec_nid2curve_id(sect233k1) -> 6; +ec_nid2curve_id(sect233r1) -> 7; +ec_nid2curve_id(sect239k1) -> 8; +ec_nid2curve_id(sect283k1) -> 9; +ec_nid2curve_id(sect283r1) -> 10; +ec_nid2curve_id(sect409k1) -> 11; +ec_nid2curve_id(sect409r1) -> 12; +ec_nid2curve_id(sect571k1) -> 13; +ec_nid2curve_id(sect571r1) -> 14; +ec_nid2curve_id(secp160k1) -> 15; +ec_nid2curve_id(secp160r1) -> 16; +ec_nid2curve_id(secp160r2) -> 17; +ec_nid2curve_id(secp192k1) -> 18; +ec_nid2curve_id(secp192r1) -> 19; +ec_nid2curve_id(secp224k1) -> 20; +ec_nid2curve_id(secp224r1) -> 21; +ec_nid2curve_id(secp256k1) -> 22; +ec_nid2curve_id(secp256r1) -> 23; +ec_nid2curve_id(secp384r1) -> 24; +ec_nid2curve_id(secp521r1) -> 25. + +ec_curve_id2nid(1) -> sect163k1; +ec_curve_id2nid(2) -> sect163r1; +ec_curve_id2nid(3) -> sect163r2; +ec_curve_id2nid(4) -> sect193r1; +ec_curve_id2nid(5) -> sect193r2; +ec_curve_id2nid(6) -> sect233k1; +ec_curve_id2nid(7) -> sect233r1; +ec_curve_id2nid(8) -> sect239k1; +ec_curve_id2nid(9) -> sect283k1; +ec_curve_id2nid(10) -> sect283r1; +ec_curve_id2nid(11) -> sect409k1; +ec_curve_id2nid(12) -> sect409r1; +ec_curve_id2nid(13) -> sect571k1; +ec_curve_id2nid(14) -> sect571r1; +ec_curve_id2nid(15) -> secp160k1; +ec_curve_id2nid(16) -> secp160r1; +ec_curve_id2nid(17) -> secp160r2; +ec_curve_id2nid(18) -> secp192k1; +ec_curve_id2nid(19) -> secp192r1; +ec_curve_id2nid(20) -> secp224k1; +ec_curve_id2nid(21) -> secp224r1; +ec_curve_id2nid(22) -> secp256k1; +ec_curve_id2nid(23) -> secp256r1; +ec_curve_id2nid(24) -> secp384r1; +ec_curve_id2nid(25) -> secp521r1. diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl index 5b92e551a5..1dc140a472 100644 --- a/lib/ssl/test/erl_make_certs.erl +++ b/lib/ssl/test/erl_make_certs.erl @@ -45,7 +45,7 @@ %% {dnQualifer, DnQ} %% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created) %% (obs IssuerKey migth be {Key, Password} -%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key +%% key = KeyFile|KeyBin|rsa|dsa|ec Subject PublicKey rsa, dsa or ec generates key %% %% %% (OBS: The generated keys are for testing only) @@ -91,6 +91,16 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) -> {Key, encode_key(Key)}. %%-------------------------------------------------------------------- +%% @doc Creates a ec key (OBS: for testing only) +%% the sizes are in bytes +%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()} +%% @end +%%-------------------------------------------------------------------- +gen_ec(Curve) when is_atom(Curve) -> + Key = gen_ec2(Curve), + {Key, encode_key(Key)}. + +%%-------------------------------------------------------------------- %% @doc Verifies cert signatures %% @spec (::binary(), ::tuple()) -> ::boolean() %% @end @@ -102,7 +112,10 @@ verify_signature(DerEncodedCert, DerKey, _KeyParams) -> public_key:pkix_verify(DerEncodedCert, #'RSAPublicKey'{modulus=Mod, publicExponent=Exp}); #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} -> - public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}) + public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}); + #'ECPrivateKey'{version = _Version, privateKey = _PrivKey, + parameters = _Params, publicKey = _PubKey} -> + public_key:pkix_verify(DerEncodedCert, Key) end. %%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -112,6 +125,7 @@ get_key(Opts) -> undefined -> make_key(rsa, Opts); rsa -> make_key(rsa, Opts); dsa -> make_key(dsa, Opts); + ec -> make_key(ec, Opts); Key -> Password = proplists:get_value(password, Opts, no_passwd), decode_key(Key, Password) @@ -129,6 +143,8 @@ decode_key(#'RSAPrivateKey'{} = Key,_) -> Key; decode_key(#'DSAPrivateKey'{} = Key,_) -> Key; +decode_key(#'ECPrivateKey'{} = Key,_) -> + Key; decode_key(PemEntry = {_,_,_}, Pw) -> public_key:pem_entry_decode(PemEntry, Pw); decode_key(PemBin, Pw) -> @@ -140,7 +156,10 @@ encode_key(Key = #'RSAPrivateKey'{}) -> {'RSAPrivateKey', Der, not_encrypted}; encode_key(Key = #'DSAPrivateKey'{}) -> {ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key), - {'DSAPrivateKey', Der, not_encrypted}. + {'DSAPrivateKey', Der, not_encrypted}; +encode_key(Key = #'ECPrivateKey'{}) -> + {ok, Der} = 'OTP-PUB-KEY':encode('ECPrivateKey', Key), + {'ECPrivateKey', Der, not_encrypted}. make_tbs(SubjectKey, Opts) -> Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))), @@ -277,7 +296,14 @@ publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) -> publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) -> Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa', parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}}, - #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}. + #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}; +publickey(#'ECPrivateKey'{version = _Version, + privateKey = _PrivKey, + parameters = Params, + publicKey = {0, PubKey}}) -> + Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-ecPublicKey', parameters=Params}, + #'OTPSubjectPublicKeyInfo'{algorithm = Algo, + subjectPublicKey = #'ECPoint'{point = PubKey}}. validity(Opts) -> DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1), @@ -298,13 +324,24 @@ sign_algorithm(#'RSAPrivateKey'{}, Opts) -> end, {Type, 'NULL'}; sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) -> - {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}. + {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}; +sign_algorithm(#'ECPrivateKey'{}, Opts) -> + Type = case proplists:get_value(digest, Opts, sha1) of + sha1 -> ?'ecdsa-with-SHA1'; + sha512 -> ?'ecdsa-with-SHA512'; + sha384 -> ?'ecdsa-with-SHA384'; + sha256 -> ?'ecdsa-with-SHA256' + end, + {Type, 'NULL'}. make_key(rsa, _Opts) -> %% (OBS: for testing only) gen_rsa2(64); make_key(dsa, _Opts) -> - gen_dsa2(128, 20). %% Bytes i.e. {1024, 160} + gen_dsa2(128, 20); %% Bytes i.e. {1024, 160} +make_key(ec, _Opts) -> + %% (OBS: for testing only) + gen_ec2(secp256k1). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% RSA key generation (OBS: for testing only) @@ -363,6 +400,24 @@ gen_dsa2(LSize, NSize) -> #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X} end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EC key generation (OBS: for testing only) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +int2list(I) -> + L = (length(integer_to_list(I, 16)) + 1) div 2, + binary_to_list(<<I:(L*8)>>). + +gen_ec2(CurveId) -> + Key = crypto:ec_key_new(CurveId), + crypto:ec_key_generate(Key), + {_Curve, PrivKey, PubKey} = crypto:ec_key_to_term(Key), + + #'ECPrivateKey'{version = 1, + privateKey = int2list(PrivKey), + parameters = {namedCurve, pubkey_cert_records:namedCurves(CurveId)}, + publicKey = {0, PubKey}}. + %% See fips_186-3.pdf dsa_search(T, P0, Q, Iter) when Iter > 0 -> P = 2*T*Q*P0 + 1, diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index b5c6a1da49..478b48cfa6 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -69,6 +69,7 @@ groups() -> {session, [], session_tests()}, {renegotiate, [], renegotiate_tests()}, {ciphers, [], cipher_tests()}, + {ciphers_ec, [], cipher_tests_ec()}, {error_handling_tests, [], error_handling_tests()} ]. @@ -76,6 +77,7 @@ all_versions_groups ()-> [{group, api}, {group, renegotiate}, {group, ciphers}, + {group, ciphers_ec}, {group, error_handling_tests}]. @@ -153,8 +155,18 @@ cipher_tests() -> ciphers_dsa_signed_certs, ciphers_dsa_signed_certs_openssl_names, anonymous_cipher_suites, + psk_cipher_suites, + psk_with_hint_cipher_suites, + srp_cipher_suites, + srp_dsa_cipher_suites, default_reject_anonymous]. +cipher_tests_ec() -> + [ciphers_ecdsa_signed_certs, + ciphers_ecdsa_signed_certs_openssl_names, + ciphers_ecdh_rsa_signed_certs, + ciphers_ecdh_rsa_signed_certs_openssl_names]. + error_handling_tests()-> [controller_dies, client_closes_socket, @@ -183,7 +195,9 @@ init_per_suite(Config0) -> ct:print("Make certs ~p~n", [Result]), Config1 = ssl_test_lib:make_dsa_cert(Config0), - Config = ssl_test_lib:cert_options(Config1), + Config2 = ssl_test_lib:make_ecdsa_cert(Config1), + Config3 = ssl_test_lib:make_ecdh_rsa_cert(Config2), + Config = ssl_test_lib:cert_options(Config3), [{watchdog, Dog} | Config] catch _:_ -> {skip, "Crypto did not start"} @@ -1574,7 +1588,34 @@ anonymous_cipher_suites(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), Ciphers = ssl_test_lib:anonymous_suites(), run_suites(Ciphers, Version, Config, anonymous). - +%%------------------------------------------------------------------- +psk_cipher_suites() -> + [{doc, "Test the PSK ciphersuites WITHOUT server supplied identity hint"}]. +psk_cipher_suites(Config) when is_list(Config) -> + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Ciphers = ssl_test_lib:psk_suites(), + run_suites(Ciphers, Version, Config, psk). +%%------------------------------------------------------------------- +psk_with_hint_cipher_suites()-> + [{doc, "Test the PSK ciphersuites WITH server supplied identity hint"}]. +psk_with_hint_cipher_suites(Config) when is_list(Config) -> + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Ciphers = ssl_test_lib:psk_suites(), + run_suites(Ciphers, Version, Config, psk_with_hint). +%%------------------------------------------------------------------- +srp_cipher_suites()-> + [{doc, "Test the SRP ciphersuites"}]. +srp_cipher_suites(Config) when is_list(Config) -> + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Ciphers = ssl_test_lib:srp_suites(), + run_suites(Ciphers, Version, Config, srp). +%%------------------------------------------------------------------- +srp_dsa_cipher_suites()-> + [{doc, "Test the SRP DSA ciphersuites"}]. +srp_dsa_cipher_suites(Config) when is_list(Config) -> + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Ciphers = ssl_test_lib:srp_dss_suites(), + run_suites(Ciphers, Version, Config, srp_dsa). %%-------------------------------------------------------------------- default_reject_anonymous()-> [{doc,"Test that by default anonymous cipher suites are rejected "}]. @@ -1600,6 +1641,48 @@ default_reject_anonymous(Config) when is_list(Config) -> Client, {error, {tls_alert, "insufficient security"}}). %%-------------------------------------------------------------------- +ciphers_ecdsa_signed_certs() -> + [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}]. + +ciphers_ecdsa_signed_certs(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + Ciphers = ssl_test_lib:ecdsa_suites(), + ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]), + run_suites(Ciphers, Version, Config, ecdsa). +%%-------------------------------------------------------------------- +ciphers_ecdsa_signed_certs_openssl_names() -> + [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}]. + +ciphers_ecdsa_signed_certs_openssl_names(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Ciphers = ssl_test_lib:openssl_ecdsa_suites(), + ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]), + run_suites(Ciphers, Version, Config, ecdsa). +%%-------------------------------------------------------------------- +ciphers_ecdh_rsa_signed_certs() -> + [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}]. + +ciphers_ecdh_rsa_signed_certs(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + Ciphers = ssl_test_lib:ecdh_rsa_suites(), + ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]), + run_suites(Ciphers, Version, Config, ecdh_rsa). +%%-------------------------------------------------------------------- +ciphers_ecdh_rsa_signed_certs_openssl_names() -> + [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}]. + +ciphers_ecdh_rsa_signed_certs_openssl_names(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Ciphers = ssl_test_lib:openssl_ecdh_rsa_suites(), + ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]), + run_suites(Ciphers, Version, Config, ecdh_rsa). +%%-------------------------------------------------------------------- reuse_session() -> [{doc,"Test reuse of sessions (short handshake)"}]. reuse_session(Config) when is_list(Config) -> @@ -3057,12 +3140,21 @@ rizzo_test(Cipher, Config, Version, Mfa) -> [{Cipher, Error}] end. -client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == rsa orelse KeyAlgo == dhe_rsa -> +client_server_opts({KeyAlgo,_,_}, Config) + when KeyAlgo == rsa orelse + KeyAlgo == dhe_rsa orelse + KeyAlgo == ecdhe_rsa -> {?config(client_opts, Config), ?config(server_opts, Config)}; client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == dss orelse KeyAlgo == dhe_dss -> {?config(client_dsa_opts, Config), - ?config(server_dsa_opts, Config)}. + ?config(server_dsa_opts, Config)}; +client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == ecdh_ecdsa orelse KeyAlgo == ecdhe_ecdsa -> + {?config(client_opts, Config), + ?config(server_ecdsa_opts, Config)}; +client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == ecdh_rsa -> + {?config(client_opts, Config), + ?config(server_ecdh_rsa_opts, Config)}. run_suites(Ciphers, Version, Config, Type) -> {ClientOpts, ServerOpts} = @@ -3076,7 +3168,25 @@ run_suites(Ciphers, Version, Config, Type) -> anonymous -> %% No certs in opts! {?config(client_opts, Config), - ?config(server_anon, Config)} + ?config(server_anon, Config)}; + psk -> + {?config(client_psk, Config), + ?config(server_psk, Config)}; + psk_with_hint -> + {?config(client_psk, Config), + ?config(server_psk_hint, Config)}; + srp -> + {?config(client_srp, Config), + ?config(server_srp, Config)}; + srp_dsa -> + {?config(client_srp_dsa, Config), + ?config(server_srp_dsa, Config)}; + ecdsa -> + {?config(client_opts, Config), + ?config(server_ecdsa_opts, Config)}; + ecdh_rsa -> + {?config(client_opts, Config), + ?config(server_ecdh_rsa_opts, Config)} end, Result = lists:map(fun(Cipher) -> diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 76b302b1cb..67968b879e 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -281,6 +281,13 @@ wait_for_result(Pid, Msg) -> %% Unexpected end. +user_lookup(psk, _Identity, UserState) -> + {ok, UserState}; +user_lookup(srp, Username, _UserState) -> + Salt = ssl:random_bytes(16), + UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, <<"secret">>])]), + {ok, {srp_1024, Salt, UserPassHash}}. + cert_options(Config) -> ClientCaCertFile = filename:join([?config(priv_dir, Config), "client", "cacerts.pem"]), @@ -307,6 +314,7 @@ cert_options(Config) -> "badcert.pem"]), BadKeyFile = filename:join([?config(priv_dir, Config), "badkey.pem"]), + PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>, [{client_opts, [{ssl_imp, new},{reuseaddr, true}]}, {client_verification_opts, [{cacertfile, ClientCaCertFile}, {certfile, ClientCertFile}, @@ -319,6 +327,24 @@ cert_options(Config) -> {server_opts, [{ssl_imp, new},{reuseaddr, true}, {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]}, {server_anon, [{ssl_imp, new},{reuseaddr, true}, {ciphers, anonymous_suites()}]}, + {client_psk, [{ssl_imp, new},{reuseaddr, true}, + {psk_identity, "Test-User"}, + {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]}, + {server_psk, [{ssl_imp, new},{reuseaddr, true}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, + {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}, + {ciphers, psk_suites()}]}, + {server_psk_hint, [{ssl_imp, new},{reuseaddr, true}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, + {psk_identity, "HINT"}, + {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}, + {ciphers, psk_suites()}]}, + {client_srp, [{ssl_imp, new},{reuseaddr, true}, + {srp_identity, {"Test-User", "secret"}}]}, + {server_srp, [{ssl_imp, new},{reuseaddr, true}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, + {user_lookup_fun, {fun user_lookup/3, undefined}}, + {ciphers, srp_suites()}]}, {server_verification_opts, [{ssl_imp, new},{reuseaddr, true}, {cacertfile, ServerCaCertFile}, {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]}, @@ -356,9 +382,61 @@ make_dsa_cert(Config) -> {verify, verify_peer}]}, {client_dsa_opts, [{ssl_imp, new},{reuseaddr, true}, {cacertfile, ClientCaCertFile}, - {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]} + {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}, + {server_srp_dsa, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ServerCaCertFile}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, + {user_lookup_fun, {fun user_lookup/3, undefined}}, + {ciphers, srp_dss_suites()}]}, + {client_srp_dsa, [{ssl_imp, new},{reuseaddr, true}, + {srp_identity, {"Test-User", "secret"}}, + {cacertfile, ClientCaCertFile}, + {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]} | Config]. +make_ecdsa_cert(Config) -> + case proplists:get_bool(ec, crypto:algorithms()) of + true -> + {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, ec, ec, ""), + {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, ec, ec, ""), + [{server_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ServerCaCertFile}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]}, + {server_ecdsa_verify_opts, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ClientCaCertFile}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, + {verify, verify_peer}]}, + {client_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ClientCaCertFile}, + {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]} + | Config]; + _ -> + Config + end. + +%% RFC 4492, Sect. 2.3. ECDH_RSA +%% +%% This key exchange algorithm is the same as ECDH_ECDSA except that the +%% server's certificate MUST be signed with RSA rather than ECDSA. +make_ecdh_rsa_cert(Config) -> + case proplists:get_bool(ec, crypto:algorithms()) of + true -> + {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, rsa, ec, "rsa_"), + {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, rsa, ec, "rsa_"), + [{server_ecdh_rsa_opts, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ServerCaCertFile}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]}, + {server_ecdh_rsa_verify_opts, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ClientCaCertFile}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}, + {verify, verify_peer}]}, + {client_ecdh_rsa_opts, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ClientCaCertFile}, + {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]} + | Config]; + _ -> + Config + end. make_mix_cert(Config) -> {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, dsa, @@ -622,10 +700,14 @@ send_selected_port(_,_,_) -> ok. rsa_suites() -> - lists:filter(fun({dhe_dss, _, _}) -> - false; + lists:filter(fun({rsa, _, _}) -> + true; + ({dhe_rsa, _, _}) -> + true; + ({ecdhe_rsa, _, _}) -> + true; (_) -> - true + false end, ssl:cipher_suites()). @@ -645,17 +727,32 @@ dsa_suites() -> end, ssl:cipher_suites()). +ecdsa_suites() -> + lists:filter(fun({ecdhe_ecdsa, _, _}) -> + true; + (_) -> + false + end, + ssl:cipher_suites()). + +ecdh_rsa_suites() -> + lists:filter(fun({ecdh_rsa, _, _}) -> + true; + (_) -> + false + end, + ssl:cipher_suites()). openssl_rsa_suites() -> Ciphers = ssl:cipher_suites(openssl), lists:filter(fun(Str) -> - case re:run(Str,"DSS",[]) of + case re:run(Str,"DSS|ECDH-RSA|ECDSA",[]) of nomatch -> true; _ -> false end - end, Ciphers). + end, Ciphers). openssl_dsa_suites() -> Ciphers = ssl:cipher_suites(openssl), @@ -668,12 +765,73 @@ openssl_dsa_suites() -> end end, Ciphers). +openssl_ecdsa_suites() -> + Ciphers = ssl:cipher_suites(openssl), + lists:filter(fun(Str) -> + case re:run(Str,"ECDHE-ECDSA",[]) of + nomatch -> + false; + _ -> + true + end + end, Ciphers). + +openssl_ecdh_rsa_suites() -> + Ciphers = ssl:cipher_suites(openssl), + lists:filter(fun(Str) -> + case re:run(Str,"ECDH-RSA",[]) of + nomatch -> + false; + _ -> + true + end + end, Ciphers). + anonymous_suites() -> - [{dh_anon, rc4_128, md5}, - {dh_anon, des_cbc, sha}, - {dh_anon, '3des_ede_cbc', sha}, - {dh_anon, aes_128_cbc, sha}, - {dh_anon, aes_256_cbc, sha}]. + Suites = + [{dh_anon, rc4_128, md5}, + {dh_anon, des_cbc, sha}, + {dh_anon, '3des_ede_cbc', sha}, + {dh_anon, aes_128_cbc, sha}, + {dh_anon, aes_256_cbc, sha}, + {ecdh_anon,rc4_128,sha}, + {ecdh_anon,'3des_ede_cbc',sha}, + {ecdh_anon,aes_128_cbc,sha}, + {ecdh_anon,aes_256_cbc,sha}], + ssl_cipher:filter_suites(Suites). + +psk_suites() -> + Suites = + [{psk, rc4_128, sha}, + {psk, '3des_ede_cbc', sha}, + {psk, aes_128_cbc, sha}, + {psk, aes_256_cbc, sha}, + {dhe_psk, rc4_128, sha}, + {dhe_psk, '3des_ede_cbc', sha}, + {dhe_psk, aes_128_cbc, sha}, + {dhe_psk, aes_256_cbc, sha}, + {rsa_psk, rc4_128, sha}, + {rsa_psk, '3des_ede_cbc', sha}, + {rsa_psk, aes_128_cbc, sha}, + {rsa_psk, aes_256_cbc, sha}], + ssl_cipher:filter_suites(Suites). + +srp_suites() -> + Suites = + [{srp_anon, '3des_ede_cbc', sha}, + {srp_rsa, '3des_ede_cbc', sha}, + {srp_anon, aes_128_cbc, sha}, + {srp_rsa, aes_128_cbc, sha}, + {srp_anon, aes_256_cbc, sha}, + {srp_rsa, aes_256_cbc, sha}], + ssl_cipher:filter_suites(Suites). + +srp_dss_suites() -> + Suites = + [{srp_dss, '3des_ede_cbc', sha}, + {srp_dss, aes_128_cbc, sha}, + {srp_dss, aes_256_cbc, sha}], + ssl_cipher:filter_suites(Suites). pem_to_der(File) -> {ok, PemBin} = file:read_file(File), @@ -755,15 +913,9 @@ init_tls_version(Version) -> ssl:start(). sufficient_crypto_support('tlsv1.2') -> - Data = "Sampl", - Data2 = "e #1", - Key = <<0,1,2,3,16,17,18,19,32,33,34,35,48,49,50,51,4,5,6,7,20,21,22,23,36,37,38,39, - 52,53,54,55,8,9,10,11,24,25,26,27,40,41,42,43,56,57,58,59>>, - try - crypto:sha256_mac(Key, lists:flatten([Data, Data2])), - true - catch _:_ -> false - end; + proplists:get_bool(sha256, crypto:algorithms()); +sufficient_crypto_support(ciphers_ec) -> + proplists:get_bool(ec, crypto:algorithms()); sufficient_crypto_support(_) -> true. diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index 4f53132d5d..a3e2d5e6e0 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -1002,7 +1002,7 @@ erlang_server_openssl_client_npn_only_client(Config) when is_list(Config) -> %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- -run_suites(Ciphers, Version, Config, Type) -> +run_suites(Ciphers0, Version, Config, Type) -> {ClientOpts, ServerOpts} = case Type of rsa -> @@ -1013,6 +1013,7 @@ run_suites(Ciphers, Version, Config, Type) -> ?config(server_dsa_opts, Config)} end, + Ciphers = filter_suites(Ciphers0), Result = lists:map(fun(Cipher) -> cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end, Ciphers), @@ -1380,3 +1381,18 @@ check_sane_openssl_version(Version) -> {_, _} -> true end. + +filter_suites(Suites) -> + OpenSSLSuites = gb_sets:from_list(string:tokens(os:cmd("openssl ciphers"), ":\n")), + + lists:filter(fun(Suite) -> + try + OpenSSLSuite = ssl_cipher:openssl_suite_name(ssl_cipher:suite(Suite)), + gb_sets:is_member(OpenSSLSuite, OpenSSLSuites) + catch + _:_ -> + %% no OpenSSL name known + false + end + end, Suites). + |