aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngela Anderton Andin <[email protected]>2013-04-04 09:46:45 +0200
committerIngela Anderton Andin <[email protected]>2013-04-04 09:46:45 +0200
commit8e79ce54b35d207f27e0b29ab09808aa45078e73 (patch)
tree582b828d148e3657195abcf163b81e90ac82290e
parentae295fdfcae3c51441d4f456a2180a72e2408f52 (diff)
parentb8e72765305590eb7c89166ce261843d54c9bcde (diff)
downloadotp-8e79ce54b35d207f27e0b29ab09808aa45078e73.tar.gz
otp-8e79ce54b35d207f27e0b29ab09808aa45078e73.tar.bz2
otp-8e79ce54b35d207f27e0b29ab09808aa45078e73.zip
Merge remote branch 'upstream/maint'
-rw-r--r--lib/crypto/c_src/crypto.c275
-rwxr-xr-xlib/crypto/doc/src/crypto.xml102
-rw-r--r--lib/crypto/src/crypto.erl244
-rw-r--r--lib/crypto/test/crypto_SUITE.erl731
-rw-r--r--lib/ssl/doc/src/ssl.xml72
-rw-r--r--lib/ssl/src/Makefile3
-rw-r--r--lib/ssl/src/ssl.app.src1
-rw-r--r--lib/ssl/src/ssl.erl40
-rw-r--r--lib/ssl/src/ssl_alert.erl4
-rw-r--r--lib/ssl/src/ssl_alert.hrl2
-rw-r--r--lib/ssl/src/ssl_cipher.erl292
-rw-r--r--lib/ssl/src/ssl_cipher.hrl105
-rw-r--r--lib/ssl/src/ssl_connection.erl463
-rw-r--r--lib/ssl/src/ssl_handshake.erl218
-rw-r--r--lib/ssl/src/ssl_handshake.hrl51
-rw-r--r--lib/ssl/src/ssl_internal.hrl3
-rw-r--r--lib/ssl/src/ssl_srp.hrl31
-rw-r--r--lib/ssl/src/ssl_srp_primes.erl506
-rw-r--r--lib/ssl/src/ssl_srp_primes.hrl1
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl47
-rw-r--r--lib/ssl/test/ssl_test_lib.erl64
21 files changed, 2782 insertions, 473 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index e77e5fb8f0..fac77308f6 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2010-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
@@ -136,6 +136,7 @@ static void unload(ErlNifEnv* env, void* priv_data);
/* The NIFs: */
static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -207,6 +208,9 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E
static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_server_secret_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[]);
@@ -215,6 +219,7 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N
/* helpers */
+static void init_algorithms_types(void);
static void init_digest_types(ErlNifEnv* env);
static void hmac_md5(unsigned char *key, int klen,
unsigned char *dbuf, int dlen,
@@ -247,6 +252,7 @@ static int library_refc = 0; /* number of users of this dynamic library */
static ErlNifFunc nif_funcs[] = {
{"info_lib", 0, info_lib},
+ {"algorithms", 0, algorithms},
{"md5", 1, md5},
{"md5_init", 0, md5_init},
{"md5_update", 2, md5_update},
@@ -304,7 +310,7 @@ static ErlNifFunc nif_funcs[] = {
{"rand_bytes", 3, rand_bytes_3},
{"strong_rand_mpint_nif", 3, strong_rand_mpint_nif},
{"rand_uniform_nif", 2, rand_uniform_nif},
- {"mod_exp_nif", 3, mod_exp_nif},
+ {"mod_exp_nif", 4, mod_exp_nif},
{"dss_verify", 4, dss_verify},
{"rsa_verify_nif", 4, rsa_verify_nif},
{"aes_cbc_crypt", 4, aes_cbc_crypt},
@@ -321,6 +327,9 @@ static ErlNifFunc nif_funcs[] = {
{"dh_check", 1, dh_check},
{"dh_generate_key_nif", 2, dh_generate_key_nif},
{"dh_compute_key_nif", 3, dh_compute_key_nif},
+ {"srp_value_B_nif", 5, srp_value_B_nif},
+ {"srp_client_secret_nif", 7, srp_client_secret_nif},
+ {"srp_server_secret_nif", 5, srp_server_secret_nif},
{"bf_cfb64_crypt", 4, bf_cfb64_crypt},
{"bf_cbc_crypt", 4, bf_cbc_crypt},
{"bf_ecb_crypt", 3, bf_ecb_crypt},
@@ -458,6 +467,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_digest = enif_make_atom(env,"digest");
init_digest_types(env);
+ init_algorithms_types();
#ifdef HAVE_DYNAMIC_CRYPTO_LIB
{
@@ -538,6 +548,35 @@ static void unload(ErlNifEnv* env, void* priv_data)
--library_refc;
}
+static int algos_cnt;
+static ERL_NIF_TERM algos[7]; /* increase when extending the list */
+
+static void init_algorithms_types(void)
+{
+ algos_cnt = 0;
+
+ algos[algos_cnt++] = atom_md5;
+ algos[algos_cnt++] = atom_sha;
+ algos[algos_cnt++] = atom_ripemd160;
+#ifdef HAVE_SHA224
+ algos[algos_cnt++] = atom_sha224;
+#endif
+#ifdef HAVE_SHA256
+ algos[algos_cnt++] = atom_sha256;
+#endif
+#ifdef HAVE_SHA384
+ algos[algos_cnt++] = atom_sha384;
+#endif
+#ifdef HAVE_SHA512
+ algos[algos_cnt++] = atom_sha512;
+#endif
+}
+
+static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ return enif_make_list_from_array(env, algos, algos_cnt);
+}
+
static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
/* [{<<"OpenSSL">>,9470143,<<"OpenSSL 0.9.8k 25 Mar 2009">>}] */
@@ -1515,6 +1554,17 @@ static int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
return 1;
}
+static int get_bn_from_bin(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
+{
+ ErlNifBinary bin;
+ if (!enif_inspect_binary(env,term,&bin)) {
+ return 0;
+ }
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(bin.data, bin.size);
+ *bnp = BN_bin2bn(bin.data, bin.size, NULL);
+ return 1;
+}
+
static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Lo,Hi) */
BIGNUM *bn_from = NULL, *bn_to, *bn_rand;
@@ -1543,16 +1593,19 @@ static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER
}
static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Base,Exponent,Modulo) */
+{/* (Base,Exponent,Modulo,bin_hdr) */
BIGNUM *bn_base=NULL, *bn_exponent=NULL, *bn_modulo, *bn_result;
BN_CTX *bn_ctx;
unsigned char* ptr;
unsigned dlen;
+ unsigned bin_hdr; /* return type: 0=plain binary, 4: mpint */
+ unsigned extra_byte;
ERL_NIF_TERM ret;
- if (!get_bn_from_mpint(env, argv[0], &bn_base)
- || !get_bn_from_mpint(env, argv[1], &bn_exponent)
- || !get_bn_from_mpint(env, argv[2], &bn_modulo)) {
+ if (!get_bn_from_bin(env, argv[0], &bn_base)
+ || !get_bn_from_bin(env, argv[1], &bn_exponent)
+ || !get_bn_from_bin(env, argv[2], &bn_modulo)
+ || !enif_get_uint(env,argv[3],&bin_hdr) || (bin_hdr & ~4)) {
if (bn_base) BN_free(bn_base);
if (bn_exponent) BN_free(bn_exponent);
@@ -1562,9 +1615,14 @@ static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
bn_ctx = BN_CTX_new();
BN_mod_exp(bn_result, bn_base, bn_exponent, bn_modulo, bn_ctx);
dlen = BN_num_bytes(bn_result);
- ptr = enif_make_new_binary(env, dlen+4, &ret);
- put_int32(ptr, dlen);
- BN_bn2bin(bn_result, ptr+4);
+ extra_byte = bin_hdr && BN_is_bit_set(bn_result, dlen*8-1);
+ ptr = enif_make_new_binary(env, bin_hdr+extra_byte+dlen, &ret);
+ if (bin_hdr) {
+ put_int32(ptr, extra_byte+dlen);
+ ptr[4] = 0; /* extra zeroed byte to ensure a positive mpint */
+ ptr += bin_hdr + extra_byte;
+ }
+ BN_bn2bin(bn_result, ptr);
BN_free(bn_result);
BN_CTX_free(bn_ctx);
BN_free(bn_modulo);
@@ -2344,6 +2402,205 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
return ret;
}
+static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Multiplier, Verifier, Generator, Exponent, Prime) */
+ BIGNUM *bn_verifier = NULL;
+ BIGNUM *bn_exponent, *bn_generator, *bn_prime, *bn_multiplier, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ if (!get_bn_from_bin(env, argv[0], &bn_multiplier)
+ || !get_bn_from_bin(env, argv[1], &bn_verifier)
+ || !get_bn_from_bin(env, argv[2], &bn_generator)
+ || !get_bn_from_bin(env, argv[3], &bn_exponent)
+ || !get_bn_from_bin(env, argv[4], &bn_prime)) {
+ if (bn_multiplier) BN_free(bn_multiplier);
+ if (bn_verifier) BN_free(bn_verifier);
+ if (bn_verifier) BN_free(bn_generator);
+ if (bn_verifier) BN_free(bn_exponent);
+ if (bn_verifier) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_result = BN_new();
+ bn_ctx = BN_CTX_new();
+
+ /* B = k*v + g^b % N */
+
+ /* k * v */
+ BN_mod_mul(bn_multiplier, bn_multiplier, bn_verifier, bn_prime, bn_ctx);
+
+ /* g^b % N */
+ BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx);
+
+ /* k*v + g^b % N */
+ BN_mod_add(bn_result, bn_result, bn_multiplier, bn_prime, bn_ctx);
+
+ /* check that B % N != 0, reuse bn_multiplier */
+ BN_nnmod(bn_multiplier, bn_result, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_multiplier)) {
+ ret = atom_error;
+ } else {
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ }
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+ BN_free(bn_prime);
+ BN_free(bn_generator);
+ BN_free(bn_multiplier);
+ BN_free(bn_exponent);
+ BN_free(bn_verifier);
+ return ret;
+}
+
+static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (a, u, B, Multiplier, Prime, Exponent, Generator) */
+/*
+ <premaster secret> = (B - (k * g^x)) ^ (a + (u * x)) % N
+*/
+ BIGNUM *bn_exponent = NULL, *bn_a = NULL;
+ BIGNUM *bn_u, *bn_multiplier, *bn_exp2, *bn_base,
+ *bn_prime, *bn_generator, *bn_B, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ if (!get_bn_from_bin(env, argv[0], &bn_a)
+ || !get_bn_from_bin(env, argv[1], &bn_u)
+ || !get_bn_from_bin(env, argv[2], &bn_B)
+ || !get_bn_from_bin(env, argv[3], &bn_multiplier)
+ || !get_bn_from_bin(env, argv[4], &bn_generator)
+ || !get_bn_from_bin(env, argv[5], &bn_exponent)
+ || !get_bn_from_bin(env, argv[6], &bn_prime))
+ {
+ if (bn_exponent) BN_free(bn_exponent);
+ if (bn_a) BN_free(bn_a);
+ if (bn_u) BN_free(bn_u);
+ if (bn_B) BN_free(bn_B);
+ if (bn_multiplier) BN_free(bn_multiplier);
+ if (bn_generator) BN_free(bn_generator);
+ if (bn_prime) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_ctx = BN_CTX_new();
+ bn_result = BN_new();
+
+ /* check that B % N != 0 */
+ BN_nnmod(bn_result, bn_B, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_result)) {
+ BN_free(bn_exponent);
+ BN_free(bn_a);
+ BN_free(bn_generator);
+ BN_free(bn_prime);
+ BN_free(bn_u);
+ BN_free(bn_B);
+ BN_CTX_free(bn_ctx);
+
+ return atom_error;
+ }
+
+ /* (B - (k * g^x)) */
+ bn_base = BN_new();
+ BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx);
+ BN_mod_mul(bn_result, bn_multiplier, bn_result, bn_prime, bn_ctx);
+ BN_mod_sub(bn_base, bn_B, bn_result, bn_prime, bn_ctx);
+
+ /* a + (u * x) */
+ bn_exp2 = BN_new();
+ BN_mod_mul(bn_result, bn_u, bn_exponent, bn_prime, bn_ctx);
+ BN_mod_add(bn_exp2, bn_a, bn_result, bn_prime, bn_ctx);
+
+ /* (B - (k * g^x)) ^ (a + (u * x)) % N */
+ BN_mod_exp(bn_result, bn_base, bn_exp2, bn_prime, bn_ctx);
+
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+
+ BN_free(bn_multiplier);
+ BN_free(bn_exp2);
+ BN_free(bn_u);
+ BN_free(bn_exponent);
+ BN_free(bn_a);
+ BN_free(bn_B);
+ BN_free(bn_base);
+ BN_free(bn_generator);
+ BN_free(bn_prime);
+ return ret;
+}
+
+static ERL_NIF_TERM srp_server_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Verifier, b, u, A, Prime) */
+/*
+ <premaster secret> = (A * v^u) ^ b % N
+*/
+ BIGNUM *bn_b = NULL, *bn_verifier = NULL;
+ BIGNUM *bn_prime, *bn_A, *bn_u, *bn_base, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ if (!get_bn_from_bin(env, argv[0], &bn_verifier)
+ || !get_bn_from_bin(env, argv[1], &bn_b)
+ || !get_bn_from_bin(env, argv[2], &bn_u)
+ || !get_bn_from_bin(env, argv[3], &bn_A)
+ || !get_bn_from_bin(env, argv[4], &bn_prime))
+ {
+ if (bn_verifier) BN_free(bn_verifier);
+ if (bn_b) BN_free(bn_b);
+ if (bn_u) BN_free(bn_u);
+ if (bn_A) BN_free(bn_A);
+ if (bn_prime) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_ctx = BN_CTX_new();
+ bn_result = BN_new();
+
+ /* check that A % N != 0 */
+ BN_nnmod(bn_result, bn_A, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_result)) {
+ BN_free(bn_b);
+ BN_free(bn_verifier);
+ BN_free(bn_prime);
+ BN_free(bn_A);
+ BN_CTX_free(bn_ctx);
+
+ return atom_error;
+ }
+
+ /* (A * v^u) */
+ bn_base = BN_new();
+ BN_mod_exp(bn_base, bn_verifier, bn_u, bn_prime, bn_ctx);
+ BN_mod_mul(bn_base, bn_A, bn_base, bn_prime, bn_ctx);
+
+ /* (A * v^u) ^ b % N */
+ BN_mod_exp(bn_result, bn_base, bn_b, bn_prime, bn_ctx);
+
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+
+ BN_free(bn_u);
+ BN_free(bn_base);
+ BN_free(bn_verifier);
+ BN_free(bn_prime);
+ BN_free(bn_A);
+ BN_free(bn_b);
+ return ret;
+}
+
static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, Ivec, Data, IsEncrypt) */
ErlNifBinary key_bin, ivec_bin, data_bin;
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 6b9b2ef207..f30a058ca4 100755
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -63,6 +63,11 @@
<item>
<p>dss: Digital Signature Standard (FIPS 186-2)</p>
</item>
+ <item>
+ <p>srp: Secure Remote Password Protocol (RFC 2945)</p>
+ </item>
+
+
</list>
<p>The above publications can be found at <url href="http://csrc.nist.gov/publications">NIST publications</url>, at <url href="http://www.ietf.org">IETF</url>.
</p>
@@ -99,6 +104,14 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</desc>
</func>
<func>
+ <name>algorithms() -> [atom()]</name>
+ <fsummary>Provide a list of available crypto algorithms.</fsummary>
+ <desc>
+ <p>Provides the available crypto algorithms in terms of a list
+ of atoms.</p>
+ </desc>
+ </func>
+ <func>
<name>info_lib() -> [{Name,VerNum,VerStr}]</name>
<fsummary>Provides information about the libraries used by crypto.</fsummary>
<type>
@@ -973,7 +986,17 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
using the <c>crypto</c> library.</p>
</desc>
</func>
-
+ <func>
+ <name>mod_exp_prime(N, P, M) -> Result</name>
+ <fsummary>Computes the function: N^P mod M</fsummary>
+ <type>
+ <v>N, P, M = binary()</v>
+ <v>Result = binary() | error</v>
+ </type>
+ <desc>
+ <p>Computes the function <c>N^P mod M</c>.</p>
+ </desc>
+ </func>
<func>
<name>rsa_sign(DataOrDigest, Key) -> Signature</name>
<name>rsa_sign(DigestType, DataOrDigest, Key) -> Signature</name>
@@ -1256,8 +1279,85 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</desc>
</func>
+ <func>
+ <name>srp_generate_key(Generator, Prime, Version) -> {PublicKey, PrivateKey} </name>
+ <name>srp_generate_key(Generator, Prime, Version, Private) -> {PublicKey, PrivateKey} </name>
+ <name>srp_generate_key(Verifier, Generator, Prime, Version) -> {PublicKey, PrivateKey} </name>
+ <name>srp_generate_key(Verifier, Generator, Prime, Version, Private) -> {PublicKey, PrivateKey} </name>
+ <fsummary>Generates SRP public keys</fsummary>
+ <type>
+ <v>Verifier = binary()</v>
+ <d>Parameter v from <seealso marker="http://srp.stanford.edu/design.html">SRP design</seealso>
+ </d>
+ <v>Generator = binary() </v>
+ <d>Parameter g from <seealso marker="http://srp.stanford.edu/design.html">SRP design</seealso>
+ </d>
+ <v>Prime = binary() </v>
+ <d>Parameter N from <seealso marker="http://srp.stanford.edu/design.html">SRP design</seealso>
+ </d>
+ <v>Version = '3' | '6' | '6a' </v>
+ <d>SRP version, TLS SRP cipher suites uses '6a'.</d>
+ <v>PublicKey = binary()</v>
+ <d> Parameter A or B from <seealso marker="http://srp.stanford.edu/design.html">SRP design</seealso></d>
+ <v>PrivateKey = binary() - generated if not supplied</v>
+ <d>Parameter a or b from <seealso marker="http://srp.stanford.edu/design.html">SRP design</seealso></d>
+ </type>
+ <desc>
+ <p>Generates SRP public keys</p>
+ </desc>
+ </func>
<func>
+ <name>srp_compute_key(DerivedKey, Prime, Generator,
+ ClientPublic, ClientPrivate, ServerPublic, Version) -> SessionKey</name>
+ <name>srp_compute_key(DerivedKey, Prime, Generator,
+ ClientPublic, ClientPrivate, ServerPublic, Version, Scrambler) -> SessionKey</name>
+ <name>srp_compute_key(Verifier, Prime,
+ ClientPublic, ServerPublic, ServerPrivate, Version, Scrambler)-> SessionKey</name>
+ <name>srp_compute_key(Verifier, Prime,
+ ClientPublic, ServerPublic, ServerPrivate, Version) -> SessionKey</name>
+
+ <fsummary>Computes SRP session key</fsummary>
+ <type>
+ <v>DerivedKey = binary()</v>
+ <d>Parameter x from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ </d>
+ <v>Verifier = binary()</v>
+ <d>Parameter v from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ </d>
+ <v>Prime = binary() </v>
+ <d>Parameter N from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ </d>
+ <v>Generator = binary() </v>
+ <d>Parameter g from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ </d>
+ <v>ClientPublic = binary() </v>
+ <d>Parameter A from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ </d>
+ <v>ClientPrivate = binary() </v>
+ <d>Parameter a from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ </d>
+ <v>ServerPublic = binary() </v>
+ <d>Parameter B from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ </d>
+ <v>ServerPrivate = binary() </v>
+ <d>Parameter b from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ </d>
+ <v>Version = '3' | '6' | '6a' </v>
+ <d>SRP version, TLS SRP cipher suites uses '6a'.</d>
+ <v>SessionKey = binary()</v>
+ <d>Result K from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ </d>
+ </type>
+ <desc>
+ <p>
+ Computes the SRP session key (shared secret). Also used
+ as premaster secret by TLS-SRP ciher suites.
+ </p>
+ </desc>
+ </func>
+
+ <func>
<name>exor(Data1, Data2) -> Result</name>
<fsummary>XOR data</fsummary>
<type>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 1328a95e87..1d0a9943c3 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -21,7 +21,7 @@
-module(crypto).
--export([start/0, stop/0, info/0, info_lib/0, version/0]).
+-export([start/0, stop/0, info/0, info_lib/0, algorithms/0, version/0]).
-export([hash/2, hash_init/1, hash_update/2, hash_final/1]).
-export([md4/1, md4_init/0, md4_update/2, md4_final/1]).
-export([md5/1, md5_init/0, md5_update/2, md5_final/1]).
@@ -57,7 +57,10 @@
-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, mpint/1, erlint/1]).
+-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]).
-export([aes_cbc_256_encrypt/3, aes_cbc_256_decrypt/3]).
@@ -88,7 +91,7 @@
strong_rand_bytes,
strong_rand_mpint,
rand_uniform,
- mod_exp,
+ mod_exp, mod_exp_prime,
dss_verify,dss_sign,
rsa_verify,rsa_sign,
rsa_public_encrypt,rsa_private_decrypt,
@@ -109,7 +112,8 @@
hash, hash_init, hash_update, hash_final,
hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, info,
rc2_cbc_encrypt, rc2_cbc_decrypt,
- info_lib]).
+ srp_generate_key, srp_compute_key,
+ info_lib, algorithms]).
-type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type dss_digest_type() :: 'none' | 'sha'.
@@ -184,6 +188,8 @@ info() ->
info_lib() -> ?nif_stub.
+algorithms() -> ?nif_stub.
+
%% Crypto app version history:
%% (no version): Driver implementation
%% 2.0 : NIF implementation, requires OTP R14
@@ -783,21 +789,24 @@ rand_uniform_pos(_,_) ->
rand_uniform_nif(_From,_To) -> ?nif_stub.
%%
-%% mod_exp - utility for rsa generation
+%% mod_exp - utility for rsa generation and SRP
%%
mod_exp(Base, Exponent, Modulo)
when is_integer(Base), is_integer(Exponent), is_integer(Modulo) ->
- erlint(mod_exp(mpint(Base), mpint(Exponent), mpint(Modulo)));
+ bin_to_int(mod_exp_nif(int_to_bin(Base), int_to_bin(Exponent), int_to_bin(Modulo), 0));
mod_exp(Base, Exponent, Modulo) ->
- case mod_exp_nif(Base,Exponent,Modulo) of
- <<Len:32/integer, MSB, Rest/binary>> when MSB > 127 ->
- <<(Len + 1):32/integer, 0, MSB, Rest/binary>>;
- Whatever ->
- Whatever
+ 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
+ <<0>> -> error;
+ R -> R
end.
-mod_exp_nif(_Base,_Exp,_Mod) -> ?nif_stub.
+
+mod_exp_nif(_Base,_Exp,_Mod,_bin_hdr) -> ?nif_stub.
%%
%% DSS, RSA - verify
@@ -1064,50 +1073,205 @@ dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) ->
dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub.
+
+%%% 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),
+ is_binary(Generator),
+ is_binary(ClientPublic),
+ is_binary(ClientPrivate),
+ is_binary(ServerPublic),
+ 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
+ is_binary(Verifier),
+ is_binary(Prime),
+ is_binary(ClientPublic),
+ is_binary(ServerPublic),
+ is_binary(ServerPrivate),
+ is_atom(Version) ->
+ Scrambler = srp_scrambler(Version, ClientPublic, ServerPublic, Prime),
+ srp_server_secret_nif(Verifier, ServerPrivate, Scrambler, ClientPublic, Prime).
+
%%
%% LOCAL FUNCTIONS
%%
+client_srp_gen_key(Private, Generator, Prime) ->
+ case mod_exp_prime(Generator, Private, Prime) of
+ error ->
+ error;
+ Public ->
+ {Public, Private}
+ end.
+
+server_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 ->
+ error;
+ Public ->
+ {Public, Private}
+ end.
+
+srp_multiplier('6a', Generator, Prime) ->
+ %% k = SHA1(N | PAD(g)) from http://srp.stanford.edu/design.html
+ C0 = sha_init(),
+ C1 = sha_update(C0, Prime),
+ C2 = sha_update(C1, srp_pad_to(erlang:byte_size(Prime), Generator)),
+ sha_final(C2);
+srp_multiplier('6', _, _) ->
+ <<3/integer>>;
+srp_multiplier('3', _, _) ->
+ <<1/integer>>.
+
+srp_scrambler(Version, ClientPublic, ServerPublic, 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)),
+ sha_final(C2);
+srp_scrambler('3', _, ServerPublic, _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.
+ <<U:32/bits, _/binary>> = sha(ServerPublic),
+ U.
+
+srp_pad_length(Width, Length) ->
+ (Width - Length rem Width) rem Width.
+
+srp_pad_to(Width, Binary) ->
+ case srp_pad_length(Width, size(Binary)) of
+ 0 -> Binary;
+ N -> << 0:(N*8), Binary/binary>>
+ end.
+
+srp_server_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub.
+
+srp_client_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub.
+
+srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub.
%% large integer in a binary with 32bit length
%% MP representaion (SSH2)
-mpint(X) when X < 0 ->
- case X of
- -1 ->
- <<0,0,0,1,16#ff>>;
- _ ->
- mpint_neg(X,0,[])
- end;
-mpint(X) ->
- case X of
- 0 ->
- <<0,0,0,0>>;
- _ ->
- mpint_pos(X,0,[])
- end.
+mpint(X) when X < 0 -> mpint_neg(X);
+mpint(X) -> mpint_pos(X).
-define(UINT32(X), X:32/unsigned-big-integer).
-mpint_neg(-1,I,Ds=[MSB|_]) ->
- if MSB band 16#80 =/= 16#80 ->
- <<?UINT32((I+1)), (list_to_binary([255|Ds]))/binary>>;
- true ->
- (<<?UINT32(I), (list_to_binary(Ds))/binary>>)
- end;
-mpint_neg(X,I,Ds) ->
- mpint_neg(X bsr 8,I+1,[(X band 255)|Ds]).
+
+mpint_neg(X) ->
+ Bin = int_to_bin_neg(X, []),
+ Sz = byte_size(Bin),
+ <<?UINT32(Sz), Bin/binary>>.
-mpint_pos(0,I,Ds=[MSB|_]) ->
+mpint_pos(X) ->
+ Bin = int_to_bin_pos(X, []),
+ <<MSB,_/binary>> = Bin,
+ Sz = byte_size(Bin),
if MSB band 16#80 == 16#80 ->
- <<?UINT32((I+1)), (list_to_binary([0|Ds]))/binary>>;
+ <<?UINT32((Sz+1)), 0, Bin/binary>>;
true ->
- (<<?UINT32(I), (list_to_binary(Ds))/binary>>)
- end;
-mpint_pos(X,I,Ds) ->
- mpint_pos(X bsr 8,I+1,[(X band 255)|Ds]).
+ <<?UINT32(Sz), Bin/binary>>
+ end.
+
+int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []);
+int_to_bin(X) -> int_to_bin_pos(X, []).
+
+%%int_to_bin_pos(X) when X >= 0 ->
+%% int_to_bin_pos(X, []).
+
+int_to_bin_pos(0,Ds=[_|_]) ->
+ list_to_binary(Ds);
+int_to_bin_pos(X,Ds) ->
+ int_to_bin_pos(X bsr 8, [(X band 255)|Ds]).
+
+int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 ->
+ list_to_binary(Ds);
+int_to_bin_neg(X,Ds) ->
+ int_to_bin_neg(X bsr 8, [(X band 255)|Ds]).
+
+
+bin_to_int(Bin) ->
+ Bits = bit_size(Bin),
+ <<Integer:Bits/integer>> = Bin,
+ Integer.
%% int from integer in a binary with 32bit length
erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) ->
Bits= MPIntSize * 8,
<<Integer:Bits/integer>> = MPIntValue,
Integer.
+
+mpint_to_bin(<<Len:32, Bin:Len/binary>>) ->
+ Bin.
+
+random_bytes(N) ->
+ try strong_rand_bytes(N) of
+ RandBytes ->
+ RandBytes
+ catch
+ error:low_entropy ->
+ rand_bytes(N)
+ end.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 6f2df0f07b..08ecad3233 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -39,7 +39,10 @@
hmac_update_md5_io/1,
hmac_update_md5_n/1,
hmac_rfc2202/1,
- hmac_rfc4231/1,
+ hmac_rfc4231_sha224/1,
+ hmac_rfc4231_sha256/1,
+ hmac_rfc4231_sha384/1,
+ hmac_rfc4231_sha512/1,
ripemd160/1,
ripemd160_update/1,
sha256/1,
@@ -72,6 +75,7 @@
dsa_sign_hash_test/1,
rsa_encrypt_decrypt/1,
dh/1,
+ srp3/1, srp6/1, srp6a/1,
exor_test/1,
rc4_test/1,
rc4_stream_test/1,
@@ -93,14 +97,15 @@ groups() ->
sha256, sha256_update, sha512, sha512_update,
hmac_update_sha, hmac_update_sha_n, hmac_update_sha256, hmac_update_sha512,
hmac_update_md5_n, hmac_update_md5_io, hmac_update_md5,
- hmac_rfc2202, hmac_rfc4231,
+ hmac_rfc2202, hmac_rfc4231_sha224, hmac_rfc4231_sha256,
+ hmac_rfc4231_sha384, hmac_rfc4231_sha512,
des_cbc, aes_cfb, aes_cbc,
des_cfb, des_cfb_iter, des3_cbc, des3_cfb, rc2_cbc,
aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb,
rand_uniform_test, strong_rand_test,
rsa_verify_test, dsa_verify_test, rsa_sign_test,
rsa_sign_hash_test, dsa_sign_test, dsa_sign_hash_test,
- rsa_encrypt_decrypt, dh, exor_test,
+ rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, exor_test,
rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64,
smp]}].
@@ -363,8 +368,7 @@ hmac_update_sha256(doc) ->
hmac_update_sha256(suite) ->
[];
hmac_update_sha256(Config) when is_list(Config) ->
- if_098(fun() -> hmac_update_sha256_do() end).
-
+ if_supported(sha256, fun() -> hmac_update_sha256_do() end).
hmac_update_sha256_do() ->
?line Key = hexstr2bin("00010203101112132021222330313233"
@@ -386,7 +390,7 @@ hmac_update_sha512(doc) ->
hmac_update_sha512(suite) ->
[];
hmac_update_sha512(Config) when is_list(Config) ->
- if_098(fun() -> hmac_update_sha512_do() end).
+ if_supported(sha512, fun() -> hmac_update_sha512_do() end).
hmac_update_sha512_do() ->
?line Key = hexstr2bin("00010203101112132021222330313233"
@@ -582,366 +586,192 @@ hmac_rfc2202_sha() ->
?line m(Case7Exp, Case7Mac_1),
?line m(Case7Exp, Case7Mac_2).
-hmac_rfc4231(doc) ->
- ["Generate an HMAC using crypto:shaXXX_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+hmac_rfc4231_sha224(doc) ->
+ ["Generate an HMAC using crypto:sha224_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
"Testvectors are take from RFC4231." ];
-hmac_rfc4231(suite) ->
+hmac_rfc4231_sha224(suite) ->
[];
-hmac_rfc4231(Config) when is_list(Config) ->
- if_098(fun() -> hmac_rfc4231_do() end).
+hmac_rfc4231_sha224(Config) when is_list(Config) ->
+ if_supported(sha224, fun() -> hmac_rfc4231_sha224_do() end).
-hmac_rfc4231_do() ->
- %% Test Case 1
- Case1Key = binary:copy(<<16#0b>>, 20),
- Case1Data = <<"Hi There">>,
- Case1Exp224 = hexstr2bin("896fb1128abbdf196832107cd49df33f"
- "47b4b1169912ba4f53684b22"),
- Case1Exp256 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b"
- "881dc200c9833da726e9376c2e32cff7"),
- Case1Exp384 = hexstr2bin("afd03944d84895626b0825f4ab46907f"
- "15f9dadbe4101ec682aa034c7cebc59c"
- "faea9ea9076ede7f4af152e8b2fa9cb6"),
- Case1Exp512 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0"
- "2379f4e2ce4ec2787ad0b30545e17cde"
- "daa833b7d6b8a702038b274eaea3f4e4"
- "be9d914eeb61f1702e696c203a126854"),
-
- ?line Case1Ctx224 = crypto:hmac_init(sha224, Case1Key),
- ?line Case1Ctx224_2 = crypto:hmac_update(Case1Ctx224, Case1Data),
- ?line Case1Mac224_1 = crypto:hmac_final(Case1Ctx224_2),
- ?line Case1Mac224_2 = crypto:sha224_mac(Case1Key, Case1Data),
- ?line Case1Mac224_3 = crypto:hmac(sha224, Case1Key, Case1Data),
- ?line m(Case1Exp224, Case1Mac224_1),
- ?line m(Case1Exp224, Case1Mac224_2),
- ?line m(Case1Exp224, Case1Mac224_3),
-
- ?line Case1Ctx256 = crypto:hmac_init(sha256, Case1Key),
- ?line Case1Ctx256_2 = crypto:hmac_update(Case1Ctx256, Case1Data),
- ?line Case1Mac256_1 = crypto:hmac_final(Case1Ctx256_2),
- ?line Case1Mac256_2 = crypto:sha256_mac(Case1Key, Case1Data),
- ?line Case1Mac256_3 = crypto:hmac(sha256, Case1Key, Case1Data),
- ?line m(Case1Exp256, Case1Mac256_1),
- ?line m(Case1Exp256, Case1Mac256_2),
- ?line m(Case1Exp256, Case1Mac256_3),
-
- ?line Case1Ctx384 = crypto:hmac_init(sha384, Case1Key),
- ?line Case1Ctx384_2 = crypto:hmac_update(Case1Ctx384, Case1Data),
- ?line Case1Mac384_1 = crypto:hmac_final(Case1Ctx384_2),
- ?line Case1Mac384_2 = crypto:sha384_mac(Case1Key, Case1Data),
- ?line Case1Mac384_3 = crypto:hmac(sha384, Case1Key, Case1Data),
- ?line m(Case1Exp384, Case1Mac384_1),
- ?line m(Case1Exp384, Case1Mac384_2),
- ?line m(Case1Exp384, Case1Mac384_3),
-
- ?line Case1Ctx512 = crypto:hmac_init(sha512, Case1Key),
- ?line Case1Ctx512_2 = crypto:hmac_update(Case1Ctx512, Case1Data),
- ?line Case1Mac512_1 = crypto:hmac_final(Case1Ctx512_2),
- ?line Case1Mac512_2 = crypto:sha512_mac(Case1Key, Case1Data),
- ?line Case1Mac512_3 = crypto:hmac(sha512, Case1Key, Case1Data),
- ?line m(Case1Exp512, Case1Mac512_1),
- ?line m(Case1Exp512, Case1Mac512_2),
- ?line m(Case1Exp512, Case1Mac512_3),
-
- %% Test Case 2
- Case2Key = <<"Jefe">>,
- Case2Data = <<"what do ya want for nothing?">>,
- Case2Exp224 = hexstr2bin("a30e01098bc6dbbf45690f3a7e9e6d0f"
- "8bbea2a39e6148008fd05e44"),
- Case2Exp256 = hexstr2bin("5bdcc146bf60754e6a042426089575c7"
- "5a003f089d2739839dec58b964ec3843"),
- Case2Exp384 = hexstr2bin("af45d2e376484031617f78d2b58a6b1b"
- "9c7ef464f5a01b47e42ec3736322445e"
- "8e2240ca5e69e2c78b3239ecfab21649"),
- Case2Exp512 = hexstr2bin("164b7a7bfcf819e2e395fbe73b56e0a3"
- "87bd64222e831fd610270cd7ea250554"
- "9758bf75c05a994a6d034f65f8f0e6fd"
- "caeab1a34d4a6b4b636e070a38bce737"),
-
- ?line Case2Ctx224 = crypto:hmac_init(sha224, Case2Key),
- ?line Case2Ctx224_2 = crypto:hmac_update(Case2Ctx224, Case2Data),
- ?line Case2Mac224_1 = crypto:hmac_final(Case2Ctx224_2),
- ?line Case2Mac224_2 = crypto:sha224_mac(Case2Key, Case2Data),
- ?line Case2Mac224_3 = crypto:hmac(sha224, Case2Key, Case2Data),
- ?line m(Case2Exp224, Case2Mac224_1),
- ?line m(Case2Exp224, Case2Mac224_2),
- ?line m(Case2Exp224, Case2Mac224_3),
-
- ?line Case2Ctx256 = crypto:hmac_init(sha256, Case2Key),
- ?line Case2Ctx256_2 = crypto:hmac_update(Case2Ctx256, Case2Data),
- ?line Case2Mac256_1 = crypto:hmac_final(Case2Ctx256_2),
- ?line Case2Mac256_2 = crypto:sha256_mac(Case2Key, Case2Data),
- ?line Case2Mac256_3 = crypto:hmac(sha256, Case2Key, Case2Data),
- ?line m(Case2Exp256, Case2Mac256_1),
- ?line m(Case2Exp256, Case2Mac256_2),
- ?line m(Case2Exp256, Case2Mac256_3),
-
- ?line Case2Ctx384 = crypto:hmac_init(sha384, Case2Key),
- ?line Case2Ctx384_2 = crypto:hmac_update(Case2Ctx384, Case2Data),
- ?line Case2Mac384_1 = crypto:hmac_final(Case2Ctx384_2),
- ?line Case2Mac384_2 = crypto:sha384_mac(Case2Key, Case2Data),
- ?line Case2Mac384_3 = crypto:hmac(sha384, Case2Key, Case2Data),
- ?line m(Case2Exp384, Case2Mac384_1),
- ?line m(Case2Exp384, Case2Mac384_2),
- ?line m(Case2Exp384, Case2Mac384_3),
-
- ?line Case2Ctx512 = crypto:hmac_init(sha512, Case2Key),
- ?line Case2Ctx512_2 = crypto:hmac_update(Case2Ctx512, Case2Data),
- ?line Case2Mac512_1 = crypto:hmac_final(Case2Ctx512_2),
- ?line Case2Mac512_2 = crypto:sha512_mac(Case2Key, Case2Data),
- ?line Case2Mac512_3 = crypto:hmac(sha512, Case2Key, Case2Data),
- ?line m(Case2Exp512, Case2Mac512_1),
- ?line m(Case2Exp512, Case2Mac512_2),
- ?line m(Case2Exp512, Case2Mac512_3),
-
- %% Test Case 3
- Case3Key = binary:copy(<<16#aa>>, 20),
- Case3Data = binary:copy(<<16#dd>>, 50),
- Case3Exp224 = hexstr2bin("7fb3cb3588c6c1f6ffa9694d7d6ad264"
- "9365b0c1f65d69d1ec8333ea"),
- Case3Exp256 = hexstr2bin("773ea91e36800e46854db8ebd09181a7"
- "2959098b3ef8c122d9635514ced565fe"),
- Case3Exp384 = hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f"
- "0aa635d947ac9febe83ef4e55966144b"
- "2a5ab39dc13814b94e3ab6e101a34f27"),
- Case3Exp512 = hexstr2bin("fa73b0089d56a284efb0f0756c890be9"
- "b1b5dbdd8ee81a3655f83e33b2279d39"
- "bf3e848279a722c806b485a47e67c807"
- "b946a337bee8942674278859e13292fb"),
-
- ?line Case3Ctx224 = crypto:hmac_init(sha224, Case3Key),
- ?line Case3Ctx224_2 = crypto:hmac_update(Case3Ctx224, Case3Data),
- ?line Case3Mac224_1 = crypto:hmac_final(Case3Ctx224_2),
- ?line Case3Mac224_2 = crypto:sha224_mac(Case3Key, Case3Data),
- ?line Case3Mac224_3 = crypto:hmac(sha224, Case3Key, Case3Data),
- ?line m(Case3Exp224, Case3Mac224_1),
- ?line m(Case3Exp224, Case3Mac224_2),
- ?line m(Case3Exp224, Case3Mac224_3),
-
- ?line Case3Ctx256 = crypto:hmac_init(sha256, Case3Key),
- ?line Case3Ctx256_2 = crypto:hmac_update(Case3Ctx256, Case3Data),
- ?line Case3Mac256_1 = crypto:hmac_final(Case3Ctx256_2),
- ?line Case3Mac256_2 = crypto:sha256_mac(Case3Key, Case3Data),
- ?line Case3Mac256_3 = crypto:hmac(sha256, Case3Key, Case3Data),
- ?line m(Case3Exp256, Case3Mac256_1),
- ?line m(Case3Exp256, Case3Mac256_2),
- ?line m(Case3Exp256, Case3Mac256_3),
-
- ?line Case3Ctx384 = crypto:hmac_init(sha384, Case3Key),
- ?line Case3Ctx384_2 = crypto:hmac_update(Case3Ctx384, Case3Data),
- ?line Case3Mac384_1 = crypto:hmac_final(Case3Ctx384_2),
- ?line Case3Mac384_2 = crypto:sha384_mac(Case3Key, Case3Data),
- ?line Case3Mac384_3 = crypto:hmac(sha384, Case3Key, Case3Data),
- ?line m(Case3Exp384, Case3Mac384_1),
- ?line m(Case3Exp384, Case3Mac384_2),
- ?line m(Case3Exp384, Case3Mac384_3),
-
- ?line Case3Ctx512 = crypto:hmac_init(sha512, Case3Key),
- ?line Case3Ctx512_2 = crypto:hmac_update(Case3Ctx512, Case3Data),
- ?line Case3Mac512_1 = crypto:hmac_final(Case3Ctx512_2),
- ?line Case3Mac512_2 = crypto:sha512_mac(Case3Key, Case3Data),
- ?line Case3Mac512_3 = crypto:hmac(sha512, Case3Key, Case3Data),
- ?line m(Case3Exp512, Case3Mac512_1),
- ?line m(Case3Exp512, Case3Mac512_2),
- ?line m(Case3Exp512, Case3Mac512_3),
-
- %% Test Case 4
- Case4Key = list_to_binary(lists:seq(1, 16#19)),
- Case4Data = binary:copy(<<16#cd>>, 50),
- Case4Exp224 = hexstr2bin("6c11506874013cac6a2abc1bb382627c"
- "ec6a90d86efc012de7afec5a"),
- Case4Exp256 = hexstr2bin("82558a389a443c0ea4cc819899f2083a"
- "85f0faa3e578f8077a2e3ff46729665b"),
- Case4Exp384 = hexstr2bin("3e8a69b7783c25851933ab6290af6ca7"
- "7a9981480850009cc5577c6e1f573b4e"
- "6801dd23c4a7d679ccf8a386c674cffb"),
- Case4Exp512 = hexstr2bin("b0ba465637458c6990e5a8c5f61d4af7"
- "e576d97ff94b872de76f8050361ee3db"
- "a91ca5c11aa25eb4d679275cc5788063"
- "a5f19741120c4f2de2adebeb10a298dd"),
-
- ?line Case4Ctx224 = crypto:hmac_init(sha224, Case4Key),
- ?line Case4Ctx224_2 = crypto:hmac_update(Case4Ctx224, Case4Data),
- ?line Case4Mac224_1 = crypto:hmac_final(Case4Ctx224_2),
- ?line Case4Mac224_2 = crypto:sha224_mac(Case4Key, Case4Data),
- ?line Case4Mac224_3 = crypto:hmac(sha224, Case4Key, Case4Data),
- ?line m(Case4Exp224, Case4Mac224_1),
- ?line m(Case4Exp224, Case4Mac224_2),
- ?line m(Case4Exp224, Case4Mac224_3),
-
- ?line Case4Ctx256 = crypto:hmac_init(sha256, Case4Key),
- ?line Case4Ctx256_2 = crypto:hmac_update(Case4Ctx256, Case4Data),
- ?line Case4Mac256_1 = crypto:hmac_final(Case4Ctx256_2),
- ?line Case4Mac256_2 = crypto:sha256_mac(Case4Key, Case4Data),
- ?line Case4Mac256_3 = crypto:hmac(sha256, Case4Key, Case4Data),
- ?line m(Case4Exp256, Case4Mac256_1),
- ?line m(Case4Exp256, Case4Mac256_2),
- ?line m(Case4Exp256, Case4Mac256_3),
-
- ?line Case4Ctx384 = crypto:hmac_init(sha384, Case4Key),
- ?line Case4Ctx384_2 = crypto:hmac_update(Case4Ctx384, Case4Data),
- ?line Case4Mac384_1 = crypto:hmac_final(Case4Ctx384_2),
- ?line Case4Mac384_2 = crypto:sha384_mac(Case4Key, Case4Data),
- ?line Case4Mac384_3 = crypto:hmac(sha384, Case4Key, Case4Data),
- ?line m(Case4Exp384, Case4Mac384_1),
- ?line m(Case4Exp384, Case4Mac384_2),
- ?line m(Case4Exp384, Case4Mac384_3),
-
- ?line Case4Ctx512 = crypto:hmac_init(sha512, Case4Key),
- ?line Case4Ctx512_2 = crypto:hmac_update(Case4Ctx512, Case4Data),
- ?line Case4Mac512_1 = crypto:hmac_final(Case4Ctx512_2),
- ?line Case4Mac512_2 = crypto:sha512_mac(Case4Key, Case4Data),
- ?line Case4Mac512_3 = crypto:hmac(sha512, Case4Key, Case4Data),
- ?line m(Case4Exp512, Case4Mac512_1),
- ?line m(Case4Exp512, Case4Mac512_2),
- ?line m(Case4Exp512, Case4Mac512_3),
-
- %% Test Case 5
- Case5Key = binary:copy(<<16#0c>>, 20),
- Case5Data = <<"Test With Truncation">>,
- Case5Exp224 = hexstr2bin("0e2aea68a90c8d37c988bcdb9fca6fa8"),
- Case5Exp256 = hexstr2bin("a3b6167473100ee06e0c796c2955552b"),
- Case5Exp384 = hexstr2bin("3abf34c3503b2a23a46efc619baef897"),
- Case5Exp512 = hexstr2bin("415fad6271580a531d4179bc891d87a6"),
-
- ?line Case5Ctx224 = crypto:hmac_init(sha224, Case5Key),
- ?line Case5Ctx224_2 = crypto:hmac_update(Case5Ctx224, Case5Data),
- ?line Case5Mac224_1 = crypto:hmac_final_n(Case5Ctx224_2, 16),
- ?line Case5Mac224_2 = crypto:sha224_mac(Case5Key, Case5Data, 16),
- ?line Case5Mac224_3 = crypto:hmac(sha224, Case5Key, Case5Data, 16),
- ?line m(Case5Exp224, Case5Mac224_1),
- ?line m(Case5Exp224, Case5Mac224_2),
- ?line m(Case5Exp224, Case5Mac224_3),
-
- ?line Case5Ctx256 = crypto:hmac_init(sha256, Case5Key),
- ?line Case5Ctx256_2 = crypto:hmac_update(Case5Ctx256, Case5Data),
- ?line Case5Mac256_1 = crypto:hmac_final_n(Case5Ctx256_2, 16),
- ?line Case5Mac256_2 = crypto:sha256_mac(Case5Key, Case5Data, 16),
- ?line Case5Mac256_3 = crypto:hmac(sha256, Case5Key, Case5Data, 16),
- ?line m(Case5Exp256, Case5Mac256_1),
- ?line m(Case5Exp256, Case5Mac256_2),
- ?line m(Case5Exp256, Case5Mac256_3),
-
- ?line Case5Ctx384 = crypto:hmac_init(sha384, Case5Key),
- ?line Case5Ctx384_2 = crypto:hmac_update(Case5Ctx384, Case5Data),
- ?line Case5Mac384_1 = crypto:hmac_final_n(Case5Ctx384_2, 16),
- ?line Case5Mac384_2 = crypto:sha384_mac(Case5Key, Case5Data, 16),
- ?line Case5Mac384_3 = crypto:hmac(sha384, Case5Key, Case5Data, 16),
- ?line m(Case5Exp384, Case5Mac384_1),
- ?line m(Case5Exp384, Case5Mac384_2),
- ?line m(Case5Exp384, Case5Mac384_3),
-
- ?line Case5Ctx512 = crypto:hmac_init(sha512, Case5Key),
- ?line Case5Ctx512_2 = crypto:hmac_update(Case5Ctx512, Case5Data),
- ?line Case5Mac512_1 = crypto:hmac_final_n(Case5Ctx512_2, 16),
- ?line Case5Mac512_2 = crypto:sha512_mac(Case5Key, Case5Data, 16),
- ?line Case5Mac512_3 = crypto:hmac(sha512, Case5Key, Case5Data, 16),
- ?line m(Case5Exp512, Case5Mac512_1),
- ?line m(Case5Exp512, Case5Mac512_2),
- ?line m(Case5Exp512, Case5Mac512_3),
-
- %% Test Case 6
- Case6Key = binary:copy(<<16#aa>>, 131),
- Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
- Case6Exp224 = hexstr2bin("95e9a0db962095adaebe9b2d6f0dbce2"
- "d499f112f2d2b7273fa6870e"),
- Case6Exp256 = hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f"
- "8e0bc6213728c5140546040f0ee37f54"),
- Case6Exp384 = hexstr2bin("4ece084485813e9088d2c63a041bc5b4"
- "4f9ef1012a2b588f3cd11f05033ac4c6"
- "0c2ef6ab4030fe8296248df163f44952"),
- Case6Exp512 = hexstr2bin("80b24263c7c1a3ebb71493c1dd7be8b4"
- "9b46d1f41b4aeec1121b013783f8f352"
- "6b56d037e05f2598bd0fd2215d6a1e52"
- "95e64f73f63f0aec8b915a985d786598"),
-
- ?line Case6Ctx224 = crypto:hmac_init(sha224, Case6Key),
- ?line Case6Ctx224_2 = crypto:hmac_update(Case6Ctx224, Case6Data),
- ?line Case6Mac224_1 = crypto:hmac_final(Case6Ctx224_2),
- ?line Case6Mac224_2 = crypto:sha224_mac(Case6Key, Case6Data),
- ?line Case6Mac224_3 = crypto:hmac(sha224, Case6Key, Case6Data),
- ?line m(Case6Exp224, Case6Mac224_1),
- ?line m(Case6Exp224, Case6Mac224_2),
- ?line m(Case6Exp224, Case6Mac224_3),
-
- ?line Case6Ctx256 = crypto:hmac_init(sha256, Case6Key),
- ?line Case6Ctx256_2 = crypto:hmac_update(Case6Ctx256, Case6Data),
- ?line Case6Mac256_1 = crypto:hmac_final(Case6Ctx256_2),
- ?line Case6Mac256_2 = crypto:sha256_mac(Case6Key, Case6Data),
- ?line Case6Mac256_3 = crypto:hmac(sha256, Case6Key, Case6Data),
- ?line m(Case6Exp256, Case6Mac256_1),
- ?line m(Case6Exp256, Case6Mac256_2),
- ?line m(Case6Exp256, Case6Mac256_3),
-
- ?line Case6Ctx384 = crypto:hmac_init(sha384, Case6Key),
- ?line Case6Ctx384_2 = crypto:hmac_update(Case6Ctx384, Case6Data),
- ?line Case6Mac384_1 = crypto:hmac_final(Case6Ctx384_2),
- ?line Case6Mac384_2 = crypto:sha384_mac(Case6Key, Case6Data),
- ?line Case6Mac384_3 = crypto:hmac(sha384, Case6Key, Case6Data),
- ?line m(Case6Exp384, Case6Mac384_1),
- ?line m(Case6Exp384, Case6Mac384_2),
- ?line m(Case6Exp384, Case6Mac384_3),
-
- ?line Case6Ctx512 = crypto:hmac_init(sha512, Case6Key),
- ?line Case6Ctx512_2 = crypto:hmac_update(Case6Ctx512, Case6Data),
- ?line Case6Mac512_1 = crypto:hmac_final(Case6Ctx512_2),
- ?line Case6Mac512_2 = crypto:sha512_mac(Case6Key, Case6Data),
- ?line Case6Mac512_3 = crypto:hmac(sha512, Case6Key, Case6Data),
- ?line m(Case6Exp512, Case6Mac512_1),
- ?line m(Case6Exp512, Case6Mac512_2),
- ?line m(Case6Exp512, Case6Mac512_3),
-
+hmac_rfc4231_sha256(doc) ->
+ ["Generate an HMAC using crypto:sha256_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+ "Testvectors are take from RFC4231." ];
+hmac_rfc4231_sha256(suite) ->
+ [];
+hmac_rfc4231_sha256(Config) when is_list(Config) ->
+ if_supported(sha256, fun() -> hmac_rfc4231_sha256_do() end).
+
+hmac_rfc4231_sha384(doc) ->
+ ["Generate an HMAC using crypto:sha384_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+ "Testvectors are take from RFC4231." ];
+hmac_rfc4231_sha384(suite) ->
+ [];
+hmac_rfc4231_sha384(Config) when is_list(Config) ->
+ if_supported(sha384, fun() -> hmac_rfc4231_sha384_do() end).
+
+hmac_rfc4231_sha512(doc) ->
+ ["Generate an HMAC using crypto:sha512_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+ "Testvectors are take from RFC4231." ];
+hmac_rfc4231_sha512(suite) ->
+ [];
+hmac_rfc4231_sha512(Config) when is_list(Config) ->
+ if_supported(sha512, fun() -> hmac_rfc4231_sha512_do() end).
+
+hmac_rfc4231_case(Hash, HashFun, case1, Exp) ->
+ %% Test 1
+ Key = binary:copy(<<16#0b>>, 20),
+ Data = <<"Hi There">>,
+ hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, HashFun, case2, Exp) ->
+ %% Test 2
+ Key = <<"Jefe">>,
+ Data = <<"what do ya want for nothing?">>,
+ hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, HashFun, case3, Exp) ->
+ %% Test 3
+ Key = binary:copy(<<16#aa>>, 20),
+ Data = binary:copy(<<16#dd>>, 50),
+ hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, HashFun, case4, Exp) ->
+ %% Test 4
+ Key = list_to_binary(lists:seq(1, 16#19)),
+ Data = binary:copy(<<16#cd>>, 50),
+ hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, HashFun, case5, Exp) ->
+ %% Test 5
+ Key = binary:copy(<<16#0c>>, 20),
+ Data = <<"Test With Truncation">>,
+ hmac_rfc4231_case(Hash, HashFun, Key, Data, 16, Exp);
+
+hmac_rfc4231_case(Hash, HashFun, case6, Exp) ->
+ %% Test 6
+ Key = binary:copy(<<16#aa>>, 131),
+ Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
+ hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, HashFun, case7, Exp) ->
%% Test Case 7
- Case7Key = binary:copy(<<16#aa>>, 131),
- Case7Data = <<"This is a test using a larger than block-size key and a larger t",
- "han block-size data. The key needs to be hashed before being use",
- "d by the HMAC algorithm.">>,
- Case7Exp224 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd"
- "946770db9c2b95c9f6f565d1"),
- Case7Exp256 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944"
- "bfdc63644f0713938a7f51535c3a35e2"),
- Case7Exp384 = hexstr2bin("6617178e941f020d351e2f254e8fd32c"
- "602420feb0b8fb9adccebb82461e99c5"
- "a678cc31e799176d3860e6110c46523e"),
- Case7Exp512 = hexstr2bin("e37b6a775dc87dbaa4dfa9f96e5e3ffd"
- "debd71f8867289865df5a32d20cdc944"
- "b6022cac3c4982b10d5eeb55c3e4de15"
- "134676fb6de0446065c97440fa8c6a58"),
-
- ?line Case7Ctx224 = crypto:hmac_init(sha224, Case7Key),
- ?line Case7Ctx224_2 = crypto:hmac_update(Case7Ctx224, Case7Data),
- ?line Case7Mac224_1 = crypto:hmac_final(Case7Ctx224_2),
- ?line Case7Mac224_2 = crypto:sha224_mac(Case7Key, Case7Data),
- ?line Case7Mac224_3 = crypto:hmac(sha224, Case7Key, Case7Data),
- ?line m(Case7Exp224, Case7Mac224_1),
- ?line m(Case7Exp224, Case7Mac224_2),
- ?line m(Case7Exp224, Case7Mac224_3),
-
- ?line Case7Ctx256 = crypto:hmac_init(sha256, Case7Key),
- ?line Case7Ctx256_2 = crypto:hmac_update(Case7Ctx256, Case7Data),
- ?line Case7Mac256_1 = crypto:hmac_final(Case7Ctx256_2),
- ?line Case7Mac256_2 = crypto:sha256_mac(Case7Key, Case7Data),
- ?line Case7Mac256_3 = crypto:hmac(sha256, Case7Key, Case7Data),
- ?line m(Case7Exp256, Case7Mac256_1),
- ?line m(Case7Exp256, Case7Mac256_2),
- ?line m(Case7Exp256, Case7Mac256_3),
-
- ?line Case7Ctx384 = crypto:hmac_init(sha384, Case7Key),
- ?line Case7Ctx384_2 = crypto:hmac_update(Case7Ctx384, Case7Data),
- ?line Case7Mac384_1 = crypto:hmac_final(Case7Ctx384_2),
- ?line Case7Mac384_2 = crypto:sha384_mac(Case7Key, Case7Data),
- ?line Case7Mac384_3 = crypto:hmac(sha384, Case7Key, Case7Data),
- ?line m(Case7Exp384, Case7Mac384_1),
- ?line m(Case7Exp384, Case7Mac384_2),
- ?line m(Case7Exp384, Case7Mac384_3),
-
- ?line Case7Ctx512 = crypto:hmac_init(sha512, Case7Key),
- ?line Case7Ctx512_2 = crypto:hmac_update(Case7Ctx512, Case7Data),
- ?line Case7Mac512_1 = crypto:hmac_final(Case7Ctx512_2),
- ?line Case7Mac512_2 = crypto:sha512_mac(Case7Key, Case7Data),
- ?line Case7Mac512_3 = crypto:hmac(sha512, Case7Key, Case7Data),
- ?line m(Case7Exp512, Case7Mac512_1),
- ?line m(Case7Exp512, Case7Mac512_2),
- ?line m(Case7Exp512, Case7Mac512_3).
+ Key = binary:copy(<<16#aa>>, 131),
+ Data = <<"This is a test using a larger than block-size key and a larger t",
+ "han block-size data. The key needs to be hashed before being use",
+ "d by the HMAC algorithm.">>,
+ hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp).
+
+hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp) ->
+ ?line Ctx = crypto:hmac_init(Hash, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Mac1 = crypto:hmac_final(Ctx2),
+ ?line Mac2 = crypto:HashFun(Key, Data),
+ ?line Mac3 = crypto:hmac(Hash, Key, Data),
+ ?line m(Exp, Mac1),
+ ?line m(Exp, Mac2),
+ ?line m(Exp, Mac3).
+
+hmac_rfc4231_case(Hash, HashFun, Key, Data, Trunc, Exp) ->
+ ?line Ctx = crypto:hmac_init(Hash, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Mac1 = crypto:hmac_final_n(Ctx2, Trunc),
+ ?line Mac2 = crypto:HashFun(Key, Data, Trunc),
+ ?line Mac3 = crypto:hmac(Hash, Key, Data, Trunc),
+ ?line m(Exp, Mac1),
+ ?line m(Exp, Mac2),
+ ?line m(Exp, Mac3).
+
+hmac_rfc4231_sha224_do() ->
+ Case1 = hexstr2bin("896fb1128abbdf196832107cd49df33f"
+ "47b4b1169912ba4f53684b22"),
+ Case2 = hexstr2bin("a30e01098bc6dbbf45690f3a7e9e6d0f"
+ "8bbea2a39e6148008fd05e44"),
+ Case3 = hexstr2bin("7fb3cb3588c6c1f6ffa9694d7d6ad264"
+ "9365b0c1f65d69d1ec8333ea"),
+ Case4 = hexstr2bin("6c11506874013cac6a2abc1bb382627c"
+ "ec6a90d86efc012de7afec5a"),
+ Case5 = hexstr2bin("0e2aea68a90c8d37c988bcdb9fca6fa8"),
+ Case6 = hexstr2bin("95e9a0db962095adaebe9b2d6f0dbce2"
+ "d499f112f2d2b7273fa6870e"),
+ Case7 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd"
+ "946770db9c2b95c9f6f565d1"),
+ hmac_rfc4231_cases_do(sha224, sha224_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+
+hmac_rfc4231_sha256_do() ->
+ Case1 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b"
+ "881dc200c9833da726e9376c2e32cff7"),
+ Case2 = hexstr2bin("5bdcc146bf60754e6a042426089575c7"
+ "5a003f089d2739839dec58b964ec3843"),
+ Case3 = hexstr2bin("773ea91e36800e46854db8ebd09181a7"
+ "2959098b3ef8c122d9635514ced565fe"),
+ Case4 = hexstr2bin("82558a389a443c0ea4cc819899f2083a"
+ "85f0faa3e578f8077a2e3ff46729665b"),
+ Case5 = hexstr2bin("a3b6167473100ee06e0c796c2955552b"),
+ Case6 = hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f"
+ "8e0bc6213728c5140546040f0ee37f54"),
+ Case7 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944"
+ "bfdc63644f0713938a7f51535c3a35e2"),
+ hmac_rfc4231_cases_do(sha256, sha256_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+
+hmac_rfc4231_sha384_do() ->
+ Case1 = hexstr2bin("afd03944d84895626b0825f4ab46907f"
+ "15f9dadbe4101ec682aa034c7cebc59c"
+ "faea9ea9076ede7f4af152e8b2fa9cb6"),
+ Case2 = hexstr2bin("af45d2e376484031617f78d2b58a6b1b"
+ "9c7ef464f5a01b47e42ec3736322445e"
+ "8e2240ca5e69e2c78b3239ecfab21649"),
+ Case3 = hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f"
+ "0aa635d947ac9febe83ef4e55966144b"
+ "2a5ab39dc13814b94e3ab6e101a34f27"),
+ Case4 = hexstr2bin("3e8a69b7783c25851933ab6290af6ca7"
+ "7a9981480850009cc5577c6e1f573b4e"
+ "6801dd23c4a7d679ccf8a386c674cffb"),
+ Case5 = hexstr2bin("3abf34c3503b2a23a46efc619baef897"),
+ Case6 = hexstr2bin("4ece084485813e9088d2c63a041bc5b4"
+ "4f9ef1012a2b588f3cd11f05033ac4c6"
+ "0c2ef6ab4030fe8296248df163f44952"),
+ Case7 = hexstr2bin("6617178e941f020d351e2f254e8fd32c"
+ "602420feb0b8fb9adccebb82461e99c5"
+ "a678cc31e799176d3860e6110c46523e"),
+ hmac_rfc4231_cases_do(sha384, sha384_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+
+hmac_rfc4231_sha512_do() ->
+ Case1 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0"
+ "2379f4e2ce4ec2787ad0b30545e17cde"
+ "daa833b7d6b8a702038b274eaea3f4e4"
+ "be9d914eeb61f1702e696c203a126854"),
+ Case2 = hexstr2bin("164b7a7bfcf819e2e395fbe73b56e0a3"
+ "87bd64222e831fd610270cd7ea250554"
+ "9758bf75c05a994a6d034f65f8f0e6fd"
+ "caeab1a34d4a6b4b636e070a38bce737"),
+ Case3 = hexstr2bin("fa73b0089d56a284efb0f0756c890be9"
+ "b1b5dbdd8ee81a3655f83e33b2279d39"
+ "bf3e848279a722c806b485a47e67c807"
+ "b946a337bee8942674278859e13292fb"),
+ Case4 = hexstr2bin("b0ba465637458c6990e5a8c5f61d4af7"
+ "e576d97ff94b872de76f8050361ee3db"
+ "a91ca5c11aa25eb4d679275cc5788063"
+ "a5f19741120c4f2de2adebeb10a298dd"),
+ Case5 = hexstr2bin("415fad6271580a531d4179bc891d87a6"),
+ Case6 = hexstr2bin("80b24263c7c1a3ebb71493c1dd7be8b4"
+ "9b46d1f41b4aeec1121b013783f8f352"
+ "6b56d037e05f2598bd0fd2215d6a1e52"
+ "95e64f73f63f0aec8b915a985d786598"),
+ Case7 = hexstr2bin("e37b6a775dc87dbaa4dfa9f96e5e3ffd"
+ "debd71f8867289865df5a32d20cdc944"
+ "b6022cac3c4982b10d5eeb55c3e4de15"
+ "134676fb6de0446065c97440fa8c6a58"),
+ hmac_rfc4231_cases_do(sha512, sha512_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+
+hmac_rfc4231_cases_do(Hash, HashFun, CasesData) ->
+ hmac_rfc4231_cases_do(Hash, HashFun, [case1, case2, case3, case4, case5, case6, case7], CasesData).
+
+hmac_rfc4231_cases_do(_Hash, _HashFun, _, []) ->
+ ok;
+hmac_rfc4231_cases_do(Hash, HashFun, [C|Cases], [D|CasesData]) ->
+ hmac_rfc4231_case(Hash, HashFun, C, D),
+ hmac_rfc4231_cases_do(Hash, HashFun, Cases, CasesData).
hmac_update_md5_io(doc) ->
["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
@@ -1025,7 +855,7 @@ sha256(doc) ->
sha256(suite) ->
[];
sha256(Config) when is_list(Config) ->
- if_098(fun() -> sha256_do() end).
+ if_supported(sha256, fun() -> sha256_do() end).
sha256_do() ->
?line m(crypto:sha256("abc"),
@@ -1044,7 +874,7 @@ sha256_update(doc) ->
sha256_update(suite) ->
[];
sha256_update(Config) when is_list(Config) ->
- if_098(fun() -> sha256_update_do() end).
+ if_supported(sha256, fun() -> sha256_update_do() end).
sha256_update_do() ->
?line Ctx = crypto:sha256_init(),
@@ -1063,7 +893,7 @@ sha512(doc) ->
sha512(suite) ->
[];
sha512(Config) when is_list(Config) ->
- if_098(fun() -> sha512_do() end).
+ if_supported(sha512, fun() -> sha512_do() end).
sha512_do() ->
?line m(crypto:sha512("abc"),
@@ -1084,7 +914,7 @@ sha512_update(doc) ->
sha512_update(suite) ->
[];
sha512_update(Config) when is_list(Config) ->
- if_098(fun() -> sha512_update_do() end).
+ if_supported(sha512, fun() -> sha512_update_do() end).
sha512_update_do() ->
?line Ctx = crypto:sha512_init(),
@@ -2017,6 +1847,161 @@ dh(Config) when is_list(Config) ->
exit(Pid, kill)
end.
+srp3(doc) ->
+ ["SRP-3 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
+srp3(suite) -> [];
+srp3(Config) when is_list(Config) ->
+ Username = <<"alice">>,
+ Password = <<"password123">>,
+ Salt = hexstr2bin("2857827A19266A1F2BC6"),
+ Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+ "FD5138FE8376435B9FC61D2FC0EB06E3"),
+ Generator = <<2>>,
+ Version = '3',
+ Scrambler = hexstr2bin("02E2476A"),
+
+ %% X = hexstr2bin("96E54AB0CD4C5123EDCFA4A1502918AAD3C9E2A8"),
+ Verifier = hexstr2bin("96EB5F13621D911AA1CA405DE9C64217D4108EEEECAFFE500034FE0E"
+ "C031E42C8714667C161BCE0E7996F7DDE1B63824C130D2D7286C08C0"
+ "49758420735961347112AE102A3F23B3F687F8FEE0DF2BFAF933C608"
+ "D6FE5B5EEE3116FE54016E065BF8E8C9FDBBC08719231AC215149140"
+ "519E8FDD9AA4F410C28A58AF42974D2D"),
+ ClientPrivate = hexstr2bin("6411DE75538BED8170677D577D0608F39112BC95B503C447EB6AC945"
+ "49C75C7B"),
+ ServerPrivate = hexstr2bin("85E44A6F694DBE676145DB245A045CD37C99F05C562C7840A31F270D"
+ "9AADCF8B"),
+ ClientPublic = hexstr2bin("B22B1FFA2244B8CB94F3A9080F419CAEAB0DBA93EA1965B5E84587EE"
+ "55C79E7A118865DC59B9D0353362C2A8261E7C1B0D221A0E233C2AD1"
+ "640DACBB8664CBC9733EAC392DA7800142860380C3FC573C3C064329"
+ "CF54063FD114C7210E9CB3A611EA8002B1844B698F930D95D143899B"
+ "948A090E0C25938E5F84067D1883DC63"),
+ ServerPublic = hexstr2bin("93A8C4D8B7F7395ADCFD4ABA37B015124513D3F37B3E85EB23064BE5"
+ "F53C0AE32FFB9D8C0AA0DCFFA74D632DD67DEBB5C35AAE9812286CC8"
+ "C43CC176ECBC6D3F447594D9554E995B2509127BF88FADDDA4982D03"
+ "8EC3001320712D3B1269308CE70F319B2295FA57674F03A2D993CFB1"
+ "F84C35B7D0C012FA73CD4C8F7D5A71C7"),
+
+ SessionKey = hexstr2bin("C29A986C4D521BBC66428ED11D994CD7431574A6184B83CDCC345092"
+ "791E75748A1D38CAC4BD14760F0D2694B711236419240FF2F172454C"
+ "46ABF4FF39498DAFDD2C82924F7D7BD76CDFCE688C77D93F18A65409"
+ "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),
+
+ {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).
+
+srp6(doc) ->
+ ["SRP-6 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
+srp6(suite) -> [];
+srp6(Config) when is_list(Config) ->
+ Username = <<"alice">>,
+ Password = <<"password123">>,
+ Salt = hexstr2bin("2857827A19266A1F2BC6"),
+ Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+ "FD5138FE8376435B9FC61D2FC0EB06E3"),
+ Generator = <<2>>,
+ Version = '6',
+ Scrambler = hexstr2bin("0A2534C0BF52A0DA9001EEC62CF2A546AB0908A7"),
+ Verifier = hexstr2bin("96EB5F13621D911AA1CA405DE9C64217D4108EEEECAFFE500034FE0E"
+ "C031E42C8714667C161BCE0E7996F7DDE1B63824C130D2D7286C08C0"
+ "49758420735961347112AE102A3F23B3F687F8FEE0DF2BFAF933C608"
+ "D6FE5B5EEE3116FE54016E065BF8E8C9FDBBC08719231AC215149140"
+ "519E8FDD9AA4F410C28A58AF42974D2D"),
+ ClientPrivate = hexstr2bin("6411DE75538BED8170677D577D0608F39112BC95B503C447EB6AC945"
+ "49C75C7B"),
+ ServerPrivate = hexstr2bin("85E44A6F694DBE676145DB245A045CD37C99F05C562C7840A31F270D"
+ "9AADCF8B"),
+ ClientPublic = hexstr2bin("B22B1FFA2244B8CB94F3A9080F419CAEAB0DBA93EA1965B5E84587EE"
+ "55C79E7A118865DC59B9D0353362C2A8261E7C1B0D221A0E233C2AD1"
+ "640DACBB8664CBC9733EAC392DA7800142860380C3FC573C3C064329"
+ "CF54063FD114C7210E9CB3A611EA8002B1844B698F930D95D143899B"
+ "948A090E0C25938E5F84067D1883DC63"),
+ ServerPublic = hexstr2bin("D2D07845CE7ECDB9845DD36B10ACD3598CC29049DE9F467F84CE16B6"
+ "D97A6DC567AF8B0F9FEDF74962400AD5C357951E64E67B641246F264"
+ "C8DE6D9A72E554D6C8D3194548780A0C438A0FCC509CA88A14AA1DEB"
+ "C0F09E4B37A965D1545DB4AD361346F3189B0EA569C06D326C4E4797"
+ "9E381C748293B7C0591BE0BE419E053E"),
+
+ SessionKey = hexstr2bin("19D22C19612874EBF1F2581F8EFCFDC44C6FDA3B87B0A73823D7E962"
+ "554295D4E48D3A336523ADBDDD0EC8FB0F02687109E97E01C17C93CC"
+ "7216F9CD8A4AC39F0429857D8D1023066614BDFCBCB89F59A0FEB81C"
+ "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),
+
+ {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).
+
+srp6a(doc) ->
+ ["SRP-6a test vectors from RFC5054."];
+srp6a(suite) -> [];
+srp6a(Config) when is_list(Config) ->
+ Username = <<"alice">>,
+ Password = <<"password123">>,
+ Salt = hexstr2bin("BEB25379D1A8581EB5A727673A2441EE"),
+ Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+ "FD5138FE8376435B9FC61D2FC0EB06E3"),
+ Generator = <<2>>,
+ Version = '6a',
+ Scrambler = hexstr2bin("CE38B9593487DA98554ED47D70A7AE5F462EF019"),
+ Verifier = hexstr2bin("7E273DE8696FFC4F4E337D05B4B375BEB0DDE1569E8FA00A9886D812"
+ "9BADA1F1822223CA1A605B530E379BA4729FDC59F105B4787E5186F5"
+ "C671085A1447B52A48CF1970B4FB6F8400BBF4CEBFBB168152E08AB5"
+ "EA53D15C1AFF87B2B9DA6E04E058AD51CC72BFC9033B564E26480D78"
+ "E955A5E29E7AB245DB2BE315E2099AFB"),
+ ClientPrivate = hexstr2bin("60975527035CF2AD1989806F0407210BC81EDC04E2762A56AFD529DD"
+ "DA2D4393"),
+ ServerPrivate = hexstr2bin("E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D1"
+ "05284D20"),
+ ClientPublic = hexstr2bin("61D5E490F6F1B79547B0704C436F523DD0E560F0C64115BB72557EC4"
+ "4352E8903211C04692272D8B2D1A5358A2CF1B6E0BFCF99F921530EC"
+ "8E39356179EAE45E42BA92AEACED825171E1E8B9AF6D9C03E1327F44"
+ "BE087EF06530E69F66615261EEF54073CA11CF5858F0EDFDFE15EFEA"
+ "B349EF5D76988A3672FAC47B0769447B"),
+ ServerPublic = hexstr2bin("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011"
+ "BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC99"
+ "6C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA"
+ "37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAE"
+ "EB4012B7D7665238A8E3FB004B117B58"),
+
+ SessionKey = hexstr2bin("B0DC82BABCF30674AE450C0287745E7990A3381F63B387AAF271A10D"
+ "233861E359B48220F7C4693C9AE12B0A6F67809F0876E2D013800D6C"
+ "41BB59B6D5979B5C00A172B4A2A5903A0BDCAF8A709585EB2AFAFA8F"
+ "3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D"
+ "C346D7E474B29EDE8A469FFECA686E5A"),
+ 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),
+
+ 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).
+
%%
%%
exor_test(doc) ->
@@ -2120,8 +2105,8 @@ worker_loop(N, Config) ->
aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, strong_rand_test,
rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test,
hmac_update_md5, hmac_update_sha, hmac_update_sha256, hmac_update_sha512,
- hmac_rfc2202, hmac_rfc4231,
- aes_ctr_stream },
+ hmac_rfc2202, hmac_rfc4231_sha224, hmac_rfc4231_sha256, hmac_rfc4231_sha384,
+ hmac_rfc4231_sha512, aes_ctr_stream },
F = element(random:uniform(size(Funcs)),Funcs),
%%io:format("worker ~p calling ~p\n",[self(),F]),
@@ -2256,10 +2241,10 @@ openssl_version() ->
undefined
end.
-if_098(Fun) ->
- case openssl_version() of
- V when V < 16#908000 ->
- {skipped,"OpenSSL version too old"};
+if_supported(Algorithm, Fun) ->
+ case proplists:get_bool(Algorithm, crypto:algorithms()) of
+ true ->
+ Fun();
_ ->
- Fun()
+ {skipped, io:format("~s not spupported", [Algorithm])}
end.
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index e9858a3220..2501db858a 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -79,6 +79,7 @@
{keyfile, path()} | {password, string()} |
{cacerts, [der_encoded()]} | {cacertfile, path()} |
|{dh, der_encoded()} | {dhfile, path()} | {ciphers, ciphers()} |
+ {user_lookup_fun, {fun(), term()}}, {psk_identity, string()}, {srp_identity, {string(), string()}} |
{ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()}
{next_protocols_advertised, [binary()]} |
{client_preferred_next_protocols, client | server, [binary()]}
@@ -123,6 +124,7 @@
{key_exchange(), cipher(), hash()}</c></p>
<p><c>key_exchange() = rsa | dhe_dss | dhe_rsa | dh_anon
+ | psk | dhe_psk | rsa_psk | srp_anon | srp_dss | srp_rsa
</c></p>
<p><c>cipher() = rc4_128 | des_cbc | '3des_ede_cbc'
@@ -134,6 +136,9 @@
<p><c>prf_random() = client_random | server_random
</c></p>
+ <p><c>srp_param_type() = srp_1024 | srp_1536 | srp_2048 | srp_3072
+ | srp_4096 | srp_6144 | srp_8192</c></p>
+
</section>
<section>
@@ -179,13 +184,16 @@
<tag>{ciphers, ciphers()}</tag>
<item>The cipher suites that should be supported. The function
- <c>cipher_suites/0</c> can be used to find all available
- ciphers. Additionally some anonymous cipher suites ({dh_anon,
- rc4_128, md5}, {dh_anon, des_cbc, sha}, {dh_anon,
- '3des_ede_cbc', sha}, {dh_anon, aes_128_cbc, sha}, {dh_anon,
- aes_256_cbc, sha}) are supported for testing purposes and will
- only work if explicitly enabled by this option and they are supported/enabled
- by the peer also.
+ <c>cipher_suites/0</c> can be used to find all ciphers that are
+ supported by default. <c>cipher_suites(all)</c> may be called
+ to find all available cipher suites.
+ Pre-Shared Key (<url href="http://www.ietf.org/rfc/rfc4279.txt">RFC 4279</url> and
+ <url href="http://www.ietf.org/rfc/rfc5487.txt">RFC 5487</url>),
+ Secure Remote Password (<url href="http://www.ietf.org/rfc/rfc5054.txt">RFC 5054</url>)
+ and anonymous cipher suites only work if explicitly enabled by
+ this option and they are supported/enabled by the peer also.
+ Note that anonymous cipher suites are supported for testing purposes
+ only and should not be used when security matters.
</item>
<tag>{ssl_imp, new | old}</tag>
@@ -195,10 +203,10 @@
<tag>{secure_renegotiate, boolean()}</tag>
<item>Specifies if to reject renegotiation attempt that does
- not live up to RFC 5746. By default secure_renegotiate is
+ not live up to <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>. By default secure_renegotiate is
set to false i.e. secure renegotiation will be used if possible
but it will fallback to unsecure renegotiation if the peer
- does not support RFC 5746.
+ does not support <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>.
</item>
<tag>{depth, integer()}</tag>
@@ -292,6 +300,32 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<c>undefined</c> is specified (this is the default), the process
will never go into hibernation.
</item>
+
+ <tag>{user_lookup_fun, {Lookupfun :: fun(), UserState :: term()}}</tag>
+ <item>
+ <p>The lookup fun should be defined as:</p>
+ <code>
+fun(psk, PSKIdentity, UserState :: term()) ->
+ {ok, SharedSecret :: binary()} | error;
+fun(srp, Username, UserState :: term()) ->
+ {ok, {SRPParams :: srp_param_type(), Salt :: binary(), DerivedKey :: binary()}} | error.
+ </code>
+
+ <p>For Pre-Shared Key (PSK) cipher suites, the lookup fun will
+ be called by the client and server to determine the shared
+ secret. When called by the client, PSKIdentity will be set to the
+ hint presented by the server or undefined. When called by the
+ server, PSKIdentity is the identity presented by the client.
+ </p>
+
+ <p>For Secure Remote Password (SRP), the fun will only be used by the server to obtain
+ parameters that it will use to generate its session keys. <c>DerivedKey</c> should be
+ derived according to <url href="http://tools.ietf.org/html/rfc2945#section-3"> RFC 2945</url> and
+ <url href="http://tools.ietf.org/html/rfc5054#section-2.4"> RFC 5054</url>:
+ <c>crypto:sha([Salt, crypto:sha([Username, &lt;&lt;$:&gt;&gt;, Password])]) </c>
+ </p>
+ </item>
+
</taglist>
</section>
@@ -334,6 +368,14 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
server does not support Next Protocol Negotiation the
connection will be aborted if no default protocol is supplied.</p>
</item>
+
+ <tag>{psk_identity, string()}</tag>
+ <item>Specifies the identity the client presents to the server. The matching secret is
+ found by calling the user_look_fun.
+ </item>
+ <tag>{srp_identity, {Username :: string(), Password :: string()}</tag>
+ <item>Specifies the Username and Password to use to authenticate to the server.
+ </item>
</taglist>
</section>
@@ -396,6 +438,10 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
using <c>negotiated_next_protocol/1</c> method.
</item>
+ <tag>{psk_identity, string()}</tag>
+ <item>Specifies the server identity hint the server presents to the client.
+ </item>
+
</taglist>
</section>
@@ -427,13 +473,16 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<name>cipher_suites(Type) -> ciphers()</name>
<fsummary> Returns a list of supported cipher suites</fsummary>
<type>
- <v>Type = erlang | openssl</v>
+ <v>Type = erlang | openssl | all</v>
</type>
<desc><p>Returns a list of supported cipher suites.
cipher_suites() is equivalent to cipher_suites(erlang).
Type openssl is provided for backwards compatibility with
- old ssl that used openssl.
+ old ssl that used openssl. cipher_suites(all) returns
+ all available cipher suites. The cipher suites not present
+ in cipher_suites(erlang) but in included in cipher_suites(all)
+ will not be used unless explicitly configured by the user.
</p>
</desc>
</func>
@@ -821,7 +870,6 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
</desc>
</func>
-
</funcs>
<section>
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index e61f415c84..d3ba76d34e 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -50,6 +50,7 @@ MODULES= \
ssl_certificate\
ssl_certificate_db\
ssl_cipher \
+ ssl_srp_primes \
ssl_connection \
ssl_connection_sup \
ssl_handshake \
@@ -65,7 +66,7 @@ MODULES= \
INTERNAL_HRL_FILES = \
ssl_alert.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_internal.hrl \
- ssl_record.hrl
+ ssl_record.hrl ssl_srp.hrl ssl_srp_primes.hrl
ERL_FILES= \
$(MODULES:%=%.erl) \
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index 897a097f73..5c34de905e 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -20,6 +20,7 @@
ssl_connection_sup,
ssl_connection,
ssl_cipher,
+ ssl_srp_primes,
ssl_certificate_db,
ssl_certificate,
ssl_alert
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index fc06b5f1b0..70f3b4f050 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -37,6 +37,7 @@
-include("ssl_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_handshake.hrl").
+-include("ssl_srp_primes.hrl").
-include_lib("public_key/include/public_key.hrl").
@@ -65,6 +66,9 @@
{cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} |
{keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} |
{cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} |
+ {user_lookup_fun, {fun(), InitialUserState::term()}} |
+ {psk_identity, string()} |
+ {srp_identity, {string(), string()}} |
{ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} |
{reuse_session, fun()} | {hibernate_after, integer()|undefined} |
{next_protocols_advertised, list(binary())} |
@@ -351,7 +355,7 @@ negotiated_next_protocol(#sslsocket{pid = Pid}) ->
ssl_connection:negotiated_next_protocol(Pid).
-spec cipher_suites() -> [erl_cipher_suite()].
--spec cipher_suites(erlang | openssl) -> [erl_cipher_suite()] | [string()].
+-spec cipher_suites(erlang | openssl | all ) -> [erl_cipher_suite()] | [string()].
%% Description: Returns all supported cipher suites.
%%--------------------------------------------------------------------
@@ -364,8 +368,15 @@ cipher_suites(erlang) ->
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 <- ssl_cipher:suites(Version)];
+cipher_suites(all) ->
+ Version = ssl_record:highest_protocol_version([]),
+ Supported = ssl_cipher:suites(Version)
+ ++ ssl_cipher:anonymous_suites()
+ ++ ssl_cipher:psk_suites(Version)
+ ++ ssl_cipher:srp_suites(),
+ [suite_definition(S) || S <- Supported].
%%--------------------------------------------------------------------
-spec getopts(#sslsocket{}, [gen_tcp:option_name()]) ->
{ok, [gen_tcp:option()]} | {error, reason()}.
@@ -635,6 +646,9 @@ handle_options(Opts0, _Role) ->
cacertfile = handle_option(cacertfile, Opts, CaCertDefault),
dh = handle_option(dh, Opts, undefined),
dhfile = handle_option(dhfile, Opts, undefined),
+ user_lookup_fun = handle_option(user_lookup_fun, Opts, undefined),
+ psk_identity = handle_option(psk_identity, Opts, undefined),
+ srp_identity = handle_option(srp_identity, Opts, undefined),
ciphers = handle_option(ciphers, Opts, []),
%% Server side option
reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun),
@@ -654,7 +668,8 @@ handle_options(Opts0, _Role) ->
SslOptions = [versions, verify, verify_fun,
fail_if_no_peer_cert, verify_client_once,
depth, cert, certfile, key, keyfile,
- password, cacerts, cacertfile, dh, dhfile, ciphers,
+ password, cacerts, cacertfile, dh, dhfile,
+ user_lookup_fun, psk_identity, srp_identity, ciphers,
reuse_session, reuse_sessions, ssl_imp,
cb_info, renegotiate_at, secure_renegotiate, hibernate_after,
erl_dist, next_protocols_advertised,
@@ -756,6 +771,20 @@ validate_option(dhfile, Value) when is_binary(Value) ->
Value;
validate_option(dhfile, Value) when is_list(Value), Value =/= "" ->
list_to_binary(Value);
+validate_option(psk_identity, undefined) ->
+ undefined;
+validate_option(psk_identity, Identity)
+ when is_list(Identity), Identity =/= "", length(Identity) =< 65535 ->
+ list_to_binary(Identity);
+validate_option(user_lookup_fun, undefined) ->
+ undefined;
+validate_option(user_lookup_fun, {Fun, _} = Value) when is_function(Fun, 3) ->
+ Value;
+validate_option(srp_identity, undefined) ->
+ undefined;
+validate_option(srp_identity, {Username, Password})
+ when is_list(Username), is_list(Password), Username =/= "", length(Username) =< 255 ->
+ {list_to_binary(Username), list_to_binary(Password)};
validate_option(ciphers, Value) when is_list(Value) ->
Version = ssl_record:highest_protocol_version([]),
try cipher_suites(Version, Value)
@@ -926,7 +955,10 @@ cipher_suites(Version, [{_,_,_}| _] = Ciphers0) ->
Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
cipher_suites(Version, Ciphers);
cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
- Supported = ssl_cipher:suites(Version) ++ ssl_cipher:anonymous_suites(),
+ Supported = 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
[] ->
Supported;
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index 94e95d3cd3..1810043dfb 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -112,4 +112,6 @@ description_txt(?INTERNAL_ERROR) ->
description_txt(?USER_CANCELED) ->
"user canceled";
description_txt(?NO_RENEGOTIATION) ->
- "no renegotiation".
+ "no renegotiation";
+description_txt(?UNKNOWN_PSK_IDENTITY) ->
+ "unknown psk identity".
diff --git a/lib/ssl/src/ssl_alert.hrl b/lib/ssl/src/ssl_alert.hrl
index 92548edab7..2a8a91aefa 100644
--- a/lib/ssl/src/ssl_alert.hrl
+++ b/lib/ssl/src/ssl_alert.hrl
@@ -60,6 +60,7 @@
%% internal_error(80),
%% user_canceled(90),
%% no_renegotiation(100),
+%% unknown_psk_identity(115),
%% (255)
%% } AlertDescription;
@@ -87,6 +88,7 @@
-define(INTERNAL_ERROR, 80).
-define(USER_CANCELED, 90).
-define(NO_RENEGOTIATION, 100).
+-define(UNKNOWN_PSK_IDENTITY, 115).
-define(ALERT_REC(Level,Desc), #alert{level=Level,description=Desc,where={?FILE, ?LINE}}).
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index d91e2a89a0..173c53709b 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -34,7 +34,7 @@
-export([security_parameters/3, suite_definition/1,
decipher/5, cipher/5,
- suite/1, suites/1, anonymous_suites/0,
+ suite/1, suites/1, anonymous_suites/0, psk_suites/1, srp_suites/0,
openssl_suite/1, openssl_suite_name/1, filter/2,
hash_algorithm/1, sign_algorithm/1]).
@@ -215,6 +215,56 @@ anonymous_suites() ->
?TLS_DH_anon_WITH_AES_256_CBC_SHA256].
%%--------------------------------------------------------------------
+-spec psk_suites(tls_version()) -> [cipher_suite()].
+%%
+%% Description: Returns a list of the PSK cipher suites, only supported
+%% if explicitly set by user.
+%%--------------------------------------------------------------------
+psk_suites({3, N}) ->
+ psk_suites(N);
+
+psk_suites(N)
+ when N >= 3 ->
+ psk_suites(0) ++
+ [?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
+ ?TLS_PSK_WITH_AES_128_CBC_SHA256];
+
+psk_suites(_) ->
+ [?TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_PSK_WITH_RC4_128_SHA,
+ ?TLS_RSA_PSK_WITH_RC4_128_SHA,
+ ?TLS_PSK_WITH_RC4_128_SHA].
+
+%%--------------------------------------------------------------------
+-spec srp_suites() -> [cipher_suite()].
+%%
+%% Description: Returns a list of the SRP cipher suites, only supported
+%% if explicitly set by user.
+%%--------------------------------------------------------------------
+srp_suites() ->
+ [?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
+
+%%--------------------------------------------------------------------
-spec suite_definition(cipher_suite()) -> int_cipher_suite().
%%
%% Description: Return erlang cipher suite definition.
@@ -297,7 +347,84 @@ suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) ->
suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA256) ->
{dh_anon, aes_128_cbc, sha256, default_prf};
suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA256) ->
- {dh_anon, aes_256_cbc, sha256, default_prf}.
+ {dh_anon, aes_256_cbc, sha256, default_prf};
+
+%%% PSK Cipher Suites RFC 4279
+
+suite_definition(?TLS_PSK_WITH_RC4_128_SHA) ->
+ {psk, rc4_128, sha, default_prf};
+suite_definition(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ {psk, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA) ->
+ {psk, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA) ->
+ {psk, aes_256_cbc, sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_RC4_128_SHA) ->
+ {dhe_psk, rc4_128, sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ {dhe_psk, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA) ->
+ {dhe_psk, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA) ->
+ {dhe_psk, aes_256_cbc, sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_RC4_128_SHA) ->
+ {rsa_psk, rc4_128, sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ {rsa_psk, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA) ->
+ {rsa_psk, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA) ->
+ {rsa_psk, aes_256_cbc, sha, default_prf};
+
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+
+suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA256) ->
+ {psk, aes_128_cbc, sha256, default_prf};
+suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA384) ->
+ {psk, aes_256_cbc, sha384, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256) ->
+ {dhe_psk, aes_128_cbc, sha256, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384) ->
+ {dhe_psk, aes_256_cbc, sha384, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256) ->
+ {rsa_psk, aes_128_cbc, sha256, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384) ->
+ {rsa_psk, aes_256_cbc, sha384, default_prf};
+
+suite_definition(?TLS_PSK_WITH_NULL_SHA256) ->
+ {psk, null, sha256, default_prf};
+suite_definition(?TLS_PSK_WITH_NULL_SHA384) ->
+ {psk, null, sha384, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA256) ->
+ {dhe_psk, null, sha256, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA384) ->
+ {dhe_psk, null, sha384, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA256) ->
+ {rsa_psk, null, sha256, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA384) ->
+ {rsa_psk, null, sha384, default_prf};
+
+%%% SRP Cipher Suites RFC 5054
+
+suite_definition(?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA) ->
+ {srp_anon, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ {srp_rsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) ->
+ {srp_dss, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_SRP_SHA_WITH_AES_128_CBC_SHA) ->
+ {srp_anon, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) ->
+ {srp_rsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) ->
+ {srp_dss, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) ->
+ {srp_anon, aes_256_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
+ {srp_rsa, aes_256_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
+ {srp_dss, aes_256_cbc, sha, default_prf}.
+
%%--------------------------------------------------------------------
-spec suite(erl_cipher_suite()) -> cipher_suite().
@@ -370,7 +497,83 @@ suite({dhe_rsa, aes_256_cbc, sha256}) ->
suite({dh_anon, aes_128_cbc, sha256}) ->
?TLS_DH_anon_WITH_AES_128_CBC_SHA256;
suite({dh_anon, aes_256_cbc, sha256}) ->
- ?TLS_DH_anon_WITH_AES_256_CBC_SHA256.
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA256;
+
+%%% PSK Cipher Suites RFC 4279
+
+suite({psk, rc4_128,sha}) ->
+ ?TLS_PSK_WITH_RC4_128_SHA;
+suite({psk, '3des_ede_cbc',sha}) ->
+ ?TLS_PSK_WITH_3DES_EDE_CBC_SHA;
+suite({psk, aes_128_cbc,sha}) ->
+ ?TLS_PSK_WITH_AES_128_CBC_SHA;
+suite({psk, aes_256_cbc,sha}) ->
+ ?TLS_PSK_WITH_AES_256_CBC_SHA;
+suite({dhe_psk, rc4_128,sha}) ->
+ ?TLS_DHE_PSK_WITH_RC4_128_SHA;
+suite({dhe_psk, '3des_ede_cbc',sha}) ->
+ ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA;
+suite({dhe_psk, aes_128_cbc,sha}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA;
+suite({dhe_psk, aes_256_cbc,sha}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA;
+suite({rsa_psk, rc4_128,sha}) ->
+ ?TLS_RSA_PSK_WITH_RC4_128_SHA;
+suite({rsa_psk, '3des_ede_cbc',sha}) ->
+ ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA;
+suite({rsa_psk, aes_128_cbc,sha}) ->
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA;
+suite({rsa_psk, aes_256_cbc,sha}) ->
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA;
+
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+
+suite({psk, aes_128_cbc, sha256}) ->
+ ?TLS_PSK_WITH_AES_128_CBC_SHA256;
+suite({psk, aes_256_cbc, sha384}) ->
+ ?TLS_PSK_WITH_AES_256_CBC_SHA384;
+suite({dhe_psk, aes_128_cbc, sha256}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256;
+suite({dhe_psk, aes_256_cbc, sha384}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384;
+suite({rsa_psk, aes_128_cbc, sha256}) ->
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256;
+suite({rsa_psk, aes_256_cbc, sha384}) ->
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384;
+
+suite({psk, null, sha256}) ->
+ ?TLS_PSK_WITH_NULL_SHA256;
+suite({psk, null, sha384}) ->
+ ?TLS_PSK_WITH_NULL_SHA384;
+suite({dhe_psk, null, sha256}) ->
+ ?TLS_DHE_PSK_WITH_NULL_SHA256;
+suite({dhe_psk, null, sha384}) ->
+ ?TLS_DHE_PSK_WITH_NULL_SHA384;
+suite({rsa_psk, null, sha256}) ->
+ ?TLS_RSA_PSK_WITH_NULL_SHA256;
+suite({rsa_psk, null, sha384}) ->
+ ?TLS_RSA_PSK_WITH_NULL_SHA384;
+
+%%% SRP Cipher Suites RFC 5054
+
+suite({srp_anon, '3des_ede_cbc', sha}) ->
+ ?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA;
+suite({srp_rsa, '3des_ede_cbc', sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
+suite({srp_dss, '3des_ede_cbc', sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
+suite({srp_anon, aes_128_cbc, sha}) ->
+ ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA;
+suite({srp_rsa, aes_128_cbc, sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
+suite({srp_dss, aes_128_cbc, sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
+suite({srp_anon, aes_256_cbc, sha}) ->
+ ?TLS_SRP_SHA_WITH_AES_256_CBC_SHA;
+suite({srp_rsa, aes_256_cbc, sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
+suite({srp_dss, aes_256_cbc, sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA.
%%--------------------------------------------------------------------
-spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
@@ -415,7 +618,24 @@ openssl_suite("RC4-MD5") ->
openssl_suite("EDH-RSA-DES-CBC-SHA") ->
?TLS_DHE_RSA_WITH_DES_CBC_SHA;
openssl_suite("DES-CBC-SHA") ->
- ?TLS_RSA_WITH_DES_CBC_SHA.
+ ?TLS_RSA_WITH_DES_CBC_SHA;
+
+%%% SRP Cipher Suites RFC 5054
+
+openssl_suite("SRP-DSS-AES-256-CBC-SHA") ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
+openssl_suite("SRP-RSA-AES-256-CBC-SHA") ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
+openssl_suite("SRP-DSS-3DES-EDE-CBC-SHA") ->
+ ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("SRP-RSA-3DES-EDE-CBC-SHA") ->
+ ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("SRP-DSS-AES-128-CBC-SHA") ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
+openssl_suite("SRP-RSA-AES-128-CBC-SHA") ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA.
+
+
%%--------------------------------------------------------------------
-spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite().
%%
@@ -469,6 +689,33 @@ openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) ->
"DHE-DSS-AES256-SHA256";
openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) ->
"DHE-RSA-AES256-SHA256";
+
+%%% PSK Cipher Suites RFC 4279
+
+openssl_suite_name(?TLS_PSK_WITH_AES_256_CBC_SHA) ->
+ "PSK-AES256-CBC-SHA";
+openssl_suite_name(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ "PSK-3DES-EDE-CBC-SHA";
+openssl_suite_name(?TLS_PSK_WITH_AES_128_CBC_SHA) ->
+ "PSK-AES128-CBC-SHA";
+openssl_suite_name(?TLS_PSK_WITH_RC4_128_SHA) ->
+ "PSK-RC4-SHA";
+
+%%% SRP Cipher Suites RFC 5054
+
+openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "SRP-RSA-3DES-EDE-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) ->
+ "SRP-DSS-3DES-EDE-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) ->
+ "SRP-RSA-AES-128-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) ->
+ "SRP-DSS-AES-128-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
+ "SRP-RSA-AES-256-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
+ "SRP-DSS-AES-256-CBC-SHA";
+
%% No oppenssl name
openssl_suite_name(Cipher) ->
suite_definition(Cipher).
@@ -605,14 +852,14 @@ hash_size(md5) ->
16;
hash_size(sha) ->
20;
+hash_size(sha224) ->
+ 28;
hash_size(sha256) ->
- 32.
-%% Currently no supported cipher suites defaults to sha384 or sha512
-%% so these clauses are not needed at the moment.
-%% hash_size(sha384) ->
-%% 48;
-%% hash_size(sha512) ->
-%% 64.
+ 32;
+hash_size(sha384) ->
+ 48;
+hash_size(sha512) ->
+ 64.
%% RFC 5246: 6.2.3.2. CBC Block Cipher
%%
@@ -702,7 +949,8 @@ next_iv(Bin, IV) ->
NextIV.
rsa_signed_suites() ->
- dhe_rsa_suites() ++ rsa_suites().
+ dhe_rsa_suites() ++ rsa_suites() ++
+ psk_rsa_suites() ++ srp_rsa_suites().
dhe_rsa_suites() ->
[?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
@@ -712,6 +960,19 @@ dhe_rsa_suites() ->
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_RSA_WITH_DES_CBC_SHA].
+psk_rsa_suites() ->
+ [?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_RC4_128_SHA].
+
+srp_rsa_suites() ->
+ [?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA].
+
rsa_suites() ->
[?TLS_RSA_WITH_AES_256_CBC_SHA256,
?TLS_RSA_WITH_AES_256_CBC_SHA,
@@ -723,7 +984,7 @@ rsa_suites() ->
?TLS_RSA_WITH_DES_CBC_SHA].
dsa_signed_suites() ->
- dhe_dss_suites().
+ dhe_dss_suites() ++ srp_dss_suites().
dhe_dss_suites() ->
[?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
@@ -733,6 +994,11 @@ dhe_dss_suites() ->
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA].
+srp_dss_suites() ->
+ [?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
+
filter_rsa(OtpCert, RsaCiphers) ->
TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
TBSExtensions = TBSCert#'OTPTBSCertificate'.extensions,
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index 0f439f8ed5..90d3704efd 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -250,4 +250,109 @@
%% hello extension data as they should.
-define(TLS_EMPTY_RENEGOTIATION_INFO_SCSV, <<?BYTE(16#00), ?BYTE(16#FF)>>).
+%%% PSK Cipher Suites RFC 4279
+
+%% TLS_PSK_WITH_RC4_128_SHA = { 0x00, 0x8A };
+-define(TLS_PSK_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#8A)>>).
+
+%% TLS_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x8B };
+-define(TLS_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8B)>>).
+
+%% TLS_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x8C };
+-define(TLS_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8C)>>).
+
+%% TLS_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x8D };
+-define(TLS_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8D)>>).
+
+%% TLS_DHE_PSK_WITH_RC4_128_SHA = { 0x00, 0x8E };
+-define(TLS_DHE_PSK_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#8E)>>).
+
+%% TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x8F };
+-define(TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8F)>>).
+
+%% TLS_DHE_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x90 };
+-define(TLS_DHE_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#90)>>).
+
+%% TLS_DHE_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x91 };
+-define(TLS_DHE_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#91)>>).
+
+%% TLS_RSA_PSK_WITH_RC4_128_SHA = { 0x00, 0x92 };
+-define(TLS_RSA_PSK_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#92)>>).
+
+%% TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x93 };
+-define(TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#93)>>).
+
+%% TLS_RSA_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x94 };
+-define(TLS_RSA_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#94)>>).
+
+%% TLS_RSA_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x95 };
+-define(TLS_RSA_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#95)>>).
+
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+
+%% TLS_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xAE};
+-define(TLS_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#AE)>>).
+
+%% TLS_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xAF};
+-define(TLS_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#00), ?BYTE(16#AF)>>).
+
+%% TLS_PSK_WITH_NULL_SHA256 = {0x00,0xB0};
+-define(TLS_PSK_WITH_NULL_SHA256, <<?BYTE(16#00), ?BYTE(16#B0)>>).
+
+%% TLS_PSK_WITH_NULL_SHA384 = {0x00,0xB1};
+-define(TLS_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B1)>>).
+
+%% TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xB2};
+-define(TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#B2)>>).
+
+%% TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xB3};
+-define(TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#00), ?BYTE(16#B3)>>).
+
+%% TLS_DHE_PSK_WITH_NULL_SHA256 = {0x00,0xB4};
+-define(TLS_DHE_PSK_WITH_NULL_SHA256, <<?BYTE(16#00), ?BYTE(16#B4)>>).
+
+%% TLS_DHE_PSK_WITH_NULL_SHA384 = {0x00,0xB5};
+-define(TLS_DHE_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B5)>>).
+
+%% TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xB6};
+-define(TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#B6)>>).
+
+%% TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xB7};
+-define(TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#00), ?BYTE(16#B7)>>).
+
+%% TLS_RSA_PSK_WITH_NULL_SHA256 = {0x00,0xB8};
+-define(TLS_RSA_PSK_WITH_NULL_SHA256, <<?BYTE(16#00), ?BYTE(16#B8)>>).
+
+%% TLS_RSA_PSK_WITH_NULL_SHA384 = {0x00,0xB9};
+-define(TLS_RSA_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B9)>>).
+
+%%% SRP Cipher Suites RFC 5054
+
+%% TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1A };
+-define(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1A)>>).
+
+%% TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1B };
+-define(TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1B)>>).
+
+%% TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1C };
+-define(TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1C)>>).
+
+%% TLS_SRP_SHA_WITH_AES_128_CBC_SHA = { 0xC0,0x1D };
+-define(TLS_SRP_SHA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1D)>>).
+
+%% TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = { 0xC0,0x1E };
+-define(TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1E)>>).
+
+%% TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = { 0xC0,0x1F };
+-define(TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1F)>>).
+
+%% TLS_SRP_SHA_WITH_AES_256_CBC_SHA = { 0xC0,0x20 };
+-define(TLS_SRP_SHA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#20)>>).
+
+%% TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = { 0xC0,0x21 };
+-define(TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#21)>>).
+
+%% TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = { 0xC0,0x22 };
+-define(TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#22)>>).
+
-endif. % -ifdef(ssl_cipher).
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 4f241ecc0a..1843377582 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -34,6 +34,8 @@
-include("ssl_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_internal.hrl").
+-include("ssl_srp.hrl").
+-include("ssl_srp_primes.hrl").
-include_lib("public_key/include/public_key.hrl").
%% Internal application API
@@ -80,6 +82,9 @@
private_key, % PKIX: #'RSAPrivateKey'{}
diffie_hellman_params, % PKIX: #'DHParameter'{} relevant for server side
diffie_hellman_keys, % {PublicKey, PrivateKey}
+ psk_identity, % binary() - server psk identity hint
+ srp_params, % #srp_user{}
+ srp_keys, % {PublicKey, PrivateKey}
premaster_secret, %
file_ref_db, % ets()
cert_db_ref, % ref()
@@ -528,7 +533,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 == dh_anon;
+ Alg == psk; Alg == dhe_psk; Alg == rsa_psk;
+ Alg == srp_dss; Alg == srp_rsa; Alg == srp_anon ->
case handle_server_key(KeyExchangeMsg, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
@@ -545,6 +552,45 @@ certify(#certificate_request{}, State0) ->
{Record, State} = next_record(State0#state{client_certificate_requested = true}),
next_state(certify, certify, Record, State);
+%% PSK and RSA_PSK might bypass the Server-Key-Exchange
+certify(#server_hello_done{},
+ #state{session = #session{master_secret = undefined},
+ negotiated_version = Version,
+ psk_identity = PSKIdentity,
+ premaster_secret = undefined,
+ role = client,
+ key_algorithm = Alg} = State0)
+ when Alg == psk ->
+ case server_psk_master_secret(PSKIdentity, State0) of
+ #state{} = State ->
+ client_certify_and_key_exchange(State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify(#server_hello_done{},
+ #state{session = #session{master_secret = undefined},
+ ssl_options = SslOpts,
+ negotiated_version = Version,
+ psk_identity = PSKIdentity,
+ premaster_secret = undefined,
+ role = client,
+ key_algorithm = Alg} = State0)
+ when Alg == rsa_psk ->
+ case handle_psk_identity(PSKIdentity, SslOpts#ssl_options.user_lookup_fun) of
+ {ok, PSK} when is_binary(PSK) ->
+ PremasterSecret = make_premaster_secret(Version, rsa),
+ Len = byte_size(PSK),
+ RealPMS = <<?UINT16(48), PremasterSecret/binary, ?UINT16(Len), PSK/binary>>,
+ State1 = State0#state{premaster_secret = PremasterSecret},
+ State = master_from_premaster_secret(RealPMS, State1),
+ client_certify_and_key_exchange(State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end;
+
%% Master secret was determined with help of server-key exchange msg
certify(#server_hello_done{},
#state{session = #session{master_secret = MasterSecret} = Session,
@@ -631,6 +677,60 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl
next_state(certify, cipher, Record, State);
#alert{} = Alert ->
handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify_client_key_exchange(#client_psk_identity{identity = ClientPSKIdentity},
+ #state{negotiated_version = Version} = State0) ->
+ case server_psk_master_secret(ClientPSKIdentity, State0) of
+ #state{} = State1 ->
+ {Record, State} = next_record(State1),
+ next_state(certify, cipher, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify_client_key_exchange(#client_dhe_psk_identity{
+ identity = ClientPSKIdentity,
+ dh_public = ClientPublicDhKey},
+ #state{negotiated_version = Version,
+ diffie_hellman_params = #'DHParameter'{prime = P,
+ base = G},
+ diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) ->
+ case dhe_psk_master_secret(ClientPSKIdentity, crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ #state{} = State1 ->
+ {Record, State} = next_record(State1),
+ next_state(certify, cipher, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify_client_key_exchange(#client_rsa_psk_identity{
+ identity = PskIdentity,
+ exchange_keys =
+ #encrypted_premaster_secret{premaster_secret= EncPMS}},
+ #state{negotiated_version = Version,
+ private_key = Key} = State0) ->
+ PremasterSecret = ssl_handshake:decrypt_premaster_secret(EncPMS, Key),
+ case server_rsa_psk_master_secret(PskIdentity, PremasterSecret, State0) of
+ #state{} = State1 ->
+ {Record, State} = next_record(State1),
+ next_state(certify, cipher, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify_client_key_exchange(#client_srp_public{srp_a = ClientPublicKey},
+ #state{negotiated_version = Version,
+ srp_params =
+ #srp_user{prime = Prime,
+ verifier = Verifier}
+ } = State0) ->
+ case server_srp_master_secret(Verifier, Prime, ClientPublicKey, State0) of
+ #state{} = State1 ->
+ {Record, State} = next_record(State1),
+ next_state(certify, cipher, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
end.
%%--------------------------------------------------------------------
@@ -1446,7 +1546,8 @@ server_hello_done(#state{transport_cb = Transport,
State#state{connection_states = ConnectionStates,
tls_handshake_history = Handshake}.
-certify_server(#state{key_algorithm = dh_anon} = State) ->
+certify_server(#state{key_algorithm = Algo} = State)
+ when Algo == dh_anon; Algo == psk; Algo == dhe_psk ->
State;
certify_server(#state{transport_cb = Transport,
@@ -1501,6 +1602,128 @@ key_exchange(#state{role = server, key_algorithm = Algo,
diffie_hellman_keys = Keys,
tls_handshake_history = Handshake};
+key_exchange(#state{role = server, key_algorithm = psk,
+ ssl_options = #ssl_options{psk_identity = undefined}} = State) ->
+ State;
+key_exchange(#state{role = server, key_algorithm = psk,
+ ssl_options = #ssl_options{psk_identity = PskIdentityHint},
+ hashsign_algorithm = HashSignAlgo,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State) ->
+ ConnectionState =
+ ssl_record:pending_connection_state(ConnectionStates0, read),
+ SecParams = ConnectionState#connection_state.security_parameters,
+ #security_parameters{client_random = ClientRandom,
+ server_random = ServerRandom} = SecParams,
+ Msg = ssl_handshake:key_exchange(server, Version, {psk, PskIdentityHint,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = server, key_algorithm = dhe_psk,
+ ssl_options = #ssl_options{psk_identity = PskIdentityHint},
+ hashsign_algorithm = HashSignAlgo,
+ diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State) ->
+ Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
+ ConnectionState =
+ ssl_record:pending_connection_state(ConnectionStates0, read),
+ SecParams = ConnectionState#connection_state.security_parameters,
+ #security_parameters{client_random = ClientRandom,
+ server_random = ServerRandom} = SecParams,
+ Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, Keys, Params,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ diffie_hellman_keys = Keys,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = server, key_algorithm = rsa_psk,
+ ssl_options = #ssl_options{psk_identity = undefined}} = State) ->
+ State;
+key_exchange(#state{role = server, key_algorithm = rsa_psk,
+ ssl_options = #ssl_options{psk_identity = PskIdentityHint},
+ hashsign_algorithm = HashSignAlgo,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State) ->
+ ConnectionState =
+ ssl_record:pending_connection_state(ConnectionStates0, read),
+ SecParams = ConnectionState#connection_state.security_parameters,
+ #security_parameters{client_random = ClientRandom,
+ server_random = ServerRandom} = SecParams,
+ Msg = ssl_handshake:key_exchange(server, Version, {psk, PskIdentityHint,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = server, key_algorithm = Algo,
+ ssl_options = #ssl_options{user_lookup_fun = LookupFun},
+ hashsign_algorithm = HashSignAlgo,
+ session = #session{srp_username = Username},
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State)
+ when Algo == srp_dss;
+ Algo == srp_rsa;
+ Algo == srp_anon ->
+ SrpParams = handle_srp_identity(Username, LookupFun),
+ Keys = case generate_srp_server_keys(SrpParams, 0) of
+ Alert = #alert{} ->
+ throw(Alert);
+ Keys0 = {_,_} ->
+ Keys0
+ end,
+ ConnectionState =
+ ssl_record:pending_connection_state(ConnectionStates0, read),
+ SecParams = ConnectionState#connection_state.security_parameters,
+ #security_parameters{client_random = ClientRandom,
+ server_random = ServerRandom} = SecParams,
+ Msg = ssl_handshake:key_exchange(server, Version, {srp, Keys, SrpParams,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ srp_params = SrpParams,
+ srp_keys = Keys,
+ tls_handshake_history = Handshake};
+
key_exchange(#state{role = client,
connection_states = ConnectionStates0,
key_algorithm = rsa,
@@ -1530,6 +1753,68 @@ key_exchange(#state{role = client,
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = client,
+ ssl_options = SslOpts,
+ connection_states = ConnectionStates0,
+ key_algorithm = psk,
+ negotiated_version = Version,
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State) ->
+ Msg = ssl_handshake:key_exchange(client, Version, {psk, SslOpts#ssl_options.psk_identity}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = client,
+ ssl_options = SslOpts,
+ connection_states = ConnectionStates0,
+ key_algorithm = dhe_psk,
+ negotiated_version = Version,
+ diffie_hellman_keys = {DhPubKey, _},
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State) ->
+ Msg = ssl_handshake:key_exchange(client, Version, {dhe_psk, SslOpts#ssl_options.psk_identity, DhPubKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = client,
+ ssl_options = SslOpts,
+ connection_states = ConnectionStates0,
+ key_algorithm = rsa_psk,
+ public_key_info = PublicKeyInfo,
+ negotiated_version = Version,
+ premaster_secret = PremasterSecret,
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State) ->
+ Msg = rsa_psk_key_exchange(Version, SslOpts#ssl_options.psk_identity, PremasterSecret, PublicKeyInfo),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = client,
+ connection_states = ConnectionStates0,
+ key_algorithm = Algorithm,
+ negotiated_version = Version,
+ srp_keys = {ClientPubKey, _},
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State)
+ when Algorithm == srp_dss;
+ Algorithm == srp_rsa;
+ Algorithm == srp_anon ->
+ Msg = ssl_handshake:key_exchange(client, Version, {srp, ClientPubKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
tls_handshake_history = Handshake}.
rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
@@ -1548,6 +1833,22 @@ rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
rsa_key_exchange(_, _, _) ->
throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE)).
+rsa_psk_key_exchange(Version, PskIdentity, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
+ when Algorithm == ?rsaEncryption;
+ Algorithm == ?md2WithRSAEncryption;
+ Algorithm == ?md5WithRSAEncryption;
+ Algorithm == ?sha1WithRSAEncryption;
+ Algorithm == ?sha224WithRSAEncryption;
+ Algorithm == ?sha256WithRSAEncryption;
+ Algorithm == ?sha384WithRSAEncryption;
+ Algorithm == ?sha512WithRSAEncryption
+ ->
+ ssl_handshake:key_exchange(client, Version,
+ {psk_premaster_secret, PskIdentity, PremasterSecret,
+ PublicKeyInfo});
+rsa_psk_key_exchange(_, _, _, _) ->
+ throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE)).
+
request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer},
connection_states = ConnectionStates0,
cert_db = CertDbHandle,
@@ -1666,7 +1967,23 @@ verify_server_key(#server_key_params{params = Params,
server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDhKey},
State) ->
- dh_master_secret(P, G, ServerPublicDhKey, undefined, State).
+ dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
+
+server_master_secret(#server_psk_params{
+ hint = IdentityHint},
+ State) ->
+ %% store for later use
+ State#state{psk_identity = IdentityHint};
+
+server_master_secret(#server_dhe_psk_params{
+ hint = IdentityHint,
+ dh_params = #server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDhKey}},
+ State) ->
+ dhe_psk_master_secret(IdentityHint, P, G, ServerPublicDhKey, undefined, State);
+
+server_master_secret(#server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B},
+ State) ->
+ client_srp_master_secret(G, N, S, B, undefined, State).
master_from_premaster_secret(PremasterSecret,
#state{session = Session,
@@ -1696,6 +2013,131 @@ dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) ->
[PMpint, GMpint]),
master_from_premaster_secret(PremasterSecret, State).
+handle_psk_identity(_PSKIdentity, LookupFun)
+ when LookupFun == undefined ->
+ error;
+handle_psk_identity(PSKIdentity, {Fun, UserState}) ->
+ Fun(psk, PSKIdentity, UserState).
+
+server_psk_master_secret(ClientPSKIdentity,
+ #state{ssl_options = SslOpts} = State) ->
+ case handle_psk_identity(ClientPSKIdentity, SslOpts#ssl_options.user_lookup_fun) of
+ {ok, PSK} when is_binary(PSK) ->
+ Len = byte_size(PSK),
+ PremasterSecret = <<?UINT16(Len), 0:(Len*8), ?UINT16(Len), PSK/binary>>,
+ master_from_premaster_secret(PremasterSecret, State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end.
+
+dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, undefined, State) ->
+ PMpint = mpint_binary(Prime),
+ GMpint = mpint_binary(Base),
+ Keys = {_, PrivateDhKey} =
+ crypto:dh_generate_key([PMpint,GMpint]),
+ dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey,
+ State#state{diffie_hellman_keys = Keys});
+
+dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey,
+ #state{ssl_options = SslOpts} = State) ->
+ case handle_psk_identity(PSKIdentity, SslOpts#ssl_options.user_lookup_fun) of
+ {ok, PSK} when is_binary(PSK) ->
+ DHSecret =
+ crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey,
+ [PMpint, GMpint]),
+ DHLen = erlang:byte_size(DHSecret),
+ Len = erlang:byte_size(PSK),
+ PremasterSecret = <<?UINT16(DHLen), DHSecret/binary, ?UINT16(Len), PSK/binary>>,
+ master_from_premaster_secret(PremasterSecret, State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end.
+
+server_rsa_psk_master_secret(PskIdentity, PremasterSecret,
+ #state{ssl_options = SslOpts} = State) ->
+ case handle_psk_identity(PskIdentity, SslOpts#ssl_options.user_lookup_fun) of
+ {ok, PSK} when is_binary(PSK) ->
+ Len = byte_size(PSK),
+ RealPMS = <<?UINT16(48), PremasterSecret/binary, ?UINT16(Len), PSK/binary>>,
+ master_from_premaster_secret(RealPMS, State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end.
+
+generate_srp_server_keys(_SrpParams, 10) ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+generate_srp_server_keys(SrpParams =
+ #srp_user{generator = Generator, prime = Prime,
+ verifier = Verifier}, N) ->
+ case crypto:srp_generate_key(Verifier, Generator, Prime, '6a') of
+ error ->
+ generate_srp_server_keys(SrpParams, N+1);
+ Keys ->
+ Keys
+ end.
+
+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
+ error ->
+ generate_srp_client_keys(Generator, Prime, N+1);
+ Keys ->
+ Keys
+ end.
+
+handle_srp_identity(Username, {Fun, UserState}) ->
+ case Fun(srp, Username, UserState) of
+ {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),
+ #srp_user{generator = Generator, prime = Prime,
+ salt = Salt, verifier = Verifier};
+ #alert{} = Alert ->
+ throw(Alert);
+ _ ->
+ throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER))
+ end.
+
+server_srp_master_secret(Verifier, Prime, 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 ->
+ master_from_premaster_secret(PremasterSecret, State)
+ end.
+
+client_srp_master_secret(_Generator, _Prime, _Salt, _ServerPub, #alert{} = Alert, _State) ->
+ Alert;
+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},
+ #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
+ error ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+ PremasterSecret ->
+ master_from_premaster_secret(PremasterSecret, State)
+ end;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end.
+
cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0),
next_state_connection(cipher, ack_connection(State#state{session = Session,
@@ -2495,19 +2937,26 @@ default_hashsign(_Version = {Major, Minor}, KeyExchange)
when Major == 3 andalso Minor >= 3 andalso
(KeyExchange == rsa orelse
KeyExchange == dhe_rsa orelse
- KeyExchange == dh_rsa) ->
+ KeyExchange == dh_rsa orelse
+ KeyExchange == srp_rsa) ->
{sha, rsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == rsa;
KeyExchange == dhe_rsa;
- KeyExchange == dh_rsa ->
+ KeyExchange == dh_rsa;
+ KeyExchange == srp_rsa ->
{md5sha, rsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == dhe_dss;
- KeyExchange == dh_dss ->
+ KeyExchange == dh_dss;
+ KeyExchange == srp_dss ->
{sha, dsa};
default_hashsign(_Version, KeyExchange)
- when KeyExchange == dh_anon ->
+ when KeyExchange == dh_anon;
+ KeyExchange == psk;
+ KeyExchange == dhe_psk;
+ KeyExchange == rsa_psk;
+ KeyExchange == srp_anon ->
{null, anon}.
start_or_recv_cancel_timer(infinity, _RecvFrom) ->
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 889d310ca8..83c0092de2 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -28,6 +28,7 @@
-include("ssl_cipher.hrl").
-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
+-include("ssl_srp.hrl").
-include_lib("public_key/include/public_key.hrl").
-export([master_secret/4, client_hello/8, server_hello/5, hello/4,
@@ -65,6 +66,7 @@ client_hello(Host, Port, ConnectionStates,
Pending = ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
Ciphers = available_suites(UserSuites, Version),
+ SRP = srp_user(SslOpts),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
@@ -76,6 +78,7 @@ client_hello(Host, Port, ConnectionStates,
renegotiation_info =
renegotiation_info(client, ConnectionStates, Renegotiation),
+ srp = SRP,
hash_signs = default_hash_signs(),
next_protocol_negotiation =
encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector, Renegotiation)
@@ -162,7 +165,8 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version,
hello(#client_hello{client_version = ClientVersion, random = Random,
cipher_suites = CipherSuites,
- renegotiation_info = Info} = Hello,
+ renegotiation_info = Info,
+ srp = SRP} = Hello,
#ssl_options{versions = Versions,
secure_renegotiate = SecureRenegotation} = SslOpts,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) ->
@@ -171,13 +175,14 @@ hello(#client_hello{client_version = ClientVersion, random = Random,
case ssl_record:is_acceptable_version(Version, Versions) of
true ->
{Type, #session{cipher_suite = CipherSuite,
- compression_method = Compression} = Session}
+ compression_method = Compression} = Session1}
= select_session(Hello, Port, Session0, Version,
SslOpts, Cache, CacheCb, Cert),
case CipherSuite of
no_suite ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY);
_ ->
+ Session = handle_srp_info(SRP, Session1),
case handle_renegotiation_info(server, Info, ConnectionStates0,
Renegotiation, SecureRenegotation,
CipherSuites) of
@@ -372,6 +377,10 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) ->
{premaster_secret, binary(), public_key_info()} |
{dh, binary()} |
{dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()},
+ binary(), binary(), private_key()} |
+ {psk, binary()} |
+ {dhe_psk, binary(), binary()} |
+ {srp, {binary(), binary()}, #srp_user{}, {HashAlgo::atom(), SignAlgo::atom()},
binary(), binary(), private_key()}) ->
#client_key_exchange{} | #server_key_exchange{}.
%%
@@ -388,6 +397,33 @@ key_exchange(client, _Version, {dh, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
dh_public = PublicKey}
};
+key_exchange(client, _Version, {psk, Identity}) ->
+ #client_key_exchange{
+ exchange_keys = #client_psk_identity{
+ identity = Identity}
+ };
+
+key_exchange(client, _Version, {dhe_psk, Identity, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
+ #client_key_exchange{
+ exchange_keys = #client_dhe_psk_identity{
+ identity = Identity,
+ dh_public = PublicKey}
+ };
+
+key_exchange(client, _Version, {psk_premaster_secret, PskIdentity, Secret, {_, PublicKey, _}}) ->
+ EncPremasterSecret =
+ encrypted_premaster_secret(Secret, PublicKey),
+ #client_key_exchange{
+ exchange_keys = #client_rsa_psk_identity{
+ identity = PskIdentity,
+ exchange_keys = EncPremasterSecret}};
+
+key_exchange(client, _Version, {srp, PublicKey}) ->
+ #client_key_exchange{
+ exchange_keys = #client_srp_public{
+ srp_a = PublicKey}
+ };
+
key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
#'DHParameter'{prime = P, base = G},
HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
@@ -396,6 +432,34 @@ key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
ServerDHParams = #server_dh_params{dh_p = PBin,
dh_g = GBin, dh_y = PublicKey},
enc_server_key_exchange(Version, ServerDHParams, HashSign,
+ ClientRandom, ServerRandom, PrivateKey);
+
+key_exchange(server, Version, {psk, PskIdentityHint,
+ HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
+ ServerPSKParams = #server_psk_params{hint = PskIdentityHint},
+ enc_server_key_exchange(Version, ServerPSKParams, HashSign,
+ ClientRandom, ServerRandom, PrivateKey);
+
+key_exchange(server, Version, {dhe_psk, PskIdentityHint, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
+ #'DHParameter'{prime = P, base = G},
+ HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
+ <<?UINT32(_), PBin/binary>> = crypto:mpint(P),
+ <<?UINT32(_), GBin/binary>> = crypto:mpint(G),
+ ServerEDHPSKParams = #server_dhe_psk_params{
+ hint = PskIdentityHint,
+ dh_params = #server_dh_params{dh_p = PBin,
+ dh_g = GBin, dh_y = PublicKey}
+ },
+ enc_server_key_exchange(Version, ServerEDHPSKParams,
+ HashSign, ClientRandom, ServerRandom, PrivateKey);
+
+key_exchange(server, Version, {srp, {PublicKey, _},
+ #srp_user{generator = Generator, prime = Prime,
+ salt = Salt},
+ HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
+ ServerSRPParams = #server_srp_params{srp_n = Prime, srp_g = Generator,
+ srp_s = Salt, srp_b = PublicKey},
+ enc_server_key_exchange(Version, ServerSRPParams, HashSign,
ClientRandom, ServerRandom, PrivateKey).
enc_server_key_exchange(Version, Params, {HashAlgo, SignAlgo},
@@ -525,7 +589,12 @@ get_tls_handshake(Version, Data, Buffer) ->
%%--------------------------------------------------------------------
-spec decode_client_key(binary(), key_algo(), tls_version()) ->
- #encrypted_premaster_secret{} | #client_diffie_hellman_public{}.
+ #encrypted_premaster_secret{}
+ | #client_diffie_hellman_public{}
+ | #client_psk_identity{}
+ | #client_dhe_psk_identity{}
+ | #client_rsa_psk_identity{}
+ | #client_srp_public{}.
%%
%% Description: Decode client_key data and return appropriate type
%%--------------------------------------------------------------------
@@ -677,6 +746,11 @@ cipher_suites(Suites, false) ->
cipher_suites(Suites, true) ->
Suites.
+srp_user(#ssl_options{srp_identity = {UserName, _}}) ->
+ #srp{username = UserName};
+srp_user(_) ->
+ undefined.
+
renegotiation_info(client, _, false) ->
#renegotiation_info{renegotiated_connection = undefined};
renegotiation_info(server, ConnectionStates, false) ->
@@ -759,6 +833,11 @@ select_next_protocol(Protocols, NextProtocolSelector) ->
Protocol
end.
+handle_srp_info(undefined, Session) ->
+ Session;
+handle_srp_info(#srp{username = Username}, Session) ->
+ Session#session{srp_username = Username}.
+
handle_renegotiation_info(_, #renegotiation_info{renegotiated_connection = ?byte(0)},
ConnectionStates, false, _, _) ->
{ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)};
@@ -941,6 +1020,7 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
DecodedExtensions = dec_hello_extensions(Extensions),
RenegotiationInfo = proplists:get_value(renegotiation_info, DecodedExtensions, undefined),
+ SRP = proplists:get_value(srp, DecodedExtensions, undefined),
HashSigns = proplists:get_value(hash_signs, DecodedExtensions, undefined),
NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, DecodedExtensions, undefined),
@@ -951,6 +1031,7 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
cipher_suites = from_2bytes(CipherSuites),
compression_methods = Comp_methods,
renegotiation_info = RenegotiationInfo,
+ srp = SRP,
hash_signs = HashSigns,
next_protocol_negotiation = NextProtocolNegotiation
};
@@ -1029,7 +1110,23 @@ dec_client_key(<<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE));
dec_client_key(<<?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
- #client_diffie_hellman_public{dh_public = DH_Y}.
+ #client_diffie_hellman_public{dh_public = DH_Y};
+dec_client_key(<<?UINT16(Len), Id:Len/binary>>,
+ ?KEY_EXCHANGE_PSK, _) ->
+ #client_psk_identity{identity = Id};
+dec_client_key(<<?UINT16(Len), Id:Len/binary,
+ ?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
+ ?KEY_EXCHANGE_DHE_PSK, _) ->
+ #client_dhe_psk_identity{identity = Id, dh_public = DH_Y};
+dec_client_key(<<?UINT16(Len), Id:Len/binary, PKEPMS/binary>>,
+ ?KEY_EXCHANGE_RSA_PSK, {3, 0}) ->
+ #client_rsa_psk_identity{identity = Id, exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}};
+dec_client_key(<<?UINT16(Len), Id:Len/binary, ?UINT16(_), PKEPMS/binary>>,
+ ?KEY_EXCHANGE_RSA_PSK, _) ->
+ #client_rsa_psk_identity{identity = Id, exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}};
+dec_client_key(<<?UINT16(ALen), A:ALen/binary>>,
+ ?KEY_EXCHANGE_SRP, _) ->
+ #client_srp_public{srp_a = A}.
dec_ske_params(Len, Keys, Version) ->
<<Params:Len/bytes, Signature/binary>> = Keys,
@@ -1064,6 +1161,41 @@ dec_server_key(<<?UINT16(PLen), P:PLen/binary,
params_bin = BinMsg,
hashsign = HashSign,
signature = Signature};
+dec_server_key(<<?UINT16(Len), PskIdentityHint:Len/binary>> = KeyStruct,
+ KeyExchange, Version)
+ when KeyExchange == ?KEY_EXCHANGE_PSK; KeyExchange == ?KEY_EXCHANGE_RSA_PSK ->
+ Params = #server_psk_params{
+ hint = PskIdentityHint},
+ {BinMsg, HashSign, Signature} = dec_ske_params(Len + 2, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
+dec_server_key(<<?UINT16(Len), IdentityHint:Len/binary,
+ ?UINT16(PLen), P:PLen/binary,
+ ?UINT16(GLen), G:GLen/binary,
+ ?UINT16(YLen), Y:YLen/binary, _/binary>> = KeyStruct,
+ ?KEY_EXCHANGE_DHE_PSK, Version) ->
+ DHParams = #server_dh_params{dh_p = P, dh_g = G, dh_y = Y},
+ Params = #server_dhe_psk_params{
+ hint = IdentityHint,
+ dh_params = DHParams},
+ {BinMsg, HashSign, Signature} = dec_ske_params(Len + PLen + GLen + YLen + 8, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
+dec_server_key(<<?UINT16(NLen), N:NLen/binary,
+ ?UINT16(GLen), G:GLen/binary,
+ ?BYTE(SLen), S:SLen/binary,
+ ?UINT16(BLen), B:BLen/binary, _/binary>> = KeyStruct,
+ ?KEY_EXCHANGE_SRP, Version) ->
+ Params = #server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B},
+ {BinMsg, HashSign, Signature} = dec_ske_params(NLen + GLen + SLen + BLen + 7, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
dec_server_key(_, _, _) ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)).
@@ -1091,6 +1223,11 @@ dec_hello_extensions(<<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info:Len/binar
dec_hello_extensions(Rest, [{renegotiation_info,
#renegotiation_info{renegotiated_connection = RenegotiateInfo}} | Acc]);
+dec_hello_extensions(<<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), SRP:SRPLen/binary, Rest/binary>>, Acc)
+ when Len == SRPLen + 2 ->
+ dec_hello_extensions(Rest, [{srp,
+ #srp{username = SRP}} | Acc]);
+
dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
ExtData:Len/binary, Rest/binary>>, Acc) ->
SignAlgoListLen = Len - 2,
@@ -1148,6 +1285,7 @@ enc_hs(#client_hello{client_version = {Major, Minor},
cipher_suites = CipherSuites,
compression_methods = CompMethods,
renegotiation_info = RenegotiationInfo,
+ srp = SRP,
hash_signs = HashSigns,
next_protocol_negotiation = NextProtocolNegotiation}, _Version) ->
SIDLength = byte_size(SessionID),
@@ -1155,7 +1293,7 @@ enc_hs(#client_hello{client_version = {Major, Minor},
CmLength = byte_size(BinCompMethods),
BinCipherSuites = list_to_binary(CipherSuites),
CsLength = byte_size(BinCipherSuites),
- Extensions0 = hello_extensions(RenegotiationInfo, NextProtocolNegotiation),
+ Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation),
Extensions1 = if
Major == 3, Minor >=3 -> Extensions0 ++ hello_extensions(HashSigns);
true -> Extensions0
@@ -1231,13 +1369,56 @@ enc_cke(#encrypted_premaster_secret{premaster_secret = PKEPMS}, _) ->
<<?UINT16(PKEPMSLen), PKEPMS/binary>>;
enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) ->
Len = byte_size(DHPublic),
- <<?UINT16(Len), DHPublic/binary>>.
+ <<?UINT16(Len), DHPublic/binary>>;
+enc_cke(#client_psk_identity{identity = undefined}, _) ->
+ Id = <<"psk_identity">>,
+ Len = byte_size(Id),
+ <<?UINT16(Len), Id/binary>>;
+enc_cke(#client_psk_identity{identity = Id}, _) ->
+ Len = byte_size(Id),
+ <<?UINT16(Len), Id/binary>>;
+enc_cke(Identity = #client_dhe_psk_identity{identity = undefined}, Version) ->
+ enc_cke(Identity#client_dhe_psk_identity{identity = <<"psk_identity">>}, Version);
+enc_cke(#client_dhe_psk_identity{identity = Id, dh_public = DHPublic}, _) ->
+ Len = byte_size(Id),
+ DHLen = byte_size(DHPublic),
+ <<?UINT16(Len), Id/binary, ?UINT16(DHLen), DHPublic/binary>>;
+enc_cke(Identity = #client_rsa_psk_identity{identity = undefined}, Version) ->
+ enc_cke(Identity#client_rsa_psk_identity{identity = <<"psk_identity">>}, Version);
+enc_cke(#client_rsa_psk_identity{identity = Id, exchange_keys = ExchangeKeys}, Version) ->
+ EncPMS = enc_cke(ExchangeKeys, Version),
+ Len = byte_size(Id),
+ <<?UINT16(Len), Id/binary, EncPMS/binary>>;
+enc_cke(#client_srp_public{srp_a = A}, _) ->
+ Len = byte_size(A),
+ <<?UINT16(Len), A/binary>>.
enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) ->
PLen = byte_size(P),
GLen = byte_size(G),
YLen = byte_size(Y),
- <<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>.
+ <<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>;
+enc_server_key(#server_psk_params{hint = PskIdentityHint}) ->
+ Len = byte_size(PskIdentityHint),
+ <<?UINT16(Len), PskIdentityHint/binary>>;
+enc_server_key(Params = #server_dhe_psk_params{hint = undefined}) ->
+ enc_server_key(Params#server_dhe_psk_params{hint = <<>>});
+enc_server_key(#server_dhe_psk_params{
+ hint = PskIdentityHint,
+ dh_params = #server_dh_params{dh_p = P, dh_g = G, dh_y = Y}}) ->
+ Len = byte_size(PskIdentityHint),
+ PLen = byte_size(P),
+ GLen = byte_size(G),
+ YLen = byte_size(Y),
+ <<?UINT16(Len), PskIdentityHint/binary,
+ ?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>;
+enc_server_key(#server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B}) ->
+ NLen = byte_size(N),
+ GLen = byte_size(G),
+ SLen = byte_size(S),
+ BLen = byte_size(B),
+ <<?UINT16(NLen), N/binary, ?UINT16(GLen), G/binary,
+ ?BYTE(SLen), S/binary, ?UINT16(BLen), B/binary>>.
enc_sign({_, anon}, _Sign, _Version) ->
<<>>;
@@ -1253,13 +1434,20 @@ enc_sign(_HashSign, Sign, _Version) ->
hello_extensions(RenegotiationInfo, NextProtocolNegotiation) ->
hello_extensions(RenegotiationInfo) ++ next_protocol_extension(NextProtocolNegotiation).
+hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation) ->
+ hello_extensions(RenegotiationInfo) ++ hello_extensions(SRP) ++ next_protocol_extension(NextProtocolNegotiation).
+
%% Renegotiation info
hello_extensions(#renegotiation_info{renegotiated_connection = undefined}) ->
[];
hello_extensions(#renegotiation_info{} = Info) ->
[Info];
+hello_extensions(#srp{} = Info) ->
+ [Info];
hello_extensions(#hash_sign_algos{} = Info) ->
- [Info].
+ [Info];
+hello_extensions(undefined) ->
+ [].
next_protocol_extension(undefined) ->
[];
@@ -1286,6 +1474,11 @@ enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest
Len = InfoLen +1,
enc_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen), Info/binary, Acc/binary>>);
+enc_hello_extensions([#srp{username = UserName} | Rest], Acc) ->
+ SRPLen = byte_size(UserName),
+ Len = SRPLen + 2,
+ enc_hello_extensions(Rest, <<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), UserName/binary, Acc/binary>>);
+
enc_hello_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Rest], Acc) ->
SignAlgoList = << <<(ssl_cipher:hash_algorithm(Hash)):8, (ssl_cipher:sign_algorithm(Sign)):8>> ||
{Hash, Sign} <- HashSignAlgos >>,
@@ -1395,6 +1588,15 @@ 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(psk) ->
+ ?KEY_EXCHANGE_PSK;
+key_exchange_alg(dhe_psk) ->
+ ?KEY_EXCHANGE_DHE_PSK;
+key_exchange_alg(rsa_psk) ->
+ ?KEY_EXCHANGE_RSA_PSK;
+key_exchange_alg(Alg)
+ when Alg == srp_rsa; Alg == srp_dss; Alg == srp_anon ->
+ ?KEY_EXCHANGE_SRP;
key_exchange_alg(_) ->
?NULL.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 2414d5b666..1fbb88f5f6 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -48,6 +48,7 @@
compression_method,
cipher_suite,
master_secret,
+ srp_username,
is_resumable,
time_stamp
}).
@@ -99,6 +100,7 @@
cipher_suites, % cipher_suites<2..2^16-1>
compression_methods, % compression_methods<1..2^8-1>,
renegotiation_info,
+ srp, % srp username to send
hash_signs, % supported combinations of hashes/signature algos
next_protocol_negotiation = undefined % [binary()]
}).
@@ -128,6 +130,10 @@
-define(KEY_EXCHANGE_RSA, 0).
-define(KEY_EXCHANGE_DIFFIE_HELLMAN, 1).
+-define(KEY_EXCHANGE_PSK, 2).
+-define(KEY_EXCHANGE_DHE_PSK, 3).
+-define(KEY_EXCHANGE_RSA_PSK, 4).
+-define(KEY_EXCHANGE_SRP, 5).
-record(server_rsa_params, {
rsa_modulus, %% opaque RSA_modulus<1..2^16-1>
@@ -139,7 +145,23 @@
dh_g, %% opaque DH_g<1..2^16-1>
dh_y %% opaque DH_Ys<1..2^16-1>
}).
-
+
+-record(server_psk_params, {
+ hint
+ }).
+
+-record(server_dhe_psk_params, {
+ hint,
+ dh_params
+ }).
+
+-record(server_srp_params, {
+ srp_n, %% opaque srp_N<1..2^16-1>
+ srp_g, %% opaque srp_g<1..2^16-1>
+ srp_s, %% opaque srp_s<1..2^8-1>
+ srp_b %% opaque srp_B<1..2^16-1>
+ }).
+
-record(server_key_exchange, {
exchange_keys
}).
@@ -209,6 +231,24 @@
dh_public
}).
+-record(client_psk_identity, {
+ identity
+ }).
+
+-record(client_dhe_psk_identity, {
+ identity,
+ dh_public
+ }).
+
+-record(client_rsa_psk_identity, {
+ identity,
+ exchange_keys
+ }).
+
+-record(client_srp_public, {
+ srp_a
+ }).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Certificate verify - RFC 4346 section 7.4.8
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -235,6 +275,15 @@
}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SRP RFC 5054 section 2.8.1.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-define(SRP_EXT, 12).
+
+-record(srp, {
+ username
+ }).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Signature Algorithms RFC 5746 section 7.4.1.4.1.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(SIGNATURE_ALGORITHMS_EXT, 13).
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index ed0dc34adf..96a1c8e1ce 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -90,6 +90,9 @@
cacertfile, % file()
dh, % der_encoded()
dhfile, % file()
+ user_lookup_fun, % server option, fun to lookup the user
+ psk_identity, % binary
+ srp_identity, % client option {User, Password}
ciphers, %
%% Local policy for the server if it want's to reuse the session
%% or not. Defaluts to allways returning true.
diff --git a/lib/ssl/src/ssl_srp.hrl b/lib/ssl/src/ssl_srp.hrl
new file mode 100644
index 0000000000..ab2be33ab2
--- /dev/null
+++ b/lib/ssl/src/ssl_srp.hrl
@@ -0,0 +1,31 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record definition for the TLS SRP protocol
+%% see RFC 5054
+%%----------------------------------------------------------------------
+
+-record(srp_user, {
+ generator :: binary(),
+ prime :: binary(),
+ salt :: binary(),
+ verifier :: binary()
+ }).
diff --git a/lib/ssl/src/ssl_srp_primes.erl b/lib/ssl/src/ssl_srp_primes.erl
new file mode 100644
index 0000000000..ca20a8d673
--- /dev/null
+++ b/lib/ssl/src/ssl_srp_primes.erl
@@ -0,0 +1,506 @@
+-module(ssl_srp_primes).
+
+-export([get_srp_params/1, check_srp_params/2]).
+
+-define(PRIME_1024, <<16#EE, 16#AF, 16#0A, 16#B9, 16#AD, 16#B3, 16#8D,
+ 16#D6, 16#9C, 16#33, 16#F8, 16#0A, 16#FA, 16#8F,
+ 16#C5, 16#E8, 16#60, 16#72, 16#61, 16#87, 16#75,
+ 16#FF, 16#3C, 16#0B, 16#9E, 16#A2, 16#31, 16#4C,
+ 16#9C, 16#25, 16#65, 16#76, 16#D6, 16#74, 16#DF,
+ 16#74, 16#96, 16#EA, 16#81, 16#D3, 16#38, 16#3B,
+ 16#48, 16#13, 16#D6, 16#92, 16#C6, 16#E0, 16#E0,
+ 16#D5, 16#D8, 16#E2, 16#50, 16#B9, 16#8B, 16#E4,
+ 16#8E, 16#49, 16#5C, 16#1D, 16#60, 16#89, 16#DA,
+ 16#D1, 16#5D, 16#C7, 16#D7, 16#B4, 16#61, 16#54,
+ 16#D6, 16#B6, 16#CE, 16#8E, 16#F4, 16#AD, 16#69,
+ 16#B1, 16#5D, 16#49, 16#82, 16#55, 16#9B, 16#29,
+ 16#7B, 16#CF, 16#18, 16#85, 16#C5, 16#29, 16#F5,
+ 16#66, 16#66, 16#0E, 16#57, 16#EC, 16#68, 16#ED,
+ 16#BC, 16#3C, 16#05, 16#72, 16#6C, 16#C0, 16#2F,
+ 16#D4, 16#CB, 16#F4, 16#97, 16#6E, 16#AA, 16#9A,
+ 16#FD, 16#51, 16#38, 16#FE, 16#83, 16#76, 16#43,
+ 16#5B, 16#9F, 16#C6, 16#1D, 16#2F, 16#C0, 16#EB,
+ 16#06, 16#E3>>).
+-define(GENERATOR_1024, <<2>>).
+
+
+-define(PRIME_1536, <<16#9D, 16#EF, 16#3C, 16#AF, 16#B9, 16#39, 16#27,
+ 16#7A, 16#B1, 16#F1, 16#2A, 16#86, 16#17, 16#A4,
+ 16#7B, 16#BB, 16#DB, 16#A5, 16#1D, 16#F4, 16#99,
+ 16#AC, 16#4C, 16#80, 16#BE, 16#EE, 16#A9, 16#61,
+ 16#4B, 16#19, 16#CC, 16#4D, 16#5F, 16#4F, 16#5F,
+ 16#55, 16#6E, 16#27, 16#CB, 16#DE, 16#51, 16#C6,
+ 16#A9, 16#4B, 16#E4, 16#60, 16#7A, 16#29, 16#15,
+ 16#58, 16#90, 16#3B, 16#A0, 16#D0, 16#F8, 16#43,
+ 16#80, 16#B6, 16#55, 16#BB, 16#9A, 16#22, 16#E8,
+ 16#DC, 16#DF, 16#02, 16#8A, 16#7C, 16#EC, 16#67,
+ 16#F0, 16#D0, 16#81, 16#34, 16#B1, 16#C8, 16#B9,
+ 16#79, 16#89, 16#14, 16#9B, 16#60, 16#9E, 16#0B,
+ 16#E3, 16#BA, 16#B6, 16#3D, 16#47, 16#54, 16#83,
+ 16#81, 16#DB, 16#C5, 16#B1, 16#FC, 16#76, 16#4E,
+ 16#3F, 16#4B, 16#53, 16#DD, 16#9D, 16#A1, 16#15,
+ 16#8B, 16#FD, 16#3E, 16#2B, 16#9C, 16#8C, 16#F5,
+ 16#6E, 16#DF, 16#01, 16#95, 16#39, 16#34, 16#96,
+ 16#27, 16#DB, 16#2F, 16#D5, 16#3D, 16#24, 16#B7,
+ 16#C4, 16#86, 16#65, 16#77, 16#2E, 16#43, 16#7D,
+ 16#6C, 16#7F, 16#8C, 16#E4, 16#42, 16#73, 16#4A,
+ 16#F7, 16#CC, 16#B7, 16#AE, 16#83, 16#7C, 16#26,
+ 16#4A, 16#E3, 16#A9, 16#BE, 16#B8, 16#7F, 16#8A,
+ 16#2F, 16#E9, 16#B8, 16#B5, 16#29, 16#2E, 16#5A,
+ 16#02, 16#1F, 16#FF, 16#5E, 16#91, 16#47, 16#9E,
+ 16#8C, 16#E7, 16#A2, 16#8C, 16#24, 16#42, 16#C6,
+ 16#F3, 16#15, 16#18, 16#0F, 16#93, 16#49, 16#9A,
+ 16#23, 16#4D, 16#CF, 16#76, 16#E3, 16#FE, 16#D1,
+ 16#35, 16#F9, 16#BB>>).
+-define(GENERATOR_1536, <<2>>).
+
+-define(PRIME_2048, <<16#AC, 16#6B, 16#DB, 16#41, 16#32, 16#4A, 16#9A,
+ 16#9B, 16#F1, 16#66, 16#DE, 16#5E, 16#13, 16#89,
+ 16#58, 16#2F, 16#AF, 16#72, 16#B6, 16#65, 16#19,
+ 16#87, 16#EE, 16#07, 16#FC, 16#31, 16#92, 16#94,
+ 16#3D, 16#B5, 16#60, 16#50, 16#A3, 16#73, 16#29,
+ 16#CB, 16#B4, 16#A0, 16#99, 16#ED, 16#81, 16#93,
+ 16#E0, 16#75, 16#77, 16#67, 16#A1, 16#3D, 16#D5,
+ 16#23, 16#12, 16#AB, 16#4B, 16#03, 16#31, 16#0D,
+ 16#CD, 16#7F, 16#48, 16#A9, 16#DA, 16#04, 16#FD,
+ 16#50, 16#E8, 16#08, 16#39, 16#69, 16#ED, 16#B7,
+ 16#67, 16#B0, 16#CF, 16#60, 16#95, 16#17, 16#9A,
+ 16#16, 16#3A, 16#B3, 16#66, 16#1A, 16#05, 16#FB,
+ 16#D5, 16#FA, 16#AA, 16#E8, 16#29, 16#18, 16#A9,
+ 16#96, 16#2F, 16#0B, 16#93, 16#B8, 16#55, 16#F9,
+ 16#79, 16#93, 16#EC, 16#97, 16#5E, 16#EA, 16#A8,
+ 16#0D, 16#74, 16#0A, 16#DB, 16#F4, 16#FF, 16#74,
+ 16#73, 16#59, 16#D0, 16#41, 16#D5, 16#C3, 16#3E,
+ 16#A7, 16#1D, 16#28, 16#1E, 16#44, 16#6B, 16#14,
+ 16#77, 16#3B, 16#CA, 16#97, 16#B4, 16#3A, 16#23,
+ 16#FB, 16#80, 16#16, 16#76, 16#BD, 16#20, 16#7A,
+ 16#43, 16#6C, 16#64, 16#81, 16#F1, 16#D2, 16#B9,
+ 16#07, 16#87, 16#17, 16#46, 16#1A, 16#5B, 16#9D,
+ 16#32, 16#E6, 16#88, 16#F8, 16#77, 16#48, 16#54,
+ 16#45, 16#23, 16#B5, 16#24, 16#B0, 16#D5, 16#7D,
+ 16#5E, 16#A7, 16#7A, 16#27, 16#75, 16#D2, 16#EC,
+ 16#FA, 16#03, 16#2C, 16#FB, 16#DB, 16#F5, 16#2F,
+ 16#B3, 16#78, 16#61, 16#60, 16#27, 16#90, 16#04,
+ 16#E5, 16#7A, 16#E6, 16#AF, 16#87, 16#4E, 16#73,
+ 16#03, 16#CE, 16#53, 16#29, 16#9C, 16#CC, 16#04,
+ 16#1C, 16#7B, 16#C3, 16#08, 16#D8, 16#2A, 16#56,
+ 16#98, 16#F3, 16#A8, 16#D0, 16#C3, 16#82, 16#71,
+ 16#AE, 16#35, 16#F8, 16#E9, 16#DB, 16#FB, 16#B6,
+ 16#94, 16#B5, 16#C8, 16#03, 16#D8, 16#9F, 16#7A,
+ 16#E4, 16#35, 16#DE, 16#23, 16#6D, 16#52, 16#5F,
+ 16#54, 16#75, 16#9B, 16#65, 16#E3, 16#72, 16#FC,
+ 16#D6, 16#8E, 16#F2, 16#0F, 16#A7, 16#11, 16#1F,
+ 16#9E, 16#4A, 16#FF, 16#73>>).
+-define(GENERATOR_2048, <<2>>).
+
+-define(PRIME_3072, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#3A, 16#D2, 16#CA, 16#FF, 16#FF,
+ 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF>>).
+-define(GENERATOR_3072, <<5>>).
+
+-define(PRIME_4096, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#21, 16#08, 16#01, 16#1A, 16#72,
+ 16#3C, 16#12, 16#A7, 16#87, 16#E6, 16#D7, 16#88,
+ 16#71, 16#9A, 16#10, 16#BD, 16#BA, 16#5B, 16#26,
+ 16#99, 16#C3, 16#27, 16#18, 16#6A, 16#F4, 16#E2,
+ 16#3C, 16#1A, 16#94, 16#68, 16#34, 16#B6, 16#15,
+ 16#0B, 16#DA, 16#25, 16#83, 16#E9, 16#CA, 16#2A,
+ 16#D4, 16#4C, 16#E8, 16#DB, 16#BB, 16#C2, 16#DB,
+ 16#04, 16#DE, 16#8E, 16#F9, 16#2E, 16#8E, 16#FC,
+ 16#14, 16#1F, 16#BE, 16#CA, 16#A6, 16#28, 16#7C,
+ 16#59, 16#47, 16#4E, 16#6B, 16#C0, 16#5D, 16#99,
+ 16#B2, 16#96, 16#4F, 16#A0, 16#90, 16#C3, 16#A2,
+ 16#23, 16#3B, 16#A1, 16#86, 16#51, 16#5B, 16#E7,
+ 16#ED, 16#1F, 16#61, 16#29, 16#70, 16#CE, 16#E2,
+ 16#D7, 16#AF, 16#B8, 16#1B, 16#DD, 16#76, 16#21,
+ 16#70, 16#48, 16#1C, 16#D0, 16#06, 16#91, 16#27,
+ 16#D5, 16#B0, 16#5A, 16#A9, 16#93, 16#B4, 16#EA,
+ 16#98, 16#8D, 16#8F, 16#DD, 16#C1, 16#86, 16#FF,
+ 16#B7, 16#DC, 16#90, 16#A6, 16#C0, 16#8F, 16#4D,
+ 16#F4, 16#35, 16#C9, 16#34, 16#06, 16#31, 16#99,
+ 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF>>).
+-define(GENERATOR_4096, <<5>>).
+
+-define(PRIME_6144, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#21, 16#08, 16#01, 16#1A, 16#72,
+ 16#3C, 16#12, 16#A7, 16#87, 16#E6, 16#D7, 16#88,
+ 16#71, 16#9A, 16#10, 16#BD, 16#BA, 16#5B, 16#26,
+ 16#99, 16#C3, 16#27, 16#18, 16#6A, 16#F4, 16#E2,
+ 16#3C, 16#1A, 16#94, 16#68, 16#34, 16#B6, 16#15,
+ 16#0B, 16#DA, 16#25, 16#83, 16#E9, 16#CA, 16#2A,
+ 16#D4, 16#4C, 16#E8, 16#DB, 16#BB, 16#C2, 16#DB,
+ 16#04, 16#DE, 16#8E, 16#F9, 16#2E, 16#8E, 16#FC,
+ 16#14, 16#1F, 16#BE, 16#CA, 16#A6, 16#28, 16#7C,
+ 16#59, 16#47, 16#4E, 16#6B, 16#C0, 16#5D, 16#99,
+ 16#B2, 16#96, 16#4F, 16#A0, 16#90, 16#C3, 16#A2,
+ 16#23, 16#3B, 16#A1, 16#86, 16#51, 16#5B, 16#E7,
+ 16#ED, 16#1F, 16#61, 16#29, 16#70, 16#CE, 16#E2,
+ 16#D7, 16#AF, 16#B8, 16#1B, 16#DD, 16#76, 16#21,
+ 16#70, 16#48, 16#1C, 16#D0, 16#06, 16#91, 16#27,
+ 16#D5, 16#B0, 16#5A, 16#A9, 16#93, 16#B4, 16#EA,
+ 16#98, 16#8D, 16#8F, 16#DD, 16#C1, 16#86, 16#FF,
+ 16#B7, 16#DC, 16#90, 16#A6, 16#C0, 16#8F, 16#4D,
+ 16#F4, 16#35, 16#C9, 16#34, 16#02, 16#84, 16#92,
+ 16#36, 16#C3, 16#FA, 16#B4, 16#D2, 16#7C, 16#70,
+ 16#26, 16#C1, 16#D4, 16#DC, 16#B2, 16#60, 16#26,
+ 16#46, 16#DE, 16#C9, 16#75, 16#1E, 16#76, 16#3D,
+ 16#BA, 16#37, 16#BD, 16#F8, 16#FF, 16#94, 16#06,
+ 16#AD, 16#9E, 16#53, 16#0E, 16#E5, 16#DB, 16#38,
+ 16#2F, 16#41, 16#30, 16#01, 16#AE, 16#B0, 16#6A,
+ 16#53, 16#ED, 16#90, 16#27, 16#D8, 16#31, 16#17,
+ 16#97, 16#27, 16#B0, 16#86, 16#5A, 16#89, 16#18,
+ 16#DA, 16#3E, 16#DB, 16#EB, 16#CF, 16#9B, 16#14,
+ 16#ED, 16#44, 16#CE, 16#6C, 16#BA, 16#CE, 16#D4,
+ 16#BB, 16#1B, 16#DB, 16#7F, 16#14, 16#47, 16#E6,
+ 16#CC, 16#25, 16#4B, 16#33, 16#20, 16#51, 16#51,
+ 16#2B, 16#D7, 16#AF, 16#42, 16#6F, 16#B8, 16#F4,
+ 16#01, 16#37, 16#8C, 16#D2, 16#BF, 16#59, 16#83,
+ 16#CA, 16#01, 16#C6, 16#4B, 16#92, 16#EC, 16#F0,
+ 16#32, 16#EA, 16#15, 16#D1, 16#72, 16#1D, 16#03,
+ 16#F4, 16#82, 16#D7, 16#CE, 16#6E, 16#74, 16#FE,
+ 16#F6, 16#D5, 16#5E, 16#70, 16#2F, 16#46, 16#98,
+ 16#0C, 16#82, 16#B5, 16#A8, 16#40, 16#31, 16#90,
+ 16#0B, 16#1C, 16#9E, 16#59, 16#E7, 16#C9, 16#7F,
+ 16#BE, 16#C7, 16#E8, 16#F3, 16#23, 16#A9, 16#7A,
+ 16#7E, 16#36, 16#CC, 16#88, 16#BE, 16#0F, 16#1D,
+ 16#45, 16#B7, 16#FF, 16#58, 16#5A, 16#C5, 16#4B,
+ 16#D4, 16#07, 16#B2, 16#2B, 16#41, 16#54, 16#AA,
+ 16#CC, 16#8F, 16#6D, 16#7E, 16#BF, 16#48, 16#E1,
+ 16#D8, 16#14, 16#CC, 16#5E, 16#D2, 16#0F, 16#80,
+ 16#37, 16#E0, 16#A7, 16#97, 16#15, 16#EE, 16#F2,
+ 16#9B, 16#E3, 16#28, 16#06, 16#A1, 16#D5, 16#8B,
+ 16#B7, 16#C5, 16#DA, 16#76, 16#F5, 16#50, 16#AA,
+ 16#3D, 16#8A, 16#1F, 16#BF, 16#F0, 16#EB, 16#19,
+ 16#CC, 16#B1, 16#A3, 16#13, 16#D5, 16#5C, 16#DA,
+ 16#56, 16#C9, 16#EC, 16#2E, 16#F2, 16#96, 16#32,
+ 16#38, 16#7F, 16#E8, 16#D7, 16#6E, 16#3C, 16#04,
+ 16#68, 16#04, 16#3E, 16#8F, 16#66, 16#3F, 16#48,
+ 16#60, 16#EE, 16#12, 16#BF, 16#2D, 16#5B, 16#0B,
+ 16#74, 16#74, 16#D6, 16#E6, 16#94, 16#F9, 16#1E,
+ 16#6D, 16#CC, 16#40, 16#24, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#FF, 16#FF, 16#FF, 16#FF>>).
+-define(GENERATOR_6144, <<5>>).
+
+-define(PRIME_8192, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#21, 16#08, 16#01, 16#1A, 16#72,
+ 16#3C, 16#12, 16#A7, 16#87, 16#E6, 16#D7, 16#88,
+ 16#71, 16#9A, 16#10, 16#BD, 16#BA, 16#5B, 16#26,
+ 16#99, 16#C3, 16#27, 16#18, 16#6A, 16#F4, 16#E2,
+ 16#3C, 16#1A, 16#94, 16#68, 16#34, 16#B6, 16#15,
+ 16#0B, 16#DA, 16#25, 16#83, 16#E9, 16#CA, 16#2A,
+ 16#D4, 16#4C, 16#E8, 16#DB, 16#BB, 16#C2, 16#DB,
+ 16#04, 16#DE, 16#8E, 16#F9, 16#2E, 16#8E, 16#FC,
+ 16#14, 16#1F, 16#BE, 16#CA, 16#A6, 16#28, 16#7C,
+ 16#59, 16#47, 16#4E, 16#6B, 16#C0, 16#5D, 16#99,
+ 16#B2, 16#96, 16#4F, 16#A0, 16#90, 16#C3, 16#A2,
+ 16#23, 16#3B, 16#A1, 16#86, 16#51, 16#5B, 16#E7,
+ 16#ED, 16#1F, 16#61, 16#29, 16#70, 16#CE, 16#E2,
+ 16#D7, 16#AF, 16#B8, 16#1B, 16#DD, 16#76, 16#21,
+ 16#70, 16#48, 16#1C, 16#D0, 16#06, 16#91, 16#27,
+ 16#D5, 16#B0, 16#5A, 16#A9, 16#93, 16#B4, 16#EA,
+ 16#98, 16#8D, 16#8F, 16#DD, 16#C1, 16#86, 16#FF,
+ 16#B7, 16#DC, 16#90, 16#A6, 16#C0, 16#8F, 16#4D,
+ 16#F4, 16#35, 16#C9, 16#34, 16#02, 16#84, 16#92,
+ 16#36, 16#C3, 16#FA, 16#B4, 16#D2, 16#7C, 16#70,
+ 16#26, 16#C1, 16#D4, 16#DC, 16#B2, 16#60, 16#26,
+ 16#46, 16#DE, 16#C9, 16#75, 16#1E, 16#76, 16#3D,
+ 16#BA, 16#37, 16#BD, 16#F8, 16#FF, 16#94, 16#06,
+ 16#AD, 16#9E, 16#53, 16#0E, 16#E5, 16#DB, 16#38,
+ 16#2F, 16#41, 16#30, 16#01, 16#AE, 16#B0, 16#6A,
+ 16#53, 16#ED, 16#90, 16#27, 16#D8, 16#31, 16#17,
+ 16#97, 16#27, 16#B0, 16#86, 16#5A, 16#89, 16#18,
+ 16#DA, 16#3E, 16#DB, 16#EB, 16#CF, 16#9B, 16#14,
+ 16#ED, 16#44, 16#CE, 16#6C, 16#BA, 16#CE, 16#D4,
+ 16#BB, 16#1B, 16#DB, 16#7F, 16#14, 16#47, 16#E6,
+ 16#CC, 16#25, 16#4B, 16#33, 16#20, 16#51, 16#51,
+ 16#2B, 16#D7, 16#AF, 16#42, 16#6F, 16#B8, 16#F4,
+ 16#01, 16#37, 16#8C, 16#D2, 16#BF, 16#59, 16#83,
+ 16#CA, 16#01, 16#C6, 16#4B, 16#92, 16#EC, 16#F0,
+ 16#32, 16#EA, 16#15, 16#D1, 16#72, 16#1D, 16#03,
+ 16#F4, 16#82, 16#D7, 16#CE, 16#6E, 16#74, 16#FE,
+ 16#F6, 16#D5, 16#5E, 16#70, 16#2F, 16#46, 16#98,
+ 16#0C, 16#82, 16#B5, 16#A8, 16#40, 16#31, 16#90,
+ 16#0B, 16#1C, 16#9E, 16#59, 16#E7, 16#C9, 16#7F,
+ 16#BE, 16#C7, 16#E8, 16#F3, 16#23, 16#A9, 16#7A,
+ 16#7E, 16#36, 16#CC, 16#88, 16#BE, 16#0F, 16#1D,
+ 16#45, 16#B7, 16#FF, 16#58, 16#5A, 16#C5, 16#4B,
+ 16#D4, 16#07, 16#B2, 16#2B, 16#41, 16#54, 16#AA,
+ 16#CC, 16#8F, 16#6D, 16#7E, 16#BF, 16#48, 16#E1,
+ 16#D8, 16#14, 16#CC, 16#5E, 16#D2, 16#0F, 16#80,
+ 16#37, 16#E0, 16#A7, 16#97, 16#15, 16#EE, 16#F2,
+ 16#9B, 16#E3, 16#28, 16#06, 16#A1, 16#D5, 16#8B,
+ 16#B7, 16#C5, 16#DA, 16#76, 16#F5, 16#50, 16#AA,
+ 16#3D, 16#8A, 16#1F, 16#BF, 16#F0, 16#EB, 16#19,
+ 16#CC, 16#B1, 16#A3, 16#13, 16#D5, 16#5C, 16#DA,
+ 16#56, 16#C9, 16#EC, 16#2E, 16#F2, 16#96, 16#32,
+ 16#38, 16#7F, 16#E8, 16#D7, 16#6E, 16#3C, 16#04,
+ 16#68, 16#04, 16#3E, 16#8F, 16#66, 16#3F, 16#48,
+ 16#60, 16#EE, 16#12, 16#BF, 16#2D, 16#5B, 16#0B,
+ 16#74, 16#74, 16#D6, 16#E6, 16#94, 16#F9, 16#1E,
+ 16#6D, 16#BE, 16#11, 16#59, 16#74, 16#A3, 16#92,
+ 16#6F, 16#12, 16#FE, 16#E5, 16#E4, 16#38, 16#77,
+ 16#7C, 16#B6, 16#A9, 16#32, 16#DF, 16#8C, 16#D8,
+ 16#BE, 16#C4, 16#D0, 16#73, 16#B9, 16#31, 16#BA,
+ 16#3B, 16#C8, 16#32, 16#B6, 16#8D, 16#9D, 16#D3,
+ 16#00, 16#74, 16#1F, 16#A7, 16#BF, 16#8A, 16#FC,
+ 16#47, 16#ED, 16#25, 16#76, 16#F6, 16#93, 16#6B,
+ 16#A4, 16#24, 16#66, 16#3A, 16#AB, 16#63, 16#9C,
+ 16#5A, 16#E4, 16#F5, 16#68, 16#34, 16#23, 16#B4,
+ 16#74, 16#2B, 16#F1, 16#C9, 16#78, 16#23, 16#8F,
+ 16#16, 16#CB, 16#E3, 16#9D, 16#65, 16#2D, 16#E3,
+ 16#FD, 16#B8, 16#BE, 16#FC, 16#84, 16#8A, 16#D9,
+ 16#22, 16#22, 16#2E, 16#04, 16#A4, 16#03, 16#7C,
+ 16#07, 16#13, 16#EB, 16#57, 16#A8, 16#1A, 16#23,
+ 16#F0, 16#C7, 16#34, 16#73, 16#FC, 16#64, 16#6C,
+ 16#EA, 16#30, 16#6B, 16#4B, 16#CB, 16#C8, 16#86,
+ 16#2F, 16#83, 16#85, 16#DD, 16#FA, 16#9D, 16#4B,
+ 16#7F, 16#A2, 16#C0, 16#87, 16#E8, 16#79, 16#68,
+ 16#33, 16#03, 16#ED, 16#5B, 16#DD, 16#3A, 16#06,
+ 16#2B, 16#3C, 16#F5, 16#B3, 16#A2, 16#78, 16#A6,
+ 16#6D, 16#2A, 16#13, 16#F8, 16#3F, 16#44, 16#F8,
+ 16#2D, 16#DF, 16#31, 16#0E, 16#E0, 16#74, 16#AB,
+ 16#6A, 16#36, 16#45, 16#97, 16#E8, 16#99, 16#A0,
+ 16#25, 16#5D, 16#C1, 16#64, 16#F3, 16#1C, 16#C5,
+ 16#08, 16#46, 16#85, 16#1D, 16#F9, 16#AB, 16#48,
+ 16#19, 16#5D, 16#ED, 16#7E, 16#A1, 16#B1, 16#D5,
+ 16#10, 16#BD, 16#7E, 16#E7, 16#4D, 16#73, 16#FA,
+ 16#F3, 16#6B, 16#C3, 16#1E, 16#CF, 16#A2, 16#68,
+ 16#35, 16#90, 16#46, 16#F4, 16#EB, 16#87, 16#9F,
+ 16#92, 16#40, 16#09, 16#43, 16#8B, 16#48, 16#1C,
+ 16#6C, 16#D7, 16#88, 16#9A, 16#00, 16#2E, 16#D5,
+ 16#EE, 16#38, 16#2B, 16#C9, 16#19, 16#0D, 16#A6,
+ 16#FC, 16#02, 16#6E, 16#47, 16#95, 16#58, 16#E4,
+ 16#47, 16#56, 16#77, 16#E9, 16#AA, 16#9E, 16#30,
+ 16#50, 16#E2, 16#76, 16#56, 16#94, 16#DF, 16#C8,
+ 16#1F, 16#56, 16#E8, 16#80, 16#B9, 16#6E, 16#71,
+ 16#60, 16#C9, 16#80, 16#DD, 16#98, 16#ED, 16#D3,
+ 16#DF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#FF>>).
+-define(GENERATOR_8192, <<19>>).
+
+get_srp_params(srp_1024) -> {?GENERATOR_1024, ?PRIME_1024};
+get_srp_params(srp_1536) -> {?GENERATOR_1536, ?PRIME_1536};
+get_srp_params(srp_2048) -> {?GENERATOR_2048, ?PRIME_2048};
+get_srp_params(srp_3072) -> {?GENERATOR_3072, ?PRIME_3072};
+get_srp_params(srp_4096) -> {?GENERATOR_4096, ?PRIME_4096};
+get_srp_params(srp_6144) -> {?GENERATOR_6144, ?PRIME_6144};
+get_srp_params(srp_8192) -> {?GENERATOR_8192, ?PRIME_8192}.
+
+check_srp_params(?GENERATOR_1024, ?PRIME_1024) -> ok;
+check_srp_params(?GENERATOR_1536, ?PRIME_1536) -> ok;
+check_srp_params(?GENERATOR_2048, ?PRIME_2048) -> ok;
+check_srp_params(?GENERATOR_3072, ?PRIME_3072) -> ok;
+check_srp_params(?GENERATOR_4096, ?PRIME_4096) -> ok;
+check_srp_params(?GENERATOR_6144, ?PRIME_6144) -> ok;
+check_srp_params(?GENERATOR_8192, ?PRIME_8192) -> ok;
+check_srp_params(_Generator, _Prime) ->
+ not_accepted.
diff --git a/lib/ssl/src/ssl_srp_primes.hrl b/lib/ssl/src/ssl_srp_primes.hrl
new file mode 100644
index 0000000000..4bd534efbf
--- /dev/null
+++ b/lib/ssl/src/ssl_srp_primes.hrl
@@ -0,0 +1 @@
+-type srp_parameters() :: srp_1024 | srp_1536 | srp_2048 | srp_3072 | srp_4096 | srp_6144 | srp_8192.
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 6b8f226a77..5cedde5d27 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -154,6 +154,10 @@ cipher_tests() ->
ciphers_dsa_signed_certs,
ciphers_dsa_signed_certs_openssl_names,
anonymous_cipher_suites,
+ psk_cipher_suites,
+ psk_with_hint_cipher_suites,
+ srp_cipher_suites,
+ srp_dsa_cipher_suites,
default_reject_anonymous].
error_handling_tests()->
@@ -1575,7 +1579,34 @@ anonymous_cipher_suites(Config) when is_list(Config) ->
Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:anonymous_suites(),
run_suites(Ciphers, Version, Config, anonymous).
-
+%%-------------------------------------------------------------------
+psk_cipher_suites() ->
+ [{doc, "Test the PSK ciphersuites WITHOUT server supplied identity hint"}].
+psk_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:psk_suites(),
+ run_suites(Ciphers, Version, Config, psk).
+%%-------------------------------------------------------------------
+psk_with_hint_cipher_suites()->
+ [{doc, "Test the PSK ciphersuites WITH server supplied identity hint"}].
+psk_with_hint_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:psk_suites(),
+ run_suites(Ciphers, Version, Config, psk_with_hint).
+%%-------------------------------------------------------------------
+srp_cipher_suites()->
+ [{doc, "Test the SRP ciphersuites"}].
+srp_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:srp_suites(),
+ run_suites(Ciphers, Version, Config, srp).
+%%-------------------------------------------------------------------
+srp_dsa_cipher_suites()->
+ [{doc, "Test the SRP DSA ciphersuites"}].
+srp_dsa_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:srp_dss_suites(),
+ run_suites(Ciphers, Version, Config, srp_dsa).
%%--------------------------------------------------------------------
default_reject_anonymous()->
[{doc,"Test that by default anonymous cipher suites are rejected "}].
@@ -3113,7 +3144,19 @@ run_suites(Ciphers, Version, Config, Type) ->
anonymous ->
%% No certs in opts!
{?config(client_opts, Config),
- ?config(server_anon, Config)}
+ ?config(server_anon, Config)};
+ psk ->
+ {?config(client_psk, Config),
+ ?config(server_psk, Config)};
+ psk_with_hint ->
+ {?config(client_psk, Config),
+ ?config(server_psk_hint, Config)};
+ srp ->
+ {?config(client_srp, Config),
+ ?config(server_srp, Config)};
+ srp_dsa ->
+ {?config(client_srp_dsa, Config),
+ ?config(server_srp_dsa, Config)}
end,
Result = lists:map(fun(Cipher) ->
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 76b302b1cb..d655d7659e 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -281,6 +281,13 @@ wait_for_result(Pid, Msg) ->
%% Unexpected
end.
+user_lookup(psk, _Identity, UserState) ->
+ {ok, UserState};
+user_lookup(srp, Username, _UserState) ->
+ Salt = ssl:random_bytes(16),
+ UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, <<"secret">>])]),
+ {ok, {srp_1024, Salt, UserPassHash}}.
+
cert_options(Config) ->
ClientCaCertFile = filename:join([?config(priv_dir, Config),
"client", "cacerts.pem"]),
@@ -307,6 +314,7 @@ cert_options(Config) ->
"badcert.pem"]),
BadKeyFile = filename:join([?config(priv_dir, Config),
"badkey.pem"]),
+ PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
[{client_opts, [{ssl_imp, new},{reuseaddr, true}]},
{client_verification_opts, [{cacertfile, ClientCaCertFile},
{certfile, ClientCertFile},
@@ -319,6 +327,24 @@ cert_options(Config) ->
{server_opts, [{ssl_imp, new},{reuseaddr, true},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
{server_anon, [{ssl_imp, new},{reuseaddr, true}, {ciphers, anonymous_suites()}]},
+ {client_psk, [{ssl_imp, new},{reuseaddr, true},
+ {psk_identity, "Test-User"},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
+ {server_psk, [{ssl_imp, new},{reuseaddr, true},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
+ {ciphers, psk_suites()}]},
+ {server_psk_hint, [{ssl_imp, new},{reuseaddr, true},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {psk_identity, "HINT"},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
+ {ciphers, psk_suites()}]},
+ {client_srp, [{ssl_imp, new},{reuseaddr, true},
+ {srp_identity, {"Test-User", "secret"}}]},
+ {server_srp, [{ssl_imp, new},{reuseaddr, true},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {user_lookup_fun, {fun user_lookup/3, undefined}},
+ {ciphers, srp_suites()}]},
{server_verification_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
@@ -356,7 +382,16 @@ make_dsa_cert(Config) ->
{verify, verify_peer}]},
{client_dsa_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ClientCaCertFile},
- {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
+ {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]},
+ {server_srp_dsa, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ServerCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {user_lookup_fun, {fun user_lookup/3, undefined}},
+ {ciphers, srp_dss_suites()}]},
+ {client_srp_dsa, [{ssl_imp, new},{reuseaddr, true},
+ {srp_identity, {"Test-User", "secret"}},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
| Config].
@@ -675,6 +710,33 @@ anonymous_suites() ->
{dh_anon, aes_128_cbc, sha},
{dh_anon, aes_256_cbc, sha}].
+psk_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}].
+
+srp_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}].
+
+srp_dss_suites() ->
+ [{srp_dss, '3des_ede_cbc', sha},
+ {srp_dss, aes_128_cbc, sha},
+ {srp_dss, aes_256_cbc, sha}].
+
pem_to_der(File) ->
{ok, PemBin} = file:read_file(File),
public_key:pem_decode(PemBin).