From c6c2e82f8b94010e78bfa5fedce7629e7fd32d58 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Thu, 28 Mar 2013 16:19:40 +0100 Subject: CRYPTO: add support for Elliptic Curves to crypto app Conflicts: lib/crypto/src/crypto.erl --- lib/crypto/c_src/crypto.c | 835 ++++++++++++++++++++++++++++++++++++++- lib/crypto/doc/src/crypto.xml | 149 ++++++- lib/crypto/src/crypto.erl | 107 ++++- lib/crypto/test/crypto_SUITE.erl | 67 +++- 4 files changed, 1152 insertions(+), 6 deletions(-) mode change 100755 => 100644 lib/crypto/doc/src/crypto.xml diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index fac77308f6..1e6c2f24e7 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -74,6 +74,19 @@ # define HAVE_DES_ede3_cfb_encrypt #endif +#if OPENSSL_VERSION_NUMBER >= 0x009080ffL \ + && !defined(OPENSSL_NO_EC) \ + && !defined(OPENSSL_NO_ECDH) \ + && !defined(OPENSSL_NO_ECDSA) +# define HAVE_EC +#endif + +#if defined(HAVE_EC) +#include +#include +#include +#endif + #ifdef VALGRIND # include @@ -216,6 +229,13 @@ static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar 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 */ @@ -333,9 +353,114 @@ static ErlNifFunc nif_funcs[] = { {"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(HAVE_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) @@ -386,6 +511,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(HAVE_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) @@ -415,6 +553,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; @@ -466,6 +605,22 @@ 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(HAVE_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(); @@ -549,7 +704,7 @@ static void unload(ErlNifEnv* env, void* priv_data) } static int algos_cnt; -static ERL_NIF_TERM algos[7]; /* increase when extending the list */ +static ERL_NIF_TERM algos[8]; /* increase when extending the list */ static void init_algorithms_types(void) { @@ -570,6 +725,9 @@ static void init_algorithms_types(void) #ifdef HAVE_SHA512 algos[algos_cnt++] = atom_sha512; #endif +#if defined(HAVE_EC) + algos[algos_cnt++] = atom_ec; +#endif } static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -2686,7 +2844,680 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N return ret; } +#if defined(HAVE_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(HAVE_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(HAVE_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(HAVE_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(HAVE_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(HAVE_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(HAVE_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(HAVE_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(HAVE_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(HAVE_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(HAVE_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 old mode 100755 new mode 100644 index 7eca4557d9..9201d649d7 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -66,8 +66,20 @@

srp: Secure Remote Password Protocol (RFC 2945)

- - + +

ecdsa: "Public Key Cryptography for the Financial + Services Industry: The Elliptic Curve Digital + Signature Standard (ECDSA)", November, 2005.

+
+ +

ec: Standards for Efficient Cryptography Group (SECG), "SEC 1: + Elliptic Curve Cryptography", Version 1.0, September 2000.

+
+ +

ecdsa: American National Standards Institute (ANSI), + ANS X9.62-2005: The Elliptic Curve Digital Signature + Algorithm (ECDSA), 2005.

+

The above publications can be found at NIST publications, at IETF.

@@ -1359,6 +1371,116 @@ Mpint() = >]]> + + ec_key_new(NamedCurve) -> ECKey + + NamedCurve = atom() + ECKey = EC key resource() + + +

Generate an new EC key from the named curve. The private key + will be initialized with random data. +

+
+
+ + + ec_key_generate(ECKey) -> ok | error + + ECKey = EC key resource() + + +

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. +

+
+
+ + + ec_key_to_term(ECKey) -> ECKeyTerm. + + ECKey = EC key resource() + ECKeyTerm = EC key as Erlang term + + +

Convert a EC key from a NIF resource into an Erlang term. +

+
+
+ + + term_to_ec_key(ECKeyTerm) -> ECKey + + ECKeyTerm = EC key as Erlang term + ECKey = EC key resource() + + +

Convert a EC key an Erlang term into a NIF resource. +

+
+
+ + + ecdsa_sign(DataOrDigest, ECKey) -> Signature + ecdsa_sign(DigestType, DataOrDigest, ECKey) -> Signature + Sign the data using ecdsa with the given key. + + DataOrDigest = Data | {digest,Digest} + Data = Mpint + Digest = binary() + ECKey = EC key resource() + DigestType = md5 | sha | sha256 | sha384 | sha512 + The default DigestType is sha. + Mpint = binary() + Signature = binary() + + +

Creates a ESDSA signature with the private key Key + of a digest. The digest is either calculated as a + DigestType digest of Data or a precalculated + binary Digest.

+
+
+ + + ecdsa_verify(DataOrDigest, Signature, ECKey) -> Verified + ecdsa_verify(DigestType, DataOrDigest, Signature, ECKey) -> Verified + Verify the digest and signature using ecdsa with given public key. + + Verified = boolean() + DataOrDigest = Data | {digest|Digest} + Data, Signature = Mpint + Digest = binary() + ECKey = EC key resource() + DigestType = md5 | sha | sha256 | sha384 | sha512 + The default DigestType is sha. + Mpint = binary() + + +

Verifies that a digest matches the ECDSA signature using the + signer's public key Key. + The digest is either calculated as a DigestType + digest of Data or a precalculated binary Digest.

+

May throw exception notsup in case the chosen DigestType + is not supported by the underlying OpenSSL implementation.

+
+
+ + + ecdh_compute_key(OthersPublicKey, MyPrivateKey) -> SharedSecret + ecdh_compute_key(OthersPublicKey, MyECPoint) -> SharedSecret + Computes the shared secret + + OthersPublicKey, MyPrivateKey = ECKey() + MyPrivatePoint = binary() + SharedSecret = binary() + + +

Computes the shared secret from the private key and the other party's public key. +

+
+
+ exor(Data1, Data2) -> Result XOR data @@ -1372,6 +1494,29 @@ Mpint() = >]]> +
+ Elliptic Curve Key +

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 ec_key_to_term/1 + and term_to_ec_key are provided to convert between Erlang + terms and the resource format

+

Key in term form

+
+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}
+    
+
+
DES in CBC mode

The Data Encryption Standard (DES) defines an algorithm for diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 1d0a9943c3..7558087d99 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -67,6 +67,8 @@ -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 @@ -113,12 +115,25 @@ hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, info, rc2_cbc_encrypt, rc2_cbc_decrypt, srp_generate_key, srp_compute_key, + 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)). @@ -1154,6 +1169,94 @@ srp_compute_key(Verifier, Prime, ClientPublic, ServerPublic, ServerPrivate, Vers srp_server_secret_nif(Verifier, ServerPrivate, Scrambler, ClientPublic, Prime). %% +%% 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. + + %% LOCAL FUNCTIONS %% @@ -1262,7 +1365,9 @@ bin_to_int(Bin) -> erlint(<>) -> Bits= MPIntSize * 8, <> = MPIntValue, - Integer. + Integer; +erlint(undefined) -> + undefined. mpint_to_bin(<>) -> Bin. diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 08ecad3233..c5597be34c 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -76,6 +76,7 @@ rsa_encrypt_decrypt/1, dh/1, srp3/1, srp6/1, srp6a/1, + ec/1, exor_test/1, rc4_test/1, rc4_stream_test/1, @@ -105,7 +106,7 @@ groups() -> 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, srp3, srp6, srp6a, exor_test, + rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, ec, exor_test, rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64, smp]}]. @@ -1847,6 +1848,70 @@ 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>>, + <> = <<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>>, + <> = <<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>>, + <> = <<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>>, + <> = <<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) -> []; -- cgit v1.2.3 From 709d0482af92ca52d26296f008b495a36161ca00 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Tue, 14 Aug 2012 16:53:00 +0200 Subject: PUBLIC_KEY: add support for Elliptic Curves to public_key app --- lib/public_key/asn1/ECPrivateKey.asn1 | 24 ++++++ lib/public_key/asn1/OTP-PKIX.asn1 | 42 +++++++++- lib/public_key/asn1/OTP-PUB-KEY.set.asn | 1 + lib/public_key/asn1/PKCS-1.asn1 | 32 ++++++++ lib/public_key/asn1/PKIX1Algorithms88.asn1 | 118 ++++++++++++++++++++--------- lib/public_key/doc/src/public_key.xml | 15 ++-- lib/public_key/include/public_key.hrl | 4 + lib/public_key/src/pubkey_cert_records.erl | 88 ++++++++++++++++++++- lib/public_key/src/pubkey_pem.erl | 16 +++- lib/public_key/src/public_key.erl | 90 +++++++++++++++++++++- lib/public_key/test/erl_make_certs.erl | 67 ++++++++++++++-- 11 files changed, 441 insertions(+), 56 deletions(-) create mode 100644 lib/public_key/asn1/ECPrivateKey.asn1 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 a90fe2840c..4a9d401345 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, @@ -321,7 +322,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 } @@ -439,6 +444,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 } @@ -489,6 +510,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 b5754790e7..117eacd8ad 100644 --- a/lib/public_key/asn1/PKCS-1.asn1 +++ b/lib/public_key/asn1/PKCS-1.asn1 @@ -52,8 +52,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 74225747d3..6cc6745af6 100644 --- a/lib/public_key/asn1/PKIX1Algorithms88.asn1 +++ b/lib/public_key/asn1/PKIX1Algorithms88.asn1 @@ -98,6 +98,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 @@ -199,40 +204,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 84300f6e65..9cad17e4c3 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -84,7 +84,8 @@

pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey' | 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo' | - 'PrivateKeyInfo' | 'CertificationRequest'

+ 'PrivateKeyInfo' | 'CertificationRequest' | 'ECPrivateKey'| + 'OTPEcpkParameters'

pem_entry () = {pki_asn1_type(), binary(), %% DER or encrypted DER not_encrypted | cipher_info()}

@@ -100,6 +101,8 @@

dsa_private_key() = #'DSAPrivateKey'{}

+

ec_key() = {'ECKey', Key}

+

public_crypt_options() = [{rsa_pad, rsa_padding()}].

rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' @@ -109,6 +112,8 @@

dss_digest_type() = 'sha'

+

ecdsa_digest_type() = 'sha'

+

crl_reason() = unspecified | keyCompromise | cACompromise | affiliationChanged | superseded | cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise

@@ -528,8 +533,8 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | 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. - DigestType = rsa_digest_type() | dss_digest_type() - Key = rsa_private_key() | dsa_private_key() + DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type() + Key = rsa_private_key() | dsa_private_key() | ec_key()

Creates a digital signature.

@@ -592,9 +597,9 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | Msg = binary() | {digest,binary()} The msg is either the binary "plain text" data or it is the hashed value of "plain text" i.e. the digest. - DigestType = rsa_digest_type() | dss_digest_type() + DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type() Signature = binary() - Key = rsa_public_key() | dsa_public_key() + Key = rsa_public_key() | dsa_public_key() | ec_key()

Verifies a digital signature

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_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 736c18cdd4..6c25428ea4 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -94,7 +94,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) -> @@ -336,6 +338,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, + <> = 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 pkix_sign_types(SignatureAlg::oid()) -> @@ -362,7 +398,15 @@ pkix_sign_types(?md5WithRSAEncryption) -> pkix_sign_types(?'id-dsa-with-sha1') -> {sha, dsa}; pkix_sign_types(?'id-dsaWithSHA1') -> - {sha, dsa}. + {sha, dsa}; +pkix_sign_types(?'ecdsa-with-SHA1') -> + {sha, ecdsa}; +pkix_sign_types(?'ecdsa-with-SHA256') -> + {sha256, ecdsa}; +pkix_sign_types(?'ecdsa-with-SHA384') -> + {sha384, ecdsa}; +pkix_sign_types(?'ecdsa-with-SHA512') -> + {sha512, ecdsa}. %%-------------------------------------------------------------------- -spec sign(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type(), @@ -386,6 +430,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). @@ -414,6 +470,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); @@ -458,7 +532,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 897cf2f350..14efbcc7e0 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) @@ -90,6 +90,16 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) -> Key = gen_dsa2(LSize, 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() @@ -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(<>). + +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, -- cgit v1.2.3 From 432d3c39ad28fb4033b9e9c2c6aa4474dbfad03c Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Tue, 19 Feb 2013 18:06:26 +0100 Subject: SSL: filter TLS cipher suites for supported algorithms --- lib/ssl/src/ssl.erl | 17 +++++++------ lib/ssl/src/ssl_cipher.erl | 48 ++++++++++++++++++++++++++++++++++- lib/ssl/test/ssl_test_lib.erl | 59 +++++++++++++++++++++++++------------------ 3 files changed, 90 insertions(+), 34 deletions(-) diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 70f3b4f050..742889d8f8 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -364,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, [])]; cipher_suites(all) -> Version = ssl_record:highest_protocol_version([]), @@ -947,21 +947,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) + Supported0 = ssl_cipher:suites(Version) ++ ssl_cipher:anonymous_suites() ++ ssl_cipher:psk_suites(Version) ++ ssl_cipher:srp_suites(), - case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported)] of + 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_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 173c53709b..a7622c156c 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -35,7 +35,7 @@ -export([security_parameters/3, suite_definition/1, decipher/5, cipher/5, suite/1, suites/1, anonymous_suites/0, psk_suites/1, srp_suites/0, - openssl_suite/1, openssl_suite_name/1, filter/2, + openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1, hash_algorithm/1, sign_algorithm/1]). -compile(inline). @@ -737,6 +737,52 @@ filter(DerCert, Ciphers) -> Ciphers -- 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(_, _) -> + 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 %%-------------------------------------------------------------------- diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index e4fedcd118..50afad95a5 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -714,32 +714,39 @@ openssl_dsa_suites() -> 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}], + ssl_cipher:filter_suites(Suites). psk_suites() -> - [{rsa_psk, rc4_128, sha}, - {rsa_psk, '3des_ede_cbc', sha}, - {rsa_psk, aes_128_cbc, sha}, - {rsa_psk, aes_256_cbc, sha}]. - -psk_anon_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}]. + 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() -> - [{srp_rsa, '3des_ede_cbc', sha}, - {srp_rsa, aes_128_cbc, sha}, - {srp_rsa, aes_256_cbc, sha}]. + 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_anon_suites() -> [{srp_anon, '3des_ede_cbc', sha}, @@ -747,9 +754,11 @@ srp_anon_suites() -> {srp_anon, aes_256_cbc, sha}]. srp_dss_suites() -> - [{srp_dss, '3des_ede_cbc', sha}, - {srp_dss, aes_128_cbc, sha}, - {srp_dss, aes_256_cbc, sha}]. + 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), -- cgit v1.2.3 From 9c1fac89a82828106f2aac697fb748eee2f7bdc8 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Thu, 21 Feb 2013 15:02:36 +0100 Subject: SSL: add Elliptic Curve support for ssl app --- lib/ssl/doc/src/ssl.xml | 10 +- lib/ssl/src/ssl.erl | 1 + lib/ssl/src/ssl_certificate.erl | 15 +- lib/ssl/src/ssl_cipher.erl | 371 +++++++++++++++++++++++++++++++++-- lib/ssl/src/ssl_cipher.hrl | 116 ++++++++++- lib/ssl/src/ssl_connection.erl | 163 +++++++++++++-- lib/ssl/src/ssl_handshake.erl | 198 ++++++++++++++++--- lib/ssl/src/ssl_handshake.hrl | 46 ++++- lib/ssl/src/ssl_tls1.erl | 95 ++++++++- lib/ssl/test/ssl_npn_hello_SUITE.erl | 6 +- 10 files changed, 958 insertions(+), 63 deletions(-) diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index d5615fecfc..b02493d2cb 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -37,10 +37,13 @@ ssl requires the crypto and public_key applications. 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). + TLS-1.1 and TLS-1.2. For security reasons sslv2 is not supported. Ephemeral Diffie-Hellman cipher suites are supported but not Diffie Hellman Certificates cipher suites. + Elliptic Curve cipher suites are supported on + systems with a OpenSSL library that has EC support + compiled in. Export cipher suites are not supported as the U.S. lifted its export restrictions in early 2000. IDEA cipher suites are not supported as they have @@ -75,7 +78,7 @@ {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()} | @@ -125,6 +128,7 @@

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

cipher() = rc4_128 | des_cbc | '3des_ede_cbc' @@ -157,7 +161,7 @@ {certfile, path()} Path to a file containing the user's certificate. - {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'PrivateKeyInfo', der_encoded()}} + {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' |'PrivateKeyInfo', der_encoded()}} The DER encoded users private key. If this option is supplied it will override the keyfile option. diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 742889d8f8..f52862729a 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -739,6 +739,7 @@ validate_option(key, {KeyType, Value}) when is_binary(Value), KeyType == dsa; %% Backwards compatibility KeyType == 'RSAPrivateKey'; KeyType == 'DSAPrivateKey'; + KeyType == 'ECPrivateKey'; KeyType == 'PrivateKeyInfo' -> {KeyType, Value}; diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index 01a7cd93b5..9e1c3a09bf 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -37,7 +37,8 @@ is_valid_extkey_usage/2, is_valid_key_usage/2, select_extension/2, - extensions_list/1 + extensions_list/1, + public_key_type/1 ]). %%==================================================================== @@ -165,6 +166,18 @@ extensions_list(asn1_NOVALUE) -> extensions_list(Extensions) -> Extensions. +%%-------------------------------------------------------------------- +-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 a7622c156c..b162d862af 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -212,7 +212,11 @@ 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()]. @@ -423,8 +427,81 @@ suite_definition(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) -> 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}. - + {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(). @@ -573,7 +650,81 @@ suite({srp_anon, 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. + ?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(). @@ -633,8 +784,62 @@ openssl_suite("SRP-RSA-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. + ?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(). @@ -716,6 +921,61 @@ openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_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). @@ -730,11 +990,27 @@ 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()) -- ec_keyed_suites()) -- ecdh_suites(), + rsa_suites(), dhe_rsa_suites() ++ ecdhe_rsa_suites()); + dsa -> + (Ciphers -- rsa_keyed_suites()) -- ec_keyed_suites(); + ec -> + filter_keyuse(OtpCert, (Ciphers -- rsa_keyed_suites()) -- dsa_signed_suites(), + [], ecdhe_ecdsa_suites()) + end, case public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm) of {_, rsa} -> - filter_rsa(OtpCert, Ciphers -- dsa_signed_suites()); + Ciphers1 -- ecdsa_signed_suites(); {_, dsa} -> - Ciphers -- rsa_signed_suites() + Ciphers1; + {_, ecdsa} -> + Ciphers1 -- rsa_signed_suites() end. %%-------------------------------------------------------------------- @@ -769,12 +1045,21 @@ filter_suites(Suites) -> 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(null, _Algos) -> + true; is_acceptable_hash(Hash, Algos) -> proplists:get_bool(Hash, Algos). @@ -996,7 +1281,13 @@ next_iv(Bin, IV) -> rsa_signed_suites() -> dhe_rsa_suites() ++ rsa_suites() ++ - psk_rsa_suites() ++ srp_rsa_suites(). + psk_rsa_suites() ++ srp_rsa_suites() ++ + ecdh_rsa_suites(). + +rsa_keyed_suites() -> + dhe_rsa_suites() ++ rsa_suites() ++ + psk_rsa_suites() ++ srp_rsa_suites() ++ + ecdhe_rsa_suites(). dhe_rsa_suites() -> [?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, @@ -1028,7 +1319,25 @@ 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() ++ srp_dss_suites(). @@ -1045,24 +1354,52 @@ srp_dss_suites() -> ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA]. -filter_rsa(OtpCert, RsaCiphers) -> +ec_keyed_suites() -> + ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites() + ++ ecdh_rsa_suites(). + +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 90d3704efd..c59f5e81c8 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2012. All Rights Reserved. +%% Copyright Ericsson AB 2007-2013. 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 @@ -219,6 +219,120 @@ %% TLS_DH_anon_WITH_AES_256_CBC_SHA256 = { 0x00,0x6D }; -define(TLS_DH_anon_WITH_AES_256_CBC_SHA256, <>). +%% RFC 4492 EC TLS suites + +%% ECDH_ECDSA + +%% TLS_ECDH_ECDSA_WITH_NULL_SHA = { 0xC0, 0x01 } +-define(TLS_ECDH_ECDSA_WITH_NULL_SHA, <>). + +%% TLS_ECDH_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x02 } +-define(TLS_ECDH_ECDSA_WITH_RC4_128_SHA, <>). + +%% TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x03 } +-define(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x04 } +-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, <>). + +%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x05 } +-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, <>). + +%% ECDHE_ECDSA + +%% TLS_ECDHE_ECDSA_WITH_NULL_SHA = { 0xC0, 0x06 } +-define(TLS_ECDHE_ECDSA_WITH_NULL_SHA, <>). + +%% TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x07 } +-define(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, <>). + +%% TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x08 } +-define(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x09 } +-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, <>). + +%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0A } +-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, <>). + +%% ECDH_RSA + +%% TLS_ECDH_RSA_WITH_NULL_SHA = { 0xC0, 0x0B } +-define(TLS_ECDH_RSA_WITH_NULL_SHA, <>). + +%% TLS_ECDH_RSA_WITH_RC4_128_SHA = { 0xC0, 0x0C } +-define(TLS_ECDH_RSA_WITH_RC4_128_SHA, <>). + +%% TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x0D } +-define(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x0E } +-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, <>). + +%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0F } +-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, <>). + +%% ECDHE_RSA + +%% TLS_ECDHE_RSA_WITH_NULL_SHA = { 0xC0, 0x10 } +-define(TLS_ECDHE_RSA_WITH_NULL_SHA, <>). + +%% TLS_ECDHE_RSA_WITH_RC4_128_SHA = { 0xC0, 0x11 } +-define(TLS_ECDHE_RSA_WITH_RC4_128_SHA, <>). + +%% TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x12 } +-define(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x13 } +-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, <>). + +%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x14 } +-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, <>). + +%% ECDH_anon + +%% TLS_ECDH_anon_WITH_NULL_SHA = { 0xC0, 0x15 } +-define(TLS_ECDH_anon_WITH_NULL_SHA, <>). + +%% TLS_ECDH_anon_WITH_RC4_128_SHA = { 0xC0, 0x16 } +-define(TLS_ECDH_anon_WITH_RC4_128_SHA, <>). + +%% TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x17 } +-define(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_ECDH_anon_WITH_AES_128_CBC_SHA = { 0xC0, 0x18 } +-define(TLS_ECDH_anon_WITH_AES_128_CBC_SHA, <>). + +%% TLS_ECDH_anon_WITH_AES_256_CBC_SHA = { 0xC0, 0x19 } +-define(TLS_ECDH_anon_WITH_AES_256_CBC_SHA, <>). + + +%% RFC 5289 EC TLS suites + +%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x23}; +-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x24}; +-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, <>). + +%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x25}; +-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x26}; +-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, <>). + +%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x27}; +-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x28}; +-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, <>). + +%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x29}; +-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x2A}; +-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, <>). + %%% Kerberos Cipher Suites %% TLS_KRB5_WITH_DES_CBC_SHA = { 0x00,0x1E }; diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index fa64915fd0..aa02c47a3d 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -416,11 +416,13 @@ hello(Hello = #client_hello{client_version = ClientVersion}, ssl_options = SslOpts}) -> case ssl_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) of - {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise} -> - do_server_hello(Type, ProtocolsToAdvertise, State#state{connection_states = - ConnectionStates, - negotiated_version = Version, - session = Session}); + {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise, + EcPointFormats, EllipticCurves} -> + do_server_hello(Type, ProtocolsToAdvertise, + EcPointFormats, EllipticCurves, + State#state{connection_states = ConnectionStates, + negotiated_version = Version, + session = Session}); #alert{} = Alert -> handle_own_alert(Alert, ClientVersion, hello, State) end; @@ -533,7 +535,9 @@ 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 @@ -679,6 +683,17 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl 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 @@ -1278,6 +1293,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)) @@ -1291,6 +1307,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)). @@ -1306,9 +1324,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, + <> = erlang:iolist_to_binary(L), + R. + -spec(file_error(_,_) -> no_return()). file_error(File, Throw) -> case Throw of @@ -1357,7 +1395,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, @@ -1407,15 +1463,18 @@ verify_client_cert(#state{client_certificate_requested = true, role = client, verify_client_cert(#state{client_certificate_requested = false} = State) -> State. -do_server_hello(Type, NextProtocolsToSend, #state{negotiated_version = Version, - session = #session{session_id = SessId}, - connection_states = ConnectionStates0, - renegotiation = {Renegotiation, _}} +do_server_hello(Type, NextProtocolsToSend, + EcPointFormats, EllipticCurves, + #state{negotiated_version = Version, + session = #session{session_id = SessId}, + connection_states = ConnectionStates0, + renegotiation = {Renegotiation, _}} = State0) when is_atom(Type) -> ServerHello = ssl_handshake:server_hello(SessId, Version, - ConnectionStates0, Renegotiation, NextProtocolsToSend), + ConnectionStates0, Renegotiation, + NextProtocolsToSend, EcPointFormats, EllipticCurves), State = server_hello(ServerHello, State0#state{expecting_next_protocol_negotiation = NextProtocolsToSend =/= undefined}), @@ -1547,7 +1606,7 @@ server_hello_done(#state{transport_cb = Transport, tls_handshake_history = Handshake}. certify_server(#state{key_algorithm = Algo} = State) - when Algo == dh_anon; Algo == psk; Algo == dhe_psk; Algo == srp_anon -> + when Algo == dh_anon; Algo == ecdh_anon; Algo == psk; Algo == dhe_psk; Algo == srp_anon -> State; certify_server(#state{transport_cb = Transport, @@ -1602,6 +1661,43 @@ 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; @@ -1755,6 +1851,23 @@ key_exchange(#state{role = client, 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, @@ -1936,7 +2049,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) @@ -1969,6 +2082,15 @@ server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDh 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) -> @@ -2013,6 +2135,11 @@ 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; @@ -2938,14 +3065,21 @@ default_hashsign(_Version = {Major, Minor}, KeyExchange) (KeyExchange == rsa orelse KeyExchange == dhe_rsa orelse 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 == 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; @@ -2953,6 +3087,7 @@ default_hashsign(_Version, KeyExchange) {sha, dsa}; default_hashsign(_Version, KeyExchange) when KeyExchange == dh_anon; + KeyExchange == ecdh_anon; KeyExchange == psk; KeyExchange == dhe_psk; KeyExchange == rsa_psk; diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 83c0092de2..bddae820ef 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -31,7 +31,7 @@ -include("ssl_srp.hrl"). -include_lib("public_key/include/public_key.hrl"). --export([master_secret/4, client_hello/8, server_hello/5, hello/4, +-export([master_secret/4, client_hello/8, server_hello/7, hello/4, hello_request/0, certify/7, certificate/4, client_certificate_verify/6, certificate_verify/6, verify_signature/5, certificate_request/3, key_exchange/3, server_key_exchange_hash/2, @@ -47,6 +47,8 @@ #client_key_exchange{} | #finished{} | #certificate_verify{} | #hello_request{} | #next_protocol{}. +-define(NAMED_CURVE_TYPE, 3). + %%==================================================================== %% Internal application API %%==================================================================== @@ -67,6 +69,7 @@ client_hello(Host, Port, ConnectionStates, SecParams = Pending#connection_state.security_parameters, Ciphers = available_suites(UserSuites, Version), SRP = srp_user(SslOpts), + {EcPointFormats, EllipticCurves} = default_ecc_extensions(Version), Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert), @@ -80,6 +83,8 @@ client_hello(Host, Port, ConnectionStates, renegotiation_info(client, ConnectionStates, Renegotiation), srp = SRP, hash_signs = default_hash_signs(), + ec_point_formats = EcPointFormats, + elliptic_curves = EllipticCurves, next_protocol_negotiation = encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector, Renegotiation) }. @@ -96,11 +101,14 @@ encode_protocols_advertised_on_server(Protocols) -> %%-------------------------------------------------------------------- -spec server_hello(session_id(), tls_version(), #connection_states{}, - boolean(), [binary()] | undefined) -> #server_hello{}. + boolean(), [binary()] | undefined, + #ec_point_formats{} | undefined, + #elliptic_curves{} | undefined) -> #server_hello{}. %% %% Description: Creates a server hello message. %%-------------------------------------------------------------------- -server_hello(SessionId, Version, ConnectionStates, Renegotiation, ProtocolsAdvertisedOnServer) -> +server_hello(SessionId, Version, ConnectionStates, Renegotiation, + ProtocolsAdvertisedOnServer, EcPointFormats, EllipticCurves) -> Pending = ssl_record:pending_connection_state(ConnectionStates, read), SecParams = Pending#connection_state.security_parameters, #server_hello{server_version = Version, @@ -111,6 +119,8 @@ server_hello(SessionId, Version, ConnectionStates, Renegotiation, ProtocolsAdver session_id = SessionId, renegotiation_info = renegotiation_info(server, ConnectionStates, Renegotiation), + ec_point_formats = EcPointFormats, + elliptic_curves = EllipticCurves, next_protocol_negotiation = encode_protocols_advertised_on_server(ProtocolsAdvertisedOnServer) }. @@ -166,7 +176,9 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version, hello(#client_hello{client_version = ClientVersion, random = Random, cipher_suites = CipherSuites, renegotiation_info = Info, - srp = SRP} = Hello, + srp = SRP, + ec_point_formats = EcPointFormats0, + elliptic_curves = EllipticCurves0} = Hello, #ssl_options{versions = Versions, secure_renegotiate = SecureRenegotation} = SslOpts, {Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) -> @@ -174,6 +186,8 @@ hello(#client_hello{client_version = ClientVersion, random = Random, Version = select_version(ClientVersion, Versions), case ssl_record:is_acceptable_version(Version, Versions) of true -> + %% TODO: need to take supported Curves into Account when selecting the CipherSuite.... + %% if whe have an ECDSA cert with an unsupported curve, we need to drop ECDSA ciphers {Type, #session{cipher_suite = CipherSuite, compression_method = Compression} = Session1} = select_session(Hello, Port, Session0, Version, @@ -198,7 +212,11 @@ hello(#client_hello{client_version = ClientVersion, random = Random, #alert{} = Alert -> Alert; ProtocolsToAdvertise -> - {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise} + {EcPointFormats1, EllipticCurves1} = + handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0), + + {Version, {Type, Session}, ConnectionStates, + ProtocolsToAdvertise, EcPointFormats1, EllipticCurves1} end; #alert{} = Alert -> Alert @@ -350,9 +368,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{}. @@ -378,6 +397,8 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) -> {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()}, @@ -397,6 +418,13 @@ key_exchange(client, _Version, {dh, <>}) -> 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{ @@ -434,6 +462,13 @@ key_exchange(server, Version, {dh, {<>, _}, 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}, @@ -833,6 +868,36 @@ select_next_protocol(Protocols, NextProtocolSelector) -> Protocol end. +default_ecc_extensions(Version) -> + case proplists:get_bool(ec, crypto:algorithms()) of + true -> + EcPointFormats = #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]}, + EllipticCurves = #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)}, + {EcPointFormats, EllipticCurves}; + _ -> + {undefined, undefined} + end. + +handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0) -> + case proplists:get_bool(ec, crypto:algorithms()) of + true -> + EcPointFormats1 = handle_ecc_point_fmt_extension(EcPointFormats0), + EllipticCurves1 = handle_ecc_curves_extension(Version, EllipticCurves0), + {EcPointFormats1, EllipticCurves1}; + _ -> + {undefined, undefined} + end. + +handle_ecc_point_fmt_extension(undefined) -> + undefined; +handle_ecc_point_fmt_extension(_) -> + #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]}. + +handle_ecc_curves_extension(Version, undefined) -> + undefined; +handle_ecc_curves_extension(Version, _) -> + #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)}. + handle_srp_info(undefined, Session) -> Session; handle_srp_info(#srp{username = Username}, Session) -> @@ -1022,6 +1087,8 @@ dec_hs(_Version, ?CLIENT_HELLO, <>) -> #certificate{asn1_certificates = certs_to_list(ASN1Certs)}; @@ -1111,6 +1183,11 @@ dec_client_key(<<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) -> dec_client_key(<>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) -> #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(<>, + ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) -> + #client_ec_diffie_hellman_public{dh_public = DH_Y}; dec_client_key(<>, ?KEY_EXCHANGE_PSK, _) -> #client_psk_identity{identity = Id}; @@ -1161,6 +1238,19 @@ dec_server_key(<> = 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(<> = KeyStruct, KeyExchange, Version) when KeyExchange == ?KEY_EXCHANGE_PSK; KeyExchange == ?KEY_EXCHANGE_RSA_PSK -> @@ -1237,6 +1327,22 @@ dec_hello_extensions(<>, Acc) -> + EllipticCurveListLen = Len - 2, + <> = ExtData, + EllipticCurves = [ssl_tls1:ec_curve_id2nid(X) || <> <= EllipticCurveList], + dec_hello_extensions(Rest, [{elliptic_curves, + #elliptic_curves{elliptic_curve_list = EllipticCurves}} | Acc]); + +dec_hello_extensions(<>, Acc) -> + ECPointFormatListLen = Len - 1, + <> = 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. @@ -1287,13 +1393,17 @@ enc_hs(#client_hello{client_version = {Major, Minor}, renegotiation_info = RenegotiationInfo, srp = SRP, hash_signs = HashSigns, + ec_point_formats = EcPointFormats, + 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, SRP, NextProtocolNegotiation), + Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation) + ++ hello_extensions(EcPointFormats) + ++ hello_extensions(EllipticCurves), Extensions1 = if Major == 3, Minor >=3 -> Extensions0 ++ hello_extensions(HashSigns); true -> Extensions0 @@ -1311,9 +1421,13 @@ enc_hs(#server_hello{server_version = {Major, Minor}, cipher_suite = Cipher_suite, compression_method = Comp_method, renegotiation_info = RenegotiationInfo, + ec_point_formats = EcPointFormats, + elliptic_curves = EllipticCurves, next_protocol_negotiation = NextProtocolNegotiation}, _Version) -> SID_length = byte_size(Session_ID), - Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation), + Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation) + ++ hello_extensions(EcPointFormats) + ++ hello_extensions(EllipticCurves), ExtensionsBin = enc_hello_extensions(Extensions), {?SERVER_HELLO, < enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) -> Len = byte_size(DHPublic), <>; +enc_cke(#client_ec_diffie_hellman_public{dh_public = DHPublic}, _) -> + Len = byte_size(DHPublic), + <>; enc_cke(#client_psk_identity{identity = undefined}, _) -> Id = <<"psk_identity">>, Len = byte_size(Id), @@ -1398,6 +1515,11 @@ enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) -> GLen = byte_size(G), YLen = byte_size(Y), <>; +enc_server_key(#server_ecdh_params{curve = ECCurve, public = ECPubKey}) -> + %%TODO: support arbitrary keys + KLen = size(ECPubKey), + <>; enc_server_key(#server_psk_params{hint = PskIdentityHint}) -> Len = byte_size(PskIdentityHint), <>; @@ -1435,13 +1557,19 @@ 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). + 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) -> @@ -1473,12 +1601,22 @@ enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest InfoLen = byte_size(Info), Len = InfoLen +1, enc_hello_extensions(Rest, <>); - +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, <>); +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, <>); enc_hello_extensions([#srp{username = UserName} | Rest], Acc) -> SRPLen = byte_size(UserName), Len = SRPLen + 2, enc_hello_extensions(Rest, <>); - 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 >>, @@ -1513,9 +1651,15 @@ from_2bytes(<>, Acc) -> certificate_types({KeyExchange, _, _, _}) when KeyExchange == rsa; KeyExchange == dhe_dss; - KeyExchange == dhe_rsa -> + KeyExchange == dhe_rsa; + KeyExchange == ecdhe_rsa -> <>; +certificate_types({KeyExchange, _, _, _}) + when KeyExchange == dh_ecdsa; + KeyExchange == dhe_ecdsa -> + <>; + certificate_types(_) -> <>. @@ -1555,7 +1699,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); @@ -1588,6 +1734,10 @@ 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) -> @@ -1612,15 +1762,19 @@ 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_ECDSA(MD), ?TLSEXT_SIGALG_RSA(MD)). default_hash_signs() -> + HashSigns = [?TLSEXT_SIGALG(sha512), + ?TLSEXT_SIGALG(sha384), + ?TLSEXT_SIGALG(sha256), + ?TLSEXT_SIGALG(sha224), + ?TLSEXT_SIGALG(sha), + ?TLSEXT_SIGALG_DSA(sha), + ?TLSEXT_SIGALG_RSA(md5)], + HasECC = proplists:get_bool(ec, crypto:algorithms()), #hash_sign_algos{hash_sign_algos = - [?TLSEXT_SIGALG(sha512), - ?TLSEXT_SIGALG(sha384), - ?TLSEXT_SIGALG(sha256), - ?TLSEXT_SIGALG(sha224), - ?TLSEXT_SIGALG(sha), - ?TLSEXT_SIGALG_DSA(sha), - ?TLSEXT_SIGALG_RSA(md5)]}. + lists:filter(fun({_, ecdsa}) -> HasECC; + (_) -> true end, HashSigns)}. diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index 1fbb88f5f6..df21468862 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2012. All Rights Reserved. +%% Copyright Ericsson AB 2007-2013. 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 @@ -102,6 +102,8 @@ renegotiation_info, srp, % srp username to send hash_signs, % supported combinations of hashes/signature algos + ec_point_formats, % supported ec point formats + elliptic_curves, % supported elliptic curver next_protocol_negotiation = undefined % [binary()] }). @@ -113,6 +115,8 @@ compression_method, % compression_method renegotiation_info, hash_signs, % supported combinations of hashes/signature algos + ec_point_formats, % supported ec point formats + elliptic_curves, % supported elliptic curver next_protocol_negotiation = undefined % [binary()] }). @@ -130,6 +134,7 @@ -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). @@ -146,6 +151,11 @@ dh_y %% opaque DH_Ys<1..2^16-1> }). +-record(server_ecdh_params, { + curve, + public %% opaque encoded ECpoint + }). + -record(server_psk_params, { hint }). @@ -195,6 +205,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>; @@ -231,6 +244,10 @@ dh_public }). +-record(client_ec_diffie_hellman_public, { + dh_public + }). + -record(client_psk_identity, { identity }). @@ -304,6 +321,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_tls1.erl b/lib/ssl/src/ssl_tls1.erl index 41dc1bf0dc..39931ff29f 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2012. All Rights Reserved. +%% Copyright Ericsson AB 2007-2013. 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 @@ -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/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl index 72768bcb55..d818993fe6 100644 --- a/lib/ssl/test/ssl_npn_hello_SUITE.erl +++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl @@ -80,12 +80,14 @@ encode_and_decode_npn_server_hello_test(_Config) -> %%-------------------------------------------------------------------- create_server_hello_with_no_advertised_protocols_test(_Config) -> - Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false, undefined), + Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false, + undefined, undefined, undefined), undefined = Hello#server_hello.next_protocol_negotiation. %%-------------------------------------------------------------------- create_server_hello_with_advertised_protocols_test(_Config) -> Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), - false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]), + false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>], + undefined, undefined), #next_protocol_negotiation{extension_data = <<6, "spdy/1", 8, "http/1.0", 8, "http/1.1">>} = Hello#server_hello.next_protocol_negotiation. %%-------------------------------------------------------------------- -- cgit v1.2.3 From 3aba3fb6ddca49f37c592c86f838423e0698c6f6 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Tue, 19 Feb 2013 18:10:10 +0100 Subject: SSL: add Elliptic Curve ciphers unit tests --- lib/ssl/test/erl_make_certs.erl | 67 ++++++++++++++++++++--- lib/ssl/test/ssl_basic_SUITE.erl | 75 ++++++++++++++++++++++++-- lib/ssl/test/ssl_test_lib.erl | 112 +++++++++++++++++++++++++++++++++------ 3 files changed, 229 insertions(+), 25 deletions(-) diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl index 71aa985c4f..f37928be85 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) @@ -90,6 +90,16 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) -> Key = gen_dsa2(LSize, 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() @@ -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(<>). + +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 10bbd4d88b..aa87224305 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}]. @@ -163,6 +165,12 @@ cipher_tests() -> 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, @@ -191,7 +199,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"} @@ -1656,6 +1666,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) -> @@ -3149,12 +3201,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} = @@ -3189,7 +3250,13 @@ run_suites(Ciphers, Version, Config, Type) -> ?config(server_srp_anon, Config)}; srp_dsa -> {?config(client_srp_dsa, Config), - ?config(server_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 50afad95a5..fc1817ec49 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -404,6 +404,49 @@ make_dsa_cert(Config) -> {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, @@ -667,10 +710,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()). @@ -690,17 +737,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), @@ -713,13 +775,39 @@ 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() -> 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}], + {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() -> @@ -840,15 +928,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. -- cgit v1.2.3 From 2976421b28202961b470c9450c5b98429a8a19f1 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 21 Mar 2013 11:32:45 +0100 Subject: ssl: Skip ECC cipher tests on versions of openssl pre 0.9.9 EEC is not fully supported before 0.9.9. Also skip tests on opensslversions with known bugs in ECC support --- lib/ssl/test/ssl_basic_SUITE.erl | 2 +- lib/ssl/test/ssl_test_lib.erl | 23 +++++++++++++++++++++-- lib/ssl/test/ssl_to_openssl_SUITE.erl | 2 +- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index aa87224305..2e820299c5 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -1549,7 +1549,7 @@ ciphers_rsa_signed_certs(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), - Ciphers = ssl_test_lib:rsa_suites(), + Ciphers = ssl_test_lib:rsa_suites(erlang), ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]), run_suites(Ciphers, Version, Config, rsa). %%------------------------------------------------------------------- diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index fc1817ec49..1dfaf099f1 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -709,12 +709,13 @@ send_selected_port(Pid, 0, Socket) -> send_selected_port(_,_,_) -> ok. -rsa_suites() -> +rsa_suites(CounterPart) -> + ECC = is_sane_ecc(CounterPart), lists:filter(fun({rsa, _, _}) -> true; ({dhe_rsa, _, _}) -> true; - ({ecdhe_rsa, _, _}) -> + ({ecdhe_rsa, _, _}) when ECC == true -> true; (_) -> false @@ -963,3 +964,21 @@ send_recv_result_active_once(Socket) -> {ssl, Socket, "Hello world"} -> ok end. + +is_sane_ecc(openssl) -> + case os:cmd("openssl version") of + "OpenSSL 1.0.0a" ++ _ -> % Known bug in openssl + %% manifests as SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list + false; + "OpenSSL 1.0.0" ++ _ -> % Known bug in openssl + %% manifests as SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list + false; + "OpenSSL 0.9.8" ++ _ -> % Does not support ECC + false; + "OpenSSL 0.9.7" ++ _ -> % Does not support ECC + false; + _ -> + true + end; +is_sane_ecc(_) -> + true. diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index a3d382f837..1324ffdf9c 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -749,7 +749,7 @@ ciphers_rsa_signed_certs(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), - Ciphers = ssl_test_lib:rsa_suites(), + Ciphers = ssl_test_lib:rsa_suites(openssl), run_suites(Ciphers, Version, Config, rsa). %%-------------------------------------------------------------------- -- cgit v1.2.3 From 8623dd8c37801ef65b1d1db5279cb5808b102cfa Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 20 Mar 2013 15:53:26 +0100 Subject: ssl: ct:print -> ct:log and assert port_command --- lib/ssl/test/ssl_basic_SUITE.erl | 102 ++++++++++----------- lib/ssl/test/ssl_certificate_verify_SUITE.erl | 18 ++-- lib/ssl/test/ssl_npn_handshake_SUITE.erl | 12 +-- lib/ssl/test/ssl_npn_hello_SUITE.erl | 2 +- lib/ssl/test/ssl_packet_SUITE.erl | 4 +- lib/ssl/test/ssl_payload_SUITE.erl | 12 +-- lib/ssl/test/ssl_session_cache_SUITE.erl | 2 +- lib/ssl/test/ssl_test_lib.erl | 74 +++++++-------- lib/ssl/test/ssl_to_openssl_SUITE.erl | 124 +++++++++++++------------- 9 files changed, 175 insertions(+), 175 deletions(-) diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 2e820299c5..165a8a5fcc 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -196,7 +196,7 @@ init_per_suite(Config0) -> Result = (catch make_certs:all(?config(data_dir, Config0), ?config(priv_dir, Config0))), - ct:print("Make certs ~p~n", [Result]), + ct:log("Make certs ~p~n", [Result]), Config1 = ssl_test_lib:make_dsa_cert(Config0), Config2 = ssl_test_lib:make_ecdsa_cert(Config1), @@ -266,7 +266,7 @@ init_per_testcase(empty_protocol_versions, Config) -> %% ssl_test_lib:make_mix_cert(Config0); init_per_testcase(_TestCase, Config0) -> - ct:print("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]), + ct:log("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]), Config = lists:keydelete(watchdog, 1, Config0), Dog = ct:timetrap(?TIMEOUT), [{watchdog, Dog} | Config]. @@ -329,7 +329,7 @@ connection_info(Config) when is_list(Config) -> [{ciphers,[{rsa,rc4_128,sha,no_export}]} | ClientOpts]}]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), Version = @@ -382,7 +382,7 @@ controlling_process(Config) when is_list(Config) -> ClientMsg]}}, {options, ClientOpts}]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), receive @@ -432,7 +432,7 @@ controller_dies(Config) when is_list(Config) -> ClientMsg]}}, {options, ClientOpts}]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ct:sleep(?SLEEP), %% so that they are connected process_flag(trap_exit, true), @@ -470,12 +470,12 @@ controller_dies(Config) when is_list(Config) -> Client3 ! die_nice end, - ct:print("Wating on exit ~p~n",[Client3]), + ct:log("Wating on exit ~p~n",[Client3]), receive {'EXIT', Client3, normal} -> ok end, receive %% Client3 is dead but that doesn't matter, socket should not be closed. Unexpected -> - ct:print("Unexpected ~p~n",[Unexpected]), + ct:log("Unexpected ~p~n",[Unexpected]), ct:fail({line, ?LINE-1}) after 1000 -> ok @@ -606,7 +606,7 @@ peername(Config) when is_list(Config) -> ServerMsg = {ok, {ClientIp, ClientPort}}, ClientMsg = {ok, {ServerIp, Port}}, - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), @@ -639,7 +639,7 @@ peercert(Config) when is_list(Config) -> ServerMsg = {error, no_peercert}, ClientMsg = {ok, BinCert}, - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), @@ -677,7 +677,7 @@ peercert_with_client_cert(Config) when is_list(Config) -> ServerMsg = {ok, ClientBinCert}, ClientMsg = {ok, ServerBinCert}, - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), @@ -709,7 +709,7 @@ sockname(Config) when is_list(Config) -> ServerMsg = {ok, {ServerIp, Port}}, ClientMsg = {ok, {ClientIp, ClientPort}}, - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), @@ -782,7 +782,7 @@ socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) -> ssl:setopts(Socket, [{nodelay, true}]), {ok,[{nodelay, true}]} = ssl:getopts(Socket, [nodelay]), {ok, All} = ssl:getopts(Socket, []), - ct:print("All opts ~p~n", [All]), + ct:log("All opts ~p~n", [All]), ok. @@ -805,7 +805,7 @@ invalid_inet_get_option(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), @@ -831,7 +831,7 @@ invalid_inet_get_option_not_list(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), @@ -863,7 +863,7 @@ invalid_inet_get_option_improper_list(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), @@ -894,7 +894,7 @@ invalid_inet_set_option(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), @@ -926,7 +926,7 @@ invalid_inet_set_option_not_list(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), @@ -958,7 +958,7 @@ invalid_inet_set_option_improper_list(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok), @@ -999,7 +999,7 @@ misc_ssl_options(Config) when is_list(Config) -> {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, TestOpts ++ ClientOpts}]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -1012,7 +1012,7 @@ versions() -> versions(Config) when is_list(Config) -> [_|_] = Versions = ssl:versions(), - ct:print("~p~n", [Versions]). + ct:log("~p~n", [Versions]). %%-------------------------------------------------------------------- send_recv() -> @@ -1034,7 +1034,7 @@ send_recv(Config) when is_list(Config) -> {mfa, {ssl_test_lib, send_recv_result, []}}, {options, [{active, false} | ClientOpts]}]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -1060,7 +1060,7 @@ send_close(Config) when is_list(Config) -> {ok, SslS} = rpc:call(ClientNode, ssl, connect, [TcpS,[{active, false}|ClientOpts]]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), self(), Server]), ok = ssl:send(SslS, "Hello world"), {ok,<<"Hello world">>} = ssl:recv(SslS, 11), @@ -1145,7 +1145,7 @@ upgrade(Config) when is_list(Config) -> {tcp_options, TcpOpts}, {ssl_options, ClientOpts}]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -1195,7 +1195,7 @@ upgrade_with_timeout(Config) when is_list(Config) -> {tcp_options, TcpOpts}, {ssl_options, ClientOpts}]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -1221,14 +1221,14 @@ tcp_connect(Config) when is_list(Config) -> Port = ssl_test_lib:inet_port(Server), {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]), - ct:print("Testcase ~p connected to Server ~p ~n", [self(), Server]), + ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]), gen_tcp:send(Socket, ""), receive {tcp_closed, Socket} -> receive {Server, {error, Error}} -> - ct:print("Error ~p", [Error]) + ct:log("Error ~p", [Error]) end end. %%-------------------------------------------------------------------- @@ -1249,7 +1249,7 @@ tcp_connect_big(Config) when is_list(Config) -> Port = ssl_test_lib:inet_port(Server), {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]), - ct:print("Testcase ~p connected to Server ~p ~n", [self(), Server]), + ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]), Rand = crypto:rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1), gen_tcp:send(Socket, < {Server, {error, timeout}} -> ct:fail("hangs"); {Server, {error, Error}} -> - ct:print("Error ~p", [Error]) + ct:log("Error ~p", [Error]) end end. @@ -1291,7 +1291,7 @@ ipv6(Config) when is_list(Config) -> {options, [inet6, {active, false} | ClientOpts]}]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -1550,7 +1550,7 @@ ciphers_rsa_signed_certs(Config) when is_list(Config) -> ssl_record:protocol_version(ssl_record:highest_protocol_version([])), Ciphers = ssl_test_lib:rsa_suites(erlang), - ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]), + ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]), run_suites(Ciphers, Version, Config, rsa). %%------------------------------------------------------------------- ciphers_rsa_signed_certs_openssl_names() -> @@ -1560,7 +1560,7 @@ ciphers_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_rsa_suites(), - ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]), + ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]), run_suites(Ciphers, Version, Config, rsa). %%------------------------------------------------------------------- @@ -1572,7 +1572,7 @@ ciphers_dsa_signed_certs(Config) when is_list(Config) -> ssl_record:protocol_version(ssl_record:highest_protocol_version([])), Ciphers = ssl_test_lib:dsa_suites(), - ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]), + ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]), run_suites(Ciphers, Version, Config, dsa). %%------------------------------------------------------------------- ciphers_dsa_signed_certs_openssl_names() -> @@ -1583,7 +1583,7 @@ ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) -> ssl_record:protocol_version(ssl_record:highest_protocol_version([])), Ciphers = ssl_test_lib:openssl_dsa_suites(), - ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]), + ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]), run_suites(Ciphers, Version, Config, dsa). %%------------------------------------------------------------------- anonymous_cipher_suites()-> @@ -1674,7 +1674,7 @@ ciphers_ecdsa_signed_certs(Config) when is_list(Config) -> 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]), + ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]), run_suites(Ciphers, Version, Config, ecdsa). %%-------------------------------------------------------------------- ciphers_ecdsa_signed_certs_openssl_names() -> @@ -1684,7 +1684,7 @@ 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]), + ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]), run_suites(Ciphers, Version, Config, ecdsa). %%-------------------------------------------------------------------- ciphers_ecdh_rsa_signed_certs() -> @@ -1695,7 +1695,7 @@ ciphers_ecdh_rsa_signed_certs(Config) when is_list(Config) -> 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]), + ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]), run_suites(Ciphers, Version, Config, ecdh_rsa). %%-------------------------------------------------------------------- ciphers_ecdh_rsa_signed_certs_openssl_names() -> @@ -1705,7 +1705,7 @@ 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]), + ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]), run_suites(Ciphers, Version, Config, ecdh_rsa). %%-------------------------------------------------------------------- reuse_session() -> @@ -1746,7 +1746,7 @@ reuse_session(Config) when is_list(Config) -> {Client1, SessionInfo} -> ok; {Client1, Other} -> - ct:print("Expected: ~p, Unexpected: ~p~n", + ct:log("Expected: ~p, Unexpected: ~p~n", [SessionInfo, Other]), ct:fail(session_not_reused) end, @@ -1804,7 +1804,7 @@ reuse_session(Config) when is_list(Config) -> ct:fail( session_reused_when_session_reuse_disabled_by_server); {Client4, _Other} -> - ct:print("OTHER: ~p ~n", [_Other]), + ct:log("OTHER: ~p ~n", [_Other]), ok end, @@ -1854,7 +1854,7 @@ reuse_session_expired(Config) when is_list(Config) -> {Client1, SessionInfo} -> ok; {Client1, Other} -> - ct:print("Expected: ~p, Unexpected: ~p~n", + ct:log("Expected: ~p, Unexpected: ~p~n", [SessionInfo, Other]), ct:fail(session_not_reused) end, @@ -2557,7 +2557,7 @@ connect_twice(Config) when is_list(Config) -> {options, [{keepalive, true},{active, false} | ClientOpts]}]), - ct:print("Testcase ~p, Client ~p Server ~p ~n", + ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -2903,9 +2903,9 @@ result_ok(_Socket) -> ok. renegotiate(Socket, Data) -> - ct:print("Renegotiating ~n", []), + ct:log("Renegotiating ~n", []), Result = ssl:renegotiate(Socket), - ct:print("Result ~p~n", [Result]), + ct:log("Result ~p~n", [Result]), ssl:send(Socket, Data), case Result of ok -> @@ -2934,7 +2934,7 @@ renegotiate_immediately(Socket) -> {error, renegotiation_rejected} = ssl:renegotiate(Socket), ct:sleep(?RENEGOTIATION_DISABLE_TIME +1), ok = ssl:renegotiate(Socket), - ct:print("Renegotiated again"), + ct:log("Renegotiated again"), ssl:send(Socket, "Hello world"), ok. @@ -2953,7 +2953,7 @@ new_config(PrivDir, ServerOpts0) -> ServerOpts = proplists:delete(keyfile, ServerOpts2), {ok, PEM} = file:read_file(NewCaCertFile), - ct:print("CA file content: ~p~n", [public_key:pem_decode(PEM)]), + ct:log("CA file content: ~p~n", [public_key:pem_decode(PEM)]), [{cacertfile, NewCaCertFile}, {certfile, NewCertFile}, {keyfile, NewKeyFile} | ServerOpts]. @@ -3149,15 +3149,15 @@ get_close(Pid, Where) -> {'EXIT', Pid, _Reason} -> receive {_, {ssl_closed, Socket}} -> - ct:print("Socket closed ~p~n",[Socket]); + ct:log("Socket closed ~p~n",[Socket]); Unexpected -> - ct:print("Unexpected ~p~n",[Unexpected]), + ct:log("Unexpected ~p~n",[Unexpected]), ct:fail({line, ?LINE-1}) after 5000 -> ct:fail({timeout, {line, ?LINE, Where}}) end; Unexpected -> - ct:print("Unexpected ~p~n",[Unexpected]), + ct:log("Unexpected ~p~n",[Unexpected]), ct:fail({line, ?LINE-1}) after 5000 -> ct:fail({timeout, {line, ?LINE, Where}}) @@ -3171,7 +3171,7 @@ run_send_recv_rizzo(Ciphers, Config, Version, Mfa) -> [] -> ok; Error -> - ct:print("Cipher suite errors: ~p~n", [Error]), + ct:log("Cipher suite errors: ~p~n", [Error]), ct:fail(cipher_suite_failed_see_test_case_log) end. @@ -3266,7 +3266,7 @@ run_suites(Ciphers, Version, Config, Type) -> [] -> ok; Error -> - ct:print("Cipher suite errors: ~p~n", [Error]), + ct:log("Cipher suite errors: ~p~n", [Error]), ct:fail(cipher_suite_failed_see_test_case_log) end. @@ -3277,7 +3277,7 @@ erlang_cipher_suite(Suite) -> cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> %% process_flag(trap_exit, true), - ct:print("Testing CipherSuite ~p~n", [CipherSuite]), + ct:log("Testing CipherSuite ~p~n", [CipherSuite]), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), ErlangCipherSuite = erlang_cipher_suite(CipherSuite), diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl index 26938bda50..2703d2d79c 100644 --- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl +++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl @@ -86,7 +86,7 @@ init_per_suite(Config0) -> Result = (catch make_certs:all(?config(data_dir, Config0), ?config(priv_dir, Config0))), - ct:print("Make certs ~p~n", [Result]), + ct:log("Make certs ~p~n", [Result]), Config1 = ssl_test_lib:make_dsa_cert(Config0), Config = ssl_test_lib:cert_options(Config1), @@ -297,7 +297,7 @@ verify_fun_always_run_client(Config) when is_list(Config) -> %% this is not a bug it is a circumstance of how tcp works! receive {Server, ServerError} -> - ct:print("Server Error ~p~n", [ServerError]) + ct:log("Server Error ~p~n", [ServerError]) end, ssl_test_lib:check_result(Client, {error, {tls_alert, "handshake failure"}}). @@ -346,7 +346,7 @@ verify_fun_always_run_server(Config) when is_list(Config) -> %% this is not a bug it is a circumstance of how tcp works! receive {Client, ClientError} -> - ct:print("Client Error ~p~n", [ClientError]) + ct:log("Client Error ~p~n", [ClientError]) end, ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}}). @@ -413,7 +413,7 @@ cert_expired(Config) when is_list(Config) -> two_digits_str(Sec)])), NewValidity = {'Validity', {generalTime, NotBeforeStr}, {generalTime, NotAfterStr}}, - ct:print("Validity: ~p ~n NewValidity: ~p ~n", + ct:log("Validity: ~p ~n NewValidity: ~p ~n", [OTPTbsCert#'OTPTBSCertificate'.validity, NewValidity]), NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{validity = NewValidity}, @@ -644,7 +644,7 @@ no_authority_key_identifier(Config) when is_list(Config) -> NewExtensions = delete_authority_key_extension(Extensions, []), NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{extensions = NewExtensions}, - ct:print("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]), + ct:log("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]), NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key), ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]), @@ -955,10 +955,10 @@ client_msg(Client, ClientMsg) -> {Client, ClientMsg} -> ok; {Client, {error,closed}} -> - ct:print("client got close"), + ct:log("client got close"), ok; {Client, {error, Reason}} -> - ct:print("client got econnaborted: ~p", [Reason]), + ct:log("client got econnaborted: ~p", [Reason]), ok; Unexpected -> ct:fail(Unexpected) @@ -968,10 +968,10 @@ server_msg(Server, ServerMsg) -> {Server, ServerMsg} -> ok; {Server, {error,closed}} -> - ct:print("server got close"), + ct:log("server got close"), ok; {Server, {error, Reason}} -> - ct:print("server got econnaborted: ~p", [Reason]), + ct:log("server got econnaborted: ~p", [Reason]), ok; Unexpected -> ct:fail(Unexpected) diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl index 8c1b22cf5e..7b271c4d5d 100644 --- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl +++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl @@ -74,7 +74,7 @@ init_per_suite(Config) -> Result = (catch make_certs:all(?config(data_dir, Config), ?config(priv_dir, Config))), - ct:print("Make certs ~p~n", [Result]), + ct:log("Make certs ~p~n", [Result]), ssl_test_lib:cert_options(Config) catch _:_ -> {skip, "Crypto did not start"} @@ -311,13 +311,13 @@ run_npn_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) -> assert_npn(Socket, Protocol) -> - ct:print("Negotiated Protocol ~p, Expecting: ~p ~n", + ct:log("Negotiated Protocol ~p, Expecting: ~p ~n", [ssl:negotiated_next_protocol(Socket), Protocol]), Protocol = ssl:negotiated_next_protocol(Socket). assert_npn_and_renegotiate_and_send_data(Socket, Protocol, Data) -> assert_npn(Socket, Protocol), - ct:print("Renegotiating ~n", []), + ct:log("Renegotiating ~n", []), ok = ssl:renegotiate(Socket), ssl:send(Socket, Data), assert_npn(Socket, Protocol), @@ -332,7 +332,7 @@ ssl_receive_and_assert_npn(Socket, Protocol, Data) -> ssl_receive(Socket, Data). ssl_send(Socket, Data) -> - ct:print("Connection info: ~p~n", + ct:log("Connection info: ~p~n", [ssl:connection_info(Socket)]), ssl:send(Socket, Data). @@ -340,11 +340,11 @@ ssl_receive(Socket, Data) -> ssl_receive(Socket, Data, []). ssl_receive(Socket, Data, Buffer) -> - ct:print("Connection info: ~p~n", + ct:log("Connection info: ~p~n", [ssl:connection_info(Socket)]), receive {ssl, Socket, MoreData} -> - ct:print("Received ~p~n",[MoreData]), + ct:log("Received ~p~n",[MoreData]), NewBuffer = Buffer ++ MoreData, case NewBuffer of Data -> diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl index d818993fe6..0bcc0b1fc2 100644 --- a/lib/ssl/test/ssl_npn_hello_SUITE.erl +++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl @@ -75,7 +75,7 @@ encode_and_decode_npn_server_hello_test(_Config) -> {[{DecodedHandshakeMessage, _Raw}], _} = ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>), NextProtocolNegotiation = DecodedHandshakeMessage#server_hello.next_protocol_negotiation, - ct:print("~p ~n", [NextProtocolNegotiation]), + ct:log("~p ~n", [NextProtocolNegotiation]), NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<6, "spdy/2">>}. %%-------------------------------------------------------------------- diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl index 4116bb39d1..5a374e234d 100644 --- a/lib/ssl/test/ssl_packet_SUITE.erl +++ b/lib/ssl/test/ssl_packet_SUITE.erl @@ -143,7 +143,7 @@ init_per_suite(Config) -> Result = (catch make_certs:all(?config(data_dir, Config), ?config(priv_dir, Config))), - ct:print("Make certs ~p~n", [Result]), + ct:log("Make certs ~p~n", [Result]), ssl_test_lib:cert_options(Config) catch _:_ -> {skip, "Crypto did not start"} @@ -2069,7 +2069,7 @@ client_packet_decode(Socket, [Head | Tail] = Packet) -> client_packet_decode(Socket, [Head], Tail, Packet). client_packet_decode(Socket, P1, P2, Packet) -> - ct:print("Packet: ~p ~n", [Packet]), + ct:log("Packet: ~p ~n", [Packet]), ok = ssl:send(Socket, P1), ok = ssl:send(Socket, P2), receive diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl index 77ad546420..5f5166391f 100644 --- a/lib/ssl/test/ssl_payload_SUITE.erl +++ b/lib/ssl/test/ssl_payload_SUITE.erl @@ -556,33 +556,33 @@ send(Socket, Data, Size, Repeate,F) -> sender(Socket, Data, Size) -> ok = send(Socket, Data, Size, 100, fun() -> do_recv(Socket, Data, Size, <<>>, false) end), - ct:print("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]), + ct:log("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]), ok. sender_once(Socket, Data, Size) -> send(Socket, Data, Size, 100, fun() -> do_active_once(Socket, Data, Size, <<>>, false) end), - ct:print("Sender active once: ~p~n", + ct:log("Sender active once: ~p~n", [ssl:getopts(Socket, [active])]), ok. sender_active(Socket, Data, Size) -> F = fun() -> do_active(Socket, Data, Size, <<>>, false) end, send(Socket, Data, Size, 100, F), - ct:print("Sender active: ~p~n", [ssl:getopts(Socket, [active])]), + ct:log("Sender active: ~p~n", [ssl:getopts(Socket, [active])]), ok. echoer(Socket, Data, Size) -> - ct:print("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]), + ct:log("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]), echo(fun() -> do_recv(Socket, Data, Size, <<>>, true) end, 100). echoer_once(Socket, Data, Size) -> - ct:print("Echoer active once: ~p ~n", + ct:log("Echoer active once: ~p ~n", [ssl:getopts(Socket, [active])]), echo(fun() -> do_active_once(Socket, Data, Size, <<>>, true) end, 100). echoer_active(Socket, Data, Size) -> - ct:print("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]), + ct:log("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]), echo(fun() -> do_active(Socket, Data, Size, <<>>, true) end, 100). echo(_Fun, 0) -> ok; diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl index fd9a0a594c..6cc6c4bdb2 100644 --- a/lib/ssl/test/ssl_session_cache_SUITE.erl +++ b/lib/ssl/test/ssl_session_cache_SUITE.erl @@ -63,7 +63,7 @@ init_per_suite(Config0) -> Result = (catch make_certs:all(?config(data_dir, Config0), ?config(priv_dir, Config0))), - ct:print("Make certs ~p~n", [Result]), + ct:log("Make certs ~p~n", [Result]), Config1 = ssl_test_lib:make_dsa_cert(Config0), Config = ssl_test_lib:cert_options(Config1), diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 1dfaf099f1..3b63886a07 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -59,7 +59,7 @@ run_server(Opts) -> Options = proplists:get_value(options, Opts), Pid = proplists:get_value(from, Opts), Transport = proplists:get_value(transport, Opts, ssl), - ct:print("ssl:listen(~p, ~p)~n", [Port, Options]), + ct:log("ssl:listen(~p, ~p)~n", [Port, Options]), {ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]), Pid ! {listen, up}, send_selected_port(Pid, Port, ListenSocket), @@ -77,13 +77,13 @@ do_run_server(ListenSocket, AcceptSocket, Opts) -> Pid = proplists:get_value(from, Opts), Transport = proplists:get_value(transport, Opts, ssl), {Module, Function, Args} = proplists:get_value(mfa, Opts), - ct:print("Server: apply(~p,~p,~p)~n", + ct:log("Server: apply(~p,~p,~p)~n", [Module, Function, [AcceptSocket | Args]]), case rpc:call(Node, Module, Function, [AcceptSocket | Args]) of no_result_msg -> ok; Msg -> - ct:print("Server Msg: ~p ~n", [Msg]), + ct:log("Server Msg: ~p ~n", [Msg]), Pid ! {self(), Msg} end, receive @@ -92,10 +92,10 @@ do_run_server(ListenSocket, AcceptSocket, Opts) -> {listen, MFA} -> run_server(ListenSocket, [MFA | proplists:delete(mfa, Opts)]); close -> - ct:print("Server closing ~p ~n", [self()]), + ct:log("Server closing ~p ~n", [self()]), Result = rpc:call(Node, Transport, close, [AcceptSocket], 500), Result1 = rpc:call(Node, Transport, close, [ListenSocket], 500), - ct:print("Result ~p : ~p ~n", [Result, Result1]); + ct:log("Result ~p : ~p ~n", [Result, Result1]); {ssl_closed, _} -> ok end. @@ -115,7 +115,7 @@ connect(#sslsocket{} = ListenSocket, Opts) -> end; connect(ListenSocket, Opts) -> Node = proplists:get_value(node, Opts), - ct:print("gen_tcp:accept(~p)~n", [ListenSocket]), + ct:log("gen_tcp:accept(~p)~n", [ListenSocket]), {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]), AcceptSocket. @@ -123,10 +123,10 @@ connect(ListenSocket, Opts) -> connect(_, _, 0, AcceptSocket, _) -> AcceptSocket; connect(ListenSocket, Node, N, _, Timeout) -> - ct:print("ssl:transport_accept(~p)~n", [ListenSocket]), + ct:log("ssl:transport_accept(~p)~n", [ListenSocket]), {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept, [ListenSocket]), - ct:print("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]), + ct:log("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]), case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of ok -> @@ -161,27 +161,27 @@ run_client(Opts) -> Pid = proplists:get_value(from, Opts), Transport = proplists:get_value(transport, Opts, ssl), Options = proplists:get_value(options, Opts), - ct:print("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]), + ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]), case rpc:call(Node, Transport, connect, [Host, Port, Options]) of {ok, Socket} -> Pid ! { connected, Socket }, - ct:print("Client: connected~n", []), + ct:log("Client: connected~n", []), %% In special cases we want to know the client port, it will %% be indicated by sending {port, 0} in options list! send_selected_port(Pid, proplists:get_value(port, Options), Socket), {Module, Function, Args} = proplists:get_value(mfa, Opts), - ct:print("Client: apply(~p,~p,~p)~n", + ct:log("Client: apply(~p,~p,~p)~n", [Module, Function, [Socket | Args]]), case rpc:call(Node, Module, Function, [Socket | Args]) of no_result_msg -> ok; Msg -> - ct:print("Client Msg: ~p ~n", [Msg]), + ct:log("Client Msg: ~p ~n", [Msg]), Pid ! {self(), Msg} end, receive close -> - ct:print("Client closing~n", []), + ct:log("Client closing~n", []), rpc:call(Node, Transport, close, [Socket]); {ssl_closed, Socket} -> ok; @@ -189,18 +189,18 @@ run_client(Opts) -> ok end; {error, Reason} -> - ct:print("Client: connection failed: ~p ~n", [Reason]), + ct:log("Client: connection failed: ~p ~n", [Reason]), Pid ! {self(), {error, Reason}} end. close(Pid) -> - ct:print("Close ~p ~n", [Pid]), + ct:log("Close ~p ~n", [Pid]), Monitor = erlang:monitor(process, Pid), Pid ! close, receive {'DOWN', Monitor, process, Pid, Reason} -> erlang:demonitor(Monitor), - ct:print("Pid: ~p down due to:~p ~n", [Pid, Reason]) + ct:log("Pid: ~p down due to:~p ~n", [Pid, Reason]) end. check_result(Server, ServerMsg, Client, ClientMsg) -> @@ -498,33 +498,33 @@ run_upgrade_server(Opts) -> SslOptions = proplists:get_value(ssl_options, Opts), Pid = proplists:get_value(from, Opts), - ct:print("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]), + ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]), {ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]), Pid ! {listen, up}, send_selected_port(Pid, Port, ListenSocket), - ct:print("gen_tcp:accept(~p)~n", [ListenSocket]), + ct:log("gen_tcp:accept(~p)~n", [ListenSocket]), {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]), try {ok, SslAcceptSocket} = case TimeOut of infinity -> - ct:print("ssl:ssl_accept(~p, ~p)~n", + ct:log("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, SslOptions]), rpc:call(Node, ssl, ssl_accept, [AcceptSocket, SslOptions]); _ -> - ct:print("ssl:ssl_accept(~p, ~p, ~p)~n", + ct:log("ssl:ssl_accept(~p, ~p, ~p)~n", [AcceptSocket, SslOptions, TimeOut]), rpc:call(Node, ssl, ssl_accept, [AcceptSocket, SslOptions, TimeOut]) end, {Module, Function, Args} = proplists:get_value(mfa, Opts), Msg = rpc:call(Node, Module, Function, [SslAcceptSocket | Args]), - ct:print("Upgrade Server Msg: ~p ~n", [Msg]), + ct:log("Upgrade Server Msg: ~p ~n", [Msg]), Pid ! {self(), Msg}, receive close -> - ct:print("Upgrade Server closing~n", []), + ct:log("Upgrade Server closing~n", []), rpc:call(Node, ssl, close, [SslAcceptSocket]) end catch error:{badmatch, Error} -> @@ -542,24 +542,24 @@ run_upgrade_client(Opts) -> TcpOptions = proplists:get_value(tcp_options, Opts), SslOptions = proplists:get_value(ssl_options, Opts), - ct:print("gen_tcp:connect(~p, ~p, ~p)~n", + ct:log("gen_tcp:connect(~p, ~p, ~p)~n", [Host, Port, TcpOptions]), {ok, Socket} = rpc:call(Node, gen_tcp, connect, [Host, Port, TcpOptions]), send_selected_port(Pid, Port, Socket), - ct:print("ssl:connect(~p, ~p)~n", [Socket, SslOptions]), + ct:log("ssl:connect(~p, ~p)~n", [Socket, SslOptions]), {ok, SslSocket} = rpc:call(Node, ssl, connect, [Socket, SslOptions]), {Module, Function, Args} = proplists:get_value(mfa, Opts), - ct:print("apply(~p, ~p, ~p)~n", + ct:log("apply(~p, ~p, ~p)~n", [Module, Function, [SslSocket | Args]]), Msg = rpc:call(Node, Module, Function, [SslSocket | Args]), - ct:print("Upgrade Client Msg: ~p ~n", [Msg]), + ct:log("Upgrade Client Msg: ~p ~n", [Msg]), Pid ! {self(), Msg}, receive close -> - ct:print("Upgrade Client closing~n", []), + ct:log("Upgrade Client closing~n", []), rpc:call(Node, ssl, close, [SslSocket]) end. @@ -578,20 +578,20 @@ run_upgrade_server_error(Opts) -> SslOptions = proplists:get_value(ssl_options, Opts), Pid = proplists:get_value(from, Opts), - ct:print("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]), + ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]), {ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]), Pid ! {listen, up}, send_selected_port(Pid, Port, ListenSocket), - ct:print("gen_tcp:accept(~p)~n", [ListenSocket]), + ct:log("gen_tcp:accept(~p)~n", [ListenSocket]), {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]), Error = case TimeOut of infinity -> - ct:print("ssl:ssl_accept(~p, ~p)~n", + ct:log("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, SslOptions]), rpc:call(Node, ssl, ssl_accept, [AcceptSocket, SslOptions]); _ -> - ct:print("ssl:ssl_accept(~p, ~p, ~p)~n", + ct:log("ssl:ssl_accept(~p, ~p, ~p)~n", [AcceptSocket, SslOptions, TimeOut]), rpc:call(Node, ssl, ssl_accept, [AcceptSocket, SslOptions, TimeOut]) @@ -611,26 +611,26 @@ run_server_error(Opts) -> Options = proplists:get_value(options, Opts), Pid = proplists:get_value(from, Opts), Transport = proplists:get_value(transport, Opts, ssl), - ct:print("ssl:listen(~p, ~p)~n", [Port, Options]), + ct:log("ssl:listen(~p, ~p)~n", [Port, Options]), case rpc:call(Node, Transport, listen, [Port, Options]) of {ok, #sslsocket{} = ListenSocket} -> %% To make sure error_client will %% get {error, closed} and not {error, connection_refused} Pid ! {listen, up}, send_selected_port(Pid, Port, ListenSocket), - ct:print("ssl:transport_accept(~p)~n", [ListenSocket]), + ct:log("ssl:transport_accept(~p)~n", [ListenSocket]), case rpc:call(Node, Transport, transport_accept, [ListenSocket]) of {error, _} = Error -> Pid ! {self(), Error}; {ok, AcceptSocket} -> - ct:print("ssl:ssl_accept(~p)~n", [AcceptSocket]), + ct:log("ssl:ssl_accept(~p)~n", [AcceptSocket]), Error = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]), Pid ! {self(), Error} end; {ok, ListenSocket} -> Pid ! {listen, up}, send_selected_port(Pid, Port, ListenSocket), - ct:print("~p:accept(~p)~n", [Transport, ListenSocket]), + ct:log("~p:accept(~p)~n", [Transport, ListenSocket]), case rpc:call(Node, Transport, accept, [ListenSocket]) of {error, _} = Error -> Pid ! {self(), Error} @@ -652,7 +652,7 @@ run_client_error(Opts) -> Pid = proplists:get_value(from, Opts), Transport = proplists:get_value(transport, Opts, ssl), Options = proplists:get_value(options, Opts), - ct:print("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]), + ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]), Error = rpc:call(Node, Transport, connect, [Host, Port, Options]), Pid ! {self(), Error}. @@ -859,7 +859,7 @@ der_to_pem(File, Entries) -> cipher_result(Socket, Result) -> Result = ssl:connection_info(Socket), - ct:print("Successfull connect: ~p~n", [Result]), + ct:log("Successfull connect: ~p~n", [Result]), %% Importante to send two packets here %% to properly test "cipher state" handling ssl:send(Socket, "Hello\n"), diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index 1324ffdf9c..fc88a8f23c 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -104,7 +104,7 @@ init_per_suite(Config0) -> Result = (catch make_certs:all(?config(data_dir, Config0), ?config(priv_dir, Config0))), - ct:print("Make certs ~p~n", [Result]), + ct:log("Make certs ~p~n", [Result]), Config1 = ssl_test_lib:make_dsa_cert(Config0), Config = ssl_test_lib:cert_options(Config1), [{watchdog, Dog} | Config] @@ -200,7 +200,7 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) -> Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile, - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -212,7 +212,7 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) -> {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, {options, ClientOpts}]), - port_command(OpensslPort, Data), + true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Client, ok), @@ -241,10 +241,10 @@ basic_erlang_server_openssl_client(Config) when is_list(Config) -> Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ " -host localhost", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - port_command(OpenSslPort, Data), + true = port_command(OpenSslPort, Data), ssl_test_lib:check_result(Server, ok), @@ -272,7 +272,7 @@ erlang_client_openssl_server(Config) when is_list(Config) -> Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile, - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -284,7 +284,7 @@ erlang_client_openssl_server(Config) when is_list(Config) -> {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, {options, ClientOpts}]), - port_command(OpensslPort, Data), + true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Client, ok), @@ -314,10 +314,10 @@ erlang_server_openssl_client(Config) when is_list(Config) -> Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -host localhost", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - port_command(OpenSslPort, Data), + true = port_command(OpenSslPort, Data), ssl_test_lib:check_result(Server, ok), @@ -349,7 +349,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile ++ " -key " ++ KeyFile ++ " -Verify 2 -msg", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -362,7 +362,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> erlang_ssl_receive, [Data]}}, {options, ClientOpts}]), - port_command(OpensslPort, Data), + true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Client, ok), @@ -396,10 +396,10 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) -> " -host localhost " ++ " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile ++ " -key " ++ KeyFile ++ " -msg", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - port_command(OpenSslPort, Data), + true = port_command(OpenSslPort, Data), ssl_test_lib:check_result(Server, ok), @@ -431,11 +431,11 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) -> Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -host localhost -reconnect", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - port_command(OpenSslPort, Data), + true = port_command(OpenSslPort, Data), ssl_test_lib:check_result(Server, ok), @@ -467,7 +467,7 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -480,9 +480,9 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> delayed_send, [[ErlData, OpenSslData]]}}, {options, ClientOpts}]), - port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), + true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), ct:sleep(?SLEEP), - port_command(OpensslPort, OpenSslData), + true = port_command(OpensslPort, OpenSslData), ssl_test_lib:check_result(Client, ok), @@ -516,7 +516,7 @@ erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) -> Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -562,11 +562,11 @@ erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) -> Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -host localhost -msg", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - port_command(OpenSslPort, Data), + true = port_command(OpenSslPort, Data), ssl_test_lib:check_result(Server, ok), @@ -597,7 +597,7 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) -> Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -610,7 +610,7 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) -> erlang_ssl_receive, [Data]}}, {options, ClientOpts}]), - port_command(OpensslPort, Data), + true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Client, ok), @@ -640,7 +640,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile ++ " -key " ++ KeyFile ++ " -Verify 2", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -652,7 +652,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, {options, ClientOpts}]), - port_command(OpensslPort, Data), + true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Client, ok), @@ -691,10 +691,10 @@ erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> ++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -host localhost", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - port_command(OpenSslPort, Data), + true = port_command(OpenSslPort, Data), ssl_test_lib:check_result(Server, ok), @@ -779,7 +779,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) -> Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -793,7 +793,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) -> [{versions, [Version]} | ClientOpts]}]), %% Send garbage - port_command(OpensslPort, ?OPENSSL_GARBAGE), + true = port_command(OpensslPort, ?OPENSSL_GARBAGE), ct:sleep(?SLEEP), @@ -835,7 +835,7 @@ expired_session(Config) when is_list(Config) -> Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -893,10 +893,10 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) -> Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ " -host localhost -ssl2 -msg", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - port_command(OpenSslPort, Data), + true = port_command(OpenSslPort, Data), receive {'EXIT', OpenSslPort, _} -> ok @@ -912,7 +912,7 @@ erlang_client_openssl_server_npn() -> erlang_client_openssl_server_npn(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) -> - port_command(OpensslPort, Data), + true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Client, ok) end), @@ -925,9 +925,9 @@ erlang_client_openssl_server_npn_renegotiate() -> erlang_client_openssl_server_npn_renegotiate(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) -> - port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), + true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), ct:sleep(?SLEEP), - port_command(OpensslPort, Data), + true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Client, ok) end), ok. @@ -939,7 +939,7 @@ erlang_server_openssl_client_npn(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) -> - port_command(OpensslPort, Data), + true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) end), ok. @@ -951,9 +951,9 @@ erlang_server_openssl_client_npn_renegotiate() -> erlang_server_openssl_client_npn_renegotiate(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) -> - port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), + true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), ct:sleep(?SLEEP), - port_command(OpensslPort, Data), + true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) end), ok. @@ -962,7 +962,7 @@ erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_client_and_openssl_server_with_opts(Config, [], "-nextprotoneg spdy/2", Data, fun(Server, OpensslPort) -> - port_command(OpensslPort, Data), + true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) end), ok. @@ -975,7 +975,7 @@ erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) -> [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}}], "", Data, fun(Server, OpensslPort) -> - port_command(OpensslPort, Data), + true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) end), ok. @@ -985,7 +985,7 @@ erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_server_and_openssl_client_with_opts(Config, [{next_protocols_advertised, [<<"spdy/2">>]}], "", Data, fun(Server, OpensslPort) -> - port_command(OpensslPort, Data), + true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) end), ok. @@ -994,7 +994,7 @@ erlang_server_openssl_client_npn_only_client(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_server_and_openssl_client_with_opts(Config, [], "-nextprotoneg spdy/2", Data, fun(Server, OpensslPort) -> - port_command(OpensslPort, Data), + true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) end), ok. @@ -1020,13 +1020,13 @@ run_suites(Ciphers, Version, Config, Type) -> [] -> ok; Error -> - ct:print("Cipher suite errors: ~p~n", [Error]), + ct:log("Cipher suite errors: ~p~n", [Error]), ct:fail(cipher_suite_failed_see_test_case_log) end. cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> process_flag(trap_exit, true), - ct:print("Testing CipherSuite ~p~n", [CipherSuite]), + ct:log("Testing CipherSuite ~p~n", [CipherSuite]), {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config), Port = ssl_test_lib:inet_port(node()), @@ -1036,7 +1036,7 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -1052,19 +1052,19 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> [{ciphers,[CipherSuite]} | ClientOpts]}]), - port_command(OpenSslPort, "Hello\n"), + true = port_command(OpenSslPort, "Hello\n"), receive {Port, {data, _}} when is_port(Port) -> ok after 500 -> - ct:print("Time out on openssl port, check that" + ct:log("Time out on openssl port, check that" " the messages Hello and world are received" " during close of port" , []), ok end, - port_command(OpenSslPort, " world\n"), + true = port_command(OpenSslPort, " world\n"), Result = ssl_test_lib:wait_for_result(Client, ok), @@ -1100,7 +1100,7 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile, - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -1139,7 +1139,7 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac Cmd = "openssl s_server -msg -nextprotoneg http/1.1,spdy/2 -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile, - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -1177,7 +1177,7 @@ start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callbac Cmd = "openssl s_client -nextprotoneg http/1.0,spdy/2 -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -host localhost", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -1206,7 +1206,7 @@ start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenS Cmd = "openssl s_client " ++ OpenSSLClientOpts ++ " -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -host localhost", - ct:print("openssl cmd: ~p~n", [Cmd]), + ct:log("openssl cmd: ~p~n", [Cmd]), OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), @@ -1225,7 +1225,7 @@ erlang_ssl_receive_and_assert_npn(Socket, Protocol, Data) -> ok. erlang_ssl_receive(Socket, Data) -> - ct:print("Connection info: ~p~n", + ct:log("Connection info: ~p~n", [ssl:connection_info(Socket)]), receive {ssl, Socket, Data} -> @@ -1247,7 +1247,7 @@ erlang_ssl_receive(Socket, Data) -> connection_info(Socket, Version) -> case ssl:connection_info(Socket) of {ok, {Version, _} = Info} -> - ct:print("Connection info: ~p~n", [Info]), + ct:log("Connection info: ~p~n", [Info]), ok; {ok, {OtherVersion, _}} -> {wrong_version, OtherVersion} @@ -1269,28 +1269,28 @@ close_port(Port) -> close_loop(Port, Time, SentClose) -> receive {Port, {data,Debug}} when is_port(Port) -> - io:format("openssl ~s~n",[Debug]), + ct:log("openssl ~s~n",[Debug]), close_loop(Port, Time, SentClose); {ssl,_,Msg} -> - io:format("ssl Msg ~s~n",[Msg]), + ct:log("ssl Msg ~s~n",[Msg]), close_loop(Port, Time, SentClose); {Port, closed} -> - io:format("Port Closed~n",[]), + ct:log("Port Closed~n",[]), ok; {'EXIT', Port, Reason} -> - io:format("Port Closed ~p~n",[Reason]), + ct:log("Port Closed ~p~n",[Reason]), ok; Msg -> - io:format("Port Msg ~p~n",[Msg]), + ct:log("Port Msg ~p~n",[Msg]), close_loop(Port, Time, SentClose) after Time -> case SentClose of false -> - io:format("Closing port ~n",[]), + ct:log("Closing port ~n",[]), catch erlang:port_close(Port), close_loop(Port, Time, true); true -> - io:format("Timeout~n",[]) + ct:log("Timeout~n",[]) end end. @@ -1305,7 +1305,7 @@ server_sent_garbage(Socket) -> wait_for_openssl_server() -> receive {Port, {data, Debug}} when is_port(Port) -> - io:format("openssl ~s~n",[Debug]), + ct:log("openssl ~s~n",[Debug]), %% openssl has started make sure %% it will be in accept. Parsing %% output is too error prone. (Even -- cgit v1.2.3 From 651475b0b56243e1c568e221d5401bbdcccb3a84 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 4 Apr 2013 16:31:45 +0200 Subject: crypto: Replaced all mpint's with normal binaries --- lib/crypto/c_src/crypto.c | 29 ++++++++++++++--------------- lib/crypto/src/crypto.erl | 40 ++++++++++++++++++++++++---------------- lib/crypto/test/crypto_SUITE.erl | 6 +++--- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 1e6c2f24e7..e6bbfd8c38 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -2907,9 +2907,8 @@ static ERL_NIF_TERM bn2term(ErlNifEnv* env, const BIGNUM *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); + ptr = enif_make_new_binary(env, dlen, &ret); + BN_bn2bin(bn, ptr); return ret; } @@ -3111,7 +3110,7 @@ static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T EC_GROUP *group = NULL; EC_POINT *point = NULL; - if (!(argv[1] == atom_undefined || get_bn_from_mpint(env, argv[1], &priv_key)) + if (!(argv[1] == atom_undefined || get_bn_from_bin(env, argv[1], &priv_key)) || !(argv[2] == atom_undefined || enif_is_binary(env, argv[2]))) { printf("#1\n"); goto out_err; @@ -3131,8 +3130,8 @@ static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T 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))) { + && get_bn_from_bin(env, curve[3], &bn_order) + && (curve[4] != atom_none && get_bn_from_bin(env, curve[4], &cofactor))) { //* {Field, Prime, Point, Order, CoFactor} = Curve */ int f_arity = -1; @@ -3144,8 +3143,8 @@ static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T /* {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)) + || !get_bn_from_bin(env, prime[0], &a) + || !get_bn_from_bin(env, prime[1], &b)) goto out_err; if (!enif_get_tuple(env,curve[0],&f_arity,&field)) @@ -3154,7 +3153,7 @@ static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T if (f_arity == 2 && field[0] == atom_prime_field) { /* {prime_field, Prime} */ - if (!get_bn_from_mpint(env, field[1], &p)) + if (!get_bn_from_bin(env, field[1], &p)) goto out_err; if (BN_is_negative(p) || BN_is_zero(p)) @@ -3378,11 +3377,11 @@ static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM digest = data_bin.data; } else { - if (!inspect_mpint(env,argv[1],&data_bin)) { + if (!enif_inspect_binary(env,argv[1],&data_bin)) { return enif_make_badarg(env); } digest = hmacbuf; - digp->funcp(data_bin.data+4, data_bin.size-4, digest); + digp->funcp(data_bin.data, data_bin.size, digest); } enif_alloc_binary(ECDSA_size(obj->key), &ret_bin); @@ -3425,7 +3424,7 @@ static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER return atom_notsup; } - if (!inspect_mpint(env, argv[2], &sign_bin) + if (!enif_inspect_binary(env, argv[2], &sign_bin) || !enif_get_resource(env, argv[3], res_type_ec_key, (void **)&obj)) return enif_make_badarg(env); @@ -3438,16 +3437,16 @@ static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER } digest = data_bin.data; } - else if (inspect_mpint(env, argv[1], &data_bin)) { + else if (enif_inspect_binary(env, argv[1], &data_bin)) { digest = hmacbuf; - digp->funcp(data_bin.data+4, data_bin.size-4, digest); + digp->funcp(data_bin.data, data_bin.size, 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); + sign_bin.data, sign_bin.size, obj->key); return (i==1 ? atom_true : atom_false); #else diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 7558087d99..9503d0fcaa 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -839,9 +839,17 @@ dss_verify(_Type,_Data,_Signature,_Key) -> ?nif_stub. % Key = [E,N] E=PublicExponent N=PublicModulus rsa_verify(Data,Signature,Key) -> - rsa_verify_nif(sha, Data,Signature,Key). -rsa_verify(Type, DataOrDigest, Signature, Key) -> - case rsa_verify_nif(Type, DataOrDigest, Signature, Key) of + rsa_verify(sha, Data,Signature,Key). +rsa_verify(Type, Data, Signature, Key) when is_binary(Data) -> + verify(rsa, Type, mpint_to_bin(Data), mpint_to_bin(Signature), map_mpint_to_bin(Key)); +rsa_verify(Type, Digest, Signature, Key) -> + verify(rsa, Type, Digest, mpint_to_bin(Signature), map_mpint_to_bin(Key)). + + +verify(dss, Type, Data, Signature, Key) -> + dss_verify_nif(Type, Data, Signature, map_ensure_int_as_bin(Key)); +verify(rsa, Type, DataOrDigest, Signature, Key) -> + case rsa_verify_nif(Type, DataOrDigest, Signature, map_ensure_int_as_bin(Key)) of notsup -> erlang:error(notsup); Bool -> Bool end. @@ -1178,13 +1186,13 @@ ec_key_new(_Curve) -> ?nif_stub. ec_key_generate(_Key) -> ?nif_stub. nif_prime_to_term({prime_field, Prime}) -> - {prime_field, erlint(Prime)}; + {prime_field, bin_to_int(Prime)}; nif_prime_to_term(PrimeField) -> PrimeField. nif_curve_to_term({A, B, Seed}) -> - {erlint(A), erlint(B), Seed}. + {bin_to_int(A), bin_to_int(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_prime_to_term(PrimeField), nif_curve_to_term(Curve), BasePoint, bin_to_int(Order), bin_to_int(CoFactor)}; nif_curve_parameters_to_term(Curve) when is_atom(Curve) -> %% named curve Curve. @@ -1193,7 +1201,7 @@ nif_curve_parameters_to_term(Curve) when is_atom(Curve) -> 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}; + {nif_curve_parameters_to_term(Curve), bin_to_int(PrivKey), PubKey}; _ -> erlang:error(conversion_failed) end. @@ -1201,13 +1209,13 @@ ec_key_to_term(Key) -> ec_key_to_term_nif(_Key) -> ?nif_stub. term_to_nif_prime({prime_field, Prime}) -> - {prime_field, mpint(Prime)}; + {prime_field, int_to_bin(Prime)}; term_to_nif_prime(PrimeField) -> PrimeField. term_to_nif_curve({A, B, Seed}) -> - {mpint(A), mpint(B), Seed}. + {int_to_bin(A), int_to_bin(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_prime(PrimeField), term_to_nif_curve(Curve), BasePoint, int_to_bin(Order), int_to_bin(CoFactor)}; term_to_nif_curve_parameters(Curve) when is_atom(Curve) -> %% named curve Curve. @@ -1216,7 +1224,7 @@ term_to_nif_curve_parameters(Curve) when is_atom(Curve) -> 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(term_to_nif_curve_parameters(Curve), int_to_bin(PrivKey), PubKey). term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub. @@ -1356,18 +1364,18 @@ int_to_bin_neg(X,Ds) -> int_to_bin_neg(X bsr 8, [(X band 255)|Ds]). -bin_to_int(Bin) -> +bin_to_int(Bin) when is_binary(Bin) -> Bits = bit_size(Bin), <> = Bin, - Integer. + Integer; +bin_to_int(undefined) -> + undefined. %% int from integer in a binary with 32bit length erlint(<>) -> Bits= MPIntSize * 8, <> = MPIntValue, - Integer; -erlint(undefined) -> - undefined. + Integer. mpint_to_bin(<>) -> Bin. diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index c5597be34c..b8a041cf8f 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1906,9 +1906,9 @@ ec_do() -> ?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), + Sign = crypto:ecdsa_sign(sha, Msg, L2), + ?line true = crypto:ecdsa_verify(sha, Msg, Sign, L2), + ?line false = crypto:ecdsa_verify(sha, Msg, <<10,20>>, L2), ok. -- cgit v1.2.3 From e8ef6571e929fba0081564eca45eae4ae143e50c Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 5 Apr 2013 16:10:59 +0200 Subject: crypto: Introduce generic sign() and verify() functions for rsa, dss, and new ecdsa. No mpint's accepted. --- lib/crypto/c_src/crypto.c | 72 +++++++++++++-------------- lib/crypto/src/crypto.erl | 103 +++++++++++++++++++++------------------ lib/crypto/test/crypto_SUITE.erl | 44 +++++++++++------ 3 files changed, 117 insertions(+), 102 deletions(-) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index e6bbfd8c38..dae48898ce 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -205,7 +205,7 @@ static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar static ERL_NIF_TERM strong_rand_mpint_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -331,7 +331,7 @@ static ErlNifFunc nif_funcs[] = { {"strong_rand_mpint_nif", 3, strong_rand_mpint_nif}, {"rand_uniform_nif", 2, rand_uniform_nif}, {"mod_exp_nif", 4, mod_exp_nif}, - {"dss_verify", 4, dss_verify}, + {"dss_verify_nif", 4, dss_verify_nif}, {"rsa_verify_nif", 4, rsa_verify_nif}, {"aes_cbc_crypt", 4, aes_cbc_crypt}, {"exor", 2, exor}, @@ -1789,13 +1789,7 @@ static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg return ret; } -static int inspect_mpint(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifBinary* bin) -{ - return enif_inspect_binary(env, term, bin) && - bin->size >= 4 && get_int32(bin->data) == bin->size-4; -} - -static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (DigestType|none, Data|{digest,Digest}, Signature,Key=[P, Q, G, Y]) */ ErlNifBinary data_bin, sign_bin; BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_y = NULL; @@ -1818,10 +1812,10 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv digest = data_bin.data; } else { - if (!inspect_mpint(env, argv[1], &data_bin)) { + if (!enif_inspect_binary(env, argv[1], &data_bin)) { return enif_make_badarg(env); } - SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); + SHA1(data_bin.data, data_bin.size, hmacbuf); digest = hmacbuf; } } @@ -1833,15 +1827,15 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv return enif_make_badarg(env); } - if (!inspect_mpint(env, argv[2], &sign_bin) + if (!enif_inspect_binary(env, argv[2], &sign_bin) || !enif_get_list_cell(env, argv[3], &head, &tail) - || !get_bn_from_mpint(env, head, &dsa_p) + || !get_bn_from_bin(env, head, &dsa_p) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa_q) + || !get_bn_from_bin(env, head, &dsa_q) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa_g) + || !get_bn_from_bin(env, head, &dsa_g) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa_y) + || !get_bn_from_bin(env, head, &dsa_y) || !enif_is_empty_list(env,tail)) { if (dsa_p) BN_free(dsa_p); @@ -1858,7 +1852,7 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv dsa->priv_key = NULL; dsa->pub_key = dsa_y; i = DSA_verify(0, digest, SHA_DIGEST_LENGTH, - sign_bin.data+4, sign_bin.size-4, dsa); + sign_bin.data, sign_bin.size, dsa); DSA_free(dsa); return(i > 0) ? atom_true : atom_false; } @@ -1984,11 +1978,11 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM rsa = RSA_new(); - if (!inspect_mpint(env, argv[2], &sign_bin) + if (!enif_inspect_binary(env, argv[2], &sign_bin) || !enif_get_list_cell(env, argv[3], &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->e) + || !get_bn_from_bin(env, head, &rsa->e) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->n) + || !get_bn_from_bin(env, head, &rsa->n) || !enif_is_empty_list(env, tail)) { ret = enif_make_badarg(env); @@ -2004,9 +1998,9 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM } digest = data_bin.data; } - else if (inspect_mpint(env, argv[1], &data_bin)) { + else if (enif_inspect_binary(env, argv[1], &data_bin)) { digest = hmacbuf; - digp->funcp(data_bin.data+4, data_bin.size-4, digest); + digp->funcp(data_bin.data, data_bin.size, digest); } else { ret = enif_make_badarg(env); @@ -2014,7 +2008,7 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM } i = RSA_verify(digp->NID_type, digest, digp->len, - sign_bin.data+4, sign_bin.size-4, rsa); + sign_bin.data, sign_bin.size, rsa); ret = (i==1 ? atom_true : atom_false); @@ -2159,22 +2153,22 @@ static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa) ERL_NIF_TERM head, tail; if (!enif_get_list_cell(env, key, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->e) + || !get_bn_from_bin(env, head, &rsa->e) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->n) + || !get_bn_from_bin(env, head, &rsa->n) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->d) + || !get_bn_from_bin(env, head, &rsa->d) || (!enif_is_empty_list(env, tail) && (!enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->p) + || !get_bn_from_bin(env, head, &rsa->p) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->q) + || !get_bn_from_bin(env, head, &rsa->q) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->dmp1) + || !get_bn_from_bin(env, head, &rsa->dmp1) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->dmq1) + || !get_bn_from_bin(env, head, &rsa->dmq1) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->iqmp) + || !get_bn_from_bin(env, head, &rsa->iqmp) || !enif_is_empty_list(env, tail)))) { return 0; } @@ -2211,11 +2205,11 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar digest = data_bin.data; } else { - if (!inspect_mpint(env,argv[1],&data_bin)) { + if (!enif_inspect_binary(env,argv[1],&data_bin)) { return enif_make_badarg(env); } digest = hmacbuf; - digp->funcp(data_bin.data+4, data_bin.size-4, digest); + digp->funcp(data_bin.data, data_bin.size, digest); } rsa = RSA_new(); @@ -2270,10 +2264,10 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar digest = data_bin.data; } else { - if (!inspect_mpint(env,argv[1],&data_bin)) { + if (!enif_inspect_binary(env,argv[1],&data_bin)) { return enif_make_badarg(env); } - SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); + SHA1(data_bin.data, data_bin.size, hmacbuf); digest = hmacbuf; } } @@ -2291,13 +2285,13 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar dsa->pub_key = NULL; if (!enif_get_list_cell(env, argv[2], &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->p) + || !get_bn_from_bin(env, head, &dsa->p) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->q) + || !get_bn_from_bin(env, head, &dsa->q) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->g) + || !get_bn_from_bin(env, head, &dsa->g) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->priv_key) + || !get_bn_from_bin(env, head, &dsa->priv_key) || !enif_is_empty_list(env,tail)) { DSA_free(dsa); return enif_make_badarg(env); diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 9503d0fcaa..ae19755421 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -68,7 +68,7 @@ -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([sign/4, verify/5, ecdh_compute_key/2]). -export([dh_generate_parameters/2, dh_check/1]). %% Testing see below @@ -116,13 +116,13 @@ rc2_cbc_encrypt, rc2_cbc_decrypt, srp_generate_key, srp_compute_key, ec_key_new, ec_key_to_term, term_to_ec_key, ec_key_generate, - ecdsa_sign, ecdsa_verify, ecdh_compute_key, + sign, 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 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 @@ -834,8 +834,12 @@ mod_exp_nif(_Base,_Exp,_Mod,_bin_hdr) -> ?nif_stub. %% Key = [P,Q,G,Y] P,Q,G=DSSParams Y=PublicKey dss_verify(Data,Signature,Key) -> - dss_verify(sha, Data, Signature, Key). -dss_verify(_Type,_Data,_Signature,_Key) -> ?nif_stub. + dss_verify(sha, Data, Signature, Key). + +dss_verify(Type,Data,Signature,Key) when is_binary(Data), Type=/=none -> + verify(dss,Type,mpint_to_bin(Data),mpint_to_bin(Signature),map_mpint_to_bin(Key)); +dss_verify(Type,Digest,Signature,Key) -> + verify(dss,Type,Digest,mpint_to_bin(Signature),map_mpint_to_bin(Key)). % Key = [E,N] E=PublicExponent N=PublicModulus rsa_verify(Data,Signature,Key) -> @@ -848,13 +852,22 @@ rsa_verify(Type, Digest, Signature, Key) -> verify(dss, Type, Data, Signature, Key) -> dss_verify_nif(Type, Data, Signature, map_ensure_int_as_bin(Key)); + verify(rsa, Type, DataOrDigest, Signature, Key) -> case rsa_verify_nif(Type, DataOrDigest, Signature, map_ensure_int_as_bin(Key)) of notsup -> erlang:error(notsup); Bool -> Bool + end; +verify(ecdsa, Type, DataOrDigest, Signature, Key) -> + case ecdsa_verify_nif(Type, DataOrDigest, Signature, map_ensure_int_as_bin(Key)) of + notsup -> erlang:error(notsup); + Bool -> Bool end. + +dss_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. +ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Key) -> ?nif_stub. %% @@ -868,24 +881,52 @@ rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. dss_sign(DataOrDigest,Key) -> dss_sign(sha,DataOrDigest,Key). -dss_sign(Type, DataOrDigest, Key) -> - case dss_sign_nif(Type,DataOrDigest,Key) of - error -> erlang:error(badkey, [DataOrDigest, Key]); - Sign -> Sign - end. +dss_sign(Type, Data, Key) when is_binary(Data), Type=/=none -> + sign(dss, Type, mpint_to_bin(Data), map_mpint_to_bin(Key)); +dss_sign(Type, Digest, Key) -> + sign(dss, Type, Digest, map_mpint_to_bin(Key)). -dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub. %% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent rsa_sign(DataOrDigest,Key) -> rsa_sign(sha, DataOrDigest, Key). -rsa_sign(Type, DataOrDigest, Key) -> - case rsa_sign_nif(Type,DataOrDigest,Key) of + +rsa_sign(Type, Data, Key) when is_binary(Data) -> + sign(rsa, Type, mpint_to_bin(Data), map_mpint_to_bin(Key)); +rsa_sign(Type, Digest, Key) -> + sign(rsa, Type, Digest, map_mpint_to_bin(Key)). + +map_mpint_to_bin(List) -> + lists:map(fun(E) -> mpint_to_bin(E) end, List ). + +map_ensure_int_as_bin([H|_]=List) when is_integer(H) -> + lists:map(fun(E) -> int_to_bin(E) end, List); +map_ensure_int_as_bin(List) -> + List. + +sign(rsa, Type, DataOrDigest, Key) -> + case rsa_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of + error -> erlang:error(badkey, [Type,DataOrDigest,Key]); + Sign -> Sign + end; +sign(dss, Type, DataOrDigest, Key) -> + case dss_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of + error -> erlang:error(badkey, [DataOrDigest, Key]); + Sign -> Sign + end; +sign(ecdsa, Type, DataOrDigest, Key) -> + case ecdsa_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of error -> erlang:error(badkey, [Type,DataOrDigest,Key]); Sign -> Sign end. rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub. +dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub. +ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub. + + + + %% @@ -914,7 +955,7 @@ rsa_public_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub. %% Binary, Key = [E,N,D] rsa_private_decrypt(BinMesg, Key, Padding) -> - case rsa_private_crypt(BinMesg, Key, Padding, false) of + case rsa_private_crypt(BinMesg, map_mpint_to_bin(Key), Padding, false) of error -> erlang:error(decrypt_failed, [BinMesg,Key, Padding]); Sign -> Sign @@ -925,7 +966,7 @@ rsa_private_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub. %% Binary, Key = [E,N,D] rsa_private_encrypt(BinMesg, Key, Padding) -> - case rsa_private_crypt(BinMesg, Key, Padding, true) of + case rsa_private_crypt(BinMesg, map_mpint_to_bin(Key), Padding, true) of error -> erlang:error(encrypt_failed, [BinMesg,Key, Padding]); Sign -> Sign @@ -1228,38 +1269,6 @@ term_to_ec_key({Curve, 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. diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index b8a041cf8f..6161c03240 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1630,8 +1630,11 @@ dsa_verify_test(Config) when is_list(Config) -> BadArg = (catch my_dss_verify(sized_binary(Msg), <>, ValidKey)), - ?line m(element(1,element(2,BadArg)), badarg), - + badarg = case element(1,element(2,BadArg)) of + badarg -> badarg; + function_clause -> badarg; + X -> X + end, InValidKey = [crypto:mpint(P_p), crypto:mpint(Q_p), crypto:mpint(G_p), @@ -1664,20 +1667,29 @@ rsa_sign_test(Config) when is_list(Config) -> Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger" "09812312908312378623487263487623412039812 huagasd">>, - PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)], - PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)], - ?line Sig1 = crypto:rsa_sign(sized_binary(Msg), PrivKey), - ?line m(crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1),PubKey), true), + PrivKey = [PubEx, Mod, PrivEx], + PubKey = [PubEx, Mod], + PubKeyMpint = map_int_to_mpint(PubKey), + Sig1 = crypto:rsa_sign(sized_binary(Msg), map_int_to_mpint(PrivKey)), + Sig1 = crypto:sign(rsa, sha, Msg, PrivKey), + true = crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1), PubKeyMpint), + true = crypto:verify(rsa, sha, Msg, Sig1, PubKey), - ?line Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), PrivKey), - ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2),PubKey), true), + Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), map_int_to_mpint(PrivKey)), + Sig2 = crypto:sign(rsa, md5, Msg, PrivKey), + true = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2), PubKeyMpint), + true = crypto:verify(rsa, md5, Msg, Sig2, PubKey), - ?line m(Sig1 =:= Sig2, false), - ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1),PubKey), false), - ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1),PubKey), true), - + false = (Sig1 =:= Sig2), + false = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint), + false = crypto:verify(rsa, md5, Msg, Sig1, PubKey), + true = crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint), + true = crypto:verify(rsa, sha, Msg, Sig1, PubKey), + ok. - +map_int_to_mpint(List) -> + lists:map(fun(E) -> crypto:mpint(E) end, List). + rsa_sign_hash_test(doc) -> "rsa_sign_hash testing"; rsa_sign_hash_test(suite) -> @@ -1906,9 +1918,9 @@ ec_do() -> ?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, Msg, L2), - ?line true = crypto:ecdsa_verify(sha, Msg, Sign, L2), - ?line false = crypto:ecdsa_verify(sha, Msg, <<10,20>>, L2), + Sign = crypto:sign(ecdsa, sha, Msg, L2), + ?line true = crypto:verify(ecdsa, sha, Msg, Sign, L2), + ?line false = crypto:verify(ecdsa, sha, Msg, <<10,20>>, L2), ok. -- cgit v1.2.3 From ff58cc8976efe77f92510011d9ed7b0f242e235e Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Mon, 8 Apr 2013 16:07:56 +0200 Subject: public_key: Use new crypto API functions sign and verify --- lib/public_key/src/public_key.erl | 72 ++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 6c25428ea4..91d33fab42 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -256,7 +256,7 @@ decrypt_private(CipherText, is_integer(N), is_integer(E), is_integer(D), is_list(Options) -> Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - crypto:rsa_private_decrypt(CipherText, format_rsa_private_key(Key), Padding). + crypto:rsa_private_decrypt(CipherText, old_format_rsa_private_key(Key), Padding). %%-------------------------------------------------------------------- -spec decrypt_public(CipherText :: binary(), rsa_public_key() | rsa_private_key()) -> @@ -322,7 +322,7 @@ encrypt_private(PlainText, is_integer(N), is_integer(E), is_integer(D), is_list(Options) -> Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - crypto:rsa_private_encrypt(PlainText, format_rsa_private_key(Key), Padding). + crypto:rsa_private_encrypt(PlainText, old_format_rsa_private_key(Key), Padding). format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, @@ -332,10 +332,23 @@ format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, coefficient = C}) when is_integer(P1), is_integer(P2), is_integer(E1), is_integer(E2), is_integer(C) -> - [crypto:mpint(K) || K <- [E, N, D, P1, P2, E1, E2, C]]; + [K || K <- [E, N, D, P1, P2, E1, E2, C]]; format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, privateExponent = D}) -> + [K || K <- [E, N, D]]. + +old_format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, + privateExponent = D, + prime1 = P1, prime2 = P2, + exponent1 = E1, exponent2 = E2, + coefficient = C}) + when is_integer(P1), is_integer(P2), + is_integer(E1), is_integer(E2), is_integer(C) -> + [crypto:mpint(K) || K <- [E, N, D, P1, P2, E1, E2, C]]; + +old_format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, + privateExponent = D}) -> [crypto:mpint(K) || K <- [E, N, D]]. %% @@ -415,20 +428,16 @@ pkix_sign_types(?'ecdsa-with-SHA512') -> %% Description: Create digital signature. %%-------------------------------------------------------------------- sign({digest,_}=Digest, DigestType, Key = #'RSAPrivateKey'{}) -> - crypto:rsa_sign(DigestType, Digest, format_rsa_private_key(Key)); + crypto:sign(rsa, DigestType, Digest, format_rsa_private_key(Key)); sign(PlainText, DigestType, Key = #'RSAPrivateKey'{}) -> - crypto:rsa_sign(DigestType, sized_binary(PlainText), format_rsa_private_key(Key)); + crypto:sign(rsa, DigestType, PlainText, format_rsa_private_key(Key)); sign({digest,_}=Digest, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) -> - crypto:dss_sign(Digest, - [crypto:mpint(P), crypto:mpint(Q), - crypto:mpint(G), crypto:mpint(X)]); + crypto:sign(dss, sha, Digest, [P, Q, G, X]); sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) -> - crypto:dss_sign(sized_binary(PlainText), - [crypto:mpint(P), crypto:mpint(Q), - crypto:mpint(G), crypto:mpint(X)]); + crypto:sign(dss, sha, PlainText, [P, Q, G, X]); sign(Digest, DigestType, Key = {?'id-ecPublicKey', _, _}) -> sign(Digest, DigestType, ec_public_key_to_eckey(Key)); @@ -437,10 +446,10 @@ 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); + crypto:sign(ecdsa, DigestType, Digest, Key); sign(PlainText, DigestType, {'ECKey', Key}) -> - crypto:ecdsa_sign(DigestType, sized_binary(PlainText), Key); + crypto:sign(ecdsa, DigestType, PlainText, Key); %% Backwards compatible sign(Digest, none, #'DSAPrivateKey'{} = Key) -> @@ -452,29 +461,21 @@ sign(Digest, none, #'DSAPrivateKey'{} = Key) -> | dsa_public_key()) -> boolean(). %% Description: Verifies a digital signature. %%-------------------------------------------------------------------- -verify({digest,_}=Digest, DigestType, Signature, +verify({digest,_} = Digest, DigestType, Signature, #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) -> - crypto:rsa_verify(DigestType, Digest, - sized_binary(Signature), - [crypto:mpint(Exp), crypto:mpint(Mod)]); + crypto:verify(rsa, DigestType, Digest, Signature, [Exp, Mod]); verify(PlainText, DigestType, Signature, #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) -> - crypto:rsa_verify(DigestType, - sized_binary(PlainText), - sized_binary(Signature), - [crypto:mpint(Exp), crypto:mpint(Mod)]); + crypto:verify(rsa, DigestType, PlainText, Signature, + [Exp, Mod]); -verify({digest,_}=Digest, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) +verify({digest,_} = Digest, sha = DigestType, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) when is_integer(Key), is_binary(Signature) -> - crypto:dss_verify(Digest, sized_binary(Signature), - [crypto:mpint(P), crypto:mpint(Q), - crypto:mpint(G), crypto:mpint(Key)]); + crypto:verify(dss, DigestType, Digest, Signature, [P, Q, G, Key]); -verify({digest,_}=Digest, DigestType, Signature, {'ECKey', Key}) -> - crypto:ecdsa_verify(DigestType, Digest, - sized_binary(Signature), - Key); +verify({digest,_} = Digest, DigestType, Signature, {'ECKey', Key}) -> + crypto:verify(ecdsa, DigestType, Digest, Signature, Key); verify(PlainText, DigestType, Signature, Key = #'ECPrivateKey'{}) -> verify(PlainText, DigestType, Signature, ec_private_key_to_eckey(Key)); @@ -483,21 +484,16 @@ 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); + crypto:verify(ecdsa, DigestType, PlainText, Signature, Key); %% Backwards compatibility verify(Digest, none, Signature, {_, #'Dss-Parms'{}} = Key ) -> verify({digest,Digest}, sha, Signature, Key); -verify(PlainText, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) +verify(PlainText, sha = DigestType, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) when is_integer(Key), is_binary(PlainText), is_binary(Signature) -> - crypto:dss_verify(sized_binary(PlainText), - sized_binary(Signature), - [crypto:mpint(P), crypto:mpint(Q), - crypto:mpint(G), crypto:mpint(Key)]). + crypto:verify(dss, DigestType, PlainText, Signature, [P, Q, G, Key]). + %%-------------------------------------------------------------------- -spec pkix_sign(#'OTPTBSCertificate'{}, rsa_private_key() | dsa_private_key()) -> Der::binary(). -- cgit v1.2.3 From 07ba72cdef3d9b62b5be23611cfe869ec343cb87 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 9 Apr 2013 10:36:29 +0200 Subject: crypto: Allow integer keys for rsa_private/public_en/decrypt as well as mpint's for backward compatibility. --- lib/crypto/c_src/crypto.c | 4 ++-- lib/crypto/src/crypto.erl | 14 +++++++---- lib/crypto/test/crypto_SUITE.erl | 51 +++++++++++++++++++++++++++------------- 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index dae48898ce..a8027bb079 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -2339,9 +2339,9 @@ static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TER if (!enif_inspect_binary(env, argv[0], &data_bin) || !enif_get_list_cell(env, argv[1], &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->e) + || !get_bn_from_bin(env, head, &rsa->e) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->n) + || !get_bn_from_bin(env, head, &rsa->n) || !enif_is_empty_list(env,tail) || !rsa_pad(argv[2], &padding)) { diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index ae19755421..57ddf3fbac 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -904,6 +904,12 @@ map_ensure_int_as_bin([H|_]=List) when is_integer(H) -> map_ensure_int_as_bin(List) -> List. +map_to_norm_bin([H|_]=List) when is_integer(H) -> + lists:map(fun(E) -> int_to_bin(E) end, List); +map_to_norm_bin(List) -> + lists:map(fun(E) -> mpint_to_bin(E) end, List). + + sign(rsa, Type, DataOrDigest, Key) -> case rsa_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of error -> erlang:error(badkey, [Type,DataOrDigest,Key]); @@ -945,7 +951,7 @@ ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub. %% Binary, Key = [E,N] rsa_public_encrypt(BinMesg, Key, Padding) -> - case rsa_public_crypt(BinMesg, Key, Padding, true) of + case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of error -> erlang:error(encrypt_failed, [BinMesg,Key, Padding]); Sign -> Sign @@ -955,7 +961,7 @@ rsa_public_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub. %% Binary, Key = [E,N,D] rsa_private_decrypt(BinMesg, Key, Padding) -> - case rsa_private_crypt(BinMesg, map_mpint_to_bin(Key), Padding, false) of + case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of error -> erlang:error(decrypt_failed, [BinMesg,Key, Padding]); Sign -> Sign @@ -966,7 +972,7 @@ rsa_private_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub. %% Binary, Key = [E,N,D] rsa_private_encrypt(BinMesg, Key, Padding) -> - case rsa_private_crypt(BinMesg, map_mpint_to_bin(Key), Padding, true) of + case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of error -> erlang:error(encrypt_failed, [BinMesg,Key, Padding]); Sign -> Sign @@ -974,7 +980,7 @@ rsa_private_encrypt(BinMesg, Key, Padding) -> %% Binary, Key = [E,N] rsa_public_decrypt(BinMesg, Key, Padding) -> - case rsa_public_crypt(BinMesg, Key, Padding, false) of + case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of error -> erlang:error(decrypt_failed, [BinMesg,Key, Padding]); Sign -> Sign diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 6161c03240..09898efd49 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1787,46 +1787,65 @@ rsa_encrypt_decrypt(Config) when is_list(Config) -> PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945, Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123, - PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)], - PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)], + PrivKey = [PubEx, Mod, PrivEx], + PubKey = [PubEx, Mod], Msg = <<"7896345786348 Asldi">>, - ?line PKCS1 = crypto:rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_padding), - ?line PKCS1Dec = crypto:rsa_private_decrypt(PKCS1, PrivKey, rsa_pkcs1_padding), + ?line PKCS1 = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_padding), + ?line PKCS1Dec = rsa_private_decrypt(PKCS1, PrivKey, rsa_pkcs1_padding), io:format("PKCS1Dec ~p~n",[PKCS1Dec]), ?line Msg = PKCS1Dec, - ?line OAEP = crypto:rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_oaep_padding), - ?line Msg = crypto:rsa_private_decrypt(OAEP, PrivKey, rsa_pkcs1_oaep_padding), + ?line OAEP = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_oaep_padding), + ?line Msg = rsa_private_decrypt(OAEP, PrivKey, rsa_pkcs1_oaep_padding), <> = crypto:mpint(Mod), Msg2 = list_to_binary(lists:duplicate(Msg2Len-1, $X)), - ?line NoPad = crypto:rsa_public_encrypt(Msg2, PubKey, rsa_no_padding), - ?line NoPadDec = crypto:rsa_private_decrypt(NoPad, PrivKey, rsa_no_padding), + ?line NoPad = rsa_public_encrypt(Msg2, PubKey, rsa_no_padding), + ?line NoPadDec = rsa_private_decrypt(NoPad, PrivKey, rsa_no_padding), ?line NoPadDec = Msg2, - ShouldBeError = (catch crypto:rsa_public_encrypt(Msg, PubKey, rsa_no_padding)), + ShouldBeError = (catch rsa_public_encrypt(Msg, PubKey, rsa_no_padding)), ?line {'EXIT', {encrypt_failed,_}} = ShouldBeError, -%% ?line SSL = crypto:rsa_public_encrypt(Msg, PubKey, rsa_sslv23_padding), -%% ?line Msg = crypto:rsa_private_decrypt(SSL, PrivKey, rsa_sslv23_padding), +%% ?line SSL = rsa_public_encrypt(Msg, PubKey, rsa_sslv23_padding), +%% ?line Msg = rsa_private_decrypt(SSL, PrivKey, rsa_sslv23_padding), - ?line PKCS1_2 = crypto:rsa_private_encrypt(Msg, PrivKey, rsa_pkcs1_padding), - ?line PKCS1_2Dec = crypto:rsa_public_decrypt(PKCS1_2, PubKey, rsa_pkcs1_padding), + ?line PKCS1_2 = rsa_private_encrypt(Msg, PrivKey, rsa_pkcs1_padding), + ?line PKCS1_2Dec = rsa_public_decrypt(PKCS1_2, PubKey, rsa_pkcs1_padding), io:format("PKCS2Dec ~p~n",[PKCS1_2Dec]), ?line Msg = PKCS1_2Dec, - ?line PKCS1_3 = crypto:rsa_private_encrypt(Msg2, PrivKey, rsa_no_padding), - ?line PKCS1_3Dec = crypto:rsa_public_decrypt(PKCS1_3, PubKey, rsa_no_padding), + ?line PKCS1_3 = rsa_private_encrypt(Msg2, PrivKey, rsa_no_padding), + ?line PKCS1_3Dec = rsa_public_decrypt(PKCS1_3, PubKey, rsa_no_padding), io:format("PKCS2Dec ~p~n",[PKCS1_3Dec]), ?line Msg2 = PKCS1_3Dec, ?line {'EXIT', {encrypt_failed,_}} = - (catch crypto:rsa_private_encrypt(Msg, PrivKey, rsa_no_padding)), + (catch rsa_private_encrypt(Msg, PrivKey, rsa_no_padding)), ok. +rsa_public_encrypt(Msg, Key, Pad) -> + C1 = crypto:rsa_public_encrypt(Msg, Key, Pad), + C2 = crypto:rsa_public_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad), + {C1,C2}. + +rsa_public_decrypt(Msg, Key, Pad) -> + R = crypto:rsa_public_decrypt(Msg, Key, Pad), + R = crypto:rsa_public_decrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad). + +rsa_private_encrypt(Msg, Key, Pad) -> + R = crypto:rsa_private_encrypt(Msg, Key, Pad), + R = crypto:rsa_private_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad). + +rsa_private_decrypt({C1,C2}, Key, Pad) -> + R = crypto:rsa_private_decrypt(C1, Key, Pad), + R = crypto:rsa_private_decrypt(C2, Key, Pad), + R = crypto:rsa_private_decrypt(C1, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad), + R = crypto:rsa_private_decrypt(C2, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad). + dh(doc) -> ["Test dh (Diffie-Hellman) functions."]; -- cgit v1.2.3 From 7030e089d1090e3b9a95c96737b36d6d6fc6ef97 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 16 Apr 2013 11:48:25 +0200 Subject: public_key: Eliminate mpints in rsa_public/private_encrypt/decrypt --- lib/public_key/src/public_key.erl | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 91d33fab42..4b8fda8d40 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -253,10 +253,9 @@ decrypt_private(CipherText, privateExponent = D} = Key, Options) when is_binary(CipherText), - is_integer(N), is_integer(E), is_integer(D), is_list(Options) -> Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - crypto:rsa_private_decrypt(CipherText, old_format_rsa_private_key(Key), Padding). + crypto:rsa_private_decrypt(CipherText, format_rsa_private_key(Key), Padding). %%-------------------------------------------------------------------- -spec decrypt_public(CipherText :: binary(), rsa_public_key() | rsa_private_key()) -> @@ -320,36 +319,25 @@ encrypt_private(PlainText, Options) when is_binary(PlainText), is_integer(N), is_integer(E), is_integer(D), - is_list(Options) -> + is_list(Options) -> Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - crypto:rsa_private_encrypt(PlainText, old_format_rsa_private_key(Key), Padding). - + crypto:rsa_private_encrypt(PlainText, format_rsa_private_key(Key), Padding). format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, privateExponent = D, prime1 = P1, prime2 = P2, exponent1 = E1, exponent2 = E2, coefficient = C}) - when is_integer(P1), is_integer(P2), + when is_integer(N), is_integer(E), is_integer(D), + is_integer(P1), is_integer(P2), is_integer(E1), is_integer(E2), is_integer(C) -> - [K || K <- [E, N, D, P1, P2, E1, E2, C]]; + [E, N, D, P1, P2, E1, E2, C]; format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, - privateExponent = D}) -> - [K || K <- [E, N, D]]. - -old_format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, - privateExponent = D, - prime1 = P1, prime2 = P2, - exponent1 = E1, exponent2 = E2, - coefficient = C}) - when is_integer(P1), is_integer(P2), - is_integer(E1), is_integer(E2), is_integer(C) -> - [crypto:mpint(K) || K <- [E, N, D, P1, P2, E1, E2, C]]; - -old_format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, - privateExponent = D}) -> - [crypto:mpint(K) || K <- [E, N, D]]. + privateExponent = D}) when is_integer(N), + is_integer(E), + is_integer(D) -> + [E, N, D]. %% %% Description: convert a ECPrivate key into resource Key @@ -720,12 +708,12 @@ do_pem_entry_decode({Asn1Type,_, _} = PemEntry, Password) -> encrypt_public(PlainText, N, E, Options)-> Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - crypto:rsa_public_encrypt(PlainText, [crypto:mpint(E),crypto:mpint(N)], + crypto:rsa_public_encrypt(PlainText, [E,N], Padding). decrypt_public(CipherText, N,E, Options) -> Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - crypto:rsa_public_decrypt(CipherText,[crypto:mpint(E), crypto:mpint(N)], + crypto:rsa_public_decrypt(CipherText,[E, N], Padding). path_validation([], #path_validation_state{working_public_key_algorithm -- cgit v1.2.3 From d565a551ff2605c8abca0009ab90fbb7687a4097 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 18 Apr 2013 10:47:52 +0200 Subject: ssl: Make better use of the crypto API Use the functions in crypto that we want to keep in the API. --- lib/ssl/src/ssl_certificate_db.erl | 2 +- lib/ssl/src/ssl_handshake.erl | 4 ++-- lib/ssl/src/ssl_manager.erl | 4 ++-- lib/ssl/src/ssl_record.erl | 10 +--------- lib/ssl/src/ssl_ssl3.erl | 10 +++++----- lib/ssl/src/ssl_tls1.erl | 20 ++++++-------------- 6 files changed, 17 insertions(+), 33 deletions(-) diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl index ff36b5ee26..cdff73336e 100644 --- a/lib/ssl/src/ssl_certificate_db.erl +++ b/lib/ssl/src/ssl_certificate_db.erl @@ -100,7 +100,7 @@ add_trusted_certs(_Pid, {der, DerList}, [CerDb, _,_]) -> {ok, NewRef}; add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache] = Db) -> - MD5 = crypto:md5(File), + MD5 = crypto:hash(md5, File), case lookup_cached_pem(Db, MD5) of [{_Content, Ref}] -> ref_count(Ref, RefDb, 1), diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index bddae820ef..eca36ba650 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -696,8 +696,8 @@ decrypt_premaster_secret(Secret, RSAPrivateKey) -> %% Description: Calculate server key exchange hash %%-------------------------------------------------------------------- server_key_exchange_hash(md5sha, Value) -> - MD5 = crypto:md5(Value), - SHA = crypto:sha(Value), + MD5 = crypto:hash(md5, Value), + SHA = crypto:hash(sha, Value), <>; server_key_exchange_hash(Hash, Value) -> diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index aa9da65bb8..caea528a08 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -103,7 +103,7 @@ connection_init(Trustedcerts, Role) -> %% Description: Cach a pem file and return its content. %%-------------------------------------------------------------------- cache_pem_file(File, DbHandle) -> - MD5 = crypto:md5(File), + MD5 = crypto:hash(md5, File), case ssl_certificate_db:lookup_cached_pem(DbHandle, MD5) of [{Content,_}] -> {ok, Content}; @@ -468,7 +468,7 @@ new_id(Port, Tries, Cache, CacheCb) -> clean_cert_db(Ref, CertDb, RefDb, PemCache, File) -> case ssl_certificate_db:ref_count(Ref, RefDb, 0) of 0 -> - MD5 = crypto:md5(File), + MD5 = crypto:hash(md5, File), case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of [{Content, Ref}] -> ssl_certificate_db:insert(MD5, Content, PemCache); diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index 26aca56739..50b1b2cda9 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -712,12 +712,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_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl index a11c5b8c0c..013c27ebb5 100644 --- a/lib/ssl/src/ssl_ssl3.erl +++ b/lib/ssl/src/ssl_ssl3.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2012. All Rights Reserved. +%% Copyright Ericsson AB 2007-2013. 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 @@ -154,9 +154,9 @@ suites() -> %%-------------------------------------------------------------------- hash(?MD5, Data) -> - crypto:md5(Data); + crypto:hash(md5, Data); hash(?SHA, Data) -> - crypto:sha(Data). + crypto:hash(sha, Data). %%pad_1(?NULL) -> %% ""; @@ -198,6 +198,6 @@ gen(_Secret, _All, Wanted, Len, _C, _N, Acc) when Wanted =< Len -> Block; gen(Secret, All, Wanted, Len, C, N, Acc) -> Prefix = lists:duplicate(N, C), - SHA = crypto:sha([Prefix, All]), - MD5 = crypto:md5([Secret, SHA]), + SHA = crypto:hash(sha, [Prefix, All]), + MD5 = crypto:hash(md5, [Secret, SHA]), gen(Secret, All, Wanted, Len + 16, C+1, N+1, [MD5 | Acc]). diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index 39931ff29f..507b1de904 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -58,8 +58,8 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake) %% verify_data %% PRF(master_secret, finished_label, MD5(handshake_messages) + %% SHA-1(handshake_messages)) [0..11]; - MD5 = crypto:md5(Handshake), - SHA = crypto:sha(Handshake), + MD5 = crypto:hash(md5, Handshake), + SHA = crypto:hash(sha, Handshake), prf(?MD5SHA, MasterSecret, finished_label(Role), [MD5, SHA], 12); finished(Role, Version, PrfAlgo, MasterSecret, Handshake) @@ -77,8 +77,8 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake) -spec certificate_verify(md5sha | sha, integer(), [binary()]) -> binary(). certificate_verify(md5sha, _Version, Handshake) -> - MD5 = crypto:md5(Handshake), - SHA = crypto:sha(Handshake), + MD5 = crypto:hash(md5, Handshake), + SHA = crypto:hash(sha, Handshake), <>; certificate_verify(HashAlgo, _Version, Handshake) -> @@ -248,16 +248,8 @@ suites(Minor) when Minor == 3 -> %%%% HMAC and the Pseudorandom Functions RFC 2246 & 4346 - 5.%%%% hmac_hash(?NULL, _, _) -> <<>>; -hmac_hash(?MD5, Key, Value) -> - crypto:md5_mac(Key, Value); -hmac_hash(?SHA, Key, Value) -> - crypto:sha_mac(Key, Value); -hmac_hash(?SHA256, Key, Value) -> - crypto:sha256_mac(Key, Value); -hmac_hash(?SHA384, Key, Value) -> - crypto:sha384_mac(Key, Value); -hmac_hash(?SHA512, Key, Value) -> - crypto:sha512_mac(Key, Value). +hmac_hash(Alg, Key, Value) -> + crypto:hmac(mac_algo(Alg), Key, Value). mac_algo(?MD5) -> md5; mac_algo(?SHA) -> sha; -- cgit v1.2.3 From dfd9c13f882ef199dfcb830823cb12d83bcc4f10 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 17 Apr 2013 10:28:25 +0200 Subject: ssl & public_key: New public_key API for DH/ECDH/SRP keys --- lib/public_key/src/public_key.erl | 192 +++++++++++++++++++++++++------------- lib/ssl/src/ssl_connection.erl | 104 +++++++-------------- lib/ssl/src/ssl_handshake.erl | 16 ++-- 3 files changed, 171 insertions(+), 141 deletions(-) diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 4b8fda8d40..41ebaef76d 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -34,7 +34,8 @@ decrypt_private/2, decrypt_private/3, encrypt_public/2, encrypt_public/3, decrypt_public/2, decrypt_public/3, - sign/3, verify/4, + sign/3, verify/4, generate_key/1, generate_key/2, + compute_key/2, compute_key/3, pkix_sign/2, pkix_verify/2, pkix_sign_types/1, pkix_is_self_signed/1, @@ -323,58 +324,70 @@ encrypt_private(PlainText, Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), crypto:rsa_private_encrypt(PlainText, format_rsa_private_key(Key), Padding). -format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, - privateExponent = D, - prime1 = P1, prime2 = P2, - exponent1 = E1, exponent2 = E2, - coefficient = C}) - when is_integer(N), is_integer(E), is_integer(D), - is_integer(P1), is_integer(P2), - is_integer(E1), is_integer(E2), is_integer(C) -> - [E, N, D, P1, P2, E1, E2, C]; - -format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, - privateExponent = D}) when is_integer(N), - is_integer(E), - is_integer(D) -> - [E, N, D]. +%%-------------------------------------------------------------------- +-spec generate_key(#'ECPrivateKey'{} | {curve, Name ::atom()} | #'DHParameter'{}) -> {'ECKey', term()} | {binary(), binary()}. +-spec generate_key(#'ECPoint'{}, #'OTPECParameters'{} | {namedCurve, oid()}) -> {'ECKey', term()}. -%% -%% Description: convert a ECPrivate key into resource Key +%% Description: Generates new key(s) %%-------------------------------------------------------------------- -list2int(L) -> - S = length(L) * 8, - <> = erlang:iolist_to_binary(L), - R. +generate_key(#'ECPrivateKey'{} = Key) -> + ec_private_key_to_eckey(Key); -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)}. +generate_key({curve, Name}) -> + %% TODO: Better crypto API + ECDHKey = crypto:ec_key_new(Name), + crypto:ec_key_generate(ECDHKey), + crypto:ec_key_to_term(ECDHKey); -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)}. +generate_key(#'DHParameter'{prime = P, base = G}) -> + crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]); + +generate_key({dh, Prime, Base}) when is_binary(Prime), is_binary(Base) -> + %% TODO: Is mpint could be normal binary! + crypto:dh_generate_key([Prime, Base]); + +generate_key({srp, Version, Generator, Prime}) when is_binary(Generator), is_binary(Prime) -> + crypto:srp_generate_key(Generator, Prime, Version); + +generate_key({srp, Version, Verifier, Generator, Prime}) when is_binary(Verifier), is_binary(Generator), is_binary(Prime) -> + crypto:srp_generate_key(Verifier, Generator, Prime, Version). + +generate_key(#'ECPoint'{} = Key, Params) -> + %% TODO: Better crypto API + ECKey = ec_public_key_to_eckey({Key,Params}), + ECClntKey = crypto:term_to_ec_key(ECKey), + crypto:ec_key_generate(ECClntKey), + crypto:ec_key_to_term(ECClntKey). %%-------------------------------------------------------------------- +-spec compute_key(#'ECPoint'{}, {'ECKey', binary()}) -> binary(). +-spec compute_key(OthersKey ::binary(), MyKey::binary() | {binary(), binary()}, + {dh, binary(), binary()} | + {srp, atom(), binary(), binary()} | + {srp, string(), string(), binary(), atom(), binary(), binary()}) + -> binary(). +%% Description: Compute shared secret +%%-------------------------------------------------------------------- +compute_key(#'ECPoint'{point = Point}, Term) -> + %% TODO: Better crypto API + ECKey = crypto:term_to_ec_key(Term), + crypto:ecdh_compute_key(ECKey, Point). + +compute_key(OthersKey, MyKey, {dh, Prime, Base}) when is_binary(OthersKey), + is_binary(MyKey), + is_binary(Prime), + is_binary(Base) -> + %% TODO: Is mpint could be binary! + crypto:dh_compute_key(OthersKey, MyKey, [Prime, Base]); + +compute_key(ClientPub, {ServerPub, ServerPriv}, {srp, Version, Verifier, Prime}) -> + crypto:srp_compute_key(Verifier, Prime, ClientPub, ServerPub, ServerPriv, Version); + +compute_key(ServerPub, {ClientPub, ClientPriv}, {srp, Username, Password, Salt, Version, Prime, Generator}) -> + DerivedKey = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), + crypto:srp_compute_key(DerivedKey, Prime, Generator, ClientPub, ClientPriv, ServerPub, Version). +%%-------------------------------------------------------------------- -spec pkix_sign_types(SignatureAlg::oid()) -> %% Relevant dsa digest type is subpart of rsa digest type { DigestType :: rsa_digest_type(), @@ -430,14 +443,15 @@ sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = 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:sign(ecdsa, DigestType, Digest, Key); +sign({digest,_} = Digest, DigestType, Key = #'ECPrivateKey'{}) -> + ECDHKey = ec_private_key_to_eckey(Key), + ECKey = crypto:term_to_ec_key(ECDHKey), + crypto:sign(ecdsa, DigestType, Digest, ECKey); -sign(PlainText, DigestType, {'ECKey', Key}) -> - crypto:sign(ecdsa, DigestType, PlainText, Key); +sign(PlainText, DigestType, Key = #'ECPrivateKey'{}) -> + ECDHKey = ec_private_key_to_eckey(Key), + ECKey = crypto:term_to_ec_key(ECDHKey), + crypto:sign(ecdsa, DigestType, PlainText, ECKey); %% Backwards compatible sign(Digest, none, #'DSAPrivateKey'{} = Key) -> @@ -462,17 +476,15 @@ verify({digest,_} = Digest, sha = DigestType, Signature, {Key, #'Dss-Parms'{p = when is_integer(Key), is_binary(Signature) -> crypto:verify(dss, DigestType, Digest, Signature, [P, Q, G, Key]); -verify({digest,_} = Digest, DigestType, Signature, {'ECKey', Key}) -> - crypto:verify(ecdsa, DigestType, Digest, Signature, Key); - -verify(PlainText, DigestType, Signature, Key = #'ECPrivateKey'{}) -> - verify(PlainText, DigestType, Signature, ec_private_key_to_eckey(Key)); +verify(Digest, DigestType, Signature, Key = #'ECPrivateKey'{}) -> + ECDHKey = ec_private_key_to_eckey(Key), + ECKey = crypto:term_to_ec_key(ECDHKey), + crypto:verify(ecdsa, DigestType, Digest, Signature, ECKey); -verify(PlainText, DigestType, Signature, Key = {#'ECPoint'{}, _}) -> - verify(PlainText, DigestType, Signature, ec_public_key_to_eckey(Key)); - -verify(PlainText, DigestType, Signature, {'ECKey', Key}) -> - crypto:verify(ecdsa, DigestType, PlainText, Signature, Key); +verify(Digest, DigestType, Signature, Key = {#'ECPoint'{}, _}) -> + ECDHKey = ec_public_key_to_eckey(Key), + ECKey = crypto:term_to_ec_key(ECDHKey), + crypto:verify(ecdsa, DigestType, Digest, Signature, ECKey); %% Backwards compatibility verify(Digest, none, Signature, {_, #'Dss-Parms'{}} = Key ) -> @@ -910,3 +922,57 @@ combine(CRL, DeltaCRLs) -> end, lists:foldl(Fun, hd(Deltas), tl(Deltas)) end. + +format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, + privateExponent = D, + prime1 = P1, prime2 = P2, + exponent1 = E1, exponent2 = E2, + coefficient = C}) + when is_integer(N), is_integer(E), is_integer(D), + is_integer(P1), is_integer(P2), + is_integer(E1), is_integer(E2), is_integer(C) -> + [E, N, D, P1, P2, E1, E2, C]; + +format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, + privateExponent = D}) when is_integer(N), + is_integer(E), + is_integer(D) -> + [E, N, D]. + +%% +%% Description: convert a ECPrivate key into resource Key +%%-------------------------------------------------------------------- +list2int(L) -> + S = length(L) * 8, + <> = 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, + {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, + {ECCurve, undefined, ECPoint}. + %%{'ECKey', crypto:term_to_ec_key(Key)}. diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index aa02c47a3d..dc9ab89331 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -685,8 +685,8 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl 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 + diffie_hellman_keys = ECDHKey} = State0) -> + case ec_dh_master_secret(ECDHKey, #'ECPoint'{point = ClientPublicEcDhPoint}, State0) of #state{} = State1 -> {Record, State} = next_record(State1), next_state(certify, cipher, Record, State); @@ -1325,28 +1325,9 @@ private_key(#'PrivateKeyInfo'{privateKeyAlgorithm = 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, - <> = erlang:iolist_to_binary(L), - R. - -spec(file_error(_,_) -> no_return()). file_error(File, Throw) -> case Throw of @@ -1396,20 +1377,10 @@ handle_peer_cert(PeerCert, PublicKeyInfo, Session#session{peer_certificate = PeerCert}, public_key_info = PublicKeyInfo}, 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); + {?'id-ecPublicKey', #'ECPoint'{point = _ECPoint} = PublicKey, PublicKeyParams} -> + Keys = public_key:generate_key(PublicKey, PublicKeyParams), + State3 = State1#state{diffie_hellman_keys = Keys}, + ec_dh_master_secret(Keys, PublicKey, State3); _ -> State1 end, @@ -1633,7 +1604,7 @@ key_exchange(#state{role = server, key_algorithm = rsa} = State) -> State; key_exchange(#state{role = server, key_algorithm = Algo, hashsign_algorithm = HashSignAlgo, - diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params, + diffie_hellman_params = #'DHParameter'{} = Params, private_key = PrivateKey, connection_states = ConnectionStates0, negotiated_version = Version, @@ -1644,7 +1615,7 @@ key_exchange(#state{role = server, key_algorithm = Algo, when Algo == dhe_dss; Algo == dhe_rsa; Algo == dh_anon -> - Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]), + Keys = public_key:generate_key(Params), ConnectionState = ssl_record:pending_connection_state(ConnectionStates0, read), SecParams = ConnectionState#connection_state.security_parameters, @@ -1663,7 +1634,8 @@ key_exchange(#state{role = server, key_algorithm = Algo, 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}; + ECDH = public_key:generate_key(Key), + State#state{diffie_hellman_keys = ECDH}; key_exchange(#state{role = server, key_algorithm = Algo, hashsign_algorithm = HashSignAlgo, private_key = PrivateKey, @@ -1675,19 +1647,14 @@ key_exchange(#state{role = server, key_algorithm = Algo, } = 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}, + ECDHKey = public_key:generate_key({curve, default_curve(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, {ecdh, Keys, + Msg = ssl_handshake:key_exchange(server, Version, {ecdh, ECDHKey, HashSignAlgo, ClientRandom, ServerRandom, PrivateKey}), @@ -1695,7 +1662,7 @@ key_exchange(#state{role = server, key_algorithm = Algo, encode_handshake(Msg, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), State#state{connection_states = ConnectionStates, - diffie_hellman_keys = Keys, + diffie_hellman_keys = ECDHKey, tls_handshake_history = Handshake1}; key_exchange(#state{role = server, key_algorithm = psk, @@ -1729,7 +1696,7 @@ key_exchange(#state{role = server, key_algorithm = psk, 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, + diffie_hellman_params = #'DHParameter'{} = Params, private_key = PrivateKey, connection_states = ConnectionStates0, negotiated_version = Version, @@ -1737,7 +1704,7 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk, socket = Socket, transport_cb = Transport } = State) -> - Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]), + Keys = public_key:generate_key(Params), ConnectionState = ssl_record:pending_connection_state(ConnectionStates0, read), SecParams = ConnectionState#connection_state.security_parameters, @@ -2084,12 +2051,8 @@ server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDh 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); + Key = public_key:generate_key({curve, ECCurve}), + ec_dh_master_secret(Key, #'ECPoint'{point = ECServerPubKey}, State#state{diffie_hellman_keys = Key}); server_master_secret(#server_psk_params{ hint = IdentityHint}, @@ -2126,18 +2089,18 @@ dh_master_secret(Prime, Base, PublicDhKey, undefined, State) -> PMpint = mpint_binary(Prime), GMpint = mpint_binary(Base), Keys = {_, PrivateDhKey} = - crypto:dh_generate_key([PMpint,GMpint]), + public_key:generate_key({dh, PMpint,GMpint}), dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys}); dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) -> PremasterSecret = - crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey, - [PMpint, GMpint]), + public_key:compute_key(mpint_binary(PublicDhKey), PrivateDhKey, + {dh, PMpint, GMpint}), master_from_premaster_secret(PremasterSecret, State). ec_dh_master_secret(ECKey, ECPoint, State) -> PremasterSecret = - crypto:ecdh_compute_key(ECKey, ECPoint), + public_key:compute_key(ECPoint, ECKey), master_from_premaster_secret(PremasterSecret, State). handle_psk_identity(_PSKIdentity, LookupFun) @@ -2163,7 +2126,7 @@ 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]), + public_key:generate_key({dh, PMpint, GMpint}), dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys}); @@ -2172,8 +2135,8 @@ dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey, 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]), + public_key:compute_key(mpint_binary(PublicDhKey), PrivateDhKey, + {dh, PMpint, GMpint}), DHLen = erlang:byte_size(DHSecret), Len = erlang:byte_size(PSK), PremasterSecret = <>, @@ -2202,7 +2165,7 @@ generate_srp_server_keys(_SrpParams, 10) -> generate_srp_server_keys(SrpParams = #srp_user{generator = Generator, prime = Prime, verifier = Verifier}, N) -> - case crypto:srp_generate_key(Verifier, Generator, Prime, '6a') of + case public_key:generate_key({srp, '6a', Verifier, Generator, Prime}) of error -> generate_srp_server_keys(SrpParams, N+1); Keys -> @@ -2213,7 +2176,7 @@ generate_srp_client_keys(_Generator, _Prime, 10) -> ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); generate_srp_client_keys(Generator, Prime, N) -> - case crypto:srp_generate_key(Generator, Prime, '6a') of + case public_key:generate_key({srp, '6a', Generator, Prime}) of error -> generate_srp_client_keys(Generator, Prime, N+1); Keys -> @@ -2234,8 +2197,8 @@ handle_srp_identity(Username, {Fun, UserState}) -> throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)) end. -server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = {ServerPub, ServerPriv}}) -> - case crypto:srp_compute_key(Verifier, Prime, ClientPub, ServerPub, ServerPriv, '6a') of +server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = ServerKey}) -> + case public_key:compute_key(ClientPub, ServerKey, {srp, '6a', Verifier, Prime}) of error -> ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); PremasterSecret -> @@ -2248,14 +2211,13 @@ client_srp_master_secret(Generator, Prime, Salt, ServerPub, undefined, State) -> Keys = generate_srp_client_keys(Generator, Prime, 0), client_srp_master_secret(Generator, Prime, Salt, ServerPub, Keys, State#state{srp_keys = Keys}); -client_srp_master_secret(Generator, Prime, Salt, ServerPub, {ClientPub, ClientPriv}, +client_srp_master_secret(Generator, Prime, Salt, ServerPub, ClientKeys, #state{ssl_options = SslOpts} = State) -> case ssl_srp_primes:check_srp_params(Generator, Prime) of ok -> {Username, Password} = SslOpts#ssl_options.srp_identity, - DerivedKey = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), - - case crypto:srp_compute_key(DerivedKey, Prime, Generator, ClientPub, ClientPriv, ServerPub, '6a') of + case public_key:compute_key(ServerPub, ClientKeys, {srp, Username, Password, Salt, + '6a', Prime, Generator}) of error -> ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); PremasterSecret -> @@ -3122,3 +3084,7 @@ handle_close_alert(Data, StateName, State0) -> _ -> ok end. + +default_curve(_) -> + %%TODO: select prefered curve from extension + secp256k1. diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index eca36ba650..f736de3327 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -418,8 +418,7 @@ key_exchange(client, _Version, {dh, <>}) -> dh_public = PublicKey} }; -key_exchange(client, _Version, {ecdh, {'ECKey', ECDHKey}}) -> - {_, _, ECPublicKey} = crypto:ec_key_to_term(ECDHKey), +key_exchange(client, _Version, {ecdh, {_,_,ECPublicKey}}) -> #client_key_exchange{ exchange_keys = #client_ec_diffie_hellman_public{ dh_public = ECPublicKey} @@ -453,8 +452,8 @@ key_exchange(client, _Version, {srp, PublicKey}) -> }; key_exchange(server, Version, {dh, {<>, _}, - #'DHParameter'{prime = P, base = G}, - HashSign, ClientRandom, ServerRandom, PrivateKey}) -> + #'DHParameter'{prime = P, base = G}, + HashSign, ClientRandom, ServerRandom, PrivateKey}) -> <> = crypto:mpint(P), <> = crypto:mpint(G), ServerDHParams = #server_dh_params{dh_p = PBin, @@ -462,10 +461,9 @@ key_exchange(server, Version, {dh, {<>, _}, 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}, +key_exchange(server, Version, {ecdh, {ECCurve, _, ECPublicKey}, HashSign, ClientRandom, ServerRandom, + PrivateKey}) -> + ServerECParams = #server_ecdh_params{curve = ECCurve, public = ECPublicKey}, enc_server_key_exchange(Version, ServerECParams, HashSign, ClientRandom, ServerRandom, PrivateKey); @@ -1700,7 +1698,7 @@ digitally_signed(_Version, Hash, HashAlgo, #'DSAPrivateKey'{} = Key) -> digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) -> public_key:encrypt_private(Hash, Key, [{rsa_pad, rsa_pkcs1_padding}]); -digitally_signed(_Version, Hash, HashAlgo, {'ECKey', _} = Key) -> +digitally_signed(_Version, Hash, HashAlgo, Key) -> public_key:sign({digest, Hash}, HashAlgo, Key). calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) -> -- cgit v1.2.3 From 826ff38deec221e306b2f4a9ee529fae1dbbedf7 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 19 Apr 2013 15:47:47 +0200 Subject: ssl & public_key: Improved handling ECDH keys --- lib/public_key/src/public_key.erl | 163 ++++++++++++++++++-------------------- lib/ssl/src/ssl_connection.erl | 35 ++++---- lib/ssl/src/ssl_handshake.erl | 9 ++- lib/ssl/test/erl_make_certs.erl | 4 +- 4 files changed, 99 insertions(+), 112 deletions(-) diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 41ebaef76d..06bffeea76 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -34,7 +34,8 @@ decrypt_private/2, decrypt_private/3, encrypt_public/2, encrypt_public/3, decrypt_public/2, decrypt_public/3, - sign/3, verify/4, generate_key/1, generate_key/2, + sign/3, verify/4, + generate_key/1, compute_key/2, compute_key/3, pkix_sign/2, pkix_verify/2, pkix_sign_types/1, @@ -326,18 +327,14 @@ encrypt_private(PlainText, %%-------------------------------------------------------------------- -spec generate_key(#'ECPrivateKey'{} | {curve, Name ::atom()} | #'DHParameter'{}) -> {'ECKey', term()} | {binary(), binary()}. --spec generate_key(#'ECPoint'{}, #'OTPECParameters'{} | {namedCurve, oid()}) -> {'ECKey', term()}. - %% Description: Generates new key(s) %%-------------------------------------------------------------------- -generate_key(#'ECPrivateKey'{} = Key) -> - ec_private_key_to_eckey(Key); - generate_key({curve, Name}) -> %% TODO: Better crypto API ECDHKey = crypto:ec_key_new(Name), crypto:ec_key_generate(ECDHKey), - crypto:ec_key_to_term(ECDHKey); + Term = crypto:ec_key_to_term(ECDHKey), + ec_key(Term); generate_key(#'DHParameter'{prime = P, base = G}) -> crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]); @@ -350,27 +347,33 @@ generate_key({srp, Version, Generator, Prime}) when is_binary(Generator), is_bin crypto:srp_generate_key(Generator, Prime, Version); generate_key({srp, Version, Verifier, Generator, Prime}) when is_binary(Verifier), is_binary(Generator), is_binary(Prime) -> - crypto:srp_generate_key(Verifier, Generator, Prime, Version). + crypto:srp_generate_key(Verifier, Generator, Prime, Version); -generate_key(#'ECPoint'{} = Key, Params) -> +generate_key(Params) -> %% TODO: Better crypto API - ECKey = ec_public_key_to_eckey({Key,Params}), - ECClntKey = crypto:term_to_ec_key(ECKey), + Name = ec_curve_spec(Params), + ECClntKey = crypto:ec_key_new(Name), + %% ECDHKey = format_ecdh_key(Params), + %% ECClntKey = crypto:term_to_ec_key(ECDHKey), crypto:ec_key_generate(ECClntKey), - crypto:ec_key_to_term(ECClntKey). + Term = crypto:ec_key_to_term(ECClntKey), + ec_key(Term, Params). %%-------------------------------------------------------------------- --spec compute_key(#'ECPoint'{}, {'ECKey', binary()}) -> binary(). +-spec compute_key(#'ECPoint'{}, #'ECPrivateKey'{} | crypto:ecdh_key()) -> binary(). -spec compute_key(OthersKey ::binary(), MyKey::binary() | {binary(), binary()}, {dh, binary(), binary()} | - {srp, atom(), binary(), binary()} | - {srp, string(), string(), binary(), atom(), binary(), binary()}) + {srp,'3'|'6'| '6a' , binary(), binary()} | + {srp, string(), string(), binary(), '3'|'6'| '6a', binary(), binary()}) -> binary(). %% Description: Compute shared secret %%-------------------------------------------------------------------- -compute_key(#'ECPoint'{point = Point}, Term) -> +compute_key(PubKey, #'ECPrivateKey'{} = PrivateKey) -> + compute_key(PubKey, format_ecdh_key(PrivateKey)); + +compute_key(#'ECPoint'{point = Point}, ECDHKeys) -> %% TODO: Better crypto API - ECKey = crypto:term_to_ec_key(Term), + ECKey = crypto:term_to_ec_key(ECDHKeys), crypto:ecdh_compute_key(ECKey, Point). compute_key(OthersKey, MyKey, {dh, Prime, Base}) when is_binary(OthersKey), @@ -428,30 +431,16 @@ pkix_sign_types(?'ecdsa-with-SHA512') -> dsa_private_key()) -> Signature :: binary(). %% Description: Create digital signature. %%-------------------------------------------------------------------- -sign({digest,_}=Digest, DigestType, Key = #'RSAPrivateKey'{}) -> - crypto:sign(rsa, DigestType, Digest, format_rsa_private_key(Key)); - -sign(PlainText, DigestType, Key = #'RSAPrivateKey'{}) -> - crypto:sign(rsa, DigestType, PlainText, format_rsa_private_key(Key)); - -sign({digest,_}=Digest, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) -> - crypto:sign(dss, sha, Digest, [P, Q, G, X]); +sign(DigestOrPlainText, DigestType, Key = #'RSAPrivateKey'{}) -> + crypto:sign(rsa, DigestType, DigestOrPlainText, format_rsa_private_key(Key)); -sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) -> - crypto:sign(dss, sha, PlainText, [P, Q, G, X]); +sign(DigestOrPlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) -> + crypto:sign(dss, sha, DigestOrPlainText, [P, Q, G, X]); -sign(Digest, DigestType, Key = {?'id-ecPublicKey', _, _}) -> - sign(Digest, DigestType, ec_public_key_to_eckey(Key)); - -sign({digest,_} = Digest, DigestType, Key = #'ECPrivateKey'{}) -> - ECDHKey = ec_private_key_to_eckey(Key), - ECKey = crypto:term_to_ec_key(ECDHKey), - crypto:sign(ecdsa, DigestType, Digest, ECKey); - -sign(PlainText, DigestType, Key = #'ECPrivateKey'{}) -> - ECDHKey = ec_private_key_to_eckey(Key), +sign(DigestOrPlainText, DigestType, Key = #'ECPrivateKey'{}) -> + ECDHKey = format_ecdh_key(Key), ECKey = crypto:term_to_ec_key(ECDHKey), - crypto:sign(ecdsa, DigestType, PlainText, ECKey); + crypto:sign(ecdsa, DigestType, DigestOrPlainText, ECKey); %% Backwards compatible sign(Digest, none, #'DSAPrivateKey'{} = Key) -> @@ -463,36 +452,28 @@ sign(Digest, none, #'DSAPrivateKey'{} = Key) -> | dsa_public_key()) -> boolean(). %% Description: Verifies a digital signature. %%-------------------------------------------------------------------- -verify({digest,_} = Digest, DigestType, Signature, - #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) -> - crypto:verify(rsa, DigestType, Digest, Signature, [Exp, Mod]); - -verify(PlainText, DigestType, Signature, +verify(DigestOrPlainText, DigestType, Signature, #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) -> - crypto:verify(rsa, DigestType, PlainText, Signature, + crypto:verify(rsa, DigestType, DigestOrPlainText, Signature, [Exp, Mod]); -verify({digest,_} = Digest, sha = DigestType, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) - when is_integer(Key), is_binary(Signature) -> - crypto:verify(dss, DigestType, Digest, Signature, [P, Q, G, Key]); - verify(Digest, DigestType, Signature, Key = #'ECPrivateKey'{}) -> - ECDHKey = ec_private_key_to_eckey(Key), + ECDHKey = format_ecdh_key(Key), ECKey = crypto:term_to_ec_key(ECDHKey), crypto:verify(ecdsa, DigestType, Digest, Signature, ECKey); -verify(Digest, DigestType, Signature, Key = {#'ECPoint'{}, _}) -> - ECDHKey = ec_public_key_to_eckey(Key), +verify(DigestOrPlaintext, DigestType, Signature, Key = {#'ECPoint'{}, _}) -> + ECDHKey = format_ecdh_key(Key), ECKey = crypto:term_to_ec_key(ECDHKey), - crypto:verify(ecdsa, DigestType, Digest, Signature, ECKey); + crypto:verify(ecdsa, DigestType, DigestOrPlaintext, Signature, ECKey); %% Backwards compatibility verify(Digest, none, Signature, {_, #'Dss-Parms'{}} = Key ) -> verify({digest,Digest}, sha, Signature, Key); -verify(PlainText, sha = DigestType, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) - when is_integer(Key), is_binary(PlainText), is_binary(Signature) -> - crypto:verify(dss, DigestType, PlainText, Signature, [P, Q, G, Key]). +verify(DigestOrPlainText, sha = DigestType, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) + when is_integer(Key), is_binary(Signature) -> + crypto:verify(dss, DigestType, DigestOrPlainText, Signature, [P, Q, G, Key]). %%-------------------------------------------------------------------- -spec pkix_sign(#'OTPTBSCertificate'{}, @@ -939,40 +920,46 @@ format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, is_integer(D) -> [E, N, D]. -%% -%% Description: convert a ECPrivate key into resource Key -%%-------------------------------------------------------------------- +format_ecdh_key(#'ECPrivateKey'{privateKey = PrivKey, + parameters = Param, + publicKey = _}) -> + ECCurve = ec_curve_spec(Param), + {ECCurve, list2int(PrivKey), undefined}; + +format_ecdh_key({#'ECPoint'{point = Point}, Param}) -> + ECCurve = ec_curve_spec(Param), + {ECCurve, undefined, Point}. + +ec_curve_spec( #'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}; +ec_curve_spec({namedCurve, OID}) -> + pubkey_cert_records:namedCurves(OID). + +ec_key({Curve, PrivateKey, PubKey}) when is_atom(Curve) -> + #'ECPrivateKey'{version = 1, + privateKey = int2list(PrivateKey), + parameters = {namedCurve, pubkey_cert_records:namedCurves(Curve)}, + publicKey = {0, PubKey}}. + +ec_key({Curve, PrivateKey, PubKey}, _Params) when is_atom(Curve) -> + #'ECPrivateKey'{version = 1, + privateKey = int2list(PrivateKey), + parameters = {namedCurve, pubkey_cert_records:namedCurves(Curve)}, + publicKey = {0, PubKey}}; + +ec_key({_Curve, PrivateKey, PubKey}, Params) -> + #'ECPrivateKey'{version = 1, + privateKey = int2list(PrivateKey), + parameters = Params, + publicKey = {0, PubKey}}. + list2int(L) -> S = length(L) * 8, <> = 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, - {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, - {ECCurve, undefined, ECPoint}. - %%{'ECKey', crypto:term_to_ec_key(Key)}. +int2list(I) -> + L = (length(integer_to_list(I, 16)) + 1) div 2, + binary_to_list(<>). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index dc9ab89331..4d64cd8523 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1378,9 +1378,9 @@ handle_peer_cert(PeerCert, PublicKeyInfo, public_key_info = PublicKeyInfo}, State2 = case PublicKeyInfo of {?'id-ecPublicKey', #'ECPoint'{point = _ECPoint} = PublicKey, PublicKeyParams} -> - Keys = public_key:generate_key(PublicKey, PublicKeyParams), - State3 = State1#state{diffie_hellman_keys = Keys}, - ec_dh_master_secret(Keys, PublicKey, State3); + ECDHKey = public_key:generate_key(PublicKeyParams), + State3 = State1#state{diffie_hellman_keys = ECDHKey}, + ec_dh_master_secret(ECDHKey, PublicKey, State3); _ -> State1 end, @@ -1615,13 +1615,13 @@ key_exchange(#state{role = server, key_algorithm = Algo, when Algo == dhe_dss; Algo == dhe_rsa; Algo == dh_anon -> - Keys = public_key:generate_key(Params), + DHKeys = public_key:generate_key(Params), 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, {dh, Keys, Params, + Msg = ssl_handshake:key_exchange(server, Version, {dh, DHKeys, Params, HashSignAlgo, ClientRandom, ServerRandom, PrivateKey}), @@ -1629,13 +1629,12 @@ key_exchange(#state{role = server, key_algorithm = Algo, encode_handshake(Msg, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), State#state{connection_states = ConnectionStates, - diffie_hellman_keys = Keys, + diffie_hellman_keys = DHKeys, tls_handshake_history = Handshake}; key_exchange(#state{role = server, private_key = Key, key_algorithm = Algo} = State) when Algo == ecdh_ecdsa; Algo == ecdh_rsa -> - ECDH = public_key:generate_key(Key), - State#state{diffie_hellman_keys = ECDH}; + State#state{diffie_hellman_keys = Key}; key_exchange(#state{role = server, key_algorithm = Algo, hashsign_algorithm = HashSignAlgo, private_key = PrivateKey, @@ -1648,13 +1647,13 @@ key_exchange(#state{role = server, key_algorithm = Algo, when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa; Algo == ecdh_anon -> - ECDHKey = public_key:generate_key({curve, default_curve(State)}), + ECDHKeys = public_key:generate_key({curve, default_curve(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, {ecdh, ECDHKey, + Msg = ssl_handshake:key_exchange(server, Version, {ecdh, ECDHKeys, HashSignAlgo, ClientRandom, ServerRandom, PrivateKey}), @@ -1662,7 +1661,7 @@ key_exchange(#state{role = server, key_algorithm = Algo, encode_handshake(Msg, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), State#state{connection_states = ConnectionStates, - diffie_hellman_keys = ECDHKey, + diffie_hellman_keys = ECDHKeys, tls_handshake_history = Handshake1}; key_exchange(#state{role = server, key_algorithm = psk, @@ -1704,13 +1703,13 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk, socket = Socket, transport_cb = Transport } = State) -> - Keys = public_key:generate_key(Params), + DHKeys = public_key:generate_key(Params), 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, + Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, DHKeys, Params, HashSignAlgo, ClientRandom, ServerRandom, PrivateKey}), @@ -1718,7 +1717,7 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk, encode_handshake(Msg, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), State#state{connection_states = ConnectionStates, - diffie_hellman_keys = Keys, + diffie_hellman_keys = DHKeys, tls_handshake_history = Handshake}; key_exchange(#state{role = server, key_algorithm = rsa_psk, @@ -2051,8 +2050,8 @@ server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDh server_master_secret(#server_ecdh_params{curve = ECCurve, public = ECServerPubKey}, State) -> - Key = public_key:generate_key({curve, ECCurve}), - ec_dh_master_secret(Key, #'ECPoint'{point = ECServerPubKey}, State#state{diffie_hellman_keys = Key}); + ECDHKeys = public_key:generate_key({curve, ECCurve}), + ec_dh_master_secret(ECDHKeys, #'ECPoint'{point = ECServerPubKey}, State#state{diffie_hellman_keys = ECDHKeys}); server_master_secret(#server_psk_params{ hint = IdentityHint}, @@ -2098,9 +2097,9 @@ dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) -> {dh, PMpint, GMpint}), master_from_premaster_secret(PremasterSecret, State). -ec_dh_master_secret(ECKey, ECPoint, State) -> +ec_dh_master_secret(ECDHKeys, ECPoint, State) -> PremasterSecret = - public_key:compute_key(ECPoint, ECKey), + public_key:compute_key(ECPoint, ECDHKeys), master_from_premaster_secret(PremasterSecret, State). handle_psk_identity(_PSKIdentity, LookupFun) diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index f736de3327..cde3e6fc66 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -418,7 +418,7 @@ key_exchange(client, _Version, {dh, <>}) -> dh_public = PublicKey} }; -key_exchange(client, _Version, {ecdh, {_,_,ECPublicKey}}) -> +key_exchange(client, _Version, {ecdh, #'ECPrivateKey'{publicKey = {0, ECPublicKey}}}) -> #client_key_exchange{ exchange_keys = #client_ec_diffie_hellman_public{ dh_public = ECPublicKey} @@ -461,7 +461,8 @@ key_exchange(server, Version, {dh, {<>, _}, enc_server_key_exchange(Version, ServerDHParams, HashSign, ClientRandom, ServerRandom, PrivateKey); -key_exchange(server, Version, {ecdh, {ECCurve, _, ECPublicKey}, HashSign, ClientRandom, ServerRandom, +key_exchange(server, Version, {ecdh, #'ECPrivateKey'{publicKey = {0, ECPublicKey}, + parameters = ECCurve}, HashSign, ClientRandom, ServerRandom, PrivateKey}) -> ServerECParams = #server_ecdh_params{curve = ECCurve, public = ECPublicKey}, enc_server_key_exchange(Version, ServerECParams, HashSign, @@ -1513,10 +1514,10 @@ enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) -> GLen = byte_size(G), YLen = byte_size(Y), <>; -enc_server_key(#server_ecdh_params{curve = ECCurve, public = ECPubKey}) -> +enc_server_key(#server_ecdh_params{curve = {namedCurve, ECCurve}, public = ECPubKey}) -> %%TODO: support arbitrary keys KLen = size(ECPubKey), - <>; enc_server_key(#server_psk_params{hint = PskIdentityHint}) -> Len = byte_size(PskIdentityHint), diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl index f37928be85..f8d086513b 100644 --- a/lib/ssl/test/erl_make_certs.erl +++ b/lib/ssl/test/erl_make_certs.erl @@ -114,8 +114,8 @@ verify_signature(DerEncodedCert, DerKey, _KeyParams) -> #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} -> 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) + parameters = Params, publicKey = {0, PubKey}} -> + public_key:pkix_verify(DerEncodedCert, {#'ECPoint'{point = PubKey}, Params}) end. %%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -- cgit v1.2.3 From f5902d53588784d95674e07055fc2ef0d6fd0ed0 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 19 Apr 2013 22:07:55 +0200 Subject: ssl: Filter out ECC cipher suites when openssl is buggy Even in "normal" (not explicitly ECC tests) cases we need to filter out ECC ciper suites as they are preferd. --- lib/ssl/test/ssl_test_lib.erl | 12 ++++++++++++ lib/ssl/test/ssl_to_openssl_SUITE.erl | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 3b63886a07..6069a9da95 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -982,3 +982,15 @@ is_sane_ecc(openssl) -> end; is_sane_ecc(_) -> true. + +cipher_restriction(Config) -> + case is_sane_ecc(openssl) of + false -> + Opts = proplists:get_value(server_opts, Config), + NewConfig = proplists:delete(server_opts, Config), + Restricted0 = ssl:cipher_suites() -- ecdsa_suites(), + Restricted = Restricted0 -- ecdh_rsa_suites(), + [{server_opts, [{ciphers, Restricted} | Opts]} | NewConfig]; + true -> + Config + end. diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index fc88a8f23c..075b4b1ec4 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -107,7 +107,8 @@ init_per_suite(Config0) -> ct:log("Make certs ~p~n", [Result]), Config1 = ssl_test_lib:make_dsa_cert(Config0), Config = ssl_test_lib:cert_options(Config1), - [{watchdog, Dog} | Config] + NewConfig = [{watchdog, Dog} | Config], + ssl_test_lib:cipher_restriction(NewConfig) catch _:_ -> {skip, "Crypto did not start"} end -- cgit v1.2.3 From 3155ca5b47149a214b101f6c0b84cdcd0400a30b Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 22 Apr 2013 21:43:44 +0200 Subject: crypto, public_key & ssl: Change API to hide resource format for EC KEY --- lib/crypto/c_src/crypto.c | 6 +++--- lib/crypto/src/crypto.erl | 27 ++++++++++++++++++++------- lib/crypto/test/crypto_SUITE.erl | 17 ++++++----------- lib/public_key/src/public_key.erl | 36 +++++++----------------------------- lib/ssl/test/erl_make_certs.erl | 4 +--- 5 files changed, 37 insertions(+), 53 deletions(-) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index a8027bb079..e953eb960f 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -235,7 +235,7 @@ static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T 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[]); +static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); /* helpers */ @@ -361,7 +361,7 @@ static ErlNifFunc nif_funcs[] = { {"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} + {"ecdh_compute_key_nif", 2, ecdh_compute_key_nif} }; #if defined(HAVE_EC) @@ -3452,7 +3452,7 @@ static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER (_OthersPublicKey, _MyPrivateKey) (_OthersPublicKey, _MyEC_Point) */ -static ERL_NIF_TERM ecdh_compute_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { #if defined(HAVE_EC) ERL_NIF_TERM ret; diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 57ddf3fbac..543d589d7e 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -67,8 +67,8 @@ -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([sign/4, verify/5, ecdh_compute_key/2]). +-export([ecdh_generate_key/1, ecdh_compute_key/2]). +-export([sign/4, verify/5]). -export([dh_generate_parameters/2, dh_check/1]). %% Testing see below @@ -115,8 +115,8 @@ hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, info, rc2_cbc_encrypt, rc2_cbc_decrypt, srp_generate_key, srp_compute_key, - ec_key_new, ec_key_to_term, term_to_ec_key, ec_key_generate, - sign, verify, ecdh_compute_key, + ecdh_generate_key, ecdh_compute_key, + sign, verify, info_lib, algorithms]). -type mpint() :: binary(). @@ -859,7 +859,7 @@ verify(rsa, Type, DataOrDigest, Signature, Key) -> Bool -> Bool end; verify(ecdsa, Type, DataOrDigest, Signature, Key) -> - case ecdsa_verify_nif(Type, DataOrDigest, Signature, map_ensure_int_as_bin(Key)) of + case ecdsa_verify_nif(Type, DataOrDigest, Signature, term_to_ec_key(Key)) of notsup -> erlang:error(notsup); Bool -> Bool end. @@ -921,7 +921,7 @@ sign(dss, Type, DataOrDigest, Key) -> Sign -> Sign end; sign(ecdsa, Type, DataOrDigest, Key) -> - case ecdsa_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of + case ecdsa_sign_nif(Type, DataOrDigest, term_to_ec_key(Key)) of error -> erlang:error(badkey, [Type,DataOrDigest,Key]); Sign -> Sign end. @@ -1229,6 +1229,16 @@ srp_compute_key(Verifier, Prime, ClientPublic, ServerPublic, ServerPrivate, Vers -spec ec_key_new(ec_named_curve()) -> ec_key_res(). ec_key_new(_Curve) -> ?nif_stub. +ecdh_generate_key(Curve) when is_atom(Curve) -> + ECKey = ec_key_new(Curve), + ec_key_generate(ECKey), + ec_key_to_term(ECKey); +ecdh_generate_key(Key) -> + ECKey = term_to_ec_key(Key), + ec_key_generate(ECKey), + ec_key_to_term(ECKey). + + -spec ec_key_generate(ec_key_res()) -> ok | error. ec_key_generate(_Key) -> ?nif_stub. @@ -1277,7 +1287,10 @@ term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub. -spec ecdh_compute_key(ec_key_res(), ec_key_res() | ec_point()) -> binary(). -ecdh_compute_key(_Others, _My) -> ?nif_stub. +ecdh_compute_key(Others, My) -> + ecdh_compute_key_nif(term_to_ec_key(Others), My). + +ecdh_compute_key_nif(_Others, _My) -> ?nif_stub. %% LOCAL FUNCTIONS diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 09898efd49..55db09d9dd 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1887,12 +1887,7 @@ ec(Config) when is_list(Config) -> 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), + D2 = crypto:ecdh_generate_key(sect113r2), %%TODO: find a published test case for a EC key @@ -1933,13 +1928,13 @@ ec_do() -> 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), + %%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:sign(ecdsa, sha, Msg, L2), - ?line true = crypto:verify(ecdsa, sha, Msg, Sign, L2), - ?line false = crypto:verify(ecdsa, sha, Msg, <<10,20>>, L2), + Sign = crypto:sign(ecdsa, sha, Msg, D2), + ?line true = crypto:verify(ecdsa, sha, Msg, Sign, D2), + ?line false = crypto:verify(ecdsa, sha, Msg, <<10,20>>, D2), ok. diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 06bffeea76..d1484c5b2b 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -330,10 +330,7 @@ encrypt_private(PlainText, %% Description: Generates new key(s) %%-------------------------------------------------------------------- generate_key({curve, Name}) -> - %% TODO: Better crypto API - ECDHKey = crypto:ec_key_new(Name), - crypto:ec_key_generate(ECDHKey), - Term = crypto:ec_key_to_term(ECDHKey), + Term = crypto:ecdh_generate_key(Name), ec_key(Term); generate_key(#'DHParameter'{prime = P, base = G}) -> @@ -350,13 +347,8 @@ generate_key({srp, Version, Verifier, Generator, Prime}) when is_binary(Verifier crypto:srp_generate_key(Verifier, Generator, Prime, Version); generate_key(Params) -> - %% TODO: Better crypto API - Name = ec_curve_spec(Params), - ECClntKey = crypto:ec_key_new(Name), - %% ECDHKey = format_ecdh_key(Params), - %% ECClntKey = crypto:term_to_ec_key(ECDHKey), - crypto:ec_key_generate(ECClntKey), - Term = crypto:ec_key_to_term(ECClntKey), + Curve = ec_curve_spec(Params), + Term = crypto:ecdh_generate_key(Curve), ec_key(Term, Params). %%-------------------------------------------------------------------- @@ -372,9 +364,7 @@ compute_key(PubKey, #'ECPrivateKey'{} = PrivateKey) -> compute_key(PubKey, format_ecdh_key(PrivateKey)); compute_key(#'ECPoint'{point = Point}, ECDHKeys) -> - %% TODO: Better crypto API - ECKey = crypto:term_to_ec_key(ECDHKeys), - crypto:ecdh_compute_key(ECKey, Point). + crypto:ecdh_compute_key(ECDHKeys, Point). compute_key(OthersKey, MyKey, {dh, Prime, Base}) when is_binary(OthersKey), is_binary(MyKey), @@ -439,8 +429,7 @@ sign(DigestOrPlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) -> sign(DigestOrPlainText, DigestType, Key = #'ECPrivateKey'{}) -> ECDHKey = format_ecdh_key(Key), - ECKey = crypto:term_to_ec_key(ECDHKey), - crypto:sign(ecdsa, DigestType, DigestOrPlainText, ECKey); + crypto:sign(ecdsa, DigestType, DigestOrPlainText, ECDHKey); %% Backwards compatible sign(Digest, none, #'DSAPrivateKey'{} = Key) -> @@ -457,15 +446,9 @@ verify(DigestOrPlainText, DigestType, Signature, crypto:verify(rsa, DigestType, DigestOrPlainText, Signature, [Exp, Mod]); -verify(Digest, DigestType, Signature, Key = #'ECPrivateKey'{}) -> - ECDHKey = format_ecdh_key(Key), - ECKey = crypto:term_to_ec_key(ECDHKey), - crypto:verify(ecdsa, DigestType, Digest, Signature, ECKey); - verify(DigestOrPlaintext, DigestType, Signature, Key = {#'ECPoint'{}, _}) -> ECDHKey = format_ecdh_key(Key), - ECKey = crypto:term_to_ec_key(ECDHKey), - crypto:verify(ecdsa, DigestType, DigestOrPlaintext, Signature, ECKey); + crypto:verify(ecdsa, DigestType, DigestOrPlaintext, Signature, ECDHKey); %% Backwards compatibility verify(Digest, none, Signature, {_, #'Dss-Parms'{}} = Key ) -> @@ -511,12 +494,7 @@ pkix_verify(DerCert, #'RSAPublicKey'{} = RSAKey) {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert), 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', _}) +pkix_verify(DerCert, Key = {#'ECPoint'{}, _}) when is_binary(DerCert) -> {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert), verify(PlainText, DigestType, Signature, Key). diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl index f8d086513b..c0cf5005ed 100644 --- a/lib/ssl/test/erl_make_certs.erl +++ b/lib/ssl/test/erl_make_certs.erl @@ -409,9 +409,7 @@ int2list(I) -> binary_to_list(<>). gen_ec2(CurveId) -> - Key = crypto:ec_key_new(CurveId), - crypto:ec_key_generate(Key), - {_Curve, PrivKey, PubKey} = crypto:ec_key_to_term(Key), + {_Curve, PrivKey, PubKey} = crypto:ecdh_generate_key(CurveId), #'ECPrivateKey'{version = 1, privateKey = int2list(PrivKey), -- cgit v1.2.3 From d9d8d008728b4522c62ed90540b1d90097fddb68 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 23 Apr 2013 15:58:36 +0200 Subject: ssl: Remove dependency on internal public_key function Avoid unneccessary conversion as the input format is an oid (according to ASN1 spec) we do not need to handle it as an atom in ssl. --- lib/ssl/src/ssl_connection.erl | 8 +-- lib/ssl/src/ssl_handshake.erl | 11 ++-- lib/ssl/src/ssl_tls1.erl | 114 ++++++++++++++++++++--------------------- 3 files changed, 65 insertions(+), 68 deletions(-) diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 4d64cd8523..2a32bdf066 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1647,7 +1647,7 @@ key_exchange(#state{role = server, key_algorithm = Algo, when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa; Algo == ecdh_anon -> - ECDHKeys = public_key:generate_key({curve, default_curve(State)}), + ECDHKeys = public_key:generate_key(select_curve(State)), ConnectionState = ssl_record:pending_connection_state(ConnectionStates0, read), SecParams = ConnectionState#connection_state.security_parameters, @@ -2050,7 +2050,7 @@ server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDh server_master_secret(#server_ecdh_params{curve = ECCurve, public = ECServerPubKey}, State) -> - ECDHKeys = public_key:generate_key({curve, ECCurve}), + ECDHKeys = public_key:generate_key(ECCurve), ec_dh_master_secret(ECDHKeys, #'ECPoint'{point = ECServerPubKey}, State#state{diffie_hellman_keys = ECDHKeys}); server_master_secret(#server_psk_params{ @@ -3084,6 +3084,6 @@ handle_close_alert(Data, StateName, State0) -> ok end. -default_curve(_) -> +select_curve(_) -> %%TODO: select prefered curve from extension - secp256k1. + {namedCurve, ?secp256k1}. diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index cde3e6fc66..b40f944d28 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -1243,7 +1243,7 @@ dec_server_key(<> = KeyStruct, ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, Version) -> - Params = #server_ecdh_params{curve = ssl_tls1:ec_curve_id2nid(CurveID), + Params = #server_ecdh_params{curve = {namedCurve, ssl_tls1:enum_to_oid(CurveID)}, public = ECPoint}, {BinMsg, HashSign, Signature} = dec_ske_params(PointLen + 4, KeyStruct, Version), #server_key_params{params = Params, @@ -1330,7 +1330,7 @@ dec_hello_extensions(<>, Acc) -> EllipticCurveListLen = Len - 2, <> = ExtData, - EllipticCurves = [ssl_tls1:ec_curve_id2nid(X) || <> <= EllipticCurveList], + EllipticCurves = [ssl_tls1:enum_to_oid(X) || <> <= EllipticCurveList], dec_hello_extensions(Rest, [{elliptic_curves, #elliptic_curves{elliptic_curve_list = EllipticCurves}} | Acc]); @@ -1517,7 +1517,7 @@ enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) -> enc_server_key(#server_ecdh_params{curve = {namedCurve, ECCurve}, public = ECPubKey}) -> %%TODO: support arbitrary keys KLen = size(ECPubKey), - <>; enc_server_key(#server_psk_params{hint = PskIdentityHint}) -> Len = byte_size(PskIdentityHint), @@ -1601,7 +1601,7 @@ enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest Len = InfoLen +1, enc_hello_extensions(Rest, <>); enc_hello_extensions([#elliptic_curves{elliptic_curve_list = EllipticCurves} | Rest], Acc) -> - EllipticCurveList = << <<(ssl_tls1:ec_nid2curve_id(X)):16>> || X <- EllipticCurves>>, + EllipticCurveList = << <<(ssl_tls1:oid_to_enum(X)):16>> || X <- EllipticCurves>>, ListLen = byte_size(EllipticCurveList), Len = ListLen + 2, enc_hello_extensions(Rest, < Enc = fun(#'OTPCertificate'{tbsCertificate=TBSCert}) -> OTPSubj = TBSCert#'OTPTBSCertificate'.subject, DNEncodedBin = public_key:pkix_encode('Name', OTPSubj, otp), - %%Subj = public_key:pkix_transform(OTPSubj, encode), - %% {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj), - %% DNEncodedBin = iolist_to_binary(DNEncoded), DNEncodedLen = byte_size(DNEncodedBin), <> end, diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index 507b1de904..f8fd9efd07 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -30,7 +30,7 @@ -export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7, setup_keys/8, suites/1, prf/5, - ecc_curves/1, ec_nid2curve_id/1, ec_curve_id2nid/1]). + ecc_curves/1, oid_to_enum/1, enum_to_oid/1]). %%==================================================================== %% Internal application API @@ -328,61 +328,61 @@ finished_label(server) -> %% 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]. + [?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. +oid_to_enum(?sect163k1) -> 1; +oid_to_enum(?sect163r1) -> 2; +oid_to_enum(?sect163r2) -> 3; +oid_to_enum(?sect193r1) -> 4; +oid_to_enum(?sect193r2) -> 5; +oid_to_enum(?sect233k1) -> 6; +oid_to_enum(?sect233r1) -> 7; +oid_to_enum(?sect239k1) -> 8; +oid_to_enum(?sect283k1) -> 9; +oid_to_enum(?sect283r1) -> 10; +oid_to_enum(?sect409k1) -> 11; +oid_to_enum(?sect409r1) -> 12; +oid_to_enum(?sect571k1) -> 13; +oid_to_enum(?sect571r1) -> 14; +oid_to_enum(?secp160k1) -> 15; +oid_to_enum(?secp160r1) -> 16; +oid_to_enum(?secp160r2) -> 17; +oid_to_enum(?secp192k1) -> 18; +oid_to_enum(?secp192r1) -> 19; +oid_to_enum(?secp224k1) -> 20; +oid_to_enum(?secp224r1) -> 21; +oid_to_enum(?secp256k1) -> 22; +oid_to_enum(?secp256r1) -> 23; +oid_to_enum(?secp384r1) -> 24; +oid_to_enum(?secp521r1) -> 25. + +enum_to_oid(1) -> ?sect163k1; +enum_to_oid(2) -> ?sect163r1; +enum_to_oid(3) -> ?sect163r2; +enum_to_oid(4) -> ?sect193r1; +enum_to_oid(5) -> ?sect193r2; +enum_to_oid(6) -> ?sect233k1; +enum_to_oid(7) -> ?sect233r1; +enum_to_oid(8) -> ?sect239k1; +enum_to_oid(9) -> ?sect283k1; +enum_to_oid(10) -> ?sect283r1; +enum_to_oid(11) -> ?sect409k1; +enum_to_oid(12) -> ?sect409r1; +enum_to_oid(13) -> ?sect571k1; +enum_to_oid(14) -> ?sect571r1; +enum_to_oid(15) -> ?secp160k1; +enum_to_oid(16) -> ?secp160r1; +enum_to_oid(17) -> ?secp160r2; +enum_to_oid(18) -> ?secp192k1; +enum_to_oid(19) -> ?secp192r1; +enum_to_oid(20) -> ?secp224k1; +enum_to_oid(21) -> ?secp224r1; +enum_to_oid(22) -> ?secp256k1; +enum_to_oid(23) -> ?secp256r1; +enum_to_oid(24) -> ?secp384r1; +enum_to_oid(25) -> ?secp521r1. -- cgit v1.2.3 From 2c1b0c61e2f6177d755e5bee9a865db646b6dca1 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 23 Apr 2013 16:51:01 +0200 Subject: crypto, public_key: Switch places of ecdh_compute_key arguments --- lib/crypto/c_src/crypto.c | 13 +++---------- lib/crypto/src/crypto.erl | 4 ++-- lib/public_key/src/public_key.erl | 2 +- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index e953eb960f..5781c1de78 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -3466,21 +3466,14 @@ static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF EC_POINT *my_ecpoint; EC_KEY *other_ecdh = NULL; - if (!enif_get_resource(env, argv[0], res_type_ec_key, (void **)&other_key)) + if (!enif_get_resource(env, argv[1], 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 (!term2point(env, argv[0], group, &my_ecpoint)) { + goto out_err; } if ((other_ecdh = EC_KEY_new()) == NULL diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 543d589d7e..6f4092ea74 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -1286,9 +1286,9 @@ term_to_ec_key({Curve, PrivKey, PubKey}) -> term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub. --spec ecdh_compute_key(ec_key_res(), ec_key_res() | ec_point()) -> binary(). +-spec ecdh_compute_key(ec_point(), ec_key_res()) -> binary(). ecdh_compute_key(Others, My) -> - ecdh_compute_key_nif(term_to_ec_key(Others), My). + ecdh_compute_key_nif(Others, term_to_ec_key(My)). ecdh_compute_key_nif(_Others, _My) -> ?nif_stub. diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index d1484c5b2b..b11a225761 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -364,7 +364,7 @@ compute_key(PubKey, #'ECPrivateKey'{} = PrivateKey) -> compute_key(PubKey, format_ecdh_key(PrivateKey)); compute_key(#'ECPoint'{point = Point}, ECDHKeys) -> - crypto:ecdh_compute_key(ECDHKeys, Point). + crypto:ecdh_compute_key(Point, ECDHKeys). compute_key(OthersKey, MyKey, {dh, Prime, Base}) when is_binary(OthersKey), is_binary(MyKey), -- cgit v1.2.3 From c47e4babacedbac46d441228b514b2e650392cf7 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 23 Apr 2013 16:54:36 +0200 Subject: crypto: Combine ec_key_new into ecdh_generate_key and remove curve from the returned tuple. --- lib/crypto/c_src/crypto.c | 439 +++++++++++++++------------------------ lib/crypto/src/crypto.erl | 29 +-- lib/crypto/test/crypto_SUITE.erl | 3 +- 3 files changed, 171 insertions(+), 300 deletions(-) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 5781c1de78..99e5cb1c1f 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -229,7 +229,6 @@ static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar 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[]); @@ -267,6 +266,11 @@ static void hmac_sha512(unsigned char *key, int klen, unsigned char *dbuf, int dlen, unsigned char *hmacbuf); #endif +#ifdef HAVE_EC +static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg); +static int term2point(ErlNifEnv* env, ERL_NIF_TERM term, + EC_GROUP *group, EC_POINT **pptr); +#endif static int library_refc = 0; /* number of users of this dynamic library */ @@ -355,7 +359,6 @@ static ErlNifFunc nif_funcs[] = { {"bf_ecb_crypt", 3, bf_ecb_crypt}, {"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}, @@ -2850,249 +2853,10 @@ static int term2curve_id(ERL_NIF_TERM 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[]) +static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg) { -#if defined(HAVE_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(HAVE_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, &ret); - BN_bn2bin(bn, ptr); - - 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(HAVE_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(HAVE_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(HAVE_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; @@ -3104,28 +2868,17 @@ static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T EC_GROUP *group = NULL; EC_POINT *point = NULL; - if (!(argv[1] == atom_undefined || get_bn_from_bin(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; - } - + if (enif_is_atom(env, curve_arg)) { + nid = term2curve_id(curve_arg); + if (nid == 0) + return NULL; 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_bin(env, curve[3], &bn_order) - && (curve[4] != atom_none && get_bn_from_bin(env, curve[4], &cofactor))) { + else if (enif_is_tuple(env, curve_arg) + && enif_get_tuple(env,curve_arg,&c_arity,&curve) + && c_arity == 5 + && get_bn_from_bin(env, curve[3], &bn_order) + && (curve[4] != atom_none && get_bn_from_bin(env, curve[4], &cofactor))) { //* {Field, Prime, Point, Order, CoFactor} = Curve */ int f_arity = -1; @@ -3244,10 +2997,146 @@ static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T EC_KEY_set_group(key, group); } else { - printf("#3\n"); + printf("#3\n"); + goto out_err; + } + + + goto out; + +out_err: + if (key) EC_KEY_free(key); + key = NULL; + +out: + /* some OpenSSL structures are mem-dup'ed into the key, + so we have to free our copies here */ + 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 key; +} + + +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, &ret); + BN_bn2bin(bn, ptr); + + 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(HAVE_EC) + struct nif_ec_key *obj; + const EC_GROUP *group; + const EC_POINT *public_key; + const BIGNUM *priv_key = NULL; + ERL_NIF_TERM pub_key = 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 (public_key) + pub_key = point2term(env, group, public_key, EC_KEY_get_conv_form(obj->key)); + } + + return enif_make_tuple2(env, bn2term(env, priv_key), pub_key); +#else + return atom_notsup; +#endif +} + +#if defined(HAVE_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(HAVE_EC) + ERL_NIF_TERM ret; + EC_KEY *key = NULL; + BIGNUM *priv_key = NULL; + EC_POINT *pub_key = NULL; + struct nif_ec_key *obj; + EC_GROUP *group = NULL; + + if (!(argv[1] == atom_undefined || get_bn_from_bin(env, argv[1], &priv_key)) + || !(argv[2] == atom_undefined || enif_is_binary(env, argv[2]))) { + printf("#1\n"); goto out_err; } + key = ec_key_new(env, argv[0]); + if (!key) { printf("#4\n"); goto out_err; @@ -3300,11 +3189,6 @@ out: 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 @@ -3315,15 +3199,20 @@ out: static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { #if defined(HAVE_EC) - struct nif_ec_key *obj; + EC_KEY *key = ec_key_new(env, argv[0]); - 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; + if (key && EC_KEY_generate_key(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 atom_error; + return enif_make_badarg(env); #else return atom_notsup; #endif diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 6f4092ea74..999a65042d 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -1226,39 +1226,20 @@ srp_compute_key(Verifier, Prime, ClientPublic, ServerPublic, ServerPrivate, Vers %% %% EC %% --spec ec_key_new(ec_named_curve()) -> ec_key_res(). -ec_key_new(_Curve) -> ?nif_stub. -ecdh_generate_key(Curve) when is_atom(Curve) -> - ECKey = ec_key_new(Curve), - ec_key_generate(ECKey), - ec_key_to_term(ECKey); -ecdh_generate_key(Key) -> - ECKey = term_to_ec_key(Key), - ec_key_generate(ECKey), - ec_key_to_term(ECKey). +-spec ecdh_generate_key(ec_curve()) -> ec_key() | error. +ecdh_generate_key(Curve) -> + ec_key_to_term(ec_key_generate(Curve)). --spec ec_key_generate(ec_key_res()) -> ok | error. ec_key_generate(_Key) -> ?nif_stub. -nif_prime_to_term({prime_field, Prime}) -> - {prime_field, bin_to_int(Prime)}; -nif_prime_to_term(PrimeField) -> - PrimeField. -nif_curve_to_term({A, B, Seed}) -> - {bin_to_int(A), bin_to_int(B), Seed}. -nif_curve_parameters_to_term({PrimeField, Curve, BasePoint, Order, CoFactor}) -> - {nif_prime_to_term(PrimeField), nif_curve_to_term(Curve), BasePoint, bin_to_int(Order), bin_to_int(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), bin_to_int(PrivKey), PubKey}; + {PrivKey, PubKey} -> + {bin_to_int(PrivKey), PubKey}; _ -> erlang:error(conversion_failed) end. diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 55db09d9dd..384d15c68c 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1887,7 +1887,8 @@ ec(Config) when is_list(Config) -> ec_do() -> %% test for a name curve - D2 = crypto:ecdh_generate_key(sect113r2), + {D2_priv, D2_pub} = crypto:ecdh_generate_key(sect113r2), + D2 = {sect113r2, D2_priv, D2_pub}, %%TODO: find a published test case for a EC key -- cgit v1.2.3 From e05c31eaa6b4f09ac220bf88d78376d7ef8722d7 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Mon, 6 May 2013 15:49:15 +0200 Subject: crypto: Fix ec_key resource to be upgradeable --- lib/crypto/c_src/crypto.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 99e5cb1c1f..08c6d4dbc5 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -621,7 +621,8 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info) res_type_ec_key = enif_open_resource_type(env,NULL,"crypto.EC_KEY", ec_key_dtor, - ERL_NIF_RT_CREATE, NULL); + ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, + NULL); #endif init_digest_types(env); -- cgit v1.2.3 From 8537e256d5bb250f6e798d521deef16907a4e526 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 24 Apr 2013 09:24:02 +0200 Subject: public_key: use new crypto --- lib/public_key/src/public_key.erl | 12 +++--------- lib/ssl/test/erl_make_certs.erl | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index b11a225761..ee5c5e8552 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -331,7 +331,7 @@ encrypt_private(PlainText, %%-------------------------------------------------------------------- generate_key({curve, Name}) -> Term = crypto:ecdh_generate_key(Name), - ec_key(Term); + ec_key(Term, Name); generate_key(#'DHParameter'{prime = P, base = G}) -> crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]); @@ -916,19 +916,13 @@ ec_curve_spec( #'OTPECParameters'{fieldID = FieldId, curve = PCurve, base = Base ec_curve_spec({namedCurve, OID}) -> pubkey_cert_records:namedCurves(OID). -ec_key({Curve, PrivateKey, PubKey}) when is_atom(Curve) -> - #'ECPrivateKey'{version = 1, - privateKey = int2list(PrivateKey), - parameters = {namedCurve, pubkey_cert_records:namedCurves(Curve)}, - publicKey = {0, PubKey}}. - -ec_key({Curve, PrivateKey, PubKey}, _Params) when is_atom(Curve) -> +ec_key({PrivateKey, PubKey}, Curve) when is_atom(Curve) -> #'ECPrivateKey'{version = 1, privateKey = int2list(PrivateKey), parameters = {namedCurve, pubkey_cert_records:namedCurves(Curve)}, publicKey = {0, PubKey}}; -ec_key({_Curve, PrivateKey, PubKey}, Params) -> +ec_key({PrivateKey, PubKey}, Params) -> #'ECPrivateKey'{version = 1, privateKey = int2list(PrivateKey), parameters = Params, diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl index c0cf5005ed..8743cb13fa 100644 --- a/lib/ssl/test/erl_make_certs.erl +++ b/lib/ssl/test/erl_make_certs.erl @@ -409,7 +409,7 @@ int2list(I) -> binary_to_list(<>). gen_ec2(CurveId) -> - {_Curve, PrivKey, PubKey} = crypto:ecdh_generate_key(CurveId), + {PrivKey, PubKey} = crypto:ecdh_generate_key(CurveId), #'ECPrivateKey'{version = 1, privateKey = int2list(PrivKey), -- cgit v1.2.3 From abfa5825923caad09691313f39e843b70aee8f19 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 24 Apr 2013 10:51:51 +0200 Subject: ssl & public_key: API refinement Change API so public_key:generate_key/compute_key are only called with "public_key arguments" otherwhise crypto functions can be called explicitly. --- lib/public_key/src/public_key.erl | 55 +++++++++++---------------------------- lib/ssl/src/ssl_connection.erl | 37 ++++++++++++++------------ 2 files changed, 35 insertions(+), 57 deletions(-) diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index ee5c5e8552..df4f38f507 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -326,38 +326,19 @@ encrypt_private(PlainText, crypto:rsa_private_encrypt(PlainText, format_rsa_private_key(Key), Padding). %%-------------------------------------------------------------------- --spec generate_key(#'ECPrivateKey'{} | {curve, Name ::atom()} | #'DHParameter'{}) -> {'ECKey', term()} | {binary(), binary()}. -%% Description: Generates new key(s) +-spec generate_key(#'DHParameter'{} | {namedCurve, Name ::atom()} | #'OTPECParameters'{}) -> {Public::binary(), Private::binary()}. +%% Description: Generates a new keypair %%-------------------------------------------------------------------- -generate_key({curve, Name}) -> - Term = crypto:ecdh_generate_key(Name), - ec_key(Term, Name); - generate_key(#'DHParameter'{prime = P, base = G}) -> crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]); - -generate_key({dh, Prime, Base}) when is_binary(Prime), is_binary(Base) -> - %% TODO: Is mpint could be normal binary! - crypto:dh_generate_key([Prime, Base]); - -generate_key({srp, Version, Generator, Prime}) when is_binary(Generator), is_binary(Prime) -> - crypto:srp_generate_key(Generator, Prime, Version); - -generate_key({srp, Version, Verifier, Generator, Prime}) when is_binary(Verifier), is_binary(Generator), is_binary(Prime) -> - crypto:srp_generate_key(Verifier, Generator, Prime, Version); - -generate_key(Params) -> - Curve = ec_curve_spec(Params), - Term = crypto:ecdh_generate_key(Curve), - ec_key(Term, Params). +generate_key({namedCurve, _} = Params) -> + ec_generate_key(Params); +generate_key(#'OTPECParameters'{} = Params) -> + ec_generate_key(Params). %%-------------------------------------------------------------------- --spec compute_key(#'ECPoint'{}, #'ECPrivateKey'{} | crypto:ecdh_key()) -> binary(). --spec compute_key(OthersKey ::binary(), MyKey::binary() | {binary(), binary()}, - {dh, binary(), binary()} | - {srp,'3'|'6'| '6a' , binary(), binary()} | - {srp, string(), string(), binary(), '3'|'6'| '6a', binary(), binary()}) - -> binary(). +-spec compute_key(#'ECPoint'{} , #'ECPrivateKey'{}) -> binary(). +-spec compute_key(OthersKey ::binary(), MyKey::binary(), #'DHParameter'{}) -> binary(). %% Description: Compute shared secret %%-------------------------------------------------------------------- compute_key(PubKey, #'ECPrivateKey'{} = PrivateKey) -> @@ -366,19 +347,8 @@ compute_key(PubKey, #'ECPrivateKey'{} = PrivateKey) -> compute_key(#'ECPoint'{point = Point}, ECDHKeys) -> crypto:ecdh_compute_key(Point, ECDHKeys). -compute_key(OthersKey, MyKey, {dh, Prime, Base}) when is_binary(OthersKey), - is_binary(MyKey), - is_binary(Prime), - is_binary(Base) -> - %% TODO: Is mpint could be binary! - crypto:dh_compute_key(OthersKey, MyKey, [Prime, Base]); - -compute_key(ClientPub, {ServerPub, ServerPriv}, {srp, Version, Verifier, Prime}) -> - crypto:srp_compute_key(Verifier, Prime, ClientPub, ServerPub, ServerPriv, Version); - -compute_key(ServerPub, {ClientPub, ClientPriv}, {srp, Username, Password, Salt, Version, Prime, Generator}) -> - DerivedKey = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), - crypto:srp_compute_key(DerivedKey, Prime, Generator, ClientPub, ClientPriv, ServerPub, Version). +compute_key(PubKey, PrivKey, #'DHParameter'{prime = P, base = G}) -> + crypto:dh_compute_key(PubKey, PrivKey, [crypto:mpint(P), crypto:mpint(G)]). %%-------------------------------------------------------------------- -spec pkix_sign_types(SignatureAlg::oid()) -> @@ -898,6 +868,11 @@ format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, is_integer(D) -> [E, N, D]. +ec_generate_key(Params) -> + Curve = ec_curve_spec(Params), + Term = crypto:ecdh_generate_key(Curve), + ec_key(Term, Params). + format_ecdh_key(#'ECPrivateKey'{privateKey = PrivKey, parameters = Param, publicKey = _}) -> diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 2a32bdf066..750604c8b6 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -673,9 +673,9 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey}, #state{negotiated_version = Version, diffie_hellman_params = #'DHParameter'{prime = P, - base = G}, + base = G} = Params, diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) -> - case dh_master_secret(crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of + case dh_master_secret(Params, ClientPublicDhKey, ServerDhPrivateKey, State0) of #state{} = State1 -> {Record, State} = next_record(State1), next_state(certify, cipher, Record, State); @@ -2084,17 +2084,20 @@ master_from_premaster_secret(PremasterSecret, Alert end. +dh_master_secret(#'DHParameter'{} = Params, OtherPublicDhKey, MyPrivateKey, State) -> + PremasterSecret = + public_key:compute_key(mpint_binary(OtherPublicDhKey), MyPrivateKey, Params), + master_from_premaster_secret(PremasterSecret, State). + dh_master_secret(Prime, Base, PublicDhKey, undefined, State) -> PMpint = mpint_binary(Prime), GMpint = mpint_binary(Base), - Keys = {_, PrivateDhKey} = - public_key:generate_key({dh, PMpint,GMpint}), + Keys = {_, PrivateDhKey} = crypto:dh_generate_key([PMpint, GMpint]), dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys}); dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) -> PremasterSecret = - public_key:compute_key(mpint_binary(PublicDhKey), PrivateDhKey, - {dh, PMpint, GMpint}), + crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey, [PMpint, GMpint]), master_from_premaster_secret(PremasterSecret, State). ec_dh_master_secret(ECDHKeys, ECPoint, State) -> @@ -2125,7 +2128,7 @@ dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, undefined, State) - PMpint = mpint_binary(Prime), GMpint = mpint_binary(Base), Keys = {_, PrivateDhKey} = - public_key:generate_key({dh, PMpint, GMpint}), + crypto:dh_generate_key([PMpint, GMpint]), dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys}); @@ -2134,8 +2137,8 @@ dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey, case handle_psk_identity(PSKIdentity, SslOpts#ssl_options.user_lookup_fun) of {ok, PSK} when is_binary(PSK) -> DHSecret = - public_key:compute_key(mpint_binary(PublicDhKey), PrivateDhKey, - {dh, PMpint, GMpint}), + crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey, + [PMpint, GMpint]), DHLen = erlang:byte_size(DHSecret), Len = erlang:byte_size(PSK), PremasterSecret = <>, @@ -2164,7 +2167,7 @@ generate_srp_server_keys(_SrpParams, 10) -> generate_srp_server_keys(SrpParams = #srp_user{generator = Generator, prime = Prime, verifier = Verifier}, N) -> - case public_key:generate_key({srp, '6a', Verifier, Generator, Prime}) of + case crypto:srp_generate_key(Verifier, Generator, Prime, '6a') of error -> generate_srp_server_keys(SrpParams, N+1); Keys -> @@ -2175,7 +2178,7 @@ generate_srp_client_keys(_Generator, _Prime, 10) -> ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); generate_srp_client_keys(Generator, Prime, N) -> - case public_key:generate_key({srp, '6a', Generator, Prime}) of + case crypto:srp_generate_key(Generator, Prime, '6a') of error -> generate_srp_client_keys(Generator, Prime, N+1); Keys -> @@ -2196,8 +2199,8 @@ handle_srp_identity(Username, {Fun, UserState}) -> throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)) end. -server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = ServerKey}) -> - case public_key:compute_key(ClientPub, ServerKey, {srp, '6a', Verifier, Prime}) of +server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = {ServerPub, ServerPriv}}) -> + case crypto:srp_compute_key(Verifier, Prime, ClientPub, ServerPub, ServerPriv, '6a') of error -> ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); PremasterSecret -> @@ -2210,13 +2213,13 @@ client_srp_master_secret(Generator, Prime, Salt, ServerPub, undefined, State) -> Keys = generate_srp_client_keys(Generator, Prime, 0), client_srp_master_secret(Generator, Prime, Salt, ServerPub, Keys, State#state{srp_keys = Keys}); -client_srp_master_secret(Generator, Prime, Salt, ServerPub, ClientKeys, - #state{ssl_options = SslOpts} = State) -> +client_srp_master_secret(Generator, Prime, Salt, ServerPub, {ClientPub, ClientPriv}, + #state{ssl_options = SslOpts} = State) -> case ssl_srp_primes:check_srp_params(Generator, Prime) of ok -> {Username, Password} = SslOpts#ssl_options.srp_identity, - case public_key:compute_key(ServerPub, ClientKeys, {srp, Username, Password, Salt, - '6a', Prime, Generator}) of + DerivedKey = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), + case crypto:srp_compute_key(DerivedKey, Prime, Generator, ClientPub, ClientPriv, ServerPub, '6a') of error -> ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); PremasterSecret -> -- cgit v1.2.3 From 94cafd5217f6c295cc53c4354a40ca672d3acc0b Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 24 Apr 2013 10:55:46 +0200 Subject: ssl: test case fix --- lib/ssl/test/ssl_test_lib.erl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 6069a9da95..6b082b4eec 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -983,14 +983,16 @@ is_sane_ecc(openssl) -> is_sane_ecc(_) -> true. -cipher_restriction(Config) -> +cipher_restriction(Config0) -> case is_sane_ecc(openssl) of false -> - Opts = proplists:get_value(server_opts, Config), - NewConfig = proplists:delete(server_opts, Config), + Opts = proplists:get_value(server_opts, Config0), + Config1 = proplists:delete(server_opts, Config0), + VerOpts = proplists:get_value(server_verification_opts, Config1), + Config = proplists:delete(server_verification_opts, Config1), Restricted0 = ssl:cipher_suites() -- ecdsa_suites(), Restricted = Restricted0 -- ecdh_rsa_suites(), - [{server_opts, [{ciphers, Restricted} | Opts]} | NewConfig]; + [{server_opts, [{ciphers, Restricted} | Opts]}, {server_verification_opts, [{ciphers, Restricted} | VerOpts] } | Config]; true -> - Config + Config0 end. -- cgit v1.2.3 From 12e72ac76d2f94fd78beeb58f27105d8007cdeb0 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 25 Apr 2013 09:35:29 +0200 Subject: ssl: Improve extention handling --- lib/ssl/src/ssl_connection.erl | 3 +- lib/ssl/src/ssl_handshake.erl | 95 +++++++++++++++++++++++++----------------- 2 files changed, 58 insertions(+), 40 deletions(-) diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 750604c8b6..25a293f125 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -98,7 +98,8 @@ terminated = false, % allow_renegotiate = true, expecting_next_protocol_negotiation = false :: boolean(), - next_protocol = undefined :: undefined | binary() + next_protocol = undefined :: undefined | binary(), + client_ecc % {Curves, PointFmt} }). -define(DEFAULT_DIFFIE_HELLMAN_PARAMS, diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index b40f944d28..598877abff 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -173,52 +173,27 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version, ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION) end; -hello(#client_hello{client_version = ClientVersion, random = Random, - cipher_suites = CipherSuites, - renegotiation_info = Info, - srp = SRP, - ec_point_formats = EcPointFormats0, - elliptic_curves = EllipticCurves0} = Hello, - #ssl_options{versions = Versions, - secure_renegotiate = SecureRenegotation} = SslOpts, +hello(#client_hello{client_version = ClientVersion} = Hello, + #ssl_options{versions = Versions} = SslOpts, {Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) -> -%% TODO: select hash and signature algorithm + %% TODO: select hash and signature algorithm Version = select_version(ClientVersion, Versions), case ssl_record:is_acceptable_version(Version, Versions) of true -> %% TODO: need to take supported Curves into Account when selecting the CipherSuite.... %% if whe have an ECDSA cert with an unsupported curve, we need to drop ECDSA ciphers - {Type, #session{cipher_suite = CipherSuite, - compression_method = Compression} = Session1} + {Type, #session{cipher_suite = CipherSuite} = 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 - {ok, ConnectionStates1} -> - ConnectionStates = - hello_pending_connection_states(server, - Version, - CipherSuite, - Random, - Compression, - ConnectionStates1), - case handle_next_protocol_on_server(Hello, Renegotiation, SslOpts) of - #alert{} = Alert -> - Alert; - ProtocolsToAdvertise -> - {EcPointFormats1, EllipticCurves1} = - handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0), - - {Version, {Type, Session}, ConnectionStates, - ProtocolsToAdvertise, EcPointFormats1, EllipticCurves1} - end; - #alert{} = Alert -> + try handle_hello_extensions(Hello, Version, SslOpts, Session1, ConnectionStates0, Renegotiation) of + {Session, ConnectionStates, ProtocolsToAdvertise, ECPointFormats, EllipticCurves} -> + {Version, {Type, Session}, ConnectionStates, + ProtocolsToAdvertise, ECPointFormats, EllipticCurves} + catch throw:Alert -> Alert end end; @@ -897,11 +872,6 @@ handle_ecc_curves_extension(Version, undefined) -> handle_ecc_curves_extension(Version, _) -> #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)}. -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)}; @@ -1774,3 +1744,50 @@ default_hash_signs() -> #hash_sign_algos{hash_sign_algos = lists:filter(fun({_, ecdsa}) -> HasECC; (_) -> true end, HashSigns)}. + +handle_hello_extensions(#client_hello{random = Random, + cipher_suites = CipherSuites, + renegotiation_info = Info, + srp = SRP, + ec_point_formats = EcPointFormats0, + elliptic_curves = EllipticCurves0} = Hello, Version, + #ssl_options{secure_renegotiate = SecureRenegotation} = Opts, + Session0, ConnectionStates0, Renegotiation) -> + Session = handle_srp_extension(SRP, Session0), + ConnectionStates = handle_renegotiation_extension(Version, Info, Random, Session, ConnectionStates0, + Renegotiation, SecureRenegotation, CipherSuites), + ProtocolsToAdvertise = handle_next_protocol_extension(Hello, Renegotiation, Opts), + {EcPointFormats, EllipticCurves} = handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0), + %%TODO make extensions compund data structure + {Session, ConnectionStates, ProtocolsToAdvertise, EcPointFormats, EllipticCurves}. + + +handle_renegotiation_extension(Version, Info, Random, #session{cipher_suite = CipherSuite, + compression_method = Compression}, + ConnectionStates0, Renegotiation, SecureRenegotation, CipherSuites) -> + case handle_renegotiation_info(server, Info, ConnectionStates0, + Renegotiation, SecureRenegotation, + CipherSuites) of + {ok, ConnectionStates1} -> + hello_pending_connection_states(server, + Version, + CipherSuite, + Random, + Compression, + ConnectionStates1); + #alert{} = Alert -> + throw(Alert) + end. + +handle_next_protocol_extension(Hello, Renegotiation, SslOpts)-> + case handle_next_protocol_on_server(Hello, Renegotiation, SslOpts) of + #alert{} = Alert -> + throw(Alert); + ProtocolsToAdvertise -> + ProtocolsToAdvertise + end. + +handle_srp_extension(undefined, Session) -> + Session; +handle_srp_extension(#srp{username = Username}, Session) -> + Session#session{srp_username = Username}. -- cgit v1.2.3 From a37196319f7e62a47b43a0dc939505eede616299 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 24 Apr 2013 15:20:05 +0200 Subject: crypto: Change ecdh_compute_key to have 3 arguments --- lib/crypto/src/crypto.erl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 999a65042d..894253f84d 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -67,7 +67,7 @@ -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([ecdh_generate_key/1, ecdh_compute_key/2]). +-export([ecdh_generate_key/1, ecdh_compute_key/3]). -export([sign/4, verify/5]). -export([dh_generate_parameters/2, dh_check/1]). %% Testing see below @@ -1267,9 +1267,9 @@ term_to_ec_key({Curve, PrivKey, PubKey}) -> term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub. --spec ecdh_compute_key(ec_point(), ec_key_res()) -> binary(). -ecdh_compute_key(Others, My) -> - ecdh_compute_key_nif(Others, term_to_ec_key(My)). +-spec ecdh_compute_key(ec_point(), binary(), ec_curve()) -> binary(). +ecdh_compute_key(Others, My, Curve) -> + ecdh_compute_key_nif(Others, term_to_ec_key({Curve,My,undefined})). ecdh_compute_key_nif(_Others, _My) -> ?nif_stub. -- cgit v1.2.3 From 7bbfc0d715d2023cc27a7819c108d47ab812b89e Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 24 Apr 2013 18:00:56 +0200 Subject: crypto: Add generic functions generate_key and compute_key and remove corresponding specific functions for srp and ecdh but leave dh_ functions for backward compatibility. --- lib/crypto/c_src/crypto.c | 70 +++++++------- lib/crypto/src/crypto.erl | 197 +++++++++++++++++---------------------- lib/crypto/test/crypto_SUITE.erl | 53 ++++++----- 3 files changed, 150 insertions(+), 170 deletions(-) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 08c6d4dbc5..c5d181ea25 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -222,8 +222,8 @@ 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_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM srp_host_secret_nif(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[]); @@ -349,11 +349,11 @@ static ErlNifFunc nif_funcs[] = { {"rsa_private_crypt", 4, rsa_private_crypt}, {"dh_generate_parameters_nif", 2, dh_generate_parameters_nif}, {"dh_check", 1, dh_check}, - {"dh_generate_key_nif", 2, dh_generate_key_nif}, + {"dh_generate_key_nif", 3, 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_nif", 5, srp_server_secret_nif}, + {"srp_user_secret_nif", 7, srp_user_secret_nif}, + {"srp_host_secret_nif", 5, srp_host_secret_nif}, {"bf_cfb64_crypt", 4, bf_cfb64_crypt}, {"bf_cbc_crypt", 4, bf_cbc_crypt}, {"bf_ecb_crypt", 3, bf_ecb_crypt}, @@ -2442,14 +2442,12 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E } p_len = BN_num_bytes(dh_params->p); g_len = BN_num_bytes(dh_params->g); - p_ptr = enif_make_new_binary(env, p_len+4, &ret_p); - g_ptr = enif_make_new_binary(env, g_len+4, &ret_g); - put_int32(p_ptr, p_len); - put_int32(g_ptr, g_len); - BN_bn2bin(dh_params->p, p_ptr+4); - BN_bn2bin(dh_params->g, g_ptr+4); - ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr+4, p_len); - ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr+4, g_len); + p_ptr = enif_make_new_binary(env, p_len, &ret_p); + g_ptr = enif_make_new_binary(env, g_len, &ret_g); + BN_bn2bin(dh_params->p, p_ptr); + BN_bn2bin(dh_params->g, g_ptr); + ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr, p_len); + ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr, g_len); DH_free(dh_params); return enif_make_list2(env, ret_p, ret_g); } @@ -2461,9 +2459,9 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] ERL_NIF_TERM ret, head, tail; if (!enif_get_list_cell(env, argv[0], &head, &tail) - || !get_bn_from_mpint(env, head, &dh_params->p) + || !get_bn_from_bin(env, head, &dh_params->p) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dh_params->g) + || !get_bn_from_bin(env, head, &dh_params->g) || !enif_is_empty_list(env,tail)) { DH_free(dh_params); @@ -2485,19 +2483,21 @@ 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[]) -{/* (PrivKey, DHParams=[P,G]) */ +{/* (PrivKey, DHParams=[P,G], Mpint) */ DH* dh_params = DH_new(); int pub_len, prv_len; unsigned char *pub_ptr, *prv_ptr; ERL_NIF_TERM ret, ret_pub, ret_prv, head, tail; + int mpint; /* 0 or 4 */ - if (!(get_bn_from_mpint(env, argv[0], &dh_params->priv_key) + if (!(get_bn_from_bin(env, argv[0], &dh_params->priv_key) || argv[0] == atom_undefined) || !enif_get_list_cell(env, argv[1], &head, &tail) - || !get_bn_from_mpint(env, head, &dh_params->p) + || !get_bn_from_bin(env, head, &dh_params->p) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dh_params->g) - || !enif_is_empty_list(env, tail)) { + || !get_bn_from_bin(env, head, &dh_params->g) + || !enif_is_empty_list(env, tail) + || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4)) { DH_free(dh_params); return enif_make_badarg(env); } @@ -2505,14 +2505,16 @@ static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_ if (DH_generate_key(dh_params)) { pub_len = BN_num_bytes(dh_params->pub_key); prv_len = BN_num_bytes(dh_params->priv_key); - pub_ptr = enif_make_new_binary(env, pub_len+4, &ret_pub); - prv_ptr = enif_make_new_binary(env, prv_len+4, &ret_prv); - put_int32(pub_ptr, pub_len); - put_int32(prv_ptr, prv_len); - BN_bn2bin(dh_params->pub_key, pub_ptr+4); - BN_bn2bin(dh_params->priv_key, prv_ptr+4); - ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr+4, pub_len); - ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr+4, prv_len); + pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub); + prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv); + if (mpint) { + put_int32(pub_ptr, pub_len); pub_ptr += 4; + put_int32(prv_ptr, prv_len); prv_ptr += 4; + } + BN_bn2bin(dh_params->pub_key, pub_ptr); + BN_bn2bin(dh_params->priv_key, prv_ptr); + ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len); + ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len); ret = enif_make_tuple2(env, ret_pub, ret_prv); } else { @@ -2530,12 +2532,12 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T ErlNifBinary ret_bin; ERL_NIF_TERM ret, head, tail; - if (!get_bn_from_mpint(env, argv[0], &pubkey) - || !get_bn_from_mpint(env, argv[1], &dh_params->priv_key) + if (!get_bn_from_bin(env, argv[0], &pubkey) + || !get_bn_from_bin(env, argv[1], &dh_params->priv_key) || !enif_get_list_cell(env, argv[2], &head, &tail) - || !get_bn_from_mpint(env, head, &dh_params->p) + || !get_bn_from_bin(env, head, &dh_params->p) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dh_params->g) + || !get_bn_from_bin(env, head, &dh_params->g) || !enif_is_empty_list(env, tail)) { ret = enif_make_badarg(env); @@ -2613,7 +2615,7 @@ static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM return ret; } -static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (a, u, B, Multiplier, Prime, Exponent, Generator) */ /* = (B - (k * g^x)) ^ (a + (u * x)) % N @@ -2693,7 +2695,7 @@ static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NI return ret; } -static ERL_NIF_TERM srp_server_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Verifier, b, u, A, Prime) */ /* = (A * v^u) ^ b % N diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 894253f84d..76e4ac620c 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -58,8 +58,6 @@ -export([rand_bytes/1, rand_bytes/3, rand_uniform/2]). -export([strong_rand_bytes/1, strong_rand_mpint/3]). -export([mod_exp/3, mod_exp_prime/3, mpint/1, erlint/1]). --export([srp_generate_key/4, srp_generate_key/3, - srp_generate_key/5, srp_compute_key/6, srp_compute_key/7, srp_compute_key/8]). %% -export([idea_cbc_encrypt/3, idea_cbc_decrypt/3]). -export([aes_cbc_128_encrypt/3, aes_cbc_128_decrypt/3]). @@ -67,8 +65,9 @@ -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([ecdh_generate_key/1, ecdh_compute_key/3]). -export([sign/4, verify/5]). +-export([generate_key/2, generate_key/3, compute_key/4]). + -export([dh_generate_parameters/2, dh_check/1]). %% Testing see below @@ -114,9 +113,7 @@ hash, hash_init, hash_update, hash_final, hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, info, rc2_cbc_encrypt, rc2_cbc_decrypt, - srp_generate_key, srp_compute_key, - ecdh_generate_key, ecdh_compute_key, - sign, verify, + sign, verify, generate_key, compute_key, info_lib, algorithms]). -type mpint() :: binary(). @@ -1122,118 +1119,98 @@ dh_check([_Prime,_Gen]) -> ?nif_stub. {binary(),binary()}. dh_generate_key(DHParameters) -> - dh_generate_key(undefined, DHParameters). + dh_generate_key_nif(undefined, map_mpint_to_bin(DHParameters), 4). dh_generate_key(PrivateKey, DHParameters) -> - case dh_generate_key_nif(PrivateKey, DHParameters) of - error -> erlang:error(generation_failed, [PrivateKey,DHParameters]); - Res -> Res - end. + dh_generate_key_nif(mpint_to_bin(PrivateKey), map_mpint_to_bin(DHParameters), 4). -dh_generate_key_nif(_PrivateKey, _DHParameters) -> ?nif_stub. +dh_generate_key_nif(_PrivateKey, _DHParameters, _Mpint) -> ?nif_stub. %% DHParameters = [P (Prime)= mpint(), G(Generator) = mpint()] -%% MyPrivKey, OthersPublicKey = mpint() +%% MyPrivKey, OthersPublicKey = mpint() -spec dh_compute_key(binary(), binary(), [binary()]) -> binary(). dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) -> - case dh_compute_key_nif(OthersPublicKey,MyPrivateKey,DHParameters) of - error -> erlang:error(computation_failed, [OthersPublicKey,MyPrivateKey,DHParameters]); - Ret -> Ret - end. + compute_key(dh, mpint_to_bin(OthersPublicKey), mpint_to_bin(MyPrivateKey), + map_mpint_to_bin(DHParameters)). + dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub. +generate_key(Type, Params) -> + generate_key(Type, Params, undefined). + +generate_key(dh, DHParameters, PrivateKey) -> + dh_generate_key_nif(PrivateKey, DHParameters, 0); + +generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, PrivArg) + when is_binary(Verifier), is_binary(Generator), is_binary(Prime), is_atom(Version) -> + Private = case PrivArg of + undefined -> random_bytes(32); + _ -> PrivArg + end, + host_srp_gen_key(Private, Verifier, Generator, Prime, Version); + +generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg) + when is_binary(Generator), is_binary(Prime), is_atom(Version) -> + Private = case PrivateArg of + undefined -> random_bytes(32); + _ -> PrivateArg + end, + user_srp_gen_key(Private, Generator, Prime); + +generate_key(ecdh, Curve, undefined) -> + ec_key_to_term(ec_key_generate(Curve)). + + +ec_key_generate(_Key) -> ?nif_stub. + + +compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) -> + case dh_compute_key_nif(OthersPublicKey,MyPrivateKey,DHParameters) of + error -> erlang:error(computation_failed, + [OthersPublicKey,MyPrivateKey,DHParameters]); + Ret -> Ret + end; -%%% SRP --spec srp_generate_key(binary(), binary(), atom() | binary(), atom() | binary() ) -> {Public::binary(), Private::binary()}. -srp_generate_key(Verifier, Generator, Prime, Version) when is_binary(Verifier), - is_binary(Generator), - is_binary(Prime), - is_atom(Version) -> - Private = random_bytes(32), - server_srp_gen_key(Private, Verifier, Generator, Prime, Version); - -srp_generate_key(Generator, Prime, Version, Private) when is_binary(Generator), - is_binary(Prime), - is_atom(Version), - is_binary(Private) -> - client_srp_gen_key(Private, Generator, Prime). - --spec srp_generate_key(binary(), binary(), binary(), atom(), binary()) -> {Public::binary(), Private::binary()}. -srp_generate_key(Verifier, Generator, Prime, Version, Private) when is_binary(Verifier), - is_binary(Generator), - is_binary(Prime), - is_atom(Version), - is_binary(Private) - -> - server_srp_gen_key(Private, Verifier, Generator, Prime, Version). - --spec srp_generate_key(binary(), binary(), atom()) -> {Public::binary(), Private::binary()}. -srp_generate_key(Generator, Prime, Version) when is_binary(Generator), - is_binary(Prime), - is_atom(Version) -> - Private = random_bytes(32), - client_srp_gen_key(Private, Generator, Prime). - --spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), atom()| binary(), atom() | binary() ) -> binary(). -srp_compute_key(DerivedKey, Prime, Generator, ClientPublic, ClientPrivate, ServerPublic, Version) when - is_binary(Prime), +compute_key(srp, HostPublic, {UserPublic, UserPrivate}, + {user, [DerivedKey, Prime, Generator, Version | ScramblerArg]}) when + is_binary(Prime), is_binary(Generator), - is_binary(ClientPublic), - is_binary(ClientPrivate), - is_binary(ServerPublic), + is_binary(UserPublic), + is_binary(UserPrivate), + is_binary(HostPublic), is_atom(Version) -> Multiplier = srp_multiplier(Version, Generator, Prime), - Scrambler = srp_scrambler(Version, ClientPublic, ServerPublic, Prime), - srp_client_secret_nif(ClientPrivate, Scrambler, ServerPublic, Multiplier, - Generator, DerivedKey, Prime); - -srp_compute_key(Verifier, Prime, ClientPublic, ServerPublic, ServerPrivate, Version, Scrambler) when - is_binary(Verifier), - is_binary(Prime), - is_binary(ClientPublic), - is_binary(ServerPublic), - is_binary(ServerPrivate), - is_atom(Version), - is_binary(Scrambler) -> - srp_server_secret_nif(Verifier, ServerPrivate, Scrambler, ClientPublic, Prime). - --spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), binary(), atom(), binary()) -> binary(). -srp_compute_key(DerivedKey, Prime, Generator, ClientPublic, ClientPrivate, - ServerPublic, Version, Scrambler) when is_binary(DerivedKey), - is_binary(Prime), - is_binary(Generator), - is_binary(ClientPublic), - is_binary(ClientPrivate), - is_binary(ServerPublic), - is_atom(Version), - is_binary(Scrambler) -> - Multiplier = srp_multiplier(Version, Generator, Prime), - srp_client_secret_nif(ClientPrivate, Scrambler, ServerPublic, Multiplier, - Generator, DerivedKey, Prime). - --spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), atom()) -> binary(). -srp_compute_key(Verifier, Prime, ClientPublic, ServerPublic, ServerPrivate, Version) when + Scrambler = case ScramblerArg of + [] -> srp_scrambler(Version, UserPublic, HostPublic, Prime); + [S] -> S + end, + srp_user_secret_nif(UserPrivate, Scrambler, HostPublic, Multiplier, + Generator, DerivedKey, Prime); + +compute_key(srp, UserPublic, {HostPublic, HostPrivate}, + {host,[Verifier, Prime, Version | ScramblerArg]}) when is_binary(Verifier), - is_binary(Prime), - is_binary(ClientPublic), - is_binary(ServerPublic), - is_binary(ServerPrivate), + is_binary(Prime), + is_binary(UserPublic), + is_binary(HostPublic), + is_binary(HostPrivate), is_atom(Version) -> - Scrambler = srp_scrambler(Version, ClientPublic, ServerPublic, Prime), - srp_server_secret_nif(Verifier, ServerPrivate, Scrambler, ClientPublic, Prime). + Scrambler = case ScramblerArg of + [] -> srp_scrambler(Version, UserPublic, HostPublic, Prime); + [S] -> S + end, + srp_host_secret_nif(Verifier, HostPrivate, Scrambler, UserPublic, Prime); -%% -%% EC -%% - --spec ecdh_generate_key(ec_curve()) -> ec_key() | error. -ecdh_generate_key(Curve) -> - ec_key_to_term(ec_key_generate(Curve)). +compute_key(ecdh, Others, My, Curve) -> + ecdh_compute_key_nif(Others, term_to_ec_key({Curve,My,undefined})). +ecdh_compute_key_nif(_Others, _My) -> ?nif_stub. -ec_key_generate(_Key) -> ?nif_stub. +%% +%% EC +%% -spec ec_key_to_term(ec_key_res()) -> ec_key(). ec_key_to_term(Key) -> @@ -1267,17 +1244,11 @@ term_to_ec_key({Curve, PrivKey, PubKey}) -> term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub. --spec ecdh_compute_key(ec_point(), binary(), ec_curve()) -> binary(). -ecdh_compute_key(Others, My, Curve) -> - ecdh_compute_key_nif(Others, term_to_ec_key({Curve,My,undefined})). - -ecdh_compute_key_nif(_Others, _My) -> ?nif_stub. - %% LOCAL FUNCTIONS %% -client_srp_gen_key(Private, Generator, Prime) -> +user_srp_gen_key(Private, Generator, Prime) -> case mod_exp_prime(Generator, Private, Prime) of error -> error; @@ -1285,7 +1256,7 @@ client_srp_gen_key(Private, Generator, Prime) -> {Public, Private} end. -server_srp_gen_key(Private, Verifier, Generator, Prime, Version) -> +host_srp_gen_key(Private, Verifier, Generator, Prime, Version) -> Multiplier = srp_multiplier(Version, Generator, Prime), case srp_value_B_nif(Multiplier, Verifier, Generator, Private, Prime) of error -> @@ -1305,17 +1276,17 @@ srp_multiplier('6', _, _) -> srp_multiplier('3', _, _) -> <<1/integer>>. -srp_scrambler(Version, ClientPublic, ServerPublic, Prime) when Version == '6'; Version == '6a'-> +srp_scrambler(Version, UserPublic, HostPublic, Prime) when Version == '6'; Version == '6a'-> %% SHA1(PAD(A) | PAD(B)) from http://srp.stanford.edu/design.html PadLength = erlang:byte_size(Prime), C0 = sha_init(), - C1 = sha_update(C0, srp_pad_to(PadLength, ClientPublic)), - C2 = sha_update(C1, srp_pad_to(PadLength, ServerPublic)), + C1 = sha_update(C0, srp_pad_to(PadLength, UserPublic)), + C2 = sha_update(C1, srp_pad_to(PadLength, HostPublic)), sha_final(C2); -srp_scrambler('3', _, ServerPublic, _Prime) -> +srp_scrambler('3', _, HostPublic, _Prime) -> %% 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. - <> = sha(ServerPublic), + <> = sha(HostPublic), U. srp_pad_length(Width, Length) -> @@ -1327,9 +1298,9 @@ srp_pad_to(Width, Binary) -> N -> << 0:(N*8), Binary/binary>> end. -srp_server_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub. +srp_host_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub. -srp_client_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub. +srp_user_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub. srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub. diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 384d15c68c..473609778c 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1864,13 +1864,16 @@ dh(Config) when is_list(Config) -> {param, DHPs} -> timer:sleep(100), io:format("DHP ~p~n", [DHPs]), - ?line {Pub1,Priv1} = crypto:dh_generate_key(DHPs), + DHPs_mpint = lists:map(fun(E) -> sized_binary(E) end, DHPs), + ?line {Pub1,Priv1} = crypto:generate_key(dh, DHPs), io:format("Key1:~n~p~n~p~n~n", [Pub1,Priv1]), - ?line {Pub2,Priv2} = crypto:dh_generate_key(DHPs), + ?line {Pub2,Priv2} = crypto:dh_generate_key(DHPs_mpint), io:format("Key2:~n~p~n~p~n~n", [Pub2,Priv2]), - ?line A = crypto:dh_compute_key(Pub1, Priv2, DHPs), + ?line A = crypto:compute_key(dh, Pub1, unsized_binary(Priv2), DHPs), + ?line A = crypto:dh_compute_key(sized_binary(Pub1), Priv2, DHPs_mpint), timer:sleep(100), %% Get another thread see if that triggers problem - ?line B = crypto:dh_compute_key(Pub2, Priv1, DHPs), + ?line B = crypto:compute_key(dh, unsized_binary(Pub2), Priv1, DHPs), + ?line B = crypto:dh_compute_key(Pub2, sized_binary(Priv1), DHPs_mpint), io:format("A ~p~n",[A]), io:format("B ~p~n",[B]), ?line A = B @@ -1879,6 +1882,7 @@ dh(Config) when is_list(Config) -> exit(Pid, kill) end. + ec(doc) -> ["Test ec (Ecliptic Curve) functions."]; ec(suite) -> []; @@ -1887,7 +1891,7 @@ ec(Config) when is_list(Config) -> ec_do() -> %% test for a name curve - {D2_priv, D2_pub} = crypto:ecdh_generate_key(sect113r2), + {D2_priv, D2_pub} = crypto:generate_key(ecdh, sect113r2), D2 = {sect113r2, D2_priv, D2_pub}, %%TODO: find a published test case for a EC key @@ -1985,12 +1989,12 @@ srp3(Config) when is_list(Config) -> Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime), ClientPublic = crypto:mod_exp_prime(Generator, ClientPrivate, Prime), - {ClientPublic, ClientPrivate} = crypto:srp_generate_key(Generator, Prime, Version, ClientPrivate), - {ServerPublic, ServerPrivate} = crypto:srp_generate_key(Verifier, Generator, Prime, Version, ServerPrivate), - SessionKey = crypto:srp_compute_key(UserPassHash, Prime, Generator, ClientPublic, - ClientPrivate, ServerPublic, Version, Scrambler), - SessionKey = crypto:srp_compute_key(Verifier, Prime, ClientPublic, - ServerPublic, ServerPrivate, Version, Scrambler). + {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate), + {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate), + SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate}, + {user, [UserPassHash, Prime, Generator, Version, Scrambler]}), + SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate}, + {host, [Verifier, Prime, Version, Scrambler]}). srp6(doc) -> ["SRP-6 test vectors generated by http://srp.stanford.edu/demo/demo.html"]; @@ -2036,12 +2040,12 @@ srp6(Config) when is_list(Config) -> Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime), ClientPublic = crypto:mod_exp_prime(Generator, ClientPrivate, Prime), - {ClientPublic, ClientPrivate} = crypto:srp_generate_key(Generator, Prime, Version, ClientPrivate), - {ServerPublic, ServerPrivate} = crypto:srp_generate_key(Verifier, Generator, Prime, Version, ServerPrivate), - SessionKey = crypto:srp_compute_key(UserPassHash, Prime, Generator, ClientPublic, - ClientPrivate, ServerPublic, Version, Scrambler), - SessionKey = crypto:srp_compute_key(Verifier, Prime, ClientPublic, - ServerPublic, ServerPrivate, Version, Scrambler). + {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate), + {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate), + SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate}, + {user, [UserPassHash, Prime, Generator, Version, Scrambler]}), + SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate}, + {host, [Verifier, Prime, Version, Scrambler]}). srp6a(doc) -> ["SRP-6a test vectors from RFC5054."]; @@ -2086,13 +2090,13 @@ srp6a(Config) when is_list(Config) -> UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime), - {ClientPublic, ClientPrivate} = crypto:srp_generate_key(Generator, Prime, Version, ClientPrivate), - {ServerPublic, ServerPrivate} = crypto:srp_generate_key(Verifier, Generator, Prime, Version, ServerPrivate), + {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate), + {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate), - SessionKey = crypto:srp_compute_key(UserPassHash, Prime, Generator, ClientPublic, - ClientPrivate, ServerPublic, Version, Scrambler), - SessionKey = crypto:srp_compute_key(Verifier, Prime, ClientPublic, - ServerPublic, ServerPrivate, Version, Scrambler). + SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate}, + {user, [UserPassHash, Prime, Generator, Version, Scrambler]}), + SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate}, + {host, [Verifier, Prime, Version, Scrambler]}). %% %% @@ -2287,6 +2291,9 @@ sized_binary(Binary) when is_binary(Binary) -> sized_binary(List) -> sized_binary(list_to_binary(List)). +unsized_binary(<>) -> + Binary. + xor_bytes(Bin1, Bin2) when is_binary(Bin1), is_binary(Bin2) -> L1 = binary_to_list(Bin1), L2 = binary_to_list(Bin2), -- cgit v1.2.3 From dad86c51e920d015da390ec6bef3da24924fa063 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 25 Apr 2013 11:04:36 +0200 Subject: ssl, public_key, crypto: General generate_key and compute_key functions --- lib/crypto/src/crypto.erl | 4 ++-- lib/public_key/src/public_key.erl | 19 +++++++---------- lib/ssl/src/ssl_connection.erl | 43 ++++++++++++++++----------------------- lib/ssl/src/ssl_handshake.erl | 8 ++++---- lib/ssl/test/erl_make_certs.erl | 2 +- 5 files changed, 31 insertions(+), 45 deletions(-) diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 76e4ac620c..43ea1d48fd 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -1140,7 +1140,7 @@ generate_key(Type, Params) -> generate_key(Type, Params, undefined). generate_key(dh, DHParameters, PrivateKey) -> - dh_generate_key_nif(PrivateKey, DHParameters, 0); + dh_generate_key_nif(PrivateKey, map_ensure_int_as_bin(DHParameters), 0); generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, PrivArg) when is_binary(Verifier), is_binary(Generator), is_binary(Prime), is_atom(Version) -> @@ -1166,7 +1166,7 @@ ec_key_generate(_Key) -> ?nif_stub. compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) -> - case dh_compute_key_nif(OthersPublicKey,MyPrivateKey,DHParameters) of + case dh_compute_key_nif(OthersPublicKey,MyPrivateKey, map_ensure_int_as_bin(DHParameters)) of error -> erlang:error(computation_failed, [OthersPublicKey,MyPrivateKey,DHParameters]); Ret -> Ret diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index df4f38f507..3497018a88 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -330,7 +330,7 @@ encrypt_private(PlainText, %% Description: Generates a new keypair %%-------------------------------------------------------------------- generate_key(#'DHParameter'{prime = P, base = G}) -> - crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]); + crypto:generate_key(dh, [P, G]); generate_key({namedCurve, _} = Params) -> ec_generate_key(Params); generate_key(#'OTPECParameters'{} = Params) -> @@ -341,14 +341,13 @@ generate_key(#'OTPECParameters'{} = Params) -> -spec compute_key(OthersKey ::binary(), MyKey::binary(), #'DHParameter'{}) -> binary(). %% Description: Compute shared secret %%-------------------------------------------------------------------- -compute_key(PubKey, #'ECPrivateKey'{} = PrivateKey) -> - compute_key(PubKey, format_ecdh_key(PrivateKey)); - -compute_key(#'ECPoint'{point = Point}, ECDHKeys) -> - crypto:ecdh_compute_key(Point, ECDHKeys). +compute_key(#'ECPoint'{point = Point}, #'ECPrivateKey'{privateKey = PrivKey, + parameters = Param}) -> + ECCurve = ec_curve_spec(Param), + crypto:compute_key(ecdh, Point, list2int(PrivKey), ECCurve). compute_key(PubKey, PrivKey, #'DHParameter'{prime = P, base = G}) -> - crypto:dh_compute_key(PubKey, PrivKey, [crypto:mpint(P), crypto:mpint(G)]). + crypto:compute_key(dh, PubKey, PrivKey, [P, G]). %%-------------------------------------------------------------------- -spec pkix_sign_types(SignatureAlg::oid()) -> @@ -741,10 +740,6 @@ validate(Cert, #path_validation_state{working_issuer_name = Issuer, pubkey_cert:prepare_for_next_cert(OtpCert, ValidationState). -sized_binary(Binary) -> - Size = size(Binary), - <>. - otp_cert(Der) when is_binary(Der) -> pkix_decode_cert(Der, otp); otp_cert(#'OTPCertificate'{} =Cert) -> @@ -870,7 +865,7 @@ format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, ec_generate_key(Params) -> Curve = ec_curve_spec(Params), - Term = crypto:ecdh_generate_key(Curve), + Term = crypto:generate_key(ecdh, Curve), ec_key(Term, Params). format_ecdh_key(#'ECPrivateKey'{privateKey = PrivKey, diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 25a293f125..574032d14a 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -712,7 +712,7 @@ certify_client_key_exchange(#client_dhe_psk_identity{ 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 + case dhe_psk_master_secret(ClientPSKIdentity, P, G, ClientPublicDhKey, ServerDhPrivateKey, State0) of #state{} = State1 -> {Record, State} = next_record(State1), next_state(certify, cipher, Record, State); @@ -2087,18 +2087,16 @@ master_from_premaster_secret(PremasterSecret, dh_master_secret(#'DHParameter'{} = Params, OtherPublicDhKey, MyPrivateKey, State) -> PremasterSecret = - public_key:compute_key(mpint_binary(OtherPublicDhKey), MyPrivateKey, Params), + public_key:compute_key(OtherPublicDhKey, MyPrivateKey, Params), master_from_premaster_secret(PremasterSecret, State). dh_master_secret(Prime, Base, PublicDhKey, undefined, State) -> - PMpint = mpint_binary(Prime), - GMpint = mpint_binary(Base), - Keys = {_, PrivateDhKey} = crypto:dh_generate_key([PMpint, GMpint]), - dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys}); + Keys = {_, PrivateDhKey} = crypto:generate_key(dh, [Prime, Base]), + dh_master_secret(Prime, Base, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys}); -dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) -> +dh_master_secret(Prime, Base, PublicDhKey, PrivateDhKey, State) -> PremasterSecret = - crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey, [PMpint, GMpint]), + crypto:compute_key(dh, PublicDhKey, PrivateDhKey, [Prime, Base]), master_from_premaster_secret(PremasterSecret, State). ec_dh_master_secret(ECDHKeys, ECPoint, State) -> @@ -2126,20 +2124,18 @@ server_psk_master_secret(ClientPSKIdentity, 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, + crypto:generate_key(dh, [Prime, Base]), + dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys}); -dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey, +dhe_psk_master_secret(PSKIdentity, Prime, Base, 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]), + crypto:compute_key(dh, PublicDhKey, PrivateDhKey, + [Prime, Base]), DHLen = erlang:byte_size(DHSecret), Len = erlang:byte_size(PSK), PremasterSecret = <>, @@ -2168,7 +2164,7 @@ generate_srp_server_keys(_SrpParams, 10) -> generate_srp_server_keys(SrpParams = #srp_user{generator = Generator, prime = Prime, verifier = Verifier}, N) -> - case crypto:srp_generate_key(Verifier, Generator, Prime, '6a') of + case crypto:generate_key(srp, {host, [Verifier, Generator, Prime, '6a']}) of error -> generate_srp_server_keys(SrpParams, N+1); Keys -> @@ -2179,7 +2175,7 @@ generate_srp_client_keys(_Generator, _Prime, 10) -> ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); generate_srp_client_keys(Generator, Prime, N) -> - case crypto:srp_generate_key(Generator, Prime, '6a') of + case crypto:generate_key(srp, {user, [Generator, Prime, '6a']}) of error -> generate_srp_client_keys(Generator, Prime, N+1); Keys -> @@ -2200,8 +2196,8 @@ handle_srp_identity(Username, {Fun, UserState}) -> throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)) end. -server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = {ServerPub, ServerPriv}}) -> - case crypto:srp_compute_key(Verifier, Prime, ClientPub, ServerPub, ServerPriv, '6a') of +server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = ServerKeys}) -> + case crypto:compute_key(srp, ClientPub, ServerKeys, {host, [Verifier, Prime, '6a']}) of error -> ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); PremasterSecret -> @@ -2214,13 +2210,13 @@ client_srp_master_secret(Generator, Prime, Salt, ServerPub, undefined, State) -> Keys = generate_srp_client_keys(Generator, Prime, 0), client_srp_master_secret(Generator, Prime, Salt, ServerPub, Keys, State#state{srp_keys = Keys}); -client_srp_master_secret(Generator, Prime, Salt, ServerPub, {ClientPub, ClientPriv}, +client_srp_master_secret(Generator, Prime, Salt, ServerPub, ClientKeys, #state{ssl_options = SslOpts} = State) -> case ssl_srp_primes:check_srp_params(Generator, Prime) of ok -> {Username, Password} = SslOpts#ssl_options.srp_identity, DerivedKey = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), - case crypto:srp_compute_key(DerivedKey, Prime, Generator, ClientPub, ClientPriv, ServerPub, '6a') of + case crypto:compute_key(srp, ServerPub, ClientKeys, {user, [DerivedKey, Prime, Generator, '6a']}) of error -> ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); PremasterSecret -> @@ -2890,11 +2886,6 @@ make_premaster_secret({MajVer, MinVer}, rsa) -> make_premaster_secret(_, _) -> undefined. -mpint_binary(Binary) -> - Size = erlang:byte_size(Binary), - <>. - - ack_connection(#state{renegotiation = {true, Initiater}} = State) when Initiater == internal; Initiater == peer -> diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 598877abff..0744ef4180 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -387,7 +387,7 @@ key_exchange(client, _Version, {premaster_secret, Secret, {_, PublicKey, _}}) -> encrypted_premaster_secret(Secret, PublicKey), #client_key_exchange{exchange_keys = EncPremasterSecret}; -key_exchange(client, _Version, {dh, <>}) -> +key_exchange(client, _Version, {dh, PublicKey}) -> #client_key_exchange{ exchange_keys = #client_diffie_hellman_public{ dh_public = PublicKey} @@ -405,7 +405,7 @@ key_exchange(client, _Version, {psk, Identity}) -> identity = Identity} }; -key_exchange(client, _Version, {dhe_psk, Identity, <>}) -> +key_exchange(client, _Version, {dhe_psk, Identity, PublicKey}) -> #client_key_exchange{ exchange_keys = #client_dhe_psk_identity{ identity = Identity, @@ -426,7 +426,7 @@ key_exchange(client, _Version, {srp, PublicKey}) -> srp_a = PublicKey} }; -key_exchange(server, Version, {dh, {<>, _}, +key_exchange(server, Version, {dh, {PublicKey, _}, #'DHParameter'{prime = P, base = G}, HashSign, ClientRandom, ServerRandom, PrivateKey}) -> <> = crypto:mpint(P), @@ -449,7 +449,7 @@ key_exchange(server, Version, {psk, PskIdentityHint, enc_server_key_exchange(Version, ServerPSKParams, HashSign, ClientRandom, ServerRandom, PrivateKey); -key_exchange(server, Version, {dhe_psk, PskIdentityHint, {<>, _}, +key_exchange(server, Version, {dhe_psk, PskIdentityHint, {PublicKey, _}, #'DHParameter'{prime = P, base = G}, HashSign, ClientRandom, ServerRandom, PrivateKey}) -> <> = crypto:mpint(P), diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl index 8743cb13fa..c32ca6dd1f 100644 --- a/lib/ssl/test/erl_make_certs.erl +++ b/lib/ssl/test/erl_make_certs.erl @@ -409,7 +409,7 @@ int2list(I) -> binary_to_list(<>). gen_ec2(CurveId) -> - {PrivKey, PubKey} = crypto:ecdh_generate_key(CurveId), + {PrivKey, PubKey} = crypto:generate_key(ecdh,CurveId), #'ECPrivateKey'{version = 1, privateKey = int2list(PrivKey), -- cgit v1.2.3 From badb8f14e9829ce0a797b56702997aa355cdd9ba Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 25 Apr 2013 14:51:19 +0200 Subject: ssl, crypto: Eliminate remaining mpint and EC resource key from API --- lib/crypto/src/crypto.erl | 17 +++++++++++------ lib/crypto/test/crypto_SUITE.erl | 13 +++++-------- lib/public_key/src/public_key.erl | 29 +++++++++++------------------ lib/ssl/src/ssl_handshake.erl | 16 ++++++++-------- lib/ssl/test/erl_make_certs.erl | 2 +- 5 files changed, 36 insertions(+), 41 deletions(-) diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 43ea1d48fd..f87644b3fe 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -855,8 +855,8 @@ verify(rsa, Type, DataOrDigest, Signature, Key) -> notsup -> erlang:error(notsup); Bool -> Bool end; -verify(ecdsa, Type, DataOrDigest, Signature, Key) -> - case ecdsa_verify_nif(Type, DataOrDigest, Signature, term_to_ec_key(Key)) of +verify(ecdsa, Type, DataOrDigest, Signature, [Key, Curve]) -> + case ecdsa_verify_nif(Type, DataOrDigest, Signature, term_to_ec_key({Curve, undefined, Key})) of notsup -> erlang:error(notsup); Bool -> Bool end. @@ -901,6 +901,11 @@ map_ensure_int_as_bin([H|_]=List) when is_integer(H) -> map_ensure_int_as_bin(List) -> List. +ensure_int_as_bin(Int) when is_integer(Int) -> + int_to_bin(Int); +ensure_int_as_bin(Bin) -> + Bin. + map_to_norm_bin([H|_]=List) when is_integer(H) -> lists:map(fun(E) -> int_to_bin(E) end, List); map_to_norm_bin(List) -> @@ -917,8 +922,8 @@ sign(dss, Type, DataOrDigest, Key) -> error -> erlang:error(badkey, [DataOrDigest, Key]); Sign -> Sign end; -sign(ecdsa, Type, DataOrDigest, Key) -> - case ecdsa_sign_nif(Type, DataOrDigest, term_to_ec_key(Key)) of +sign(ecdsa, Type, DataOrDigest, [Key, Curve]) -> + case ecdsa_sign_nif(Type, DataOrDigest, term_to_ec_key({Curve, Key, undefined})) of error -> erlang:error(badkey, [Type,DataOrDigest,Key]); Sign -> Sign end. @@ -1228,9 +1233,9 @@ term_to_nif_prime({prime_field, Prime}) -> term_to_nif_prime(PrimeField) -> PrimeField. term_to_nif_curve({A, B, Seed}) -> - {int_to_bin(A), int_to_bin(B), Seed}. + {ensure_int_as_bin(A), ensure_int_as_bin(B), Seed}. term_to_nif_curve_parameters({PrimeField, Curve, BasePoint, Order, CoFactor}) -> - {term_to_nif_prime(PrimeField), term_to_nif_curve(Curve), BasePoint, int_to_bin(Order), int_to_bin(CoFactor)}; + {term_to_nif_prime(PrimeField), term_to_nif_curve(Curve), ensure_int_as_bin(BasePoint), int_to_bin(Order), int_to_bin(CoFactor)}; term_to_nif_curve_parameters(Curve) when is_atom(Curve) -> %% named curve Curve. diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 473609778c..3ebe10866c 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1892,8 +1892,8 @@ ec(Config) when is_list(Config) -> ec_do() -> %% test for a name curve {D2_priv, D2_pub} = crypto:generate_key(ecdh, sect113r2), - D2 = {sect113r2, D2_priv, D2_pub}, - + PrivECDH = [D2_priv, sect113r2], + PubECDH = [D2_pub, sect113r2], %%TODO: find a published test case for a EC key %% test for a full specified curve and public key, @@ -1932,14 +1932,11 @@ ec_do() -> 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:sign(ecdsa, sha, Msg, D2), - ?line true = crypto:verify(ecdsa, sha, Msg, Sign, D2), - ?line false = crypto:verify(ecdsa, sha, Msg, <<10,20>>, D2), + Sign = crypto:sign(ecdsa, sha, Msg, PrivECDH), + ?line true = crypto:verify(ecdsa, sha, Msg, Sign, PubECDH), + ?line false = crypto:verify(ecdsa, sha, Msg, <<10,20>>, PubECDH), ok. diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 3497018a88..a8fe9213ea 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -326,7 +326,9 @@ encrypt_private(PlainText, crypto:rsa_private_encrypt(PlainText, format_rsa_private_key(Key), Padding). %%-------------------------------------------------------------------- --spec generate_key(#'DHParameter'{} | {namedCurve, Name ::atom()} | #'OTPECParameters'{}) -> {Public::binary(), Private::binary()}. +-spec generate_key(#'DHParameter'{} | {namedCurve, Name ::atom()} | + #'OTPECParameters'{}) -> {Public::binary(), Private::binary()} | + #'ECPrivateKey'{}. %% Description: Generates a new keypair %%-------------------------------------------------------------------- generate_key(#'DHParameter'{prime = P, base = G}) -> @@ -396,9 +398,10 @@ sign(DigestOrPlainText, DigestType, Key = #'RSAPrivateKey'{}) -> sign(DigestOrPlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) -> crypto:sign(dss, sha, DigestOrPlainText, [P, Q, G, X]); -sign(DigestOrPlainText, DigestType, Key = #'ECPrivateKey'{}) -> - ECDHKey = format_ecdh_key(Key), - crypto:sign(ecdsa, DigestType, DigestOrPlainText, ECDHKey); +sign(DigestOrPlainText, DigestType, #'ECPrivateKey'{privateKey = PrivKey, + parameters = Param}) -> + ECCurve = ec_curve_spec(Param), + crypto:sign(ecdsa, DigestType, DigestOrPlainText, [list2int(PrivKey), ECCurve]); %% Backwards compatible sign(Digest, none, #'DSAPrivateKey'{} = Key) -> @@ -415,9 +418,9 @@ verify(DigestOrPlainText, DigestType, Signature, crypto:verify(rsa, DigestType, DigestOrPlainText, Signature, [Exp, Mod]); -verify(DigestOrPlaintext, DigestType, Signature, Key = {#'ECPoint'{}, _}) -> - ECDHKey = format_ecdh_key(Key), - crypto:verify(ecdsa, DigestType, DigestOrPlaintext, Signature, ECDHKey); +verify(DigestOrPlaintext, DigestType, Signature, {#'ECPoint'{point = Point}, Param}) -> + ECCurve = ec_curve_spec(Param), + crypto:verify(ecdsa, DigestType, DigestOrPlaintext, Signature, [Point, ECCurve]); %% Backwards compatibility verify(Digest, none, Signature, {_, #'Dss-Parms'{}} = Key ) -> @@ -868,20 +871,10 @@ ec_generate_key(Params) -> Term = crypto:generate_key(ecdh, Curve), ec_key(Term, Params). -format_ecdh_key(#'ECPrivateKey'{privateKey = PrivKey, - parameters = Param, - publicKey = _}) -> - ECCurve = ec_curve_spec(Param), - {ECCurve, list2int(PrivKey), undefined}; - -format_ecdh_key({#'ECPoint'{point = Point}, Param}) -> - ECCurve = ec_curve_spec(Param), - {ECCurve, undefined, Point}. - ec_curve_spec( #'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}, + Curve = {erlang:list_to_binary(PCurve#'Curve'.a), erlang:list_to_binary(PCurve#'Curve'.b), none}, {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor}; ec_curve_spec({namedCurve, OID}) -> pubkey_cert_records:namedCurves(OID). diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 0744ef4180..338319ab9e 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -429,10 +429,8 @@ key_exchange(client, _Version, {srp, PublicKey}) -> key_exchange(server, Version, {dh, {PublicKey, _}, #'DHParameter'{prime = P, base = G}, HashSign, ClientRandom, ServerRandom, PrivateKey}) -> - <> = crypto:mpint(P), - <> = crypto:mpint(G), - ServerDHParams = #server_dh_params{dh_p = PBin, - dh_g = GBin, dh_y = PublicKey}, + ServerDHParams = #server_dh_params{dh_p = int_to_bin(P), + dh_g = int_to_bin(G), dh_y = PublicKey}, enc_server_key_exchange(Version, ServerDHParams, HashSign, ClientRandom, ServerRandom, PrivateKey); @@ -452,12 +450,10 @@ key_exchange(server, Version, {psk, PskIdentityHint, key_exchange(server, Version, {dhe_psk, PskIdentityHint, {PublicKey, _}, #'DHParameter'{prime = P, base = G}, HashSign, ClientRandom, ServerRandom, PrivateKey}) -> - <> = crypto:mpint(P), - <> = crypto:mpint(G), ServerEDHPSKParams = #server_dhe_psk_params{ hint = PskIdentityHint, - dh_params = #server_dh_params{dh_p = PBin, - dh_g = GBin, dh_y = PublicKey} + dh_params = #server_dh_params{dh_p = int_to_bin(P), + dh_g = int_to_bin(G), dh_y = PublicKey} }, enc_server_key_exchange(Version, ServerEDHPSKParams, HashSign, ClientRandom, ServerRandom, PrivateKey); @@ -1791,3 +1787,7 @@ handle_srp_extension(undefined, Session) -> Session; handle_srp_extension(#srp{username = Username}, Session) -> Session#session{srp_username = Username}. + +int_to_bin(I) -> + L = (length(integer_to_list(I, 16)) + 1) div 2, + <>. diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl index c32ca6dd1f..723ccf4496 100644 --- a/lib/ssl/test/erl_make_certs.erl +++ b/lib/ssl/test/erl_make_certs.erl @@ -409,7 +409,7 @@ int2list(I) -> binary_to_list(<>). gen_ec2(CurveId) -> - {PrivKey, PubKey} = crypto:generate_key(ecdh,CurveId), + {PrivKey, PubKey} = crypto:generate_key(ecdh, CurveId), #'ECPrivateKey'{version = 1, privateKey = int2list(PrivKey), -- cgit v1.2.3 From 50a75c536b50ac2513a846256ba7798e911c1302 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 25 Apr 2013 17:43:05 +0200 Subject: ssl: Fix Curve selection --- lib/ssl/src/ssl_connection.erl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 574032d14a..eb2fc5467d 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -423,7 +423,8 @@ hello(Hello = #client_hello{client_version = ClientVersion}, EcPointFormats, EllipticCurves, State#state{connection_states = ConnectionStates, negotiated_version = Version, - session = Session}); + session = Session, + client_ecc = {EllipticCurves, EcPointFormats}}); #alert{} = Alert -> handle_own_alert(Alert, ClientVersion, hello, State) end; @@ -3079,6 +3080,7 @@ handle_close_alert(Data, StateName, State0) -> ok end. +select_curve(#state{client_ecc = {[Curve|_], _}}) -> + {namedCurve, Curve}; select_curve(_) -> - %%TODO: select prefered curve from extension {namedCurve, ?secp256k1}. -- cgit v1.2.3 From 7c901c92f5936ca2f212300d2f13f899b7a222e0 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 26 Apr 2013 18:08:48 +0200 Subject: crypto: Deprecate functions, update doc and specs --- lib/crypto/doc/src/crypto.xml | 1442 ++++++++++-------------------- lib/crypto/doc/src/crypto_app.xml | 47 +- lib/crypto/src/crypto.erl | 99 +- lib/crypto/test/crypto_SUITE.erl | 86 +- lib/public_key/doc/src/public_key.xml | 16 +- lib/public_key/include/public_key.hrl | 4 +- lib/public_key/src/public_key.erl | 21 +- lib/public_key/test/pkits_SUITE.erl | 11 +- lib/public_key/test/public_key_SUITE.erl | 2 +- lib/ssl/doc/src/ssl.xml | 11 +- lib/ssl/src/ssl_cipher.erl | 2 +- lib/ssl/src/ssl_cipher.hrl | 2 +- lib/ssl/src/ssl_handshake.erl | 9 +- lib/ssl/src/ssl_handshake.hrl | 6 +- lib/ssl/src/ssl_internal.hrl | 4 +- lib/stdlib/src/otp_internal.erl | 72 ++ 16 files changed, 710 insertions(+), 1124 deletions(-) diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 9201d649d7..c4e6993460 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -22,100 +22,115 @@ crypto - Peter Högfeldt - - 2000-06-20 - B crypto Crypto Functions

This module provides a set of cryptographic functions.

-

References:

-

md4: The MD4 Message Digest Algorithm (RFC 1320)

-
- -

md5: The MD5 Message Digest Algorithm (RFC 1321)

-
- -

sha: Secure Hash Standard (FIPS 180-2)

-
- -

hmac: Keyed-Hashing for Message Authentication (RFC 2104)

-
- -

des: Data Encryption Standard (FIPS 46-3)

-
- -

aes: Advanced Encryption Standard (AES) (FIPS 197)

+

Hash functions - The MD4 Message Digest Algorithm (RFC 1320), + The MD5 Message Digest Algorithm (RFC 1321) and + Secure Hash Standard +

-

ecb, cbc, cfb, ofb, ctr: Recommendation for Block Cipher Modes - of Operation (NIST SP 800-38A).

+

Hmac functions - Keyed-Hashing for Message Authentication (RFC 2104)

-

rsa: Recommendation for Block Cipher Modes of Operation - (NIST 800-38A)

+

Block ciphers - DES and AES and + and Block Cipher Modes - ECB, CBC, CFB, OFB and CTR

-

dss: Digital Signature Standard (FIPS 186-2)

+

RSA encryption RFC 1321

-

srp: Secure Remote Password Protocol (RFC 2945)

+

Digital signatures Digital Signature Standard (DSS) and Elliptic Curve Digital + Signature Algorithm (ECDSA)

-

ecdsa: "Public Key Cryptography for the Financial - Services Industry: The Elliptic Curve Digital - Signature Standard (ECDSA)", November, 2005.

+

Secure Remote Password Protocol (SRP - RFC 2945)

- -

ec: Standards for Efficient Cryptography Group (SECG), "SEC 1: - Elliptic Curve Cryptography", Version 1.0, September 2000.

-
- -

ecdsa: American National Standards Institute (ANSI), - ANS X9.62-2005: The Elliptic Curve Digital Signature - Algorithm (ECDSA), 2005.

-
-

The above publications can be found at NIST publications, at IETF. -

-

Types

-
-byte() = 0 ... 255
-ioelem() = byte() | binary() | iolist()
-iolist() = [ioelem()]
-Mpint() = >]]>
-    
-

+ +
+ DATA TYPES + +

byte() = 0 ... 255

+ +

ioelem() = byte() | binary() | iolist()

+ +

iolist() = [ioelem()]

+ +

key_value() = integer() | binary()

+ +

rsa_public() = [key_value()] = [E, N]

+

Where E is the public exponent and N is public modulus.

+ +

rsa_private() = [key_value()] = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]

+

Where E is the public exponent, N is public modulus and D is + the private exponent.The longer key format contains redundant + information that will make the calculation faster. P1,P2 are first + and second prime factors. E1,E2 are first and second exponents. C + is the CRT coefficient. Terminology is taken from RFC 3447.

+ +

dss_public() = [key_value()] = [P, Q, G, Y]

+

Where P, Q and G are the dss parameters and Y is the public key.

+ +

dss_private() = [key_value()] = [P, Q, G, X]

+

Where P, Q and G are the dss parameters and X is the private key.

+ +

dss_public() = [key_value()] =[P, Q, G, Y]

+ +

srp_public() = key_value()

+

Where is A or B from SRP design

+ +

srp_private() = key_value()

+

Where is a or b from SRP design

+ +

srp_params() = {user, [Generator::binary(), Prime::binary(), Version::atom()]} | + {host, [Verifier::binary(), Generator::binary(), Prime::binary(), Version::atom()]} + | {user, [DerivedKey::binary(), Prime::binary(), Generator::binary(), Version::atom() | [Scrambler:binary()]]} + | {host,[Verifier::binary(), Prime::binary(), Version::atom() | [Scrambler::binary]]}

+ +

Where Verifier is v, Generator is g and Prime is N, DerivedKey is X, and Scrambler is + u (optional will be genrated if not provided) from SRP design + Version = '3' | '6' | '6a' +

+ +

dh_public() = key_value()

+ +

dh_private() = key_value()

+ +

dh_params() = [key_value()] = [P, G]

+ +

ecdh_public() = key_value()

+ +

ecdh_private() = key_value()

+ +

ecdh_params() = ec_named_curve() | + {ec_field(), Prime :: key_value(), Point :: key_value(), Order :: integer(), CoFactor :: none | integer()}

+ +

ec_field() = {prime_field, Prime :: integer()} | + {characteristic_two_field, M :: integer(), Basis :: ec_basis()}

+ +

ec_basis() = {tpbasis, K :: non_neg_integer()} | + {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | + onbasis

+ +

ec_named_curve() -> + sect571r1| sect571k1| sect409r1| sect409k1| secp521r1| secp384r1| secp224r1| secp224k1| + secp192k1| secp160r2| secp128r2| secp128r1| sect233r1| sect233k1| sect193r2| sect193r1| + sect131r2| sect131r1| sect283r1| sect283k1| sect163r2| secp256k1| secp160k1| secp160r1| + secp112r2| secp112r1| sect113r2| sect113r1| sect239k1| sect163r1| sect163k1| secp256r1| + secp192r1

+ +
+ - - start() -> ok - Start the crypto server. - -

Starts the crypto server.

-
-
- - stop() -> ok - Stop the crypto server. - -

Stops the crypto server.

-
-
- - info() -> [atom()] - Provide a list of available crypto functions. - -

Provides the available crypto functions in terms of a list - of atoms.

-
-
- + algorithms() -> [atom()] Provide a list of available crypto algorithms. @@ -123,170 +138,52 @@ Mpint() = >]]> of atoms.

+ - info_lib() -> [{Name,VerNum,VerStr}] - Provides information about the libraries used by crypto. - - Name = binary() - VerNum = integer() - VerStr = binary() - - -

Provides the name and version of the libraries used by crypto.

-

Name is the name of the library. VerNum is - the numeric version according to the library's own versioning - scheme. VerStr contains a text variant of the version.

-
-> info_lib().
-[{<<"OpenSSL">>,9469983,<<"OpenSSL 0.9.8a 11 Oct 2005">>}]
-        
-

- From OTP R16 the numeric version represents the version of the OpenSSL - header files (openssl/opensslv.h) used when crypto was compiled. - The text variant represents the OpenSSL library used at runtime. - In earlier OTP versions both numeric and text was taken from the library. -

-
-
- - md4(Data) -> Digest - Compute an MD4message digest from Data - - Data = iolist() | binary() - Digest = binary() - - -

Computes an MD4 message digest from Data, where - the length of the digest is 128 bits (16 bytes).

-
-
- - md4_init() -> Context - Creates an MD4 context - - Context = binary() - - -

Creates an MD4 context, to be used in subsequent calls to - md4_update/2.

-
-
- - md4_update(Context, Data) -> NewContext - Update an MD4 Contextwith Data, and return a NewContext - - Data = iolist() | binary() - Context = NewContext = binary() - - -

Updates an MD4 Context with Data, and returns - a NewContext.

-
-
- - md4_final(Context) -> Digest - Finish the update of an MD4 Contextand return the computed MD4message digest - - Context = Digest = binary() - - -

Finishes the update of an MD4 Context and returns - the computed MD4 message digest.

-
-
- - md5(Data) -> Digest - Compute an MD5message digest from Data - - Data = iolist() | binary() - Digest = binary() - - -

Computes an MD5 message digest from Data, where - the length of the digest is 128 bits (16 bytes).

-
-
- - md5_init() -> Context - Creates an MD5 context - - Context = binary() - - -

Creates an MD5 context, to be used in subsequent calls to - md5_update/2.

-
-
- - md5_update(Context, Data) -> NewContext - Update an MD5 Contextwith Data, and return a NewContext - - Data = iolist() | binary() - Context = NewContext = binary() - - -

Updates an MD5 Context with Data, and returns - a NewContext.

-
-
- - md5_final(Context) -> Digest - Finish the update of an MD5 Contextand return the computed MD5message digest - - Context = Digest = binary() - - -

Finishes the update of an MD5 Context and returns - the computed MD5 message digest.

-
-
- - sha(Data) -> Digest - Compute an SHAmessage digest from Data - - Data = iolist() | binary() - Digest = binary() - - -

Computes an SHA message digest from Data, where - the length of the digest is 160 bits (20 bytes).

-
-
- - sha_init() -> Context - Create an SHA context + compute_key(Type, OthersPublicKey, MyPrivateKey, Params) -> SharedSecret + Computes the shared secret - Context = binary() + Type = dh | ecdh | srp + OthersPublicKey = dh_public() | ecdh_public() | srp_public() + MyPrivate = dh_private() | ecdh_private() | srp_private() + Params = dh_params() | edhc_params() | srp_params() + SharedSecret = binary() -

Creates an SHA context, to be used in subsequent calls to - sha_update/2.

+

Computes the shared secret from the private key and the other party's public key. +

+ - sha_update(Context, Data) -> NewContext - Update an SHA context + exor(Data1, Data2) -> Result + XOR data - Data = iolist() | binary() - Context = NewContext = binary() + Data1, Data2 = iolist() | binary() + Result = binary() -

Updates an SHA Context with Data, and returns - a NewContext.

+

Performs bit-wise XOR (exclusive or) on the data supplied.

- - sha_final(Context) -> Digest - Finish the update of an SHA context + + + generate_key(Type, Params) -> {PublicKey, PrivateKey} + generate_key(Type, Params, PrivateKey) -> {PublicKey, PrivateKey} + Generates a public keys of type Type - Context = Digest = binary() + Type = dh | ecdh | srp + Params = dh_params() | edhc_params() | srp_params() + PublicKey = dh_public() | ecdh_public() | srp_public() + PrivateKey = dh_private() | ecdh_private() | srp_private() -

Finishes the update of an SHA Context and returns - the computed SHA message digest.

+

Generates public keys of type Type. +

- + + hash(Type, Data) -> Digest @@ -300,6 +197,7 @@ Mpint() = >]]> is not supported by the underlying OpenSSL implementation.

+ hash_init(Type) -> Context @@ -314,6 +212,7 @@ Mpint() = >]]> is not supported by the underlying OpenSSL implementation.

+ hash_update(Context, Data) -> NewContext @@ -341,32 +240,7 @@ Mpint() = >]]> function used to generate it.

- - md5_mac(Key, Data) -> Mac - Compute an MD5 MACmessage authentification code - - Key = Data = iolist() | binary() - Mac = binary() - - -

Computes an MD5 MAC message authentification code - from Key and Data, where the the length of the - Mac is 128 bits (16 bytes).

-
-
- - md5_mac_96(Key, Data) -> Mac - Compute an MD5 MACmessage authentification code - - Key = Data = iolist() | binary() - Mac = binary() - - -

Computes an MD5 MAC message authentification code - from Key and Data, where the length of the Mac - is 96 bits (12 bytes).

-
-
+ hmac(Type, Key, Data) -> Mac hmac(Type, Key, Data, MacLength) -> Mac @@ -384,6 +258,7 @@ Mpint() = >]]> will limit the size of the resultant Mac. + hmac_init(Type, Key) -> Context @@ -398,6 +273,7 @@ Mpint() = >]]> key. The key can be any length.

+ hmac_update(Context, Data) -> NewContext @@ -412,6 +288,7 @@ Mpint() = >]]> must be passed into the next call to hmac_update.

+ hmac_final(Context) -> Mac @@ -423,6 +300,7 @@ Mpint() = >]]> determined by the type of hash function used to generate it.

+ hmac_final_n(Context, HashLen) -> Mac @@ -435,318 +313,143 @@ Mpint() = >]]> zero. Mac will be a binary with at most HashLen bytes. Note that if HashLen is greater than the actual number of bytes returned from the underlying hash, the returned hash will have fewer than HashLen bytes.

+ + + info() -> [atom()] + Provide a list of available crypto functions. + +

Provides the available crypto functions in terms of a list + of atoms.

+
+
+ - sha_mac(Key, Data) -> Mac - sha_mac(Key, Data, MacLength) -> Mac - Compute an MD5 MACmessage authentification code + info_lib() -> [{Name,VerNum,VerStr}] + Provides information about the libraries used by crypto. - Key = Data = iolist() | binary() - Mac = binary() - MacLenength = integer() =< 20 + Name = binary() + VerNum = integer() + VerStr = binary() -

Computes an SHA MAC message authentification code - from Key and Data, where the default length of the Mac - is 160 bits (20 bytes).

+

Provides the name and version of the libraries used by crypto.

+

Name is the name of the library. VerNum is + the numeric version according to the library's own versioning + scheme. VerStr contains a text variant of the version.

+
+> info_lib().
+[{<<"OpenSSL">>,9469983,<<"OpenSSL 0.9.8a 11 Oct 2005">>}]
+        
+

+ From OTP R16 the numeric version represents the version of the OpenSSL + header files (openssl/opensslv.h) used when crypto was compiled. + The text variant represents the OpenSSL library used at runtime. + In earlier OTP versions both numeric and text was taken from the library. +

+ - sha_mac_96(Key, Data) -> Mac - Compute an SHA MACmessage authentification code + mod_exp_prime(N, P, M) -> Result + Computes the function: N^P mod M - Key = Data = iolist() | binary() - Mac = binary() + N, P, M = binary() + Result = binary() | error -

Computes an SHA MAC message authentification code - from Key and Data, where the length of the Mac - is 96 bits (12 bytes).

+

Computes the function N^P mod M.

+ - des_cbc_encrypt(Key, IVec, Text) -> Cipher - Encrypt Textaccording to DES in CBC mode + rand_bytes(N) -> binary() + Generate a binary of random bytes - Key = Text = iolist() | binary() - IVec = Cipher = binary() + N = integer() -

Encrypts Text according to DES in CBC - mode. Text must be a multiple of 64 bits (8 - bytes). Key is the DES key, and IVec is an - arbitrary initializing vector. The lengths of Key and - IVec must be 64 bits (8 bytes).

+

Generates N bytes randomly uniform 0..255, and returns the + result in a binary. Uses the crypto library pseudo-random + number generator.

- - des_cbc_decrypt(Key, IVec, Cipher) -> Text - Decrypt Cipheraccording to DES in CBC mode + + + rand_uniform(Lo, Hi) -> N + Generate a random number - Key = Cipher = iolist() | binary() - IVec = Text = binary() + Lo, Hi, N = integer() -

Decrypts Cipher according to DES in CBC mode. - Key is the DES key, and IVec is an arbitrary - initializing vector. Key and IVec must have - the same values as those used when encrypting. Cipher - must be a multiple of 64 bits (8 bytes). The lengths of - Key and IVec must be 64 bits (8 bytes).

+

Generate a random number Uses the + crypto library pseudo-random number generator. + Hi must be larger than Lo.

+ - des_cbc_ivec(Data) -> IVec - Get IVec to be used in next iteration of - des_cbc_[ecrypt|decrypt] + sign(Algorithm, DigestType, Msg, Key) -> binary() + Create digital signature. - Data = iolist() | binary() - IVec = binary() + Algorithm = rsa | dss | ecdsa + Msg = binary() | {digest,binary()} + 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. + DigestType = digest_type() + Key = rsa_private_key() | dsa_private_key() | ec_private_key() -

Returns the IVec to be used in a next iteration of - des_cbc_[encrypt|decrypt]. Data is the encrypted - data from the previous iteration step.

-
-
- - des_cfb_encrypt(Key, IVec, Text) -> Cipher - Encrypt Textaccording to DES in CFB mode - - Key = Text = iolist() | binary() - IVec = Cipher = binary() - - -

Encrypts Text according to DES in 8-bit CFB - mode. Key is the DES key, and IVec is an - arbitrary initializing vector. The lengths of Key and - IVec must be 64 bits (8 bytes).

-
-
- - des_cfb_decrypt(Key, IVec, Cipher) -> Text - Decrypt Cipheraccording to DES in CFB mode - - Key = Cipher = iolist() | binary() - IVec = Text = binary() - - -

Decrypts Cipher according to DES in 8-bit CFB mode. - Key is the DES key, and IVec is an arbitrary - initializing vector. Key and IVec must have - the same values as those used when encrypting. The lengths of - Key and IVec must be 64 bits (8 bytes).

-
-
- - des_cfb_ivec(IVec, Data) -> NextIVec - Get IVec to be used in next iteration of - des_cfb_[ecrypt|decrypt] - - IVec = iolist() | binary() - Data = iolist() | binary() - NextIVec = binary() - - -

Returns the IVec to be used in a next iteration of - des_cfb_[encrypt|decrypt]. IVec is the vector - used in the previous iteration step. Data is the encrypted - data from the previous iteration step.

-
-
- - des3_cbc_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher - Encrypt Textaccording to DES3 in CBC mode - - Key1 =Key2 = Key3 Text = iolist() | binary() - IVec = Cipher = binary() - - -

Encrypts Text according to DES3 in CBC - mode. Text must be a multiple of 64 bits (8 - bytes). Key1, Key2, Key3, are the DES - keys, and IVec is an arbitrary initializing - vector. The lengths of each of Key1, Key2, - Key3 and IVec must be 64 bits (8 bytes).

-
-
- - des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text - Decrypt Cipheraccording to DES3 in CBC mode - - Key1 = Key2 = Key3 = Cipher = iolist() | binary() - IVec = Text = binary() - - -

Decrypts Cipher according to DES3 in CBC mode. - Key1, Key2, Key3 are the DES key, and - IVec is an arbitrary initializing vector. - Key1, Key2, Key3 and IVec must - and IVec must have the same values as those used when - encrypting. Cipher must be a multiple of 64 bits (8 - bytes). The lengths of Key1, Key2, - Key3, and IVec must be 64 bits (8 bytes).

-
-
- - des3_cfb_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher - Encrypt Textaccording to DES3 in CFB mode - - Key1 =Key2 = Key3 Text = iolist() | binary() - IVec = Cipher = binary() - - -

Encrypts Text according to DES3 in 8-bit CFB - mode. Key1, Key2, Key3, are the DES - keys, and IVec is an arbitrary initializing - vector. The lengths of each of Key1, Key2, - Key3 and IVec must be 64 bits (8 bytes).

-

May throw exception notsup for old OpenSSL - versions (0.9.7) that does not support this encryption mode.

-
-
- - des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text - Decrypt Cipheraccording to DES3 in CFB mode - - Key1 = Key2 = Key3 = Cipher = iolist() | binary() - IVec = Text = binary() - - -

Decrypts Cipher according to DES3 in 8-bit CFB mode. - Key1, Key2, Key3 are the DES key, and - IVec is an arbitrary initializing vector. - Key1, Key2, Key3 and IVec must - and IVec must have the same values as those used when - encrypting. The lengths of Key1, Key2, - Key3, and IVec must be 64 bits (8 bytes).

-

May throw exception notsup for old OpenSSL - versions (0.9.7) that does not support this encryption mode.

-
-
- - - des_ecb_encrypt(Key, Text) -> Cipher - Encrypt Textaccording to DES in ECB mode - - Key = Text = iolist() | binary() - Cipher = binary() - - -

Encrypts Text according to DES in ECB mode. - Key is the DES key. The lengths of Key and - Text must be 64 bits (8 bytes).

-
-
- - des_ecb_decrypt(Key, Cipher) -> Text - Decrypt Cipheraccording to DES in ECB mode - - Key = Cipher = iolist() | binary() - Text = binary() - - -

Decrypts Cipher according to DES in ECB mode. - Key is the DES key. The lengths of Key and - Cipher must be 64 bits (8 bytes).

-
-
- - - blowfish_ecb_encrypt(Key, Text) -> Cipher - Encrypt the first 64 bits of Text using Blowfish in ECB mode - - Key = Text = iolist() | binary() - Cipher = binary() - - -

Encrypts the first 64 bits of Text using Blowfish in ECB mode. Key is the Blowfish key. The length of Text must be at least 64 bits (8 bytes).

-
-
- - blowfish_ecb_decrypt(Key, Text) -> Cipher - Decrypt the first 64 bits of Text using Blowfish in ECB mode - - Key = Text = iolist() | binary() - Cipher = binary() - - -

Decrypts the first 64 bits of Text using Blowfish in ECB mode. Key is the Blowfish key. The length of Text must be at least 64 bits (8 bytes).

+

Creates a digital signature.

- blowfish_cbc_encrypt(Key, IVec, Text) -> Cipher - Encrypt Text using Blowfish in CBC mode - - Key = Text = iolist() | binary() - IVec = Cipher = binary() - + start() -> ok + Equivalent to application:start(crypto). -

Encrypts Text using Blowfish in CBC mode. Key is the Blowfish key, and IVec is an - arbitrary initializing vector. The length of IVec - must be 64 bits (8 bytes). The length of Text must be a multiple of 64 bits (8 bytes).

+

Equivalent to application:start(crypto).

- blowfish_cbc_decrypt(Key, IVec, Text) -> Cipher - Decrypt Text using Blowfish in CBC mode - - Key = Text = iolist() | binary() - IVec = Cipher = binary() - + stop() -> ok + Equivalent to application:stop(crypto). -

Decrypts Text using Blowfish in CBC mode. Key is the Blowfish key, and IVec is an - arbitrary initializing vector. The length of IVec - must be 64 bits (8 bytes). The length of Text must be a multiple 64 bits (8 bytes).

+

Equivalent to application:stop(crypto).

- blowfish_cfb64_encrypt(Key, IVec, Text) -> Cipher - Encrypt Textusing Blowfish in CFB mode with 64 - bit feedback - - Key = Text = iolist() | binary() - IVec = Cipher = binary() - - -

Encrypts Text using Blowfish in CFB mode with 64 bit - feedback. Key is the Blowfish key, and IVec is an - arbitrary initializing vector. The length of IVec - must be 64 bits (8 bytes).

-
-
- - blowfish_cfb64_decrypt(Key, IVec, Text) -> Cipher - Decrypt Textusing Blowfish in CFB mode with 64 - bit feedback + strong_rand_bytes(N) -> binary() + Generate a binary of random bytes - Key = Text = iolist() | binary() - IVec = Cipher = binary() + N = integer() -

Decrypts Text using Blowfish in CFB mode with 64 bit - feedback. Key is the Blowfish key, and IVec is an - arbitrary initializing vector. The length of IVec - must be 64 bits (8 bytes).

+

Generates N bytes randomly uniform 0..255, and returns the + result in a binary. Uses a cryptographically secure prng seeded and + periodically mixed with operating system provided entropy. By default + this is the RAND_bytes method from OpenSSL.

+

May throw exception low_entropy in case the random generator + failed due to lack of secure "randomness".

- - blowfish_ofb64_encrypt(Key, IVec, Text) -> Cipher - Encrypt Textusing Blowfish in OFB mode with 64 - bit feedback + verify(Algorithm, DigestType, Msg, Signature, Key) -> boolean() + Verifies a digital signature. - Key = Text = iolist() | binary() - IVec = Cipher = binary() + Algorithm = rsa | dss | ecdsa + Msg = binary() | {digest,binary()} + The msg is either the binary "plain text" data + or it is the hashed value of "plain text" i.e. the digest. + DigestType = digest_type() + Signature = binary() + Key = rsa_public_key() | dsa_public_key() | ec_public_key() -

Encrypts Text using Blowfish in OFB mode with 64 bit - feedback. Key is the Blowfish key, and IVec is an - arbitrary initializing vector. The length of IVec - must be 64 bits (8 bytes).

+

Verifies a digital signature

-
+
aes_cfb_128_encrypt(Key, IVec, Text) -> Cipher @@ -763,6 +466,7 @@ Mpint() = >]]> (16 bytes).

+ aes_cfb_128_decrypt(Key, IVec, Cipher) -> Text Decrypt Cipheraccording to AES in Cipher Feedback mode @@ -778,6 +482,7 @@ Mpint() = >]]> Key and IVec must be 128 bits (16 bytes).

+ aes_cbc_128_encrypt(Key, IVec, Text) -> Cipher Encrypt Textaccording to AES in Cipher Block Chaining mode @@ -794,6 +499,7 @@ Mpint() = >]]> (16 bytes).

+ aes_cbc_128_decrypt(Key, IVec, Cipher) -> Text Decrypt Cipheraccording to AES in Cipher Block Chaining mode @@ -811,6 +517,7 @@ Mpint() = >]]> Key and IVec must be 128 bits (16 bytes).

+ aes_cbc_ivec(Data) -> IVec Get IVec to be used in next iteration of @@ -825,6 +532,7 @@ Mpint() = >]]> data from the previous iteration step.

+ aes_ctr_encrypt(Key, IVec, Text) -> Cipher Encrypt Textaccording to AES in Counter mode @@ -839,6 +547,7 @@ Mpint() = >]]> (16 bytes).

+ aes_ctr_decrypt(Key, IVec, Cipher) -> Text Decrypt Cipheraccording to AES in Counter mode @@ -853,6 +562,7 @@ Mpint() = >]]> (16 bytes).

+ aes_ctr_stream_init(Key, IVec) -> State @@ -870,6 +580,7 @@ Mpint() = >]]> aes_ctr_stream_decrypt.

+ aes_ctr_stream_encrypt(State, Text) -> { NewState, Cipher} @@ -886,6 +597,7 @@ Mpint() = >]]> Cipher is the encrypted cipher text.

+ aes_ctr_stream_decrypt(State, Cipher) -> { NewState, Text } @@ -902,620 +614,446 @@ Mpint() = >]]> Text is the decrypted data.

- - erlint(Mpint) -> N - mpint(N) -> Mpint - Convert between binary multi-precision integer and erlang big integer - - Mpint = binary() - N = integer() + + + blowfish_ecb_encrypt(Key, Text) -> Cipher + Encrypt the first 64 bits of Text using Blowfish in ECB mode + + Key = Text = iolist() | binary() + Cipher = binary() -

Convert a binary multi-precision integer Mpint to and from - an erlang big integer. A multi-precision integer is a binary - with the following form: - >]]> where both - ByteLen and Bytes are big-endian. Mpints are used in - some of the functions in crypto and are not translated - in the API for performance reasons.

+

Encrypts the first 64 bits of Text using Blowfish in ECB mode. Key is the Blowfish key. The length of Text must be at least 64 bits (8 bytes).

+ - rand_bytes(N) -> binary() - Generate a binary of random bytes + blowfish_ecb_decrypt(Key, Text) -> Cipher + Decrypt the first 64 bits of Text using Blowfish in ECB mode - N = integer() + Key = Text = iolist() | binary() + Cipher = binary() -

Generates N bytes randomly uniform 0..255, and returns the - result in a binary. Uses the crypto library pseudo-random - number generator.

-
-
- - strong_rand_bytes(N) -> binary() - Generate a binary of random bytes - - N = integer() - - -

Generates N bytes randomly uniform 0..255, and returns the - result in a binary. Uses a cryptographically secure prng seeded and - periodically mixed with operating system provided entropy. By default - this is the RAND_bytes method from OpenSSL.

-

May throw exception low_entropy in case the random generator - failed due to lack of secure "randomness".

+

Decrypts the first 64 bits of Text using Blowfish in ECB mode. Key is the Blowfish key. The length of Text must be at least 64 bits (8 bytes).

+ - rand_uniform(Lo, Hi) -> N - Generate a random number + blowfish_cbc_encrypt(Key, IVec, Text) -> Cipher + Encrypt Text using Blowfish in CBC mode - Lo, Hi, N = Mpint | integer() - Mpint = binary() + Key = Text = iolist() | binary() + IVec = Cipher = binary() -

Generate a random number Uses the - crypto library pseudo-random number generator. The - arguments (and result) can be either erlang integers or binary - multi-precision integers. Hi must be larger than Lo.

+

Encrypts Text using Blowfish in CBC mode. Key is the Blowfish key, and IVec is an + arbitrary initializing vector. The length of IVec + must be 64 bits (8 bytes). The length of Text must be a multiple of 64 bits (8 bytes).

- strong_rand_mpint(N, Top, Bottom) -> Mpint - Generate an N bit random number + blowfish_cbc_decrypt(Key, IVec, Text) -> Cipher + Decrypt Text using Blowfish in CBC mode - N = non_neg_integer() - Top = -1 | 0 | 1 - Bottom = 0 | 1 - Mpint = binary() + Key = Text = iolist() | binary() + IVec = Cipher = binary() -

Generate an N bit random number using OpenSSL's - cryptographically strong pseudo random number generator - BN_rand.

-

The parameter Top places constraints on the most - significant bits of the generated number. If Top is 1, then the - two most significant bits will be set to 1, if Top is 0, the - most significant bit will be 1, and if Top is -1 then no - constraints are applied and thus the generated number may be less than - N bits long.

-

If Bottom is 1, then the generated number is - constrained to be odd.

-

May throw exception low_entropy in case the random generator - failed due to lack of secure "randomness".

+

Decrypts Text using Blowfish in CBC mode. Key is the Blowfish key, and IVec is an + arbitrary initializing vector. The length of IVec + must be 64 bits (8 bytes). The length of Text must be a multiple 64 bits (8 bytes).

+ - mod_exp(N, P, M) -> Result - Perform N ^ P mod M + blowfish_cfb64_encrypt(Key, IVec, Text) -> Cipher + Encrypt Textusing Blowfish in CFB mode with 64 + bit feedback - N, P, M, Result = Mpint - Mpint = binary() + Key = Text = iolist() | binary() + IVec = Cipher = binary() -

This function performs the exponentiation N ^ P mod M, - using the crypto library.

+

Encrypts Text using Blowfish in CFB mode with 64 bit + feedback. Key is the Blowfish key, and IVec is an + arbitrary initializing vector. The length of IVec + must be 64 bits (8 bytes).

+ - mod_exp_prime(N, P, M) -> Result - Computes the function: N^P mod M + blowfish_cfb64_decrypt(Key, IVec, Text) -> Cipher + Decrypt Textusing Blowfish in CFB mode with 64 + bit feedback - N, P, M = binary() - Result = binary() | error + Key = Text = iolist() | binary() + IVec = Cipher = binary() -

Computes the function N^P mod M.

+

Decrypts Text using Blowfish in CFB mode with 64 bit + feedback. Key is the Blowfish key, and IVec is an + arbitrary initializing vector. The length of IVec + must be 64 bits (8 bytes).

+ - rsa_sign(DataOrDigest, Key) -> Signature - rsa_sign(DigestType, DataOrDigest, Key) -> Signature - Sign the data using rsa with the given key. + blowfish_ofb64_encrypt(Key, IVec, Text) -> Cipher + Encrypt Textusing Blowfish in OFB mode with 64 + bit feedback - DataOrDigest = Data | {digest,Digest} - Data = Mpint - Digest = binary() - Key = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] - E, N, D = Mpint - Where E is the public exponent, N is public modulus and - D is the private exponent. - P1, P2, E1, E2, C = Mpint - The longer key format contains redundant information that will make - the calculation faster. P1,P2 are first and second prime factors. - E1,E2 are first and second exponents. C is the CRT coefficient. - Terminology is taken from RFC 3447. - DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512 - The default DigestType is sha. - Mpint = binary() - Signature = binary() + Key = Text = iolist() | binary() + IVec = Cipher = binary() -

Creates a RSA signature with the private key Key - of a digest. The digest is either calculated as a - DigestType digest of Data or a precalculated - binary Digest.

+

Encrypts Text using Blowfish in OFB mode with 64 bit + feedback. Key is the Blowfish key, and IVec is an + arbitrary initializing vector. The length of IVec + must be 64 bits (8 bytes).

- rsa_verify(DataOrDigest, Signature, Key) -> Verified - rsa_verify(DigestType, DataOrDigest, Signature, Key) -> Verified - Verify the digest and signature using rsa with given public key. + des_cbc_encrypt(Key, IVec, Text) -> Cipher + Encrypt Textaccording to DES in CBC mode - Verified = boolean() - DataOrDigest = Data | {digest|Digest} - Data, Signature = Mpint - Digest = binary() - Key = [E, N] - E, N = Mpint - Where E is the public exponent and N is public modulus. - DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512 - The default DigestType is sha. - Mpint = binary() + Key = Text = iolist() | binary() + IVec = Cipher = binary() -

Verifies that a digest matches the RSA signature using the - signer's public key Key. - The digest is either calculated as a DigestType - digest of Data or a precalculated binary Digest.

-

May throw exception notsup in case the chosen DigestType - is not supported by the underlying OpenSSL implementation.

+

Encrypts Text according to DES in CBC + mode. Text must be a multiple of 64 bits (8 + bytes). Key is the DES key, and IVec is an + arbitrary initializing vector. The lengths of Key and + IVec must be 64 bits (8 bytes).

- + - rsa_public_encrypt(PlainText, PublicKey, Padding) -> ChipherText - Encrypts Msg using the public Key. + des_cbc_decrypt(Key, IVec, Cipher) -> Text + Decrypt Cipheraccording to DES in CBC mode - PlainText = binary() - PublicKey = [E, N] - E, N = Mpint - Where E is the public exponent and N is public modulus. - Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding - ChipherText = binary() + Key = Cipher = iolist() | binary() + IVec = Text = binary() -

Encrypts the PlainText (usually a session key) using the PublicKey - and returns the cipher. The Padding decides what padding mode is used, - rsa_pkcs1_padding is PKCS #1 v1.5 currently the most - used mode and rsa_pkcs1_oaep_padding is EME-OAEP as - defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding - parameter. This mode is recommended for all new applications. - The size of the Msg must be less - than byte_size(N)-11 if - rsa_pkcs1_padding is used, byte_size(N)-41 if - rsa_pkcs1_oaep_padding is used and byte_size(N) if rsa_no_padding - is used. - Where byte_size(N) is the size part of an Mpint-1. -

+

Decrypts Cipher according to DES in CBC mode. + Key is the DES key, and IVec is an arbitrary + initializing vector. Key and IVec must have + the same values as those used when encrypting. Cipher + must be a multiple of 64 bits (8 bytes). The lengths of + Key and IVec must be 64 bits (8 bytes).

- rsa_private_decrypt(ChipherText, PrivateKey, Padding) -> PlainText - Decrypts ChipherText using the private Key. + des_cbc_ivec(Data) -> IVec + Get IVec to be used in next iteration of + des_cbc_[ecrypt|decrypt] - ChipherText = binary() - PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] - E, N, D = Mpint - Where E is the public exponent, N is public modulus and - D is the private exponent. - P1, P2, E1, E2, C = Mpint - The longer key format contains redundant information that will make - the calculation faster. P1,P2 are first and second prime factors. - E1,E2 are first and second exponents. C is the CRT coefficient. - Terminology is taken from RFC 3447. - Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding - PlainText = binary() + Data = iolist() | binary() + IVec = binary() -

Decrypts the ChipherText (usually a session key encrypted with - rsa_public_encrypt/3) - using the PrivateKey and returns the - message. The Padding is the padding mode that was - used to encrypt the data, - see rsa_public_encrypt/3. -

+

Returns the IVec to be used in a next iteration of + des_cbc_[encrypt|decrypt]. Data is the encrypted + data from the previous iteration step.

+ - rsa_private_encrypt(PlainText, PrivateKey, Padding) -> ChipherText - Encrypts Msg using the private Key. + des_cfb_encrypt(Key, IVec, Text) -> Cipher + Encrypt Textaccording to DES in CFB mode - PlainText = binary() - PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] - E, N, D = Mpint - Where E is the public exponent, N is public modulus and - D is the private exponent. - P1, P2, E1, E2, C = Mpint - The longer key format contains redundant information that will make - the calculation faster. P1,P2 are first and second prime factors. - E1,E2 are first and second exponents. C is the CRT coefficient. - Terminology is taken from RFC 3447. - Padding = rsa_pkcs1_padding | rsa_no_padding - ChipherText = binary() + Key = Text = iolist() | binary() + IVec = Cipher = binary() -

Encrypts the PlainText using the PrivateKey - and returns the cipher. The Padding decides what padding mode is used, - rsa_pkcs1_padding is PKCS #1 v1.5 currently the most - used mode. - The size of the Msg must be less than byte_size(N)-11 if - rsa_pkcs1_padding is used, and byte_size(N) if rsa_no_padding - is used. Where byte_size(N) is the size part of an Mpint-1. -

+

Encrypts Text according to DES in 8-bit CFB + mode. Key is the DES key, and IVec is an + arbitrary initializing vector. The lengths of Key and + IVec must be 64 bits (8 bytes).

- rsa_public_decrypt(ChipherText, PublicKey, Padding) -> PlainText - Decrypts ChipherText using the public Key. + des_cfb_decrypt(Key, IVec, Cipher) -> Text + Decrypt Cipheraccording to DES in CFB mode - ChipherText = binary() - PublicKey = [E, N] - E, N = Mpint - Where E is the public exponent and N is public modulus - Padding = rsa_pkcs1_padding | rsa_no_padding - PlainText = binary() + Key = Cipher = iolist() | binary() + IVec = Text = binary() -

Decrypts the ChipherText (encrypted with - rsa_private_encrypt/3) - using the PrivateKey and returns the - message. The Padding is the padding mode that was - used to encrypt the data, - see rsa_private_encrypt/3. -

+

Decrypts Cipher according to DES in 8-bit CFB mode. + Key is the DES key, and IVec is an arbitrary + initializing vector. Key and IVec must have + the same values as those used when encrypting. The lengths of + Key and IVec must be 64 bits (8 bytes).

- + - dss_sign(DataOrDigest, Key) -> Signature - dss_sign(DigestType, DataOrDigest, Key) -> Signature - Sign the data using dsa with given private key. + des_cfb_ivec(IVec, Data) -> NextIVec + Get IVec to be used in next iteration of + des_cfb_[ecrypt|decrypt] - DigestType = sha - DataOrDigest = Mpint | {digest,Digest} - Key = [P, Q, G, X] - P, Q, G, X = Mpint - Where P, Q and G are the dss - parameters and X is the private key. - Digest = binary() with length 20 bytes - Signature = binary() + IVec = iolist() | binary() + Data = iolist() | binary() + NextIVec = binary() -

Creates a DSS signature with the private key Key of - a digest. The digest is either calculated as a SHA1 - digest of Data or a precalculated binary Digest.

-

A deprecated feature is having DigestType = 'none' - in which case DataOrDigest is a precalculated SHA1 - digest.

+

Returns the IVec to be used in a next iteration of + des_cfb_[encrypt|decrypt]. IVec is the vector + used in the previous iteration step. Data is the encrypted + data from the previous iteration step.

- dss_verify(DataOrDigest, Signature, Key) -> Verified - dss_verify(DigestType, DataOrDigest, Signature, Key) -> Verified - Verify the data and signature using dsa with given public key. + des3_cbc_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher + Encrypt Textaccording to DES3 in CBC mode - Verified = boolean() - DigestType = sha - DataOrDigest = Mpint | {digest,Digest} - Data = Mpint | ShaDigest - Signature = Mpint - Key = [P, Q, G, Y] - P, Q, G, Y = Mpint - Where P, Q and G are the dss - parameters and Y is the public key. - Digest = binary() with length 20 bytes + Key1 =Key2 = Key3 Text = iolist() | binary() + IVec = Cipher = binary() -

Verifies that a digest matches the DSS signature using the - public key Key. The digest is either calculated as a SHA1 - digest of Data or is a precalculated binary Digest.

-

A deprecated feature is having DigestType = 'none' - in which case DataOrDigest is a precalculated SHA1 - digest binary.

+

Encrypts Text according to DES3 in CBC + mode. Text must be a multiple of 64 bits (8 + bytes). Key1, Key2, Key3, are the DES + keys, and IVec is an arbitrary initializing + vector. The lengths of each of Key1, Key2, + Key3 and IVec must be 64 bits (8 bytes).

- rc2_cbc_encrypt(Key, IVec, Text) -> Cipher - Encrypt Textaccording to RC2 in CBC mode + des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text + Decrypt Cipheraccording to DES3 in CBC mode - Key = Text = iolist() | binary() - Ivec = Cipher = binary() + Key1 = Key2 = Key3 = Cipher = iolist() | binary() + IVec = Text = binary() -

Encrypts Text according to RC2 in CBC mode.

+

Decrypts Cipher according to DES3 in CBC mode. + Key1, Key2, Key3 are the DES key, and + IVec is an arbitrary initializing vector. + Key1, Key2, Key3 and IVec must + and IVec must have the same values as those used when + encrypting. Cipher must be a multiple of 64 bits (8 + bytes). The lengths of Key1, Key2, + Key3, and IVec must be 64 bits (8 bytes).

- rc2_cbc_decrypt(Key, IVec, Cipher) -> Text - Decrypts Cipheraccording to RC2 in CBC mode + des3_cfb_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher + Encrypt Textaccording to DES3 in CFB mode - Key = Text = iolist() | binary() - Ivec = Cipher = binary() + Key1 =Key2 = Key3 Text = iolist() | binary() + IVec = Cipher = binary() -

Decrypts Cipher according to RC2 in CBC mode.

+

Encrypts Text according to DES3 in 8-bit CFB + mode. Key1, Key2, Key3, are the DES + keys, and IVec is an arbitrary initializing + vector. The lengths of each of Key1, Key2, + Key3 and IVec must be 64 bits (8 bytes).

+

May throw exception notsup for old OpenSSL + versions (0.9.7) that does not support this encryption mode.

- + - rc4_encrypt(Key, Data) -> Result - Encrypt data using RC4 + des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text + Decrypt Cipheraccording to DES3 in CFB mode - Key, Data = iolist() | binary() - Result = binary() + Key1 = Key2 = Key3 = Cipher = iolist() | binary() + IVec = Text = binary() -

Encrypts the data with RC4 symmetric stream encryption. - Since it is symmetric, the same function is used for - decryption.

+

Decrypts Cipher according to DES3 in 8-bit CFB mode. + Key1, Key2, Key3 are the DES key, and + IVec is an arbitrary initializing vector. + Key1, Key2, Key3 and IVec must + and IVec must have the same values as those used when + encrypting. The lengths of Key1, Key2, + Key3, and IVec must be 64 bits (8 bytes).

+

May throw exception notsup for old OpenSSL + versions (0.9.7) that does not support this encryption mode.

- dh_generate_key(DHParams) -> {PublicKey,PrivateKey} - dh_generate_key(PrivateKey, DHParams) -> {PublicKey,PrivateKey} - Generates a Diffie-Hellman public key + des_ecb_encrypt(Key, Text) -> Cipher + Encrypt Textaccording to DES in ECB mode - DHParameters = [P, G] - P, G = Mpint - Where P is the shared prime number and G is the shared generator. - PublicKey, PrivateKey = Mpint() + Key = Text = iolist() | binary() + Cipher = binary() -

Generates a Diffie-Hellman PublicKey and PrivateKey (if not given). -

+

Encrypts Text according to DES in ECB mode. + Key is the DES key. The lengths of Key and + Text must be 64 bits (8 bytes).

- - dh_compute_key(OthersPublicKey, MyPrivateKey, DHParams) -> SharedSecret - Computes the shared secret + des_ecb_decrypt(Key, Cipher) -> Text + Decrypt Cipheraccording to DES in ECB mode - DHParameters = [P, G] - P, G = Mpint - Where P is the shared prime number and G is the shared generator. - OthersPublicKey, MyPrivateKey = Mpint() - SharedSecret = binary() + Key = Cipher = iolist() | binary() + Text = binary() -

Computes the shared secret from the private key and the other party's public key. -

+

Decrypts Cipher according to DES in ECB mode. + Key is the DES key. The lengths of Key and + Cipher must be 64 bits (8 bytes).

- - - srp_generate_key(Generator, Prime, Version) -> {PublicKey, PrivateKey} - srp_generate_key(Generator, Prime, Version, Private) -> {PublicKey, PrivateKey} - srp_generate_key(Verifier, Generator, Prime, Version) -> {PublicKey, PrivateKey} - srp_generate_key(Verifier, Generator, Prime, Version, Private) -> {PublicKey, PrivateKey} - Generates SRP public keys + + rc2_cbc_encrypt(Key, IVec, Text) -> Cipher + Encrypt Textaccording to RC2 in CBC mode - Verifier = binary() - Parameter v from SRP design - - Generator = binary() - Parameter g from SRP design - - Prime = binary() - Parameter N from SRP design - - Version = '3' | '6' | '6a' - SRP version, TLS SRP cipher suites uses '6a'. - PublicKey = binary() - Parameter A or B from SRP design - Private = PrivateKey = binary() - generated if not supplied - Parameter a or b from SRP design + Key = Text = iolist() | binary() + Ivec = Cipher = binary() -

Generates SRP public keys for the client side (first argument is Generator) - or for the server side (first argument is Verifier).

+

Encrypts Text according to RC2 in CBC mode.

- srp_compute_key(DerivedKey, Prime, Generator, - ClientPublic, ClientPrivate, ServerPublic, Version) -> SessionKey - srp_compute_key(DerivedKey, Prime, Generator, - ClientPublic, ClientPrivate, ServerPublic, Version, Scrambler) -> SessionKey - srp_compute_key(Verifier, Prime, - ClientPublic, ServerPublic, ServerPrivate, Version, Scrambler)-> SessionKey - srp_compute_key(Verifier, Prime, - ClientPublic, ServerPublic, ServerPrivate, Version) -> SessionKey - - Computes SRP session key + rc2_cbc_decrypt(Key, IVec, Cipher) -> Text + Decrypts Cipheraccording to RC2 in CBC mode - DerivedKey = binary() - Parameter x from SRP design - - Verifier = binary() - Parameter v from SRP design - - Prime = binary() - Parameter N from SRP design - - Generator = binary() - Parameter g from SRP design - - ClientPublic = binary() - Parameter A from SRP design - - ClientPrivate = binary() - Parameter a from SRP design - - ServerPublic = binary() - Parameter B from SRP design - - ServerPrivate = binary() - Parameter b from SRP design - - Version = '3' | '6' | '6a' - SRP version, TLS SRP cipher suites uses '6a'. - SessionKey = binary() - Result K from SRP design - + Key = Text = iolist() | binary() + Ivec = Cipher = binary() -

- Computes the SRP session key (shared secret) for the client side (first argument is DerivedKey) - or for the server side (first argument is Verifier). Also used - as premaster secret by TLS-SRP cipher suites. -

+

Decrypts Cipher according to RC2 in CBC mode.

- ec_key_new(NamedCurve) -> ECKey + rc4_encrypt(Key, Data) -> Result + Encrypt data using RC4 - NamedCurve = atom() - ECKey = EC key resource() + Key, Data = iolist() | binary() + Result = binary() -

Generate an new EC key from the named curve. The private key - will be initialized with random data. -

+

Encrypts the data with RC4 symmetric stream encryption. + Since it is symmetric, the same function is used for + decryption.

- - ec_key_generate(ECKey) -> ok | error - - ECKey = EC key resource() - - -

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. -

-
-
- ec_key_to_term(ECKey) -> ECKeyTerm. + rsa_public_encrypt(PlainText, PublicKey, Padding) -> ChipherText + Encrypts Msg using the public Key. - ECKey = EC key resource() - ECKeyTerm = EC key as Erlang term + PlainText = binary() + PublicKey = [E, N] + E, N = integer() + Where E is the public exponent and N is public modulus. + Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding + ChipherText = binary() -

Convert a EC key from a NIF resource into an Erlang term. +

Encrypts the PlainText (usually a session key) using the PublicKey + and returns the cipher. The Padding decides what padding mode is used, + rsa_pkcs1_padding is PKCS #1 v1.5 currently the most + used mode and rsa_pkcs1_oaep_padding is EME-OAEP as + defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding + parameter. This mode is recommended for all new applications. + The size of the Msg must be less + than byte_size(N)-11 if + rsa_pkcs1_padding is used, byte_size(N)-41 if + rsa_pkcs1_oaep_padding is used and byte_size(N) if rsa_no_padding + is used.

- term_to_ec_key(ECKeyTerm) -> ECKey + rsa_private_decrypt(ChipherText, PrivateKey, Padding) -> PlainText + Decrypts ChipherText using the private Key. - ECKeyTerm = EC key as Erlang term - ECKey = EC key resource() + ChipherText = binary() + PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] + E, N, D = integer() + Where E is the public exponent, N is public modulus and + D is the private exponent. + P1, P2, E1, E2, C = integer() + The longer key format contains redundant information that will make + the calculation faster. P1,P2 are first and second prime factors. + E1,E2 are first and second exponents. C is the CRT coefficient. + Terminology is taken from RFC 3447. + Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding + PlainText = binary() -

Convert a EC key an Erlang term into a NIF resource. +

Decrypts the ChipherText (usually a session key encrypted with + rsa_public_encrypt/3) + using the PrivateKey and returns the + message. The Padding is the padding mode that was + used to encrypt the data, + see rsa_public_encrypt/3.

- ecdsa_sign(DataOrDigest, ECKey) -> Signature - ecdsa_sign(DigestType, DataOrDigest, ECKey) -> Signature - Sign the data using ecdsa with the given key. - - DataOrDigest = Data | {digest,Digest} - Data = Mpint - Digest = binary() - ECKey = EC key resource() - DigestType = md5 | sha | sha256 | sha384 | sha512 - The default DigestType is sha. - Mpint = binary() - Signature = binary() - - -

Creates a ESDSA signature with the private key Key - of a digest. The digest is either calculated as a - DigestType digest of Data or a precalculated - binary Digest.

-
-
- - - ecdsa_verify(DataOrDigest, Signature, ECKey) -> Verified - ecdsa_verify(DigestType, DataOrDigest, Signature, ECKey) -> Verified - Verify the digest and signature using ecdsa with given public key. - - Verified = boolean() - DataOrDigest = Data | {digest|Digest} - Data, Signature = Mpint - Digest = binary() - ECKey = EC key resource() - DigestType = md5 | sha | sha256 | sha384 | sha512 - The default DigestType is sha. - Mpint = binary() - - -

Verifies that a digest matches the ECDSA signature using the - signer's public key Key. - The digest is either calculated as a DigestType - digest of Data or a precalculated binary Digest.

-

May throw exception notsup in case the chosen DigestType - is not supported by the underlying OpenSSL implementation.

-
-
- - - ecdh_compute_key(OthersPublicKey, MyPrivateKey) -> SharedSecret - ecdh_compute_key(OthersPublicKey, MyECPoint) -> SharedSecret - Computes the shared secret + rsa_private_encrypt(PlainText, PrivateKey, Padding) -> ChipherText + Encrypts Msg using the private Key. - OthersPublicKey, MyPrivateKey = ECKey() - MyPrivatePoint = binary() - SharedSecret = binary() + PlainText = binary() + PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] + E, N, D = integer() + Where E is the public exponent, N is public modulus and + D is the private exponent. + P1, P2, E1, E2, C = integer() + The longer key format contains redundant information that will make + the calculation faster. P1,P2 are first and second prime factors. + E1,E2 are first and second exponents. C is the CRT coefficient. + Terminology is taken from RFC 3447. + Padding = rsa_pkcs1_padding | rsa_no_padding + ChipherText = binary() -

Computes the shared secret from the private key and the other party's public key. +

Encrypts the PlainText using the PrivateKey + and returns the cipher. The Padding decides what padding mode is used, + rsa_pkcs1_padding is PKCS #1 v1.5 currently the most + used mode. + The size of the Msg must be less than byte_size(N)-11 if + rsa_pkcs1_padding is used, and byte_size(N) if rsa_no_padding + is used.

- - exor(Data1, Data2) -> Result - XOR data + rsa_public_decrypt(ChipherText, PublicKey, Padding) -> PlainText + Decrypts ChipherText using the public Key. - Data1, Data2 = iolist() | binary() - Result = binary() + ChipherText = binary() + PublicKey = [E, N] + E, N = integer() + Where E is the public exponent and N is public modulus + Padding = rsa_pkcs1_padding | rsa_no_padding + PlainText = binary() -

Performs bit-wise XOR (exclusive or) on the data supplied.

+

Decrypts the ChipherText (encrypted with + rsa_private_encrypt/3) + using the PrivateKey and returns the + message. The Padding is the padding mode that was + used to encrypt the data, + see rsa_private_encrypt/3. +

- - -
- Elliptic Curve Key -

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 ec_key_to_term/1 - and term_to_ec_key are provided to convert between Erlang - terms and the resource format

-

Key in term form

-
-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}
-    
-
+
DES in CBC mode diff --git a/lib/crypto/doc/src/crypto_app.xml b/lib/crypto/doc/src/crypto_app.xml index 8371db1ff2..20f4ed5c45 100644 --- a/lib/crypto/doc/src/crypto_app.xml +++ b/lib/crypto/doc/src/crypto_app.xml @@ -1,4 +1,4 @@ - + @@ -24,23 +24,14 @@ crypto - Peter Högfeldt - Peter Högfeldt - - Peter Högfeldt - Peter Högfeldt - 2003-06-01 - B crypto_app.sgml crypto The Crypto Application -

The purpose of the Crypto application is to provide message - digest and DES encryption for SMNPv3. It provides computation of - message digests MD5 and SHA, and CBC-DES encryption and - decryption.

-

+

The purpose of the Crypto application is to provide erlang + acess to crypto graphic functions in openssl. +

@@ -68,36 +59,6 @@

Source releases of OpenSSL can be downloaded from the OpenSSL project home page, or mirror sites listed there.

-

The same URL also contains links to some compiled binaries and - libraries of OpenSSL (see the Related/Binaries menu) of - which the Shining Light Productions Win32 and OpenSSL pages are of - interest for the Win32 user. -

-

For some Unix flavours there are binary packages available - on the net. -

-

If you cannot find a suitable binary OpenSSL package, you - have to fetch an OpenSSL source release and compile it. -

-

You then have to compile and install the library - libcrypto.so (Unix), or the library libeay32.dll - (Win32). -

-

For Unix The crypto_drv dynamic driver is delivered linked - to OpenSSL libraries in /usr/local/lib, but the default - dynamic linking will also accept libraries in /lib and - /usr/lib. -

-

If that is not applicable to the particular Unix operating - system used, the example Makefile in the Crypto - priv/obj directory, should be used as a basis for - relinking the final version of the port program. -

-

For Win32 it is only required that the library can be - found from the PATH environment variable, or that they - reside in the appropriate SYSTEM32 directory; hence no - particular relinking is need. Hence no example Makefile - for Win32 is provided.

diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index f87644b3fe..2b5ccb6ef4 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -23,19 +23,13 @@ -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]). --export([sha/1, sha_init/0, sha_update/2, sha_final/1]). --export([sha224/1, sha224_init/0, sha224_update/2, sha224_final/1]). --export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]). --export([sha384/1, sha384_init/0, sha384_update/2, sha384_final/1]). --export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]). --export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]). --export([sha224_mac/2, sha224_mac/3]). --export([sha256_mac/2, sha256_mac/3]). --export([sha384_mac/2, sha384_mac/3]). --export([sha512_mac/2, sha512_mac/3]). +-export([sign/4, verify/5]). +-export([generate_key/2, generate_key/3, compute_key/4]). -export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]). +-export([exor/2]). +-export([strong_rand_bytes/1, mod_exp_prime/3]). +-export([rand_bytes/1, rand_bytes/3, rand_uniform/2]). + -export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]). -export([des_ecb_encrypt/2, des_ecb_decrypt/2]). -export([des_cfb_encrypt/3, des_cfb_decrypt/3, des_cfb_ivec/2]). @@ -47,41 +41,69 @@ -export([blowfish_ofb64_encrypt/3]). -export([des_ede3_cbc_encrypt/5, des_ede3_cbc_decrypt/5]). -export([aes_cfb_128_encrypt/3, aes_cfb_128_decrypt/3]). --export([exor/2]). -export([rc4_encrypt/2, rc4_set_key/1, rc4_encrypt_with_state/2]). -export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3, rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]). --export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]). --export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]). -export([rsa_public_encrypt/3, rsa_private_decrypt/3]). -export([rsa_private_encrypt/3, rsa_public_decrypt/3]). --export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]). --export([rand_bytes/1, rand_bytes/3, rand_uniform/2]). --export([strong_rand_bytes/1, strong_rand_mpint/3]). --export([mod_exp/3, mod_exp_prime/3, mpint/1, erlint/1]). - -%% -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([sign/4, verify/5]). --export([generate_key/2, generate_key/3, compute_key/4]). +-export([dh_generate_parameters/2, dh_check/1]). %% Testing see + +%% DEPRECATED +-export([md4/1, md4_init/0, md4_update/2, md4_final/1]). +-export([md5/1, md5_init/0, md5_update/2, md5_final/1]). +-export([sha/1, sha_init/0, sha_update/2, sha_final/1]). +-deprecated({md4, 1, next_major_release}). +-deprecated({md5, 1, next_major_release}). +-deprecated({sha, 1, next_major_release}). +-deprecated({md4_init, 0, next_major_release}). +-deprecated({md5_init, 0, next_major_release}). +-deprecated({sha_init, 0, next_major_release}). +-deprecated({md4_update, 2, next_major_release}). +-deprecated({md5_update, 2, next_major_release}). +-deprecated({sha_update, 2, next_major_release}). +-deprecated({md4_final, 1, next_major_release}). +-deprecated({md5_final, 1, next_major_release}). +-deprecated({sha_final, 1, next_major_release}). + +-export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]). +-deprecated({md5_mac, 2, next_major_release}). +-deprecated({md5_mac_96, 2, next_major_release}). +-deprecated({sha_mac, 2, next_major_release}). +-deprecated({sha_mac, 3, next_major_release}). +-deprecated({sha_mac_96, 2, next_major_release}). --export([dh_generate_parameters/2, dh_check/1]). %% Testing see below +-export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]). +-export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]). +-deprecated({dss_verify, 3, next_major_release}). +-deprecated({dss_verify, 4, next_major_release}). +-deprecated({rsa_verify, 3, next_major_release}). +-deprecated({rsa_verify, 4, next_major_release}). +-deprecated({dss_sign, 2, next_major_release}). +-deprecated({dss_sign, 3, next_major_release}). +-deprecated({rsa_sign, 2, next_major_release}). +-deprecated({rsa_sign, 3, next_major_release}). +-export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]). +-deprecated({dh_generate_key, 1, next_major_release}). +-deprecated({dh_generate_key, 2, next_major_release}). +-deprecated({dh_compute_key, 3, next_major_release}). + +-export([mod_exp/3, mpint/1, erlint/1, strong_rand_mpint/3]). +-deprecated({mod_exp, 3, next_major_release}). +-deprecated({mpint, 1, next_major_release}). +-deprecated({erlint, 1, next_major_release}). +-deprecated({strong_rand_mpint, 3, next_major_release}). -define(FUNC_LIST, [md4, md4_init, md4_update, md4_final, md5, md5_init, md5_update, md5_final, sha, sha_init, sha_update, sha_final, - sha224, sha224_init, sha224_update, sha224_final, - sha256, sha256_init, sha256_update, sha256_final, - sha384, sha384_init, sha384_update, sha384_final, - sha512, sha512_init, sha512_update, sha512_final, md5_mac, md5_mac_96, sha_mac, sha_mac_96, - sha224_mac, sha256_mac, sha384_mac, sha512_mac, des_cbc_encrypt, des_cbc_decrypt, des_cfb_encrypt, des_cfb_decrypt, des_ecb_encrypt, des_ecb_decrypt, @@ -102,7 +124,6 @@ exor, rc4_encrypt, rc4_set_key, rc4_encrypt_with_state, rc2_40_cbc_encrypt, rc2_40_cbc_decrypt, - %% idea_cbc_encrypt, idea_cbc_decrypt, aes_cbc_256_encrypt, aes_cbc_256_decrypt, aes_ctr_encrypt, aes_ctr_decrypt, aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt, @@ -124,13 +145,13 @@ -type crypto_integer() :: binary() | integer(). -type ec_key_res() :: any(). %% nif resource -type ec_named_curve() :: atom(). --type ec_point() :: binary(). +-type ec_point() :: crypto_integer(). -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_field() :: {prime_field, Prime :: integer()} | {characteristic_two_field, M :: integer(), Basis :: ec_basis()}. +-type ec_prime() :: {A :: crypto_integer(), B :: crypto_integer(), Seed :: binary() | none}. +-type ec_curve_spec() :: {Field :: ec_field(), Prime :: ec_prime(), Point :: crypto_integer(), Order :: integer(), CoFactor :: none | integer()}. -type ec_curve() :: ec_named_curve() | ec_curve_spec(). --type ec_key() :: {Curve :: ec_curve(), PrivKey :: mpint() | undefined, PubKey :: ec_point() | undefined}. +-type ec_key() :: {Curve :: ec_curve(), PrivKey :: binary() | undefined, PubKey :: ec_point() | undefined}. -define(nif_stub,nif_stub_error(?LINE)). @@ -944,11 +965,11 @@ ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub. -spec rsa_public_encrypt(binary(), [binary()], rsa_padding()) -> binary(). --spec rsa_public_decrypt(binary(), [binary()], rsa_padding()) -> +-spec rsa_public_decrypt(binary(), [integer() | mpint()], rsa_padding()) -> binary(). --spec rsa_private_encrypt(binary(), [binary()], rsa_padding()) -> +-spec rsa_private_encrypt(binary(), [integer() | mpint()], rsa_padding()) -> binary(). --spec rsa_private_decrypt(binary(), [binary()], rsa_padding()) -> +-spec rsa_private_decrypt(binary(), [integer() | mpint()], rsa_padding()) -> binary(). %% Binary, Key = [E,N] @@ -1216,8 +1237,6 @@ ecdh_compute_key_nif(_Others, _My) -> ?nif_stub. %% %% EC %% - --spec ec_key_to_term(ec_key_res()) -> ec_key(). ec_key_to_term(Key) -> case ec_key_to_term_nif(Key) of {PrivKey, PubKey} -> diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 3ebe10866c..eff0f8a878 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -360,7 +360,7 @@ hmac_update_sha(Config) when is_list(Config) -> ?line Ctx2 = crypto:hmac_update(Ctx, Data), ?line Ctx3 = crypto:hmac_update(Ctx2, Data2), ?line Mac = crypto:hmac_final(Ctx3), - ?line Exp = crypto:sha_mac(Key, lists:flatten([Data, Data2])), + ?line Exp = crypto:hmac(sha, Key, lists:flatten([Data, Data2])), ?line m(Exp, Mac). hmac_update_sha256(doc) -> @@ -382,7 +382,7 @@ hmac_update_sha256_do() -> ?line Ctx2 = crypto:hmac_update(Ctx, Data), ?line Ctx3 = crypto:hmac_update(Ctx2, Data2), ?line Mac = crypto:hmac_final(Ctx3), - ?line Exp = crypto:sha256_mac(Key, lists:flatten([Data, Data2])), + ?line Exp = crypto:hmac(sha256, Key, lists:flatten([Data, Data2])), ?line m(Exp, Mac). hmac_update_sha512(doc) -> @@ -404,7 +404,7 @@ hmac_update_sha512_do() -> ?line Ctx2 = crypto:hmac_update(Ctx, Data), ?line Ctx3 = crypto:hmac_update(Ctx2, Data2), ?line Mac = crypto:hmac_final(Ctx3), - ?line Exp = crypto:sha512_mac(Key, lists:flatten([Data, Data2])), + ?line Exp = crypto:hmac(sha512, Key, lists:flatten([Data, Data2])), ?line m(Exp, Mac). hmac_update_md5(doc) -> @@ -619,68 +619,64 @@ 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) -> +hmac_rfc4231_case(Hash, 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, Key, Data, Exp); -hmac_rfc4231_case(Hash, HashFun, case2, Exp) -> +hmac_rfc4231_case(Hash, 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, Key, Data, Exp); -hmac_rfc4231_case(Hash, HashFun, case3, Exp) -> +hmac_rfc4231_case(Hash, 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, Key, Data, Exp); -hmac_rfc4231_case(Hash, HashFun, case4, Exp) -> +hmac_rfc4231_case(Hash, 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, Key, Data, Exp); -hmac_rfc4231_case(Hash, HashFun, case5, Exp) -> +hmac_rfc4231_case(Hash, 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, Key, Data, 16, Exp); -hmac_rfc4231_case(Hash, HashFun, case6, Exp) -> +hmac_rfc4231_case(Hash, 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, Key, Data, Exp); -hmac_rfc4231_case(Hash, HashFun, case7, Exp) -> +hmac_rfc4231_case(Hash, case7, Exp) -> %% Test Case 7 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, Key, Data, Exp). -hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp) -> +hmac_rfc4231_case(Hash, 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) -> +hmac_rfc4231_case(Hash, 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() -> @@ -697,7 +693,7 @@ hmac_rfc4231_sha224_do() -> "d499f112f2d2b7273fa6870e"), Case7 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd" "946770db9c2b95c9f6f565d1"), - hmac_rfc4231_cases_do(sha224, sha224_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). + hmac_rfc4231_cases_do(sha224, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). hmac_rfc4231_sha256_do() -> Case1 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b" @@ -713,7 +709,7 @@ hmac_rfc4231_sha256_do() -> "8e0bc6213728c5140546040f0ee37f54"), Case7 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944" "bfdc63644f0713938a7f51535c3a35e2"), - hmac_rfc4231_cases_do(sha256, sha256_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). + hmac_rfc4231_cases_do(sha256, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). hmac_rfc4231_sha384_do() -> Case1 = hexstr2bin("afd03944d84895626b0825f4ab46907f" @@ -735,7 +731,7 @@ hmac_rfc4231_sha384_do() -> Case7 = hexstr2bin("6617178e941f020d351e2f254e8fd32c" "602420feb0b8fb9adccebb82461e99c5" "a678cc31e799176d3860e6110c46523e"), - hmac_rfc4231_cases_do(sha384, sha384_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). + hmac_rfc4231_cases_do(sha384, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). hmac_rfc4231_sha512_do() -> Case1 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0" @@ -763,16 +759,16 @@ hmac_rfc4231_sha512_do() -> "debd71f8867289865df5a32d20cdc944" "b6022cac3c4982b10d5eeb55c3e4de15" "134676fb6de0446065c97440fa8c6a58"), - hmac_rfc4231_cases_do(sha512, sha512_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). + hmac_rfc4231_cases_do(sha512, [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, CasesData) -> + hmac_rfc4231_cases_do(Hash, [case1, case2, case3, case4, case5, case6, case7], CasesData). -hmac_rfc4231_cases_do(_Hash, _HashFun, _, []) -> +hmac_rfc4231_cases_do(_Hash, _, []) -> 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_rfc4231_cases_do(Hash, [C|Cases], [D|CasesData]) -> + hmac_rfc4231_case(Hash, C, D), + hmac_rfc4231_cases_do(Hash, Cases, CasesData). hmac_update_md5_io(doc) -> ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. " @@ -859,10 +855,10 @@ sha256(Config) when is_list(Config) -> if_supported(sha256, fun() -> sha256_do() end). sha256_do() -> - ?line m(crypto:sha256("abc"), + ?line m(crypto:hash(sha256, "abc"), hexstr2bin("BA7816BF8F01CFEA4141" "40DE5DAE2223B00361A396177A9CB410FF61F20015AD")), - ?line m(crypto:sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklm" + ?line m(crypto:hash(sha256, "abcdbcdecdefdefgefghfghighijhijkijkljklmklm" "nlmnomnopnopq"), hexstr2bin("248D6A61D20638B8" "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")). @@ -878,10 +874,10 @@ sha256_update(Config) when is_list(Config) -> if_supported(sha256, fun() -> sha256_update_do() end). sha256_update_do() -> - ?line Ctx = crypto:sha256_init(), - ?line Ctx1 = crypto:sha256_update(Ctx, "abcdbcdecdefdefgefghfghighi"), - ?line Ctx2 = crypto:sha256_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"), - ?line m(crypto:sha256_final(Ctx2), + ?line Ctx = crypto:hash_init(sha256), + ?line Ctx1 = crypto:hash_update(Ctx, "abcdbcdecdefdefgefghfghighi"), + ?line Ctx2 = crypto:hash_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"), + ?line m(crypto:hash_final(Ctx2), hexstr2bin("248D6A61D20638B8" "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")). @@ -897,11 +893,11 @@ sha512(Config) when is_list(Config) -> if_supported(sha512, fun() -> sha512_do() end). sha512_do() -> - ?line m(crypto:sha512("abc"), + ?line m(crypto:hash(sha512, "abc"), hexstr2bin("DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2" "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD" "454D4423643CE80E2A9AC94FA54CA49F")), - ?line m(crypto:sha512("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + ?line m(crypto:hash(sha512, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"), hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1" "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A" @@ -918,10 +914,10 @@ sha512_update(Config) when is_list(Config) -> if_supported(sha512, fun() -> sha512_update_do() end). sha512_update_do() -> - ?line Ctx = crypto:sha512_init(), - ?line Ctx1 = crypto:sha512_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"), - ?line Ctx2 = crypto:sha512_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"), - ?line m(crypto:sha512_final(Ctx2), + ?line Ctx = crypto:hash_init(sha512), + ?line Ctx1 = crypto:hash_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"), + ?line Ctx2 = crypto:hash_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"), + ?line m(crypto:hash_final(Ctx2), hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1" "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A" "C7D329EEB6DD26545E96E55B874BE909")). diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 9cad17e4c3..45aaf21b80 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -100,8 +100,10 @@

dsa_public_key() = {integer(), #'Dss-Parms'{}}

dsa_private_key() = #'DSAPrivateKey'{}

+ +

ec_public_key() = {#'ECPoint'{}, #'OTPEcpkParameters'{} | {namedCurve, oid()}}

-

ec_key() = {'ECKey', Key}

+

ec_private_key() = #'ECPrivateKey'{}

public_crypt_options() = [{rsa_pad, rsa_padding()}].

@@ -112,7 +114,7 @@

dss_digest_type() = 'sha'

-

ecdsa_digest_type() = 'sha'

+

ecdsa_digest_type() = 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'

crl_reason() = unspecified | keyCompromise | cACompromise | affiliationChanged | superseded | cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise

@@ -534,7 +536,7 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | signed or it is the hashed value of "plain text" i.e. the digest. DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type() - Key = rsa_private_key() | dsa_private_key() | ec_key() + Key = rsa_private_key() | dsa_private_key() | ec_private_key()

Creates a digital signature.

@@ -599,10 +601,10 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | or it is the hashed value of "plain text" i.e. the digest. DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type() Signature = binary() - Key = rsa_public_key() | dsa_public_key() | ec_key() - - -

Verifies a digital signature

+ Key = rsa_public_key() | dsa_public_key() | ec_public_key() + + +

Verifies a digital signature

diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl index 976104fe6c..363305957c 100644 --- a/lib/public_key/include/public_key.hrl +++ b/lib/public_key/include/public_key.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. 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 @@ -93,6 +93,8 @@ -type rsa_private_key() :: #'RSAPrivateKey'{}. -type dsa_private_key() :: #'DSAPrivateKey'{}. -type dsa_public_key() :: {integer(), #'Dss-Parms'{}}. +-type ec_public_key() :: {#'ECPoint'{},{namedCurve, Oid::tuple()} | #'OTPECParameters'{}}. +-type ec_private_key() :: #'ECPrivateKey'{}. -type der_encoded() :: binary(). -type decrypt_der() :: binary(). -type pki_asn1_type() :: 'Certificate' | 'RSAPrivateKey' | 'RSAPublicKey' diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index a8fe9213ea..96eaacf60e 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -54,6 +54,7 @@ -type public_crypt_options() :: [{rsa_pad, rsa_padding()}]. -type rsa_digest_type() :: 'md5' | 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'. -type dss_digest_type() :: 'none' | 'sha'. %% None is for backwards compatibility +-type ecdsa_digest_type() :: 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'. -type crl_reason() :: unspecified | keyCompromise | cACompromise | affiliationChanged | superseded | cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise. -type oid() :: tuple(). @@ -97,7 +98,7 @@ pem_entry_decode({'SubjectPublicKeyInfo', Der, _}) -> 'DSAPublicKey' -> {params, DssParams} = der_decode('DSAParams', Params), {der_decode(KeyType, Key0), DssParams}; - 'ECPrivateKey' -> + 'ECPoint' -> der_decode(KeyType, Key0) end; pem_entry_decode({Asn1Type, Der, not_encrypted}) when is_atom(Asn1Type), @@ -355,7 +356,7 @@ compute_key(PubKey, PrivKey, #'DHParameter'{prime = P, base = G}) -> -spec pkix_sign_types(SignatureAlg::oid()) -> %% Relevant dsa digest type is subpart of rsa digest type { DigestType :: rsa_digest_type(), - SignatureType :: rsa | dsa + SignatureType :: rsa | dsa | ecdsa }. %% Description: %%-------------------------------------------------------------------- @@ -387,9 +388,9 @@ pkix_sign_types(?'ecdsa-with-SHA512') -> {sha512, ecdsa}. %%-------------------------------------------------------------------- --spec sign(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type(), +-spec sign(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(), rsa_private_key() | - dsa_private_key()) -> Signature :: binary(). + dsa_private_key() | ec_private_key()) -> Signature :: binary(). %% Description: Create digital signature. %%-------------------------------------------------------------------- sign(DigestOrPlainText, DigestType, Key = #'RSAPrivateKey'{}) -> @@ -408,9 +409,9 @@ sign(Digest, none, #'DSAPrivateKey'{} = Key) -> sign({digest,Digest}, sha, Key). %%-------------------------------------------------------------------- --spec verify(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type(), +-spec verify(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(), Signature :: binary(), rsa_public_key() - | dsa_public_key()) -> boolean(). + | dsa_public_key() | ec_public_key()) -> boolean(). %% Description: Verifies a digital signature. %%-------------------------------------------------------------------- verify(DigestOrPlainText, DigestType, Signature, @@ -452,7 +453,7 @@ pkix_sign(#'OTPTBSCertificate'{signature = %%-------------------------------------------------------------------- -spec pkix_verify(Cert::binary(), rsa_public_key()| - dsa_public_key()) -> boolean(). + dsa_public_key() | ec_public_key()) -> boolean(). %% %% Description: Verify pkix x.509 certificate signature. %%-------------------------------------------------------------------- @@ -879,12 +880,6 @@ ec_curve_spec( #'OTPECParameters'{fieldID = FieldId, curve = PCurve, base = Base ec_curve_spec({namedCurve, OID}) -> pubkey_cert_records:namedCurves(OID). -ec_key({PrivateKey, PubKey}, Curve) when is_atom(Curve) -> - #'ECPrivateKey'{version = 1, - privateKey = int2list(PrivateKey), - parameters = {namedCurve, pubkey_cert_records:namedCurves(Curve)}, - publicKey = {0, PubKey}}; - ec_key({PrivateKey, PubKey}, Params) -> #'ECPrivateKey'{version = 1, privateKey = int2list(PrivateKey), diff --git a/lib/public_key/test/pkits_SUITE.erl b/lib/public_key/test/pkits_SUITE.erl index d901adaadd..8cdf0aaae3 100644 --- a/lib/public_key/test/pkits_SUITE.erl +++ b/lib/public_key/test/pkits_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. 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 @@ -758,11 +758,10 @@ warning(Format, Args, File0, Line) -> io:format("~s(~p): Warning "++Format, [File,Line|Args]). crypto_support_check(Config) -> - try crypto:sha256(<<"Test">>) of - _ -> - Config - catch error:notsup -> - crypto:stop(), + case proplists:get_bool(sha256, crypto:algorithms()) of + true -> + Config; + false -> {skip, "To old version of openssl"} end. diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index 0de80edeac..5a64140c67 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -551,7 +551,7 @@ dsa_sign_verify(Config) when is_list(Config) -> false = public_key:verify(Msg, sha, <<1:8, DSASign/binary>>, {DSAPublicKey, DSAParams}), - Digest = crypto:sha(Msg), + Digest = crypto:hash(sha,Msg), DigestSign = public_key:sign(Digest, none, DSAPrivateKey), true = public_key:verify(Digest, none, DigestSign, {DSAPublicKey, DSAParams}), <<_:8, RestDigest/binary>> = Digest, diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index b02493d2cb..1645eb15f3 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -41,16 +41,17 @@ For security reasons sslv2 is not supported. Ephemeral Diffie-Hellman cipher suites are supported but not Diffie Hellman Certificates cipher suites. - Elliptic Curve cipher suites are supported on - systems with a OpenSSL library that has EC support - compiled in. + Elliptic Curve cipher suites are supported if crypto + supports it and named curves are used. + Export cipher suites are not supported as the U.S. lifted its export restrictions in early 2000. IDEA cipher suites are not supported as they have become deprecated by the latest TLS spec so there is not any real motivation to implement them. - CRL and policy certificate - extensions are not supported yet. + CRL and policy certificate extensions are not supported + yet. However CRL verification is supported by public_key, only not integrated + in ssl yet.
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index b162d862af..1bf3a885b2 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -219,7 +219,7 @@ anonymous_suites() -> ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA]. %%-------------------------------------------------------------------- --spec psk_suites(tls_version()) -> [cipher_suite()]. +-spec psk_suites(tls_version() | integer()) -> [cipher_suite()]. %% %% Description: Returns a list of the PSK cipher suites, only supported %% if explicitly set by user. diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl index c59f5e81c8..32b2c0d392 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -28,7 +28,7 @@ -type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc' | aes_128_cbc | aes_256_cbc. --type hash() :: null | sha | md5 | sha256 | sha384 | sha512. +-type hash() :: null | sha | md5 | ssh224 | sha256 | sha384 | sha512. -type erl_cipher_suite() :: {key_algo(), cipher(), hash()}. -type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash()}. -type cipher_suite() :: binary(). diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 338319ab9e..1cca644956 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -139,7 +139,8 @@ hello_request() -> atom(), #connection_states{}, binary()}, boolean()) -> {tls_version(), session_id(), #connection_states{}, binary() | undefined}| - {tls_version(), {resumed | new, #session{}}, #connection_states{}, list(binary()) | undefined} | + {tls_version(), {resumed | new, #session{}}, #connection_states{}, [binary()] | undefined, + [oid()] | undefined, [oid()] | undefined} | #alert{}. %% %% Description: Handles a recieved hello message @@ -372,8 +373,7 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) -> {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()} | + {ecdh, #'ECPrivateKey'{}} | {psk, binary()} | {dhe_psk, binary(), binary()} | {srp, {binary(), binary()}, #srp_user{}, {HashAlgo::atom(), SignAlgo::atom()}, @@ -417,7 +417,7 @@ key_exchange(client, _Version, {psk_premaster_secret, PskIdentity, Secret, {_, P encrypted_premaster_secret(Secret, PublicKey), #client_key_exchange{ exchange_keys = #client_rsa_psk_identity{ - identity = PskIdentity, + identity = PskIdentity, exchange_keys = EncPremasterSecret}}; key_exchange(client, _Version, {srp, PublicKey}) -> @@ -596,6 +596,7 @@ get_tls_handshake(Version, Data, Buffer) -> -spec decode_client_key(binary(), key_algo(), tls_version()) -> #encrypted_premaster_secret{} | #client_diffie_hellman_public{} + | #client_ec_diffie_hellman_public{} | #client_psk_identity{} | #client_dhe_psk_identity{} | #client_rsa_psk_identity{} diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index df21468862..2519fba4e1 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -28,9 +28,9 @@ -include_lib("public_key/include/public_key.hrl"). --type algo_oid() :: ?'rsaEncryption' | ?'id-dsa'. --type public_key_params() :: #'Dss-Parms'{} | term(). --type public_key_info() :: {algo_oid(), #'RSAPublicKey'{} | integer() , public_key_params()}. +-type oid() :: tuple(). +-type public_key_params() :: #'Dss-Parms'{} | {namedCurve, oid()} | #'OTPECParameters'{} | term(). +-type public_key_info() :: {oid(), #'RSAPublicKey'{} | integer() | #'ECPoint'{}, public_key_params()}. -type tls_handshake_history() :: {[binary()], [binary()]}. -define(NO_PROTOCOL, <<>>). diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index 96a1c8e1ce..89fee38c46 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2012. All Rights Reserved. +%% Copyright Ericsson AB 2007-2013. 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 @@ -39,7 +39,7 @@ -type db_handle() :: term(). -type key_algo() :: null | rsa | dhe_rsa | dhe_dss | dh_anon. -type der_cert() :: binary(). --type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{}. +-type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{} | #'ECPrivateKey'{}. -type issuer() :: tuple(). -type serialnumber() :: integer(). -type cert_key() :: {reference(), integer(), issuer()}. diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl index a4f4035c79..9805414a9a 100644 --- a/lib/stdlib/src/otp_internal.erl +++ b/lib/stdlib/src/otp_internal.erl @@ -66,6 +66,78 @@ obsolete_1(rpc, safe_multi_server_call, A) when A =:= 2; A =:= 3 -> {deprecated, {rpc, multi_server_call, A}}; +%% *** CRYPTO add in R16B01 *** + +obsolete_1(crypto, md4, 1) -> + {deprecated, {crypto, hash, 2}}; +obsolete_1(crypto, md5, 1) -> + {deprecated, {crypto, hash, 2}}; +obsolete_1(crypto, sha, 1) -> + {deprecated, {crypto, hash, 2}}; + +obsolete_1(crypto, md4_init, 1) -> + {deprecated, {crypto, hash_init, 2}}; +obsolete_1(crypto, md5_init, 1) -> + {deprecated, {crypto, hash_init, 2}}; +obsolete_1(crypto, sha_init, 1) -> + {deprecated, {crypto, hash_init, 2}}; + +obsolete_1(crypto, md4_update, 2) -> + {deprecated, {crypto, hash_update, 3}}; +obsolete_1(crypto, md5_update, 2) -> + {deprecated, {crypto, hash_update, 3}}; +obsolete_1(crypto, sah_update, 2) -> + {deprecated, {crypto, hash_update, 3}}; + +obsolete_1(crypto, md4_final, 1) -> + {deprecated, {crypto, hash_final, 2}}; +obsolete_1(crypto, md5_final, 1) -> + {deprecated, {crypto, hash_final, 2}}; +obsolete_1(crypto, sha_final, 1) -> + {deprecated, {crypto, hash_final, 2}}; + +obsolete_1(crypto, md5_mac, 2) -> + {deprecated, {crypto, hmac, 3}}; +obsolete_1(crypto, sha_mac, 2) -> + {deprecated, {crypto, hmac, 3}}; + +obsolete_1(crypto, sha_mac_96, 2) -> + {deprecated, {crypto, hmac_n, 3}}; +obsolete_1(crypto, md5_mac_96, 2) -> + {deprecated, {crypto, hmac_n, 3}}; + +obsolete_1(crypto, rsa_sign, 3) -> + {deprecated, {crypto, sign, 4}}; +obsolete_1(crypto, rsa_verify, 3) -> + {deprecated, {crypto, verify, 4}}; + +obsolete_1(crypto, dss_sign, 2) -> + {deprecated, {crypto, sign, 4}}; +obsolete_1(crypto, dss_sign, 3) -> + {deprecated, {crypto, sign, 4}}; + +obsolete_1(crypto, dss_verify, 3) -> + {deprecated, {crypto, verify, 4}}; +obsolete_1(crypto, dss_verify, 4) -> + {deprecated, {crypto, verify, 4}}; + +obsolete_1(crypto, mod_exp, 3) -> + {deprecated, {crypto, mod_exp_prime, 3}}; + +obsolete_1(crypto, dh_compute_key, 3) -> + {deprecated, {crypto, compute_key, 4}}; +obsolete_1(crypto, dh_generate_key, 1) -> + {deprecated, {crypto, generate_key, 3}}; +obsolete_1(crypto, dh_generate_key, 2) -> + {deprecated, {crypto, generate_key, 3}}; + +obsolete_1(crypto, strong_rand_mpint, 3) -> + {deprecated, "needed only by deprecated functions"}; +obsolete_1(crypto, erlint, 3) -> + {deprecated, "needed only by deprecated functions"}; +obsolete_1(crypto, mpint, 3) -> + {deprecated, "needed only by deprecated functions"}; + %% *** SNMP *** obsolete_1(snmp, N, A) -> -- cgit v1.2.3 From 50605d756a9fc0a247e19922dff53b4a9d639a59 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 30 Apr 2013 13:13:48 +0200 Subject: crypto: New API for ciphers --- lib/crypto/doc/src/crypto.xml | 929 ++++++++++++--------------------------- lib/crypto/src/crypto.erl | 305 +++++++++++-- lib/crypto/test/crypto_SUITE.erl | 16 +- lib/stdlib/src/otp_internal.erl | 61 +++ 4 files changed, 605 insertions(+), 706 deletions(-) diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index c4e6993460..0fb53346ca 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -127,15 +127,65 @@ secp112r2| secp112r1| sect113r2| sect113r1| sect239k1| sect163r1| sect163k1| secp256r1| secp192r1

+

stream_cipher() = rc4 | aes_ctr

+ +

block_cipher() = aes_cbc128 | aes_cfb128 | blowfish_cbc | + blowfish_cfb64 | des_cbc | des_cfb | des3_cbc | des3_cbf + | des_ede3 | rc2_cbc

+ +

stream_key() = aes_key() | rc4_key()

+ +

block_key() = aes_key() | blowfish_key() | des_key()| des3_key()

+ +

aes_key() = binary() Key length is 128, 192 or 256 bits

+ +

rc4_key() = binary() Variable key length from 8 bits up to 2048 bits (usually between 40 and 256)

+ +

blowfish_key() = binary() Variable key length from 32 bits up to 448 bits

+ +

des_key() = binary() Key length is 64 bits (in CBC mod only 8 bits are used)

+ +

des3_key() = [binary(), binary(), binary()] Each key part is 64 bits (in CBC mod only 8 bits are used)

- + algorithms() -> [atom()] Provide a list of available crypto algorithms.

Provides the available crypto algorithms in terms of a list - of atoms.

+ of atoms. This is interesting as older versions of the openssl + crypto library may not support all algorithms used in the crypto API.

+
+
+ + + block_encrypt(Type, Key, Ivec, PlainText) -> CipherText + Encrypt PlainTextaccording to Type block cipher + + Key = block_key() + PlainText = iodata() | binary() + IVec = CipherText = binary() + + +

Encrypt PlainTextaccording to Type block cipher. + IVec is an arbitrary initializing vector. +

+
+
+ + + block_decrypt(Type, Key, Ivec, CipherText) -> PlainText + Decrypt CipherTextaccording to Type block cipher + + Key = block_key() + PlainText = iodata() | binary() + IVec = CipherText = binary() + + +

Decrypt CipherTextaccording to Type block cipher. + IVec is an arbitrary initializing vector. +

@@ -314,15 +364,6 @@
- - info() -> [atom()] - Provide a list of available crypto functions. - -

Provides the available crypto functions in terms of a list - of atoms.

-
-
- info_lib() -> [{Name,VerNum,VerStr}] Provides information about the libraries used by crypto. @@ -361,6 +402,109 @@ + + next_iv(Type, Data) -> + + + Type = des_cbc | aes_cbc + Data = iodata() + + +

Returns the initialization vector to be used in the next + iteration of encrypt/decrypt of type Type. Data is the + encrypted data from the previous iteration step.

+
+
+ + + private_decrypt(Type, ChipherText, PrivateKey, Padding) -> PlainText + Decrypts ChipherText using the private Key. + + Type = rsa + ChipherText = binary() + PrivateKey = rsa_private() + Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding + PlainText = binary() + + +

Decrypts the ChipherText (usually a session key encrypted with + public_encrypt/3) + using the PrivateKey and returns the + message. The Padding is the padding mode that was + used to encrypt the data, + see public_encrypt/3. +

+
+
+ + + private_encrypt(Type, PlainText, PrivateKey, Padding) -> ChipherText + Encrypts Msg using the private Key. + + Type = rsa + PlainText = binary() + PrivateKey = rsa_private() + Padding = rsa_pkcs1_padding | rsa_no_padding + ChipherText = binary() + + +

Encrypts the PlainText using the PrivateKey + and returns the cipher. The Padding decides what padding mode is used, + rsa_pkcs1_padding is PKCS #1 v1.5 currently the most + used mode. + The size of the Msg must be less than byte_size(N)-11 if + rsa_pkcs1_padding is used, and byte_size(N) if rsa_no_padding + is used. +

+
+
+ + public_decrypt(Type, ChipherText, PublicKey, Padding) -> PlainText + Decrypts ChipherText using the public Key. + + Type = rsa + ChipherText = binary() + PublicKey = rsa_public() + Padding = rsa_pkcs1_padding | rsa_no_padding + PlainText = binary() + + +

Decrypts the ChipherText (encrypted with + private_encrypt/3) + using the PrivateKey and returns the + message. The Padding is the padding mode that was + used to encrypt the data, + see private_encrypt/3. +

+
+
+ + + public_encrypt(Type, PlainText, PublicKey, Padding) -> ChipherText + Encrypts Msg using the public Key. + + Type = rsa + PlainText = binary() + PublicKey = rsa_public() + Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding + ChipherText = binary() + + +

Encrypts the PlainText (usually a session key) using the PublicKey + and returns the CipherText. The Padding decides what padding mode is used, + rsa_pkcs1_padding is PKCS #1 v1.5 currently the most + used mode and rsa_pkcs1_oaep_padding is EME-OAEP as + defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding + parameter. This mode is recommended for all new applications. + The size of the Msg must be less + than byte_size(N)-11 if + rsa_pkcs1_padding is used, byte_size(N)-41 if + rsa_pkcs1_oaep_padding is used and byte_size(N) if rsa_no_padding + is used. +

+
+
+ rand_bytes(N) -> binary() Generate a binary of random bytes @@ -435,695 +579,162 @@ - verify(Algorithm, DigestType, Msg, Signature, Key) -> boolean() - Verifies a digital signature. - - Algorithm = rsa | dss | ecdsa - Msg = binary() | {digest,binary()} - The msg is either the binary "plain text" data - or it is the hashed value of "plain text" i.e. the digest. - DigestType = digest_type() - Signature = binary() - Key = rsa_public_key() | dsa_public_key() | ec_public_key() - - -

Verifies a digital signature

-
-
- - - aes_cfb_128_encrypt(Key, IVec, Text) -> Cipher - Encrypt Textaccording to AES in Cipher Feedback mode - - Key = Text = iolist() | binary() - IVec = Cipher = binary() - - -

Encrypts Text according to AES in Cipher Feedback - mode (CFB). Key is the - AES key, and IVec is an arbitrary initializing vector. - The lengths of Key and IVec must be 128 bits - (16 bytes).

-
-
- - - aes_cfb_128_decrypt(Key, IVec, Cipher) -> Text - Decrypt Cipheraccording to AES in Cipher Feedback mode - - Key = Cipher = iolist() | binary() - IVec = Text = binary() - - -

Decrypts Cipher according to AES in Cipher Feedback Mode (CFB). - Key is the AES key, and IVec is an arbitrary - initializing vector. Key and IVec must have - the same values as those used when encrypting. The lengths of - Key and IVec must be 128 bits (16 bytes).

-
-
- - - aes_cbc_128_encrypt(Key, IVec, Text) -> Cipher - Encrypt Textaccording to AES in Cipher Block Chaining mode - - Key = Text = iolist() | binary() - IVec = Cipher = binary() - - -

Encrypts Text according to AES in Cipher Block Chaining - mode (CBC). Text - must be a multiple of 128 bits (16 bytes). Key is the - AES key, and IVec is an arbitrary initializing vector. - The lengths of Key and IVec must be 128 bits - (16 bytes).

-
-
- - - aes_cbc_128_decrypt(Key, IVec, Cipher) -> Text - Decrypt Cipheraccording to AES in Cipher Block Chaining mode - - Key = Cipher = iolist() | binary() - IVec = Text = binary() - - -

Decrypts Cipher according to AES in Cipher Block - Chaining mode (CBC). - Key is the AES key, and IVec is an arbitrary - initializing vector. Key and IVec must have - the same values as those used when encrypting. Cipher - must be a multiple of 128 bits (16 bytes). The lengths of - Key and IVec must be 128 bits (16 bytes).

-
-
- - - aes_cbc_ivec(Data) -> IVec - Get IVec to be used in next iteration of - aes_cbc_*_[ecrypt|decrypt] + stream_init(Type, Key) -> State + - Data = iolist() | binary() + Type rc4 + State = opaque() + Key = iodata() IVec = binary() -

Returns the IVec to be used in a next iteration of - aes_cbc_*_[encrypt|decrypt]. Data is the encrypted - data from the previous iteration step.

+

Initializes the state for use in RC4 stream encryption + stream_encrypt and + stream_decrypt

- - aes_ctr_encrypt(Key, IVec, Text) -> Cipher - Encrypt Textaccording to AES in Counter mode - - Key = Text = iolist() | binary() - IVec = Cipher = binary() - - -

Encrypts Text according to AES in Counter mode (CTR). Text - can be any number of bytes. Key is the AES key and must be either - 128, 192 or 256 bits long. IVec is an arbitrary initializing vector of 128 bits - (16 bytes).

-
-
- - - aes_ctr_decrypt(Key, IVec, Cipher) -> Text - Decrypt Cipheraccording to AES in Counter mode - - Key = Cipher = iolist() | binary() - IVec = Text = binary() - - -

Decrypts Cipher according to AES in Counter mode (CTR). Cipher - can be any number of bytes. Key is the AES key and must be either - 128, 192 or 256 bits long. IVec is an arbitrary initializing vector of 128 bits - (16 bytes).

-
-
- - - aes_ctr_stream_init(Key, IVec) -> State + + stream_init(Type, Key, IVec) -> State - State = { K, I, E, C } - Key = K = iolist() - IVec = I = E = binary() - C = integer() + Type aes_ctr + State = opaque() + Key = iodata() + IVec = binary()

Initializes the state for use in streaming AES encryption using Counter mode (CTR). Key is the AES key and must be either 128, 192, or 256 bts long. IVec is an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with - aes_ctr_stream_encrypt and - aes_ctr_stream_decrypt.

+ stream_encrypt and + stream_decrypt.

- aes_ctr_stream_encrypt(State, Text) -> { NewState, Cipher} + stream_encrypt(Type, State, PlainText) -> { NewState, CipherText} + Type = stream_cipher() Text = iolist() | binary() - Cipher = binary() + CipherText = binary() -

Encrypts Text according to AES in Counter mode (CTR). This function can be - used to encrypt a stream of text using a series of calls instead of requiring all - text to be in memory. Text can be any number of bytes. State is initialized using - aes_ctr_stream_init. NewState is the new streaming - encryption state that must be passed to the next call to aes_ctr_stream_encrypt. - Cipher is the encrypted cipher text.

+

Encrypts PlainText according to the stream cipher Type. + Text can be any number of bytes. State is initialized using + stream_init on + the next invocation of this function the returned State shall be + given as input and so on until the end of the stream is reached.

- aes_ctr_stream_decrypt(State, Cipher) -> { NewState, Text } + stream_decrypt(Type, State, CipherText) -> { NewState, PlainText } - Cipher = iolist() | binary() - Text = binary() - - -

Decrypts Cipher according to AES in Counter mode (CTR). This function can be - used to decrypt a stream of ciphertext using a series of calls instead of requiring all - ciphertext to be in memory. Cipher can be any number of bytes. State is initialized using - aes_ctr_stream_init. NewState is the new streaming - encryption state that must be passed to the next call to aes_ctr_stream_encrypt. - Text is the decrypted data.

-
-
- - - blowfish_ecb_encrypt(Key, Text) -> Cipher - Encrypt the first 64 bits of Text using Blowfish in ECB mode - - Key = Text = iolist() | binary() - Cipher = binary() - - -

Encrypts the first 64 bits of Text using Blowfish in ECB mode. Key is the Blowfish key. The length of Text must be at least 64 bits (8 bytes).

-
-
- - - blowfish_ecb_decrypt(Key, Text) -> Cipher - Decrypt the first 64 bits of Text using Blowfish in ECB mode - - Key = Text = iolist() | binary() - Cipher = binary() - - -

Decrypts the first 64 bits of Text using Blowfish in ECB mode. Key is the Blowfish key. The length of Text must be at least 64 bits (8 bytes).

-
-
- - - blowfish_cbc_encrypt(Key, IVec, Text) -> Cipher - Encrypt Text using Blowfish in CBC mode - - Key = Text = iolist() | binary() - IVec = Cipher = binary() - - -

Encrypts Text using Blowfish in CBC mode. Key is the Blowfish key, and IVec is an - arbitrary initializing vector. The length of IVec - must be 64 bits (8 bytes). The length of Text must be a multiple of 64 bits (8 bytes).

-
-
- - blowfish_cbc_decrypt(Key, IVec, Text) -> Cipher - Decrypt Text using Blowfish in CBC mode - - Key = Text = iolist() | binary() - IVec = Cipher = binary() - - -

Decrypts Text using Blowfish in CBC mode. Key is the Blowfish key, and IVec is an - arbitrary initializing vector. The length of IVec - must be 64 bits (8 bytes). The length of Text must be a multiple 64 bits (8 bytes).

-
-
- - - blowfish_cfb64_encrypt(Key, IVec, Text) -> Cipher - Encrypt Textusing Blowfish in CFB mode with 64 - bit feedback - - Key = Text = iolist() | binary() - IVec = Cipher = binary() - - -

Encrypts Text using Blowfish in CFB mode with 64 bit - feedback. Key is the Blowfish key, and IVec is an - arbitrary initializing vector. The length of IVec - must be 64 bits (8 bytes).

-
-
- - - blowfish_cfb64_decrypt(Key, IVec, Text) -> Cipher - Decrypt Textusing Blowfish in CFB mode with 64 - bit feedback - - Key = Text = iolist() | binary() - IVec = Cipher = binary() - - -

Decrypts Text using Blowfish in CFB mode with 64 bit - feedback. Key is the Blowfish key, and IVec is an - arbitrary initializing vector. The length of IVec - must be 64 bits (8 bytes).

-
-
- - - blowfish_ofb64_encrypt(Key, IVec, Text) -> Cipher - Encrypt Textusing Blowfish in OFB mode with 64 - bit feedback - - Key = Text = iolist() | binary() - IVec = Cipher = binary() - - -

Encrypts Text using Blowfish in OFB mode with 64 bit - feedback. Key is the Blowfish key, and IVec is an - arbitrary initializing vector. The length of IVec - must be 64 bits (8 bytes).

-
-
- - - des_cbc_encrypt(Key, IVec, Text) -> Cipher - Encrypt Textaccording to DES in CBC mode - - Key = Text = iolist() | binary() - IVec = Cipher = binary() - - -

Encrypts Text according to DES in CBC - mode. Text must be a multiple of 64 bits (8 - bytes). Key is the DES key, and IVec is an - arbitrary initializing vector. The lengths of Key and - IVec must be 64 bits (8 bytes).

-
-
- - - des_cbc_decrypt(Key, IVec, Cipher) -> Text - Decrypt Cipheraccording to DES in CBC mode - - Key = Cipher = iolist() | binary() - IVec = Text = binary() - - -

Decrypts Cipher according to DES in CBC mode. - Key is the DES key, and IVec is an arbitrary - initializing vector. Key and IVec must have - the same values as those used when encrypting. Cipher - must be a multiple of 64 bits (8 bytes). The lengths of - Key and IVec must be 64 bits (8 bytes).

-
-
- - - des_cbc_ivec(Data) -> IVec - Get IVec to be used in next iteration of - des_cbc_[ecrypt|decrypt] - - Data = iolist() | binary() - IVec = binary() - - -

Returns the IVec to be used in a next iteration of - des_cbc_[encrypt|decrypt]. Data is the encrypted - data from the previous iteration step.

-
-
- - - des_cfb_encrypt(Key, IVec, Text) -> Cipher - Encrypt Textaccording to DES in CFB mode - - Key = Text = iolist() | binary() - IVec = Cipher = binary() - - -

Encrypts Text according to DES in 8-bit CFB - mode. Key is the DES key, and IVec is an - arbitrary initializing vector. The lengths of Key and - IVec must be 64 bits (8 bytes).

-
-
- - - des_cfb_decrypt(Key, IVec, Cipher) -> Text - Decrypt Cipheraccording to DES in CFB mode - - Key = Cipher = iolist() | binary() - IVec = Text = binary() - - -

Decrypts Cipher according to DES in 8-bit CFB mode. - Key is the DES key, and IVec is an arbitrary - initializing vector. Key and IVec must have - the same values as those used when encrypting. The lengths of - Key and IVec must be 64 bits (8 bytes).

-
-
- - - des_cfb_ivec(IVec, Data) -> NextIVec - Get IVec to be used in next iteration of - des_cfb_[ecrypt|decrypt] - - IVec = iolist() | binary() - Data = iolist() | binary() - NextIVec = binary() - - -

Returns the IVec to be used in a next iteration of - des_cfb_[encrypt|decrypt]. IVec is the vector - used in the previous iteration step. Data is the encrypted - data from the previous iteration step.

-
-
- - - des3_cbc_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher - Encrypt Textaccording to DES3 in CBC mode - - Key1 =Key2 = Key3 Text = iolist() | binary() - IVec = Cipher = binary() - - -

Encrypts Text according to DES3 in CBC - mode. Text must be a multiple of 64 bits (8 - bytes). Key1, Key2, Key3, are the DES - keys, and IVec is an arbitrary initializing - vector. The lengths of each of Key1, Key2, - Key3 and IVec must be 64 bits (8 bytes).

-
-
- - - des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text - Decrypt Cipheraccording to DES3 in CBC mode - - Key1 = Key2 = Key3 = Cipher = iolist() | binary() - IVec = Text = binary() - - -

Decrypts Cipher according to DES3 in CBC mode. - Key1, Key2, Key3 are the DES key, and - IVec is an arbitrary initializing vector. - Key1, Key2, Key3 and IVec must - and IVec must have the same values as those used when - encrypting. Cipher must be a multiple of 64 bits (8 - bytes). The lengths of Key1, Key2, - Key3, and IVec must be 64 bits (8 bytes).

-
-
- - - des3_cfb_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher - Encrypt Textaccording to DES3 in CFB mode - - Key1 =Key2 = Key3 Text = iolist() | binary() - IVec = Cipher = binary() - - -

Encrypts Text according to DES3 in 8-bit CFB - mode. Key1, Key2, Key3, are the DES - keys, and IVec is an arbitrary initializing - vector. The lengths of each of Key1, Key2, - Key3 and IVec must be 64 bits (8 bytes).

-

May throw exception notsup for old OpenSSL - versions (0.9.7) that does not support this encryption mode.

-
-
- - - des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text - Decrypt Cipheraccording to DES3 in CFB mode - - Key1 = Key2 = Key3 = Cipher = iolist() | binary() - IVec = Text = binary() - - -

Decrypts Cipher according to DES3 in 8-bit CFB mode. - Key1, Key2, Key3 are the DES key, and - IVec is an arbitrary initializing vector. - Key1, Key2, Key3 and IVec must - and IVec must have the same values as those used when - encrypting. The lengths of Key1, Key2, - Key3, and IVec must be 64 bits (8 bytes).

-

May throw exception notsup for old OpenSSL - versions (0.9.7) that does not support this encryption mode.

-
-
- - - des_ecb_encrypt(Key, Text) -> Cipher - Encrypt Textaccording to DES in ECB mode - - Key = Text = iolist() | binary() - Cipher = binary() - - -

Encrypts Text according to DES in ECB mode. - Key is the DES key. The lengths of Key and - Text must be 64 bits (8 bytes).

-
-
- - des_ecb_decrypt(Key, Cipher) -> Text - Decrypt Cipheraccording to DES in ECB mode - - Key = Cipher = iolist() | binary() - Text = binary() - - -

Decrypts Cipher according to DES in ECB mode. - Key is the DES key. The lengths of Key and - Cipher must be 64 bits (8 bytes).

-
-
- - rc2_cbc_encrypt(Key, IVec, Text) -> Cipher - Encrypt Textaccording to RC2 in CBC mode - - Key = Text = iolist() | binary() - Ivec = Cipher = binary() - - -

Encrypts Text according to RC2 in CBC mode.

-
-
- - - rc2_cbc_decrypt(Key, IVec, Cipher) -> Text - Decrypts Cipheraccording to RC2 in CBC mode - - Key = Text = iolist() | binary() - Ivec = Cipher = binary() - - -

Decrypts Cipher according to RC2 in CBC mode.

-
-
- - - rc4_encrypt(Key, Data) -> Result - Encrypt data using RC4 - - Key, Data = iolist() | binary() - Result = binary() - - -

Encrypts the data with RC4 symmetric stream encryption. - Since it is symmetric, the same function is used for - decryption.

-
-
- - - - rsa_public_encrypt(PlainText, PublicKey, Padding) -> ChipherText - Encrypts Msg using the public Key. - - PlainText = binary() - PublicKey = [E, N] - E, N = integer() - Where E is the public exponent and N is public modulus. - Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding - ChipherText = binary() - - -

Encrypts the PlainText (usually a session key) using the PublicKey - and returns the cipher. The Padding decides what padding mode is used, - rsa_pkcs1_padding is PKCS #1 v1.5 currently the most - used mode and rsa_pkcs1_oaep_padding is EME-OAEP as - defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding - parameter. This mode is recommended for all new applications. - The size of the Msg must be less - than byte_size(N)-11 if - rsa_pkcs1_padding is used, byte_size(N)-41 if - rsa_pkcs1_oaep_padding is used and byte_size(N) if rsa_no_padding - is used. -

-
-
- - - rsa_private_decrypt(ChipherText, PrivateKey, Padding) -> PlainText - Decrypts ChipherText using the private Key. - - ChipherText = binary() - PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] - E, N, D = integer() - Where E is the public exponent, N is public modulus and - D is the private exponent. - P1, P2, E1, E2, C = integer() - The longer key format contains redundant information that will make - the calculation faster. P1,P2 are first and second prime factors. - E1,E2 are first and second exponents. C is the CRT coefficient. - Terminology is taken from RFC 3447. - Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding + Type = stream_cipher() + CipherText = iodata() | binary() PlainText = binary() -

Decrypts the ChipherText (usually a session key encrypted with - rsa_public_encrypt/3) - using the PrivateKey and returns the - message. The Padding is the padding mode that was - used to encrypt the data, - see rsa_public_encrypt/3. -

+

Decrypts CipherText according to the stream cipher Type. + PlainText can be any number of bytes. State is initialized using + stream_init on + the next invocation of this function the returned State shall be + given as input and so on until the end of the stream is reached.

- - rsa_private_encrypt(PlainText, PrivateKey, Padding) -> ChipherText - Encrypts Msg using the private Key. - - PlainText = binary() - PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] - E, N, D = integer() - Where E is the public exponent, N is public modulus and - D is the private exponent. - P1, P2, E1, E2, C = integer() - The longer key format contains redundant information that will make - the calculation faster. P1,P2 are first and second prime factors. - E1,E2 are first and second exponents. C is the CRT coefficient. - Terminology is taken from RFC 3447. - Padding = rsa_pkcs1_padding | rsa_no_padding - ChipherText = binary() - - -

Encrypts the PlainText using the PrivateKey - and returns the cipher. The Padding decides what padding mode is used, - rsa_pkcs1_padding is PKCS #1 v1.5 currently the most - used mode. - The size of the Msg must be less than byte_size(N)-11 if - rsa_pkcs1_padding is used, and byte_size(N) if rsa_no_padding - is used. -

-
-
- - rsa_public_decrypt(ChipherText, PublicKey, Padding) -> PlainText - Decrypts ChipherText using the public Key. + + verify(Algorithm, DigestType, Msg, Signature, Key) -> boolean() + Verifies a digital signature. - ChipherText = binary() - PublicKey = [E, N] - E, N = integer() - Where E is the public exponent and N is public modulus - Padding = rsa_pkcs1_padding | rsa_no_padding - PlainText = binary() + Algorithm = rsa | dss | ecdsa + Msg = binary() | {digest,binary()} + The msg is either the binary "plain text" data + or it is the hashed value of "plain text" i.e. the digest. + DigestType = digest_type() + Signature = binary() + Key = rsa_public_key() | dsa_public_key() | ec_public_key() -

Decrypts the ChipherText (encrypted with - rsa_private_encrypt/3) - using the PrivateKey and returns the - message. The Padding is the padding mode that was - used to encrypt the data, - see rsa_private_encrypt/3. -

+

Verifies a digital signature

+
-
- DES in CBC mode -

The Data Encryption Standard (DES) defines an algorithm for - encrypting and decrypting an 8 byte quantity using an 8 byte key - (actually only 56 bits of the key is used). -

-

When it comes to encrypting and decrypting blocks that are - multiples of 8 bytes various modes are defined (NIST SP - 800-38A). One of those modes is the Cipher Block Chaining (CBC) - mode, where the encryption of an 8 byte segment depend not only - of the contents of the segment itself, but also on the result of - encrypting the previous segment: the encryption of the previous - segment becomes the initializing vector of the encryption of the - current segment. -

-

Thus the encryption of every segment depends on the encryption - key (which is secret) and the encryption of the previous - segment, except the first segment which has to be provided with - an initial initializing vector. That vector could be chosen at - random, or be a counter of some kind. It does not have to be - secret. -

-

The following example is drawn from the old FIPS 81 standard - (replaced by NIST SP 800-38A), where both the plain text and the - resulting cipher text is settled. The following code fragment - returns `true'. -

-
>,
-      IVec = <<16#12,16#34,16#56,16#78,16#90,16#ab,16#cd,16#ef>>,
-      P = "Now is the time for all ",
-      C = crypto:des_cbc_encrypt(Key, IVec, P),
-         % Which is the same as 
-      P1 = "Now is t", P2 = "he time ", P3 = "for all ",
-      C1 = crypto:des_cbc_encrypt(Key, IVec, P1),
-      C2 = crypto:des_cbc_encrypt(Key, C1, P2),
-      C3 = crypto:des_cbc_encrypt(Key, C2, P3),
-
-      C = <>,
-      C = <<16#e5,16#c7,16#cd,16#de,16#87,16#2b,16#f2,16#7c,
-             16#43,16#e9,16#34,16#00,16#8c,16#38,16#9c,16#0f,
-             16#68,16#37,16#88,16#49,16#9a,16#7c,16#05,16#f6>>,
-      <<"Now is the time for all ">> == 
-                        crypto:des_cbc_decrypt(Key, IVec, C).
-    ]]>
-

The following is true for the DES CBC mode. For all - decompositions P1 ++ P2 = P of a plain text message - P (where the length of all quantities are multiples of 8 - bytes), the encryption C of P is equal to C1 ++ - C2, where C1 is obtained by encrypting P1 with - Key and the initializing vector IVec, and where - C2 is obtained by encrypting P2 with Key - and the initializing vector last8(C1), - where last(Binary) denotes the last 8 bytes of the - binary Binary. -

-

Similarly, for all decompositions C1 ++ C2 = C of a - cipher text message C (where the length of all quantities - are multiples of 8 bytes), the decryption P of C - is equal to P1 ++ P2, where P1 is obtained by - decrypting C1 with Key and the initializing vector - IVec, and where P2 is obtained by decrypting - C2 with Key and the initializing vector - last8(C1), where last8(Binary) is as above. -

-

For DES3 (which uses three 64 bit keys) the situation is the - same. -

-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 2b5ccb6ef4..f3fd119cdd 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -21,39 +21,23 @@ -module(crypto). --export([start/0, stop/0, info/0, info_lib/0, algorithms/0, version/0]). +-export([start/0, stop/0, info_lib/0, algorithms/0, version/0]). -export([hash/2, hash_init/1, hash_update/2, hash_final/1]). -export([sign/4, verify/5]). -export([generate_key/2, generate_key/3, compute_key/4]). -export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]). --export([exor/2]). --export([strong_rand_bytes/1, mod_exp_prime/3]). +-export([exor/2, strong_rand_bytes/1, mod_exp_prime/3]). -export([rand_bytes/1, rand_bytes/3, rand_uniform/2]). - --export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]). --export([des_ecb_encrypt/2, des_ecb_decrypt/2]). --export([des_cfb_encrypt/3, des_cfb_decrypt/3, des_cfb_ivec/2]). --export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]). --export([des3_cfb_encrypt/5, des3_cfb_decrypt/5]). --export([blowfish_ecb_encrypt/2, blowfish_ecb_decrypt/2]). --export([blowfish_cbc_encrypt/3, blowfish_cbc_decrypt/3]). --export([blowfish_cfb64_encrypt/3, blowfish_cfb64_decrypt/3]). --export([blowfish_ofb64_encrypt/3]). --export([des_ede3_cbc_encrypt/5, des_ede3_cbc_decrypt/5]). --export([aes_cfb_128_encrypt/3, aes_cfb_128_decrypt/3]). --export([rc4_encrypt/2, rc4_set_key/1, rc4_encrypt_with_state/2]). --export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3, rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]). --export([rsa_public_encrypt/3, rsa_private_decrypt/3]). --export([rsa_private_encrypt/3, rsa_public_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([block_encrypt/3, block_decrypt/3, block_encrypt/4, block_decrypt/4]). +-export([next_iv/2, next_iv/3]). +-export([stream_init/2, stream_init/3, stream_encrypt/3, stream_decrypt/3]). +-export([public_encrypt/4, private_decrypt/4]). +-export([private_encrypt/4, public_decrypt/4]). -export([dh_generate_parameters/2, dh_check/1]). %% Testing see %% DEPRECATED +%% Replaced by hash_* -export([md4/1, md4_init/0, md4_update/2, md4_final/1]). -export([md5/1, md5_init/0, md5_update/2, md5_final/1]). -export([sha/1, sha_init/0, sha_update/2, sha_final/1]). @@ -70,6 +54,7 @@ -deprecated({md5_final, 1, next_major_release}). -deprecated({sha_final, 1, next_major_release}). +%% Replaced by hmac_* -export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]). -deprecated({md5_mac, 2, next_major_release}). -deprecated({md5_mac_96, 2, next_major_release}). @@ -77,6 +62,7 @@ -deprecated({sha_mac, 3, next_major_release}). -deprecated({sha_mac_96, 2, next_major_release}). +%% Replaced by sign/verify -export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]). -export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]). -deprecated({dss_verify, 3, next_major_release}). @@ -88,53 +74,150 @@ -deprecated({rsa_sign, 2, next_major_release}). -deprecated({rsa_sign, 3, next_major_release}). +%% Replaced by generate_key -export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]). -deprecated({dh_generate_key, 1, next_major_release}). -deprecated({dh_generate_key, 2, next_major_release}). -deprecated({dh_compute_key, 3, next_major_release}). +%% Replaced by mod_exp_prim and no longer needed -export([mod_exp/3, mpint/1, erlint/1, strong_rand_mpint/3]). -deprecated({mod_exp, 3, next_major_release}). -deprecated({mpint, 1, next_major_release}). -deprecated({erlint, 1, next_major_release}). -deprecated({strong_rand_mpint, 3, next_major_release}). --define(FUNC_LIST, [md4, md4_init, md4_update, md4_final, +%% Replaced by block_* +-export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]). +-export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]). +-export([des_ecb_encrypt/2, des_ecb_decrypt/2]). +-export([des_ede3_cbc_encrypt/5, des_ede3_cbc_decrypt/5]). +-export([des_cfb_encrypt/3, des_cfb_decrypt/3, des_cfb_ivec/2]). +-export([des3_cfb_encrypt/5, des3_cfb_decrypt/5]). +-deprecated({des_cbc_encrypt, 3, next_major_release}). +-deprecated({des_cbc_decrypt, 3, next_major_release}). +-deprecated({des_cbc_ivec, 1, next_major_release}). +-deprecated({des3_cbc_encrypt, 5, next_major_release}). +-deprecated({des3_cbc_decrypt, 5, next_major_release}). +-deprecated({des_ecb_encrypt, 2, next_major_release}). +-deprecated({des_ecb_decrypt, 2, next_major_release}). +-deprecated({des_ede3_cbc_encrypt, 5, next_major_release}). +-deprecated({des_ede3_cbc_decrypt, 5, next_major_release}). +-deprecated({des_cfb_encrypt, 3, next_major_release}). +-deprecated({des_cfb_decrypt, 3, next_major_release}). +-deprecated({des_cfb_ivec, 2, next_major_release}). +-deprecated({des3_cfb_encrypt, 5, next_major_release}). +-deprecated({des3_cfb_decrypt, 5, next_major_release}). +-export([blowfish_ecb_encrypt/2, blowfish_ecb_decrypt/2]). +-export([blowfish_cbc_encrypt/3, blowfish_cbc_decrypt/3]). +-export([blowfish_cfb64_encrypt/3, blowfish_cfb64_decrypt/3]). +-export([blowfish_ofb64_encrypt/3]). +-deprecated({blowfish_ecb_encrypt, 2, next_major_release}). +-deprecated({blowfish_ecb_decrypt, 2, next_major_release}). +-deprecated({blowfish_cbc_encrypt, 3, next_major_release}). +-deprecated({blowfish_cbc_decrypt, 3, next_major_release}). +-deprecated({blowfish_cfb64_encrypt, 3, next_major_release}). +-deprecated({blowfish_cfb64_decrypt, 3, next_major_release}). +-deprecated({blowfish_ofb64_encrypt, 3, next_major_release}). +-export([aes_cfb_128_encrypt/3, aes_cfb_128_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]). +-deprecated({aes_cfb_128_encrypt, 3, next_major_release}). +-deprecated({aes_cfb_128_decrypt, 3, next_major_release}). +-deprecated({aes_cbc_128_encrypt, 3, next_major_release}). +-deprecated({aes_cbc_128_decrypt, 3, next_major_release}). +-deprecated({aes_cbc_256_encrypt, 3, next_major_release}). +-deprecated({aes_cbc_256_decrypt, 3, next_major_release}). +-deprecated({aes_cbc_ivec, 1, next_major_release}). +-export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3]). +-export([rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]). +-deprecated({rc2_cbc_encrypt, 3, next_major_release}). +-deprecated({rc2_cbc_decrypt, 3, next_major_release}). +%% allready replaced by above! +-deprecated({rc2_40_cbc_encrypt, 3, next_major_release}). +-deprecated({rc2_40_cbc_decrypt, 3, next_major_release}). + +%% Replaced by stream_* +-export([aes_ctr_stream_init/2, aes_ctr_stream_encrypt/2, aes_ctr_stream_decrypt/2]). +-export([rc4_set_key/1, rc4_encrypt_with_state/2]). +-deprecated({aes_ctr_stream_init, 2, next_major_release}). +-deprecated({aes_ctr_stream_encrypt, 2, next_major_release}). +-deprecated({aes_ctr_stream_decrypt, 2, next_major_release}). +-deprecated({rc4_set_key, 1, next_major_release}). +-deprecated({rc4_encrypt_with_state, 2, next_major_release}). + +%% Not needed special case of stream_* +-export([aes_ctr_encrypt/3, aes_ctr_decrypt/3, rc4_encrypt/2]). +-deprecated({aes_ctr_encrypt, 3, next_major_release}). +-deprecated({aes_ctr_decrypt, 3, next_major_release}). +-deprecated({rc4_encrypt, 2, next_major_release}). + +%% Replace by public/private_encrypt/decrypt +-export([rsa_public_encrypt/3, rsa_private_decrypt/3]). +-export([rsa_private_encrypt/3, rsa_public_decrypt/3]). +-deprecated({rsa_public_encrypt, 3, next_major_release}). +-deprecated({rsa_private_decrypt, 3, next_major_release}). +-deprecated({rsa_public_decrypt, 3, next_major_release}). +-deprecated({rsa_private_encrypt, 3, next_major_release}). + +%% Replaced by crypto:module_info() +-export([info/0]). +-deprecated({info, 0, next_major_release}). + +-define(FUNC_LIST, [hash, hash_init, hash_update, hash_final, + hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, + %% deprecated + md4, md4_init, md4_update, md4_final, md5, md5_init, md5_update, md5_final, sha, sha_init, sha_update, sha_final, md5_mac, md5_mac_96, sha_mac, sha_mac_96, + %% + block_encrypt, block_decrypt, + %% deprecated des_cbc_encrypt, des_cbc_decrypt, des_cfb_encrypt, des_cfb_decrypt, des_ecb_encrypt, des_ecb_decrypt, des3_cbc_encrypt, des3_cbc_decrypt, des3_cfb_encrypt, des3_cfb_decrypt, aes_cfb_128_encrypt, aes_cfb_128_decrypt, + rc2_cbc_encrypt, rc2_cbc_decrypt, + rc2_40_cbc_encrypt, rc2_40_cbc_decrypt, + aes_cbc_128_encrypt, aes_cbc_128_decrypt, + aes_cbc_256_encrypt, aes_cbc_256_decrypt, + blowfish_cbc_encrypt, blowfish_cbc_decrypt, + blowfish_cfb64_encrypt, blowfish_cfb64_decrypt, + blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt, + %% rand_bytes, strong_rand_bytes, - strong_rand_mpint, rand_uniform, - mod_exp, mod_exp_prime, + mod_exp_prime, + exor, + %% deprecated + mod_exp,strong_rand_mpint,erlint, mpint, + %% + sign, verify, generate_key, compute_key, + %% deprecated dss_verify,dss_sign, rsa_verify,rsa_sign, rsa_public_encrypt,rsa_private_decrypt, rsa_private_encrypt,rsa_public_decrypt, dh_generate_key, dh_compute_key, - aes_cbc_128_encrypt, aes_cbc_128_decrypt, - exor, + %% + stream_init, stream_encrypt, stream_decrypt, + %% deprecated rc4_encrypt, rc4_set_key, rc4_encrypt_with_state, - rc2_40_cbc_encrypt, rc2_40_cbc_decrypt, - aes_cbc_256_encrypt, aes_cbc_256_decrypt, aes_ctr_encrypt, aes_ctr_decrypt, aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt, - aes_cbc_ivec, blowfish_cbc_encrypt, blowfish_cbc_decrypt, - blowfish_cfb64_encrypt, blowfish_cfb64_decrypt, - blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt, - des_cbc_ivec, des_cfb_ivec, erlint, mpint, - hash, hash_init, hash_update, hash_final, - hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, info, - rc2_cbc_encrypt, rc2_cbc_decrypt, - sign, verify, generate_key, compute_key, + %% + next_iv, + %% deprecated + aes_cbc_ivec, + des_cbc_ivec, des_cfb_ivec, + info, + %% info_lib, algorithms]). -type mpint() :: binary(). @@ -598,6 +681,106 @@ sha512_mac(Key, Data, MacSz) -> sha512_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. + +%% Ecrypt/decrypt %%% + +-spec block_encrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | + blowfish_cfb64 | aes_cbc128 | aes_cfb128 | rc2_cbc, + Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). + +block_encrypt(des_cbc, Key, Ivec, Data) -> + des_cbc_encrypt(Key, Ivec, Data); +block_encrypt(des_cfb, Key, Ivec, Data) -> + des_cfb_encrypt(Key, Ivec, Data); +block_encrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) -> + des3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data); +block_encrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) -> + des3_cfb_encrypt(Key1, Key2, Key3, Ivec, Data); +block_encrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) -> + des_ede3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data); +block_encrypt(blowfish_cbc, Key, Ivec, Data) -> + blowfish_cbc_encrypt(Key, Ivec, Data); +block_encrypt(blowfish_cfb64, Key, Ivec, Data) -> + blowfish_cfb64_encrypt(Key, Ivec, Data); +block_encrypt(blowfish_ofb64, Key, Ivec, Data) -> + blowfish_ofb64_encrypt(Key, Ivec, Data); +block_encrypt(aes_cbc128, Key, Ivec, Data) -> + aes_cbc_128_encrypt(Key, Ivec, Data); +block_encrypt(aes_cbc256, Key, Ivec, Data) -> + aes_cbc_256_encrypt(Key, Ivec, Data); +block_encrypt(aes_cfb128, Key, Ivec, Data) -> + aes_cfb_128_encrypt(Key, Ivec, Data); +block_encrypt(rc2_cbc, Key, Ivec, Data) -> + rc2_cbc_encrypt(Key, Ivec, Data). + +-spec block_decrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | + blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cfb128 | rc2_cbc, + Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). + +block_decrypt(des_cbc, Key, Ivec, Data) -> + des_cbc_decrypt(Key, Ivec, Data); +block_decrypt(des_cfb, Key, Ivec, Data) -> + des_cfb_decrypt(Key, Ivec, Data); +block_decrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) -> + des3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data); +block_decrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) -> + des3_cfb_decrypt(Key1, Key2, Key3, Ivec, Data); +block_decrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) -> + des_ede3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data); +block_decrypt(blowfish_cbc, Key, Ivec, Data) -> + blowfish_cbc_decrypt(Key, Ivec, Data); +block_decrypt(blowfish_cfb64, Key, Ivec, Data) -> + blowfish_cfb64_decrypt(Key, Ivec, Data); +block_decrypt(blowfish_ofb, Key, Ivec, Data) -> + blowfish_ofb64_decrypt(Key, Ivec, Data); +block_decrypt(aes_cbc128, Key, Ivec, Data) -> + aes_cbc_128_decrypt(Key, Ivec, Data); +block_decrypt(aes_cbc256, Key, Ivec, Data) -> + aes_cbc_256_decrypt(Key, Ivec, Data); +block_decrypt(aes_cfb128, Key, Ivec, Data) -> + aes_cfb_128_decrypt(Key, Ivec, Data); +block_decrypt(rc2_cbc, Key, Ivec, Data) -> + rc2_cbc_decrypt(Key, Ivec, Data). + +-spec block_encrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary(). + +block_encrypt(des_ecb, Key, Data) -> + des_ecb_encrypt(Key, Data); +block_encrypt(blowfish_ecb, Key, Data) -> + blowfish_ecb_encrypt(Key, Data). + +-spec block_decrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary(). + +block_decrypt(des_ecb, Key, Data) -> + des_ecb_decrypt(Key, Data); +block_decrypt(blowfish_ecb, Key, Data) -> + blowfish_ecb_decrypt(Key, Data). + +-spec next_iv(des_cbc | aes_cbc, Data::iodata()) -> binary(). + +next_iv(des_cbc, Data) -> + des_cbc_ivec(Data); +next_iv(aes_cbc, Data) -> + aes_cbc_ivec(Data). + +-spec next_iv(des_cbf, Ivec::binary(), Data::iodata()) -> binary(). + +next_iv(des_cbf, Ivec, Data) -> + des_cfb_ivec(Ivec, Data). + +stream_init(aes_ctr, Key, Ivec) -> + aes_ctr_stream_init(Key, Ivec). +stream_init(rc4, Key) -> + rc4_set_key(Key). +stream_encrypt(aes_ctr, State, Data) -> + aes_ctr_stream_encrypt(State, Data); +stream_encrypt(rc4, State, Data) -> + rc4_encrypt_with_state(State, Data). +stream_decrypt(aes_ctr, State, Data) -> + aes_ctr_stream_decrypt(State, Data); +stream_decrypt(rc4, State, Data) -> + rc4_encrypt_with_state (State, Data). + %% %% CRYPTO FUNCTIONS %% @@ -746,8 +929,12 @@ blowfish_cfb64_decrypt(Key, IVec, Data) -> bf_cfb64_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. +blowfish_ofb64_decrypt(Key, Ivec, Data) -> + blowfish_ofb64_encrypt(Key, Ivec, Data). + blowfish_ofb64_encrypt(_Key, _IVec, _Data) -> ?nif_stub. + %% %% AES in cipher feedback mode (CFB) %% @@ -956,6 +1143,46 @@ ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub. +-spec public_encrypt(rsa, binary(), [binary()], rsa_padding()) -> + binary(). +-spec public_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> + binary(). +-spec private_encrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> + binary(). +-spec private_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> + binary(). + +public_encrypt(rsa, BinMesg, Key, Padding) -> + case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of + error -> + erlang:error(encrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. + +%% Binary, Key = [E,N,D] +private_decrypt(rsa, BinMesg, Key, Padding) -> + case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of + error -> + erlang:error(decrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. + + +%% Binary, Key = [E,N,D] +private_encrypt(rsa, BinMesg, Key, Padding) -> + case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of + error -> + erlang:error(encrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. + +%% Binary, Key = [E,N] +public_decrypt(rsa, BinMesg, Key, Padding) -> + case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of + error -> + erlang:error(decrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. %% diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index eff0f8a878..cff257bb8c 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -191,8 +191,8 @@ ldd_program() -> Ldd when is_list(Ldd) -> Ldd end. -%% -%% + + info(doc) -> ["Call the info function."]; info(suite) -> @@ -208,10 +208,10 @@ info(Config) when is_list(Config) -> ?line [] = Info -- Exports, ?line NotInInfo = Exports -- Info, io:format("NotInInfo = ~p\n", [NotInInfo]), - BlackList = lists:sort([des_ede3_cbc_decrypt, des_ede3_cbc_encrypt, - dh_check, dh_generate_parameters, - module_info, start, stop, version]), - ?line BlackList = NotInInfo, + %% BlackList = lists:sort([des_ede3_cbc_decrypt, des_ede3_cbc_encrypt, + %% dh_check, dh_generate_parameters, + %% module_info, start, stop, version]), + %% ?line BlackList = NotInInfo, ?line InfoLib = crypto:info_lib(), ?line [_|_] = InfoLib, @@ -222,10 +222,10 @@ info(Config) when is_list(Config) -> Me(T,Me); ([],_) -> ok - end, + end, ?line F(InfoLib,F), ?line crypto:stop() - end. + end. %% %% diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl index 9805414a9a..38edf3781e 100644 --- a/lib/stdlib/src/otp_internal.erl +++ b/lib/stdlib/src/otp_internal.erl @@ -131,6 +131,67 @@ obsolete_1(crypto, dh_generate_key, 1) -> obsolete_1(crypto, dh_generate_key, 2) -> {deprecated, {crypto, generate_key, 3}}; +obsolete_1(crypto, des_cbc_encrypt, 3) -> + {deprecated, {crypto, block_encrypt, 4}}; +obsolete_1(crypto, des3_cbc_encrypt, 5) -> + {deprecated, {crypto, block_encrypt, 4}}; +obsolete_1(crypto, des_ecb_encrypt, 3) -> + {deprecated, {crypto, block_encrypt, 4}}; +obsolete_1(crypto, des_ede3_cbc_encrypt, 5) -> + {deprecated, {crypto, block_encrypt, 4}}; +obsolete_1(crypto, des_cfb_encrypt, 3) -> + {deprecated, {crypto, block_encrypt, 4}}; +obsolete_1(crypto, des3_cfb_encrypt, 5) -> + {deprecated, {crypto, block_encrypt, 4}}; +obsolete_1(crypto, blowfish_ecb_encrypt, 2) -> + {deprecated, {crypto, block_encrypt, 3}}; +obsolete_1(crypto, blowfish_cbc_encrypt, 3) -> + {deprecated, {crypto, block_encrypt, 4}}; +obsolete_1(crypto, blowfish_cfb64_encrypt, 3) -> + {deprecated, {crypto, block_encrypt, 4}}; +obsolete_1(crypto, blowfish_ofb64_encrypt, 3) -> + {deprecated, {crypto, block_encrypt, 4}}; +obsolete_1(crypto, aes_cfb_128_encrypt, 3) -> + {deprecated, {crypto, block_encrypt, 4}}; +obsolete_1(crypto, aes_cbc_256_encrypt, 3) -> + {deprecated, {crypto, block_encrypt, 4}}; +obsolete_1(crypto,rc2_cbc_encrypt, 3) -> + {deprecated, {crypto, block_encrypt, 4}}; +obsolete_1(crypto,rc2_40_cbc_encrypt, 3) -> + {deprecated, {crypto, block_encrypt, 4}}; + +obsolete_1(crypto, des_cbc_decrypt, 3) -> + {deprecated, {crypto, block_decrypt, 4}}; +obsolete_1(crypto, des3_cbc_decrypt, 5) -> + {deprecated, {crypto, block_decrypt, 4}}; +obsolete_1(crypto, des_ecb_decrypt, 3) -> + {deprecated, {crypto, block_decrypt, 4}}; +obsolete_1(crypto, des_ede3_cbc_decrypt, 5) -> + {deprecated, {crypto, block_decrypt, 4}}; +obsolete_1(crypto, des_cfb_decrypt, 3) -> + {deprecated, {crypto, block_decrypt, 4}}; +obsolete_1(crypto, des3_cfb_decrypt, 5) -> + {deprecated, {crypto, block_decrypt, 4}}; +obsolete_1(crypto, blowfish_ecb_decrypt, 2) -> + {deprecated, {crypto, block_decrypt, 3}}; +obsolete_1(crypto, blowfish_cbc_decrypt, 3) -> + {deprecated, {crypto, block_decrypt, 4}}; +obsolete_1(crypto, blowfish_cfb64_decrypt, 3) -> + {deprecated, {crypto, block_decrypt, 4}}; +obsolete_1(crypto, blowfish_ofb64_decrypt, 3) -> + {deprecated, {crypto, block_decrypt, 4}}; +obsolete_1(crypto, aes_cfb_128_decrypt, 3) -> + {deprecated, {crypto, block_decrypt, 4}}; +obsolete_1(crypto, aes_cbc_256_decrypt, 3) -> + {deprecated, {crypto, block_decrypt, 4}}; +obsolete_1(crypto,rc2_cbc_decrypt, 3) -> + {deprecated, {crypto, block_decrypt, 4}}; +obsolete_1(crypto,rc2_40_cbc_decrypt, 3) -> + {deprecated, {crypto, block_decrypt, 4}}; + +obsolete_1(crypto,info, 0) -> + {deprecated, {crypto, module_info, 0}}; + obsolete_1(crypto, strong_rand_mpint, 3) -> {deprecated, "needed only by deprecated functions"}; obsolete_1(crypto, erlint, 3) -> -- cgit v1.2.3 From b968404bfb277c64f3ab040fd5921f8583443c6f Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 30 Apr 2013 18:29:26 +0200 Subject: ssl & public_key: Use new crypto API functions --- lib/public_key/src/public_key.erl | 12 +++++------- lib/ssl/src/ssl_cipher.erl | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 96eaacf60e..f9042d5349 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -258,7 +258,7 @@ decrypt_private(CipherText, when is_binary(CipherText), is_list(Options) -> Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - crypto:rsa_private_decrypt(CipherText, format_rsa_private_key(Key), Padding). + crypto:private_decrypt(rsa, CipherText, format_rsa_private_key(Key), Padding). %%-------------------------------------------------------------------- -spec decrypt_public(CipherText :: binary(), rsa_public_key() | rsa_private_key()) -> @@ -324,7 +324,7 @@ encrypt_private(PlainText, is_integer(N), is_integer(E), is_integer(D), is_list(Options) -> Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - crypto:rsa_private_encrypt(PlainText, format_rsa_private_key(Key), Padding). + crypto:private_encrypt(rsa, PlainText, format_rsa_private_key(Key), Padding). %%-------------------------------------------------------------------- -spec generate_key(#'DHParameter'{} | {namedCurve, Name ::atom()} | @@ -652,13 +652,11 @@ do_pem_entry_decode({Asn1Type,_, _} = PemEntry, Password) -> encrypt_public(PlainText, N, E, Options)-> Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - crypto:rsa_public_encrypt(PlainText, [E,N], - Padding). + crypto:public_encrypt(rsa, PlainText, [E,N], Padding). -decrypt_public(CipherText, N,E, Options) -> +decrypt_public(CipherText, N,E, Options) -> Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - crypto:rsa_public_decrypt(CipherText,[E, N], - Padding). + crypto:public_decrypt(rsa, CipherText,[E, N], Padding). path_validation([], #path_validation_state{working_public_key_algorithm = Algorithm, diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 1bf3a885b2..5ce1350f09 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -73,25 +73,25 @@ cipher(?NULL, CipherState, <<>>, Fragment, _Version) -> {GenStreamCipherList, CipherState}; cipher(?RC4, CipherState, Mac, Fragment, _Version) -> State0 = case CipherState#cipher_state.state of - undefined -> crypto:rc4_set_key(CipherState#cipher_state.key); + undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key); S -> S end, GenStreamCipherList = [Fragment, Mac], - {State1, T} = crypto:rc4_encrypt_with_state(State0, GenStreamCipherList), + {State1, T} = crypto:stream_encrypt(rc4, State0, GenStreamCipherList), {T, CipherState#cipher_state{state = State1}}; cipher(?DES, CipherState, Mac, Fragment, Version) -> block_cipher(fun(Key, IV, T) -> - crypto:des_cbc_encrypt(Key, IV, T) + crypto:block_encrypt(des_cbc, Key, IV, T) end, block_size(des_cbc), CipherState, Mac, Fragment, Version); cipher(?'3DES', CipherState, Mac, Fragment, Version) -> block_cipher(fun(<>, IV, T) -> - crypto:des3_cbc_encrypt(K1, K2, K3, IV, T) + crypto:block_encrypt(des3_cbc, [K1, K2, K3], IV, T) end, block_size(des_cbc), CipherState, Mac, Fragment, Version); cipher(?AES, CipherState, Mac, Fragment, Version) -> block_cipher(fun(Key, IV, T) when byte_size(Key) =:= 16 -> - crypto:aes_cbc_128_encrypt(Key, IV, T); + crypto:block_encrypt(aes_cbc128, Key, IV, T); (Key, IV, T) when byte_size(Key) =:= 32 -> - crypto:aes_cbc_256_encrypt(Key, IV, T) + crypto:block_encrypt(aes_cbc256, Key, IV, T) end, block_size(aes_128_cbc), CipherState, Mac, Fragment, Version). build_cipher_block(BlockSz, Mac, Fragment) -> @@ -127,10 +127,10 @@ decipher(?NULL, _HashSz, CipherState, Fragment, _) -> {Fragment, <<>>, CipherState}; decipher(?RC4, HashSz, CipherState, Fragment, _) -> State0 = case CipherState#cipher_state.state of - undefined -> crypto:rc4_set_key(CipherState#cipher_state.key); + undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key); S -> S end, - try crypto:rc4_encrypt_with_state(State0, Fragment) of + try crypto:stream_decrypt(rc4, State0, Fragment) of {State, Text} -> GSC = generic_stream_cipher_from_bin(Text, HashSz), #generic_stream_cipher{content = Content, mac = Mac} = GSC, @@ -147,17 +147,17 @@ decipher(?RC4, HashSz, CipherState, Fragment, _) -> decipher(?DES, HashSz, CipherState, Fragment, Version) -> block_decipher(fun(Key, IV, T) -> - crypto:des_cbc_decrypt(Key, IV, T) + crypto:block_decrypt(des_cbc, Key, IV, T) end, CipherState, HashSz, Fragment, Version); decipher(?'3DES', HashSz, CipherState, Fragment, Version) -> block_decipher(fun(<>, IV, T) -> - crypto:des3_cbc_decrypt(K1, K2, K3, IV, T) + crypto:block_decrypt(des3_cbc, [K1, K2, K3], IV, T) end, CipherState, HashSz, Fragment, Version); decipher(?AES, HashSz, CipherState, Fragment, Version) -> block_decipher(fun(Key, IV, T) when byte_size(Key) =:= 16 -> - crypto:aes_cbc_128_decrypt(Key, IV, T); + crypto:block_decrypt(aes_cbc128, Key, IV, T); (Key, IV, T) when byte_size(Key) =:= 32 -> - crypto:aes_cbc_256_decrypt(Key, IV, T) + crypto:block_decrypt(aes_cbc256, Key, IV, T) end, CipherState, HashSz, Fragment, Version). block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0, -- cgit v1.2.3 From a9add4e3d878bbd339fc2bb36e97d1053318b4e6 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 2 May 2013 14:30:39 +0200 Subject: public_key: Add new API functions to the documentation --- lib/public_key/doc/src/public_key.xml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 45aaf21b80..ffea387404 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -153,6 +153,19 @@ + + compute_key(OthersKey, MyKey)-> + compute_key(OthersKey, MyKey, Params)-> + Compute shared secret + + OthersKey = #'ECPoint'{} | binary(), MyKey = #'ECPrivateKey'{} | binary() + Params = #'DHParameter'{} + + +

Compute shared secret

+
+
+ decrypt_private(CipherText, Key) -> binary() decrypt_private(CipherText, Key, Options) -> binary() @@ -210,6 +223,17 @@ + + generate_key(Params) -> {Public::binary(), Private::binary()} | #'ECPrivateKey'{} + Generates a new keypair + + Params = #'DHParameter'{} | {namedCurve, oid()} | #'OTPECParameters'{} + + +

Generates a new keypair

+
+
+ pem_decode(PemBin) -> [pem_entry()] Decode PEM binary data and return -- cgit v1.2.3 From cb1305212e71855890bbfb0a509a007543529d24 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 3 May 2013 10:20:37 +0200 Subject: ssl & crypto: Generalize the remaining crypto API --- lib/crypto/c_src/crypto.c | 6 ++- lib/crypto/doc/src/crypto.xml | 106 ++++++++++++++++++++------------------ lib/crypto/doc/src/crypto_app.xml | 36 ++++--------- lib/crypto/src/crypto.erl | 42 ++++++++------- lib/crypto/test/crypto_SUITE.erl | 10 ++-- lib/ssl/src/ssl_cipher.erl | 4 +- lib/ssl/src/ssl_connection.erl | 2 +- lib/stdlib/src/otp_internal.erl | 2 +- 8 files changed, 103 insertions(+), 105 deletions(-) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index c5d181ea25..0129526303 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -496,6 +496,7 @@ static ERL_NIF_TERM atom_sha256; static ERL_NIF_TERM atom_sha384; static ERL_NIF_TERM atom_sha512; static ERL_NIF_TERM atom_md5; +static ERL_NIF_TERM atom_md4; static ERL_NIF_TERM atom_ripemd160; static ERL_NIF_TERM atom_error; static ERL_NIF_TERM atom_rsa_pkcs1_padding; @@ -590,6 +591,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info) atom_sha256 = enif_make_atom(env,"sha256"); atom_sha384 = enif_make_atom(env,"sha384"); atom_sha512 = enif_make_atom(env,"sha512"); + atom_md4 = enif_make_atom(env,"md4"); atom_md5 = enif_make_atom(env,"md5"); atom_ripemd160 = enif_make_atom(env,"ripemd160"); atom_error = enif_make_atom(env,"error"); @@ -708,12 +710,12 @@ static void unload(ErlNifEnv* env, void* priv_data) } static int algos_cnt; -static ERL_NIF_TERM algos[8]; /* increase when extending the list */ +static ERL_NIF_TERM algos[9]; /* increase when extending the list */ static void init_algorithms_types(void) { algos_cnt = 0; - + algos[algos_cnt++] = atom_md4; algos[algos_cnt++] = atom_md5; algos[algos_cnt++] = atom_sha; algos[algos_cnt++] = atom_ripemd160; diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 0fb53346ca..df765ade87 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -30,23 +30,24 @@

-

Hash functions - The MD4 Message Digest Algorithm (RFC 1320), +

Hash functions - + Secure Hash Standard, The MD5 Message Digest Algorithm (RFC 1321) and - Secure Hash Standard + The MD4 Message Digest Algorithm (RFC 1320)

Hmac functions - Keyed-Hashing for Message Authentication (RFC 2104)

-

Block ciphers - DES and AES and - and Block Cipher Modes - ECB, CBC, CFB, OFB and CTR

+

Block ciphers - DES and AES in + Block Cipher Modes - ECB, CBC, CFB, OFB and CTR

RSA encryption RFC 1321

-

Digital signatures Digital Signature Standard (DSS) and Elliptic Curve Digital +

Digital signatures Digital Signature Standard (DSS) and Elliptic Curve Digital Signature Algorithm (ECDSA)

@@ -57,13 +58,7 @@
DATA TYPES - -

byte() = 0 ... 255

- -

ioelem() = byte() | binary() | iolist()

- -

iolist() = [ioelem()]

- +

key_value() = integer() | binary()

rsa_public() = [key_value()] = [E, N]

@@ -74,7 +69,7 @@ the private exponent.The longer key format contains redundant information that will make the calculation faster. P1,P2 are first and second prime factors. E1,E2 are first and second exponents. C - is the CRT coefficient. Terminology is taken from RFC 3447.

+ is the CRT coefficient. Terminology is taken from RFC 3447.

dss_public() = [key_value()] = [P, Q, G, Y]

Where P, Q and G are the dss parameters and Y is the public key.

@@ -137,25 +132,28 @@

block_key() = aes_key() | blowfish_key() | des_key()| des3_key()

-

aes_key() = binary() Key length is 128, 192 or 256 bits

+

aes_key() = iodata() Key length is 128, 192 or 256 bits

-

rc4_key() = binary() Variable key length from 8 bits up to 2048 bits (usually between 40 and 256)

+

rc4_key() = iodata() Variable key length from 8 bits up to 2048 bits (usually between 40 and 256)

-

blowfish_key() = binary() Variable key length from 32 bits up to 448 bits

+

blowfish_key() = iodata() Variable key length from 32 bits up to 448 bits

-

des_key() = binary() Key length is 64 bits (in CBC mod only 8 bits are used)

+

des_key() = iodata() Key length is 64 bits (in CBC mode only 8 bits are used)

-

des3_key() = [binary(), binary(), binary()] Each key part is 64 bits (in CBC mod only 8 bits are used)

+

des3_key() = [binary(), binary(), binary()] Each key part is 64 bits (in CBC mode only 8 bits are used)

+ +

message_digest_algorithms() = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 md4 is aslo supported for hash_init/1 and hash/2. + Note that both md4 and md5 are recommended only for compatibility with existing applications. +

- algorithms() -> [atom()] + algorithms() -> [message_digest_algorithms() | md4 | ec] Provide a list of available crypto algorithms. -

Provides the available crypto algorithms in terms of a list - of atoms. This is interesting as older versions of the openssl - crypto library may not support all algorithms used in the crypto API.

+

Can be used to determine if the crypto library has support for elliptic curve (ec) and + which message digest algorithms that are supported.

@@ -164,7 +162,7 @@ Encrypt PlainTextaccording to Type block cipher Key = block_key() - PlainText = iodata() | binary() + PlainText = iodata() IVec = CipherText = binary() @@ -179,7 +177,7 @@ Decrypt CipherTextaccording to Type block cipher Key = block_key() - PlainText = iodata() | binary() + PlainText = iodata() IVec = CipherText = binary() @@ -201,6 +199,7 @@

Computes the shared secret from the private key and the other party's public key. + See also public_key:compute_key/2

@@ -209,7 +208,7 @@ exor(Data1, Data2) -> Result XOR data - Data1, Data2 = iolist() | binary() + Data1, Data2 = iodata() Result = binary() @@ -229,6 +228,7 @@

Generates public keys of type Type. + See also public_key:generate_key/1

@@ -237,7 +237,7 @@ hash(Type, Data) -> Digest - Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 + Type = md4 | message_digest_algorithms() Data = iodata() Digest = binary() @@ -252,7 +252,7 @@ hash_init(Type) -> Context - Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 + Type = md4 | message_digest_algorithms()

Initializes the context for streaming hash operations. Type determines @@ -296,7 +296,7 @@ hmac(Type, Key, Data, MacLength) -> Mac - Type = md5 | sha | sha224 | sha256 | sha384 | sha512 + Type = message_digest_algorithms() Key = iodata() Data = iodata() MacLength = integer() @@ -313,8 +313,8 @@ hmac_init(Type, Key) -> Context - Type = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 - Key = iolist() | binary() + Type = message_digest_algorithms() + Key = iodata() Context = binary() @@ -329,13 +329,17 @@ Context = NewContext = binary() - Data = iolist() | binary() + Data = iodata()

Updates the HMAC represented by Context using the given Data. Context must have been generated using an HMAC init function (such as hmac_init). Data can be any length. NewContext - must be passed into the next call to hmac_update.

+ must be passed into the next call to hmac_update + or to one of the functions hmac_final and + hmac_final_n +

+
@@ -391,10 +395,10 @@ - mod_exp_prime(N, P, M) -> Result + mod_pow(N, P, M) -> Result Computes the function: N^P mod M - N, P, M = binary() + N, P, M = binary() | integer() Result = binary() | error @@ -433,6 +437,7 @@ message. The Padding is the padding mode that was used to encrypt the data, see public_encrypt/3. + See also public_key:decrypt_private/[2,3]

@@ -455,6 +460,7 @@ The size of the Msg must be less than byte_size(N)-11 if rsa_pkcs1_padding is used, and byte_size(N) if rsa_no_padding is used. + See also public_key:encrypt_private/[2,3]

@@ -475,6 +481,7 @@ message. The Padding is the padding mode that was used to encrypt the data, see private_encrypt/3. + See also public_key:decrypt_public/[2,3]

@@ -501,6 +508,7 @@ rsa_pkcs1_padding is used, byte_size(N)-41 if rsa_pkcs1_oaep_padding is used and byte_size(N) if rsa_no_padding is used. + See also public_key:encrypt_public/[2,3]

@@ -545,6 +553,7 @@

Creates a digital signature.

+ See also public_key:sign/3
@@ -613,36 +622,32 @@ - stream_encrypt(Type, State, PlainText) -> { NewState, CipherText} + stream_encrypt(State, PlainText) -> { NewState, CipherText} - Type = stream_cipher() - Text = iolist() | binary() + Text = iodata() CipherText = binary() -

Encrypts PlainText according to the stream cipher Type. - Text can be any number of bytes. State is initialized using - stream_init on - the next invocation of this function the returned State shall be - given as input and so on until the end of the stream is reached.

+

Encrypts PlainText according to the stream cipher Type specified in stream_init/3. + Text can be any number of bytes. The initial State is created using + stream_init. + NewState must be passed into the next call to stream_encrypt.

- stream_decrypt(Type, State, CipherText) -> { NewState, PlainText } + stream_decrypt(State, CipherText) -> { NewState, PlainText } - Type = stream_cipher() - CipherText = iodata() | binary() + CipherText = iodata() PlainText = binary() -

Decrypts CipherText according to the stream cipher Type. - PlainText can be any number of bytes. State is initialized using - stream_init on - the next invocation of this function the returned State shall be - given as input and so on until the end of the stream is reached.

+

Decrypts CipherText according to the stream cipher Type specified in stream_init/3. + PlainText can be any number of bytes. The initial State is created using + stream_init. + NewState must be passed into the next call to stream_encrypt.

@@ -660,6 +665,7 @@

Verifies a digital signature

+ See also public_key:verify/3
diff --git a/lib/crypto/doc/src/crypto_app.xml b/lib/crypto/doc/src/crypto_app.xml index 20f4ed5c45..6d26076c04 100644 --- a/lib/crypto/doc/src/crypto_app.xml +++ b/lib/crypto/doc/src/crypto_app.xml @@ -29,37 +29,23 @@ crypto The Crypto Application -

The purpose of the Crypto application is to provide erlang - acess to crypto graphic functions in openssl. +

The purpose of the Crypto application is to provide an Erlang API + to cryptographic functions, see crypto(3). + Note that the API is on a fairly low level and there are some + corresponding API functions available in public_key(3), + on a higher abstraction level, that uses the crypto application in its implementation.

- Configuration -

The following environment configuration parameters are defined - for the Crypto application. Refer to application(3) for more - information about configuration parameters. -

- - ]]> - -

Causes debug information to be written to standard - error or standard output. Default is false. -

-
-
-
+ DEPENDENCIES -
- OpenSSL libraries -

The current implementation of the Erlang Crypto application is - based on the OpenSSL package version 0.9.8 or higher. - There are source and binary releases on the web. -

+

The current crypto implementation uses nifs to interface OpenSSLs crypto library + and requires OpenSSL package version 0.9.8 or higher.

Source releases of OpenSSL can be downloaded from the OpenSSL project home page, - or mirror sites listed there. -

-
+ or mirror sites listed there. +

+
SEE ALSO diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index f3fd119cdd..f4e157198c 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -26,11 +26,11 @@ -export([sign/4, verify/5]). -export([generate_key/2, generate_key/3, compute_key/4]). -export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]). --export([exor/2, strong_rand_bytes/1, mod_exp_prime/3]). +-export([exor/2, strong_rand_bytes/1, mod_pow/3]). -export([rand_bytes/1, rand_bytes/3, rand_uniform/2]). -export([block_encrypt/3, block_decrypt/3, block_encrypt/4, block_decrypt/4]). -export([next_iv/2, next_iv/3]). --export([stream_init/2, stream_init/3, stream_encrypt/3, stream_decrypt/3]). +-export([stream_init/2, stream_init/3, stream_encrypt/2, stream_decrypt/2]). -export([public_encrypt/4, private_decrypt/4]). -export([private_encrypt/4, public_decrypt/4]). @@ -193,7 +193,7 @@ rand_bytes, strong_rand_bytes, rand_uniform, - mod_exp_prime, + mod_pow, exor, %% deprecated mod_exp,strong_rand_mpint,erlint, mpint, @@ -685,7 +685,7 @@ sha512_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. %% Ecrypt/decrypt %%% -spec block_encrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | - blowfish_cfb64 | aes_cbc128 | aes_cfb128 | rc2_cbc, + blowfish_cfb64 | aes_cbc128 | aes_cfb128 | aes_cbc256 | rc2_cbc, Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). block_encrypt(des_cbc, Key, Ivec, Data) -> @@ -714,7 +714,7 @@ block_encrypt(rc2_cbc, Key, Ivec, Data) -> rc2_cbc_encrypt(Key, Ivec, Data). -spec block_decrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | - blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cfb128 | rc2_cbc, + blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cbc256 | aes_cfb128 | rc2_cbc, Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). block_decrypt(des_cbc, Key, Ivec, Data) -> @@ -769,17 +769,21 @@ next_iv(des_cbf, Ivec, Data) -> des_cfb_ivec(Ivec, Data). stream_init(aes_ctr, Key, Ivec) -> - aes_ctr_stream_init(Key, Ivec). + {aes_ctr, aes_ctr_stream_init(Key, Ivec)}. stream_init(rc4, Key) -> - rc4_set_key(Key). -stream_encrypt(aes_ctr, State, Data) -> - aes_ctr_stream_encrypt(State, Data); -stream_encrypt(rc4, State, Data) -> - rc4_encrypt_with_state(State, Data). -stream_decrypt(aes_ctr, State, Data) -> - aes_ctr_stream_decrypt(State, Data); -stream_decrypt(rc4, State, Data) -> - rc4_encrypt_with_state (State, Data). + {rc4, rc4_set_key(Key)}. +stream_encrypt({aes_ctr, State}, Data) -> + {State, Cipher} = aes_ctr_stream_encrypt(State, Data), + {{aes_ctr, State}, Cipher}; +stream_encrypt({rc4, State0}, Data) -> + {State, Cipher} = rc4_encrypt_with_state(State0, Data), + {{rc4, State}, Cipher}. +stream_decrypt({aes_ctr, State0}, Data) -> + {State, Text} = aes_ctr_stream_decrypt(State0, Data), + {{aes_ctr, State}, Text}; +stream_decrypt({rc4, State0}, Data) -> + {State, Text} = rc4_encrypt_with_state (State0, Data), + {{rc4, State}, Text}. %% %% CRYPTO FUNCTIONS @@ -1018,9 +1022,9 @@ mod_exp(Base, Exponent, Modulo) mod_exp(Base, Exponent, Modulo) -> mod_exp_nif(mpint_to_bin(Base),mpint_to_bin(Exponent),mpint_to_bin(Modulo), 4). --spec mod_exp_prime(binary(), binary(), binary()) -> binary() | error. -mod_exp_prime(Base, Exponent, Prime) -> - case mod_exp_nif(Base, Exponent, Prime, 0) of +-spec mod_pow(binary()|integer(), binary()|integer(), binary()|integer()) -> binary() | error. +mod_pow(Base, Exponent, Prime) -> + case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of <<0>> -> error; R -> R end. @@ -1500,7 +1504,7 @@ term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub. %% user_srp_gen_key(Private, Generator, Prime) -> - case mod_exp_prime(Generator, Private, Prime) of + case mod_pow(Generator, Private, Prime) of error -> error; Public -> diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index cff257bb8c..eddb6b83f9 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1979,8 +1979,8 @@ srp3(Config) when is_list(Config) -> "9176A9192615DC0277AE7C12F1F6A7F6563FCA11675D809AF578BDE5" "2B51E05D440B63099A017A0B45044801"), UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), - Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime), - ClientPublic = crypto:mod_exp_prime(Generator, ClientPrivate, Prime), + Verifier = crypto:mod_pow(Generator, UserPassHash, Prime), + ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime), {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate), {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate), @@ -2030,8 +2030,8 @@ srp6(Config) when is_list(Config) -> "72E992AAD89095A84B6A5FADA152369AB1E350A03693BEF044DF3EDF" "0C34741F4696C30E9F675D09F58ACBEB"), UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), - Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime), - ClientPublic = crypto:mod_exp_prime(Generator, ClientPrivate, Prime), + Verifier = crypto:mod_pow(Generator, UserPassHash, Prime), + ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime), {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate), {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate), @@ -2081,7 +2081,7 @@ srp6a(Config) when is_list(Config) -> "3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D" "C346D7E474B29EDE8A469FFECA686E5A"), UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), - Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime), + Verifier = crypto:mod_pow(Generator, UserPassHash, Prime), {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate), {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate), diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 5ce1350f09..accea63344 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -77,7 +77,7 @@ cipher(?RC4, CipherState, Mac, Fragment, _Version) -> S -> S end, GenStreamCipherList = [Fragment, Mac], - {State1, T} = crypto:stream_encrypt(rc4, State0, GenStreamCipherList), + {State1, T} = crypto:stream_encrypt(State0, GenStreamCipherList), {T, CipherState#cipher_state{state = State1}}; cipher(?DES, CipherState, Mac, Fragment, Version) -> block_cipher(fun(Key, IV, T) -> @@ -130,7 +130,7 @@ decipher(?RC4, HashSz, CipherState, Fragment, _) -> undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key); S -> S end, - try crypto:stream_decrypt(rc4, State0, Fragment) of + try crypto:stream_decrypt(State0, Fragment) of {State, Text} -> GSC = generic_stream_cipher_from_bin(Text, HashSz), #generic_stream_cipher{content = Content, mac = Mac} = GSC, diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index eb2fc5467d..54eed03d3c 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -2188,7 +2188,7 @@ handle_srp_identity(Username, {Fun, UserState}) -> {ok, {SRPParams, Salt, DerivedKey}} when is_atom(SRPParams), is_binary(Salt), is_binary(DerivedKey) -> {Generator, Prime} = ssl_srp_primes:get_srp_params(SRPParams), - Verifier = crypto:mod_exp_prime(Generator, DerivedKey, Prime), + Verifier = crypto:mod_pow(Generator, DerivedKey, Prime), #srp_user{generator = Generator, prime = Prime, salt = Salt, verifier = Verifier}; #alert{} = Alert -> diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl index 38edf3781e..f2849e50ec 100644 --- a/lib/stdlib/src/otp_internal.erl +++ b/lib/stdlib/src/otp_internal.erl @@ -122,7 +122,7 @@ obsolete_1(crypto, dss_verify, 4) -> {deprecated, {crypto, verify, 4}}; obsolete_1(crypto, mod_exp, 3) -> - {deprecated, {crypto, mod_exp_prime, 3}}; + {deprecated, {crypto, mod_pow, 3}}; obsolete_1(crypto, dh_compute_key, 3) -> {deprecated, {crypto, compute_key, 4}}; -- cgit v1.2.3 From 01f5de8764b200bdd0d5e4ff69fba4523b3c2c7c Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 3 May 2013 12:28:39 +0200 Subject: ssl & public_key: Use standard name --- lib/public_key/asn1/ECPrivateKey.asn1 | 6 +++--- lib/public_key/asn1/OTP-PKIX.asn1 | 20 ++------------------ lib/public_key/doc/src/public_key.xml | 6 +++--- lib/public_key/include/public_key.hrl | 2 +- lib/public_key/src/public_key.erl | 10 +++++----- lib/ssl/src/ssl_handshake.hrl | 2 +- 6 files changed, 15 insertions(+), 31 deletions(-) diff --git a/lib/public_key/asn1/ECPrivateKey.asn1 b/lib/public_key/asn1/ECPrivateKey.asn1 index e8607c4f7b..a20fa4009c 100644 --- a/lib/public_key/asn1/ECPrivateKey.asn1 +++ b/lib/public_key/asn1/ECPrivateKey.asn1 @@ -12,13 +12,13 @@ IMPORTS -- FROM New PKIX ASN.1 [RFC5912] -OTPEcpkParameters FROM OTP-PKIX; +EcpkParameters FROM PKIX1Algorithms88; ECPrivateKey ::= SEQUENCE { version INTEGER, privateKey OCTET STRING, - parameters [0] OTPEcpkParameters OPTIONAL, + parameters [0] EcpkParameters OPTIONAL, publicKey [1] BIT STRING OPTIONAL } -END \ No newline at end of file +END diff --git a/lib/public_key/asn1/OTP-PKIX.asn1 b/lib/public_key/asn1/OTP-PKIX.asn1 index 4a9d401345..911a156d6c 100644 --- a/lib/public_key/asn1/OTP-PKIX.asn1 +++ b/lib/public_key/asn1/OTP-PKIX.asn1 @@ -103,7 +103,7 @@ IMPORTS md5WithRSAEncryption, sha1WithRSAEncryption, rsaEncryption, RSAPublicKey, - dhpublicnumber, DomainParameters, DHPublicKey, + dhpublicnumber, DomainParameters, DHPublicKey, id-keyExchangeAlgorithm, KEA-Parms-Id, --KEA-PublicKey, ecdsa-with-SHA1, ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384, ecdsa-with-SHA512, @@ -112,7 +112,7 @@ IMPORTS gnBasis, tpBasis, Trinomial, ppBasis, Pentanomial, - id-ecPublicKey, EcpkParameters, ECPoint + id-ecPublicKey, EcpkParameters, ECParameters, ECPoint FROM PKIX1Algorithms88 { iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) pkix(7) id-mod(0) id-mod-pkix1-algorithms(17) } @@ -510,22 +510,6 @@ 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 diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index ffea387404..10c95a39ac 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -85,7 +85,7 @@

pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey' | 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo' | 'PrivateKeyInfo' | 'CertificationRequest' | 'ECPrivateKey'| - 'OTPEcpkParameters'

+ 'EcpkParameters'

pem_entry () = {pki_asn1_type(), binary(), %% DER or encrypted DER not_encrypted | cipher_info()}

@@ -101,7 +101,7 @@

dsa_private_key() = #'DSAPrivateKey'{}

-

ec_public_key() = {#'ECPoint'{}, #'OTPEcpkParameters'{} | {namedCurve, oid()}}

+

ec_public_key() = {#'ECPoint'{}, #'EcpkParameters'{} | {namedCurve, oid()}}

ec_private_key() = #'ECPrivateKey'{}

@@ -227,7 +227,7 @@ generate_key(Params) -> {Public::binary(), Private::binary()} | #'ECPrivateKey'{} Generates a new keypair - Params = #'DHParameter'{} | {namedCurve, oid()} | #'OTPECParameters'{} + Params = #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{}

Generates a new keypair

diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl index 363305957c..1e882e76ee 100644 --- a/lib/public_key/include/public_key.hrl +++ b/lib/public_key/include/public_key.hrl @@ -93,7 +93,7 @@ -type rsa_private_key() :: #'RSAPrivateKey'{}. -type dsa_private_key() :: #'DSAPrivateKey'{}. -type dsa_public_key() :: {integer(), #'Dss-Parms'{}}. --type ec_public_key() :: {#'ECPoint'{},{namedCurve, Oid::tuple()} | #'OTPECParameters'{}}. +-type ec_public_key() :: {#'ECPoint'{},{namedCurve, Oid::tuple()} | #'ECParameters'{}}. -type ec_private_key() :: #'ECPrivateKey'{}. -type der_encoded() :: binary(). -type decrypt_der() :: binary(). diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index f9042d5349..648dba3d5a 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -328,7 +328,7 @@ encrypt_private(PlainText, %%-------------------------------------------------------------------- -spec generate_key(#'DHParameter'{} | {namedCurve, Name ::atom()} | - #'OTPECParameters'{}) -> {Public::binary(), Private::binary()} | + #'ECParameters'{}) -> {Public::binary(), Private::binary()} | #'ECPrivateKey'{}. %% Description: Generates a new keypair %%-------------------------------------------------------------------- @@ -336,7 +336,7 @@ generate_key(#'DHParameter'{prime = P, base = G}) -> crypto:generate_key(dh, [P, G]); generate_key({namedCurve, _} = Params) -> ec_generate_key(Params); -generate_key(#'OTPECParameters'{} = Params) -> +generate_key(#'ECParameters'{} = Params) -> ec_generate_key(Params). %%-------------------------------------------------------------------- @@ -870,9 +870,9 @@ ec_generate_key(Params) -> Term = crypto:generate_key(ecdh, Curve), ec_key(Term, Params). -ec_curve_spec( #'OTPECParameters'{fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor }) -> - Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'OTPFieldID'.fieldType), - FieldId#'OTPFieldID'.parameters}, +ec_curve_spec( #'ECParameters'{fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor }) -> + Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'FieldID'.fieldType), + FieldId#'FieldID'.parameters}, Curve = {erlang:list_to_binary(PCurve#'Curve'.a), erlang:list_to_binary(PCurve#'Curve'.b), none}, {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor}; ec_curve_spec({namedCurve, OID}) -> diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index 2519fba4e1..b2387a0ee7 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -29,7 +29,7 @@ -include_lib("public_key/include/public_key.hrl"). -type oid() :: tuple(). --type public_key_params() :: #'Dss-Parms'{} | {namedCurve, oid()} | #'OTPECParameters'{} | term(). +-type public_key_params() :: #'Dss-Parms'{} | {namedCurve, oid()} | #'ECParameters'{} | term(). -type public_key_info() :: {oid(), #'RSAPublicKey'{} | integer() | #'ECPoint'{}, public_key_params()}. -type tls_handshake_history() :: {[binary()], [binary()]}. -- cgit v1.2.3 From c5ae65889fc0dbaf12bbcabc93410245bbc11cc1 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Mon, 6 May 2013 08:49:20 +0200 Subject: ssl: Only send ECC-hello extension if ECC-cipher suites are advertised --- lib/ssl/src/ssl_cipher.erl | 5 ++++ lib/ssl/src/ssl_handshake.erl | 50 ++++++++++++++++++++++++++++-------- lib/ssl/test/ssl_npn_hello_SUITE.erl | 8 +++--- lib/ssl/test/ssl_test_lib.erl | 10 ++++++++ 4 files changed, 60 insertions(+), 13 deletions(-) diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index accea63344..dc413d6dfc 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -278,6 +278,11 @@ srp_suites() -> %% TLS v1.1 suites suite_definition(?TLS_NULL_WITH_NULL_NULL) -> {null, null, null, null}; +%% RFC 5746 - Not a real cipher suite used to signal empty "renegotiation_info" extension +%% to avoid handshake failure from old servers that do not ignore +%% hello extension data as they should. +suite_definition(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV) -> + {null, null, null, null}; %% suite_definition(?TLS_RSA_WITH_NULL_MD5) -> %% {rsa, null, md5, default_prf}; %% suite_definition(?TLS_RSA_WITH_NULL_SHA) -> diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 1cca644956..e358cbe9bb 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -1368,8 +1368,8 @@ enc_hs(#client_hello{client_version = {Major, Minor}, BinCipherSuites = list_to_binary(CipherSuites), CsLength = byte_size(BinCipherSuites), Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation) - ++ hello_extensions(EcPointFormats) - ++ hello_extensions(EllipticCurves), + ++ ec_hello_extensions(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites), EcPointFormats) + ++ ec_hello_extensions(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites), EllipticCurves), Extensions1 = if Major == 3, Minor >=3 -> Extensions0 ++ hello_extensions(HashSigns); true -> Extensions0 @@ -1384,20 +1384,21 @@ enc_hs(#client_hello{client_version = {Major, Minor}, enc_hs(#server_hello{server_version = {Major, Minor}, random = Random, session_id = Session_ID, - cipher_suite = Cipher_suite, + cipher_suite = CipherSuite, compression_method = Comp_method, renegotiation_info = RenegotiationInfo, ec_point_formats = EcPointFormats, elliptic_curves = EllipticCurves, next_protocol_negotiation = NextProtocolNegotiation}, _Version) -> SID_length = byte_size(Session_ID), + CipherSuites = [ssl_cipher:suite_definition(CipherSuite)], Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation) - ++ hello_extensions(EcPointFormats) - ++ hello_extensions(EllipticCurves), + ++ ec_hello_extensions(CipherSuites, EcPointFormats) + ++ ec_hello_extensions(CipherSuites, EllipticCurves), ExtensionsBin = enc_hello_extensions(Extensions), {?SERVER_HELLO, <>}; + CipherSuite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>}; enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version) -> ASN1Certs = certs_from_list(ASN1CertList), ACLen = erlang:iolist_size(ASN1Certs), @@ -1519,6 +1520,24 @@ enc_sign(_HashSign, Sign, _Version) -> SignLen = byte_size(Sign), <>. + +ec_hello_extensions(CipherSuites, #elliptic_curves{} = Info) -> + case advertises_ec_ciphers(CipherSuites) of + true -> + [Info]; + false -> + [] + end; +ec_hello_extensions(CipherSuites, #ec_point_formats{} = Info) -> + case advertises_ec_ciphers(CipherSuites) of + true -> + [Info]; + false -> + [] + end; +ec_hello_extensions(_, undefined) -> + []. + hello_extensions(RenegotiationInfo, NextProtocolNegotiation) -> hello_extensions(RenegotiationInfo) ++ next_protocol_extension(NextProtocolNegotiation). @@ -1527,15 +1546,26 @@ hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation) -> ++ hello_extensions(SRP) ++ next_protocol_extension(NextProtocolNegotiation). +advertises_ec_ciphers([]) -> + false; +advertises_ec_ciphers([{ecdh_ecdsa, _,_,_} | _]) -> + true; +advertises_ec_ciphers([{ecdhe_ecdsa, _,_,_} | _]) -> + true; +advertises_ec_ciphers([{ecdh_rsa, _,_,_} | _]) -> + true; +advertises_ec_ciphers([{ecdhe_rsa, _,_,_} | _]) -> + true; +advertises_ec_ciphers([{ecdh_anon, _,_,_} | _]) -> + true; +advertises_ec_ciphers([_| Rest]) -> + advertises_ec_ciphers(Rest). + %% 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) -> diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl index 0bcc0b1fc2..43fa72ea28 100644 --- a/lib/ssl/test/ssl_npn_hello_SUITE.erl +++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl @@ -25,6 +25,8 @@ -compile(export_all). -include("ssl_handshake.hrl"). -include("ssl_record.hrl"). +-include("ssl_cipher.hrl"). +-include("ssl_internal.hrl"). -include_lib("common_test/include/ct.hrl"). %%-------------------------------------------------------------------- @@ -98,7 +100,7 @@ create_client_handshake(Npn) -> client_version = {1, 2}, random = <<1:256>>, session_id = <<>>, - cipher_suites = "", + cipher_suites = [?TLS_DHE_DSS_WITH_DES_CBC_SHA], compression_methods = "", next_protocol_negotiation = Npn, renegotiation_info = #renegotiation_info{} @@ -109,7 +111,7 @@ create_server_handshake(Npn) -> server_version = {1, 2}, random = <<1:256>>, session_id = <<>>, - cipher_suite = <<1,2>>, + cipher_suite = ?TLS_DHE_DSS_WITH_DES_CBC_SHA, compression_method = 1, next_protocol_negotiation = Npn, renegotiation_info = #renegotiation_info{} @@ -121,7 +123,7 @@ create_connection_states() -> security_parameters = #security_parameters{ server_random = <<1:256>>, compression_algorithm = 1, - cipher_suite = <<1, 2>> + cipher_suite = ?TLS_DHE_DSS_WITH_DES_CBC_SHA } }, diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 6b082b4eec..a8ff5187b6 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -827,6 +827,16 @@ psk_suites() -> {rsa_psk, aes_256_cbc, sha}], ssl_cipher:filter_suites(Suites). +psk_anon_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}]. + srp_suites() -> Suites = [{srp_anon, '3des_ede_cbc', sha}, -- cgit v1.2.3 From cadab5a955d2db70d42d9e8e9c9658ad3a46d472 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 3 May 2013 15:05:17 +0200 Subject: crypto: Remove debug printouts --- lib/crypto/c_src/crypto.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 0129526303..9d43a1d907 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -3002,7 +3002,6 @@ static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg) EC_KEY_set_group(key, group); } else { - printf("#3\n"); goto out_err; } @@ -3136,14 +3135,12 @@ static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T if (!(argv[1] == atom_undefined || get_bn_from_bin(env, argv[1], &priv_key)) || !(argv[2] == atom_undefined || enif_is_binary(env, argv[2]))) { - printf("#1\n"); goto out_err; } key = ec_key_new(env, argv[0]); if (!key) { - printf("#4\n"); goto out_err; } @@ -3152,7 +3149,6 @@ static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T if (term2point(env, argv[2], group, &pub_key)) { if (!EC_KEY_set_public_key(key, pub_key)) { - printf("#5\n"); goto out_err; } } -- cgit v1.2.3 From 19d511a10d5e258b8f2f876f7c12ffbf35174d89 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Mon, 6 May 2013 16:17:56 +0200 Subject: ssl: Fix dialyzer spec --- lib/ssl/src/ssl_cipher.hrl | 2 +- lib/ssl/src/ssl_internal.hrl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl index 32b2c0d392..c7c71ee1a7 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -30,7 +30,7 @@ | aes_128_cbc | aes_256_cbc. -type hash() :: null | sha | md5 | ssh224 | sha256 | sha384 | sha512. -type erl_cipher_suite() :: {key_algo(), cipher(), hash()}. --type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash()}. +-type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash() | default_prf}. -type cipher_suite() :: binary(). -type cipher_enum() :: integer(). -type openssl_cipher_suite() :: string(). diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index 89fee38c46..14db4a6067 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -37,7 +37,7 @@ -type tls_atom_version() :: sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'. -type certdb_ref() :: reference(). -type db_handle() :: term(). --type key_algo() :: null | rsa | dhe_rsa | dhe_dss | dh_anon. +-type key_algo() :: null | rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa| ecdh_ecdsa | ecdh_rsa| srp_rsa| srp_dss | psk | dhe_psk | rsa_psk | dh_anon | ecdh_anon | srp_anon. -type der_cert() :: binary(). -type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{} | #'ECPrivateKey'{}. -type issuer() :: tuple(). -- cgit v1.2.3