summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Laurie <ben@openssl.org>2011-11-15 23:50:52 +0000
committerBen Laurie <ben@openssl.org>2011-11-15 23:50:52 +0000
commite0af04056cafff7cbfd2f4426cd0b44700a374a4 (patch)
treea8d2b07974989368206df6302fd9d13d67aa7c92
parent333f926d677d12e42279274c525c7b9af52ece8c (diff)
Add TLS exporter.
-rw-r--r--CHANGES3
-rw-r--r--apps/s_client.c41
-rw-r--r--apps/s_server.c44
-rw-r--r--ssl/d1_lib.c1
-rw-r--r--ssl/s3_lib.c3
-rw-r--r--ssl/ssl.h2
-rw-r--r--ssl/ssl_err.c2
-rw-r--r--ssl/ssl_lib.c16
-rw-r--r--ssl/ssl_locl.h7
-rw-r--r--ssl/t1_enc.c89
-rw-r--r--ssl/t1_lib.c1
-rw-r--r--ssl/tls1.h6
12 files changed, 212 insertions, 3 deletions
diff --git a/CHANGES b/CHANGES
index 927b9e7717..142dc80a51 100644
--- a/CHANGES
+++ b/CHANGES
@@ -198,6 +198,9 @@
security.
[Emilia Käsper <emilia.kasper@esat.kuleuven.be> (Google)]
+ *) Add TLS key material exporter from RFC 5705.
+ [Eric Rescorla]
+
*) Add DTLS-SRTP negotiation from RFC 5764.
[Eric Rescorla]
diff --git a/apps/s_client.c b/apps/s_client.c
index 5527dc2c9c..1621a0158a 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -206,6 +206,9 @@ static int c_status_req=0;
static int c_msg=0;
static int c_showcerts=0;
+static char *keymatexportlabel=NULL;
+static int keymatexportlen=20;
+
static void sc_usage(void);
static void print_stuff(BIO *berr,SSL *con,int full);
#ifndef OPENSSL_NO_TLSEXT
@@ -360,6 +363,8 @@ static void sc_usage(void)
#endif
BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n");
BIO_printf(bio_err," -use_srtp profiles - Offer SRTP key management with a colon-separated profile list");
+ BIO_printf(bio_err," -keymatexport label - Export keying material using label\n");
+ BIO_printf(bio_err," -keymatexportlen len - Export len bytes of keying material (default 20)\n");
}
#ifndef OPENSSL_NO_TLSEXT
@@ -942,6 +947,17 @@ int MAIN(int argc, char **argv)
if (--argc < 1) goto bad;
srtp_profiles = *(++argv);
}
+ else if (strcmp(*argv,"-keymatexport") == 0)
+ {
+ if (--argc < 1) goto bad;
+ keymatexportlabel= *(++argv);
+ }
+ else if (strcmp(*argv,"-keymatexportlen") == 0)
+ {
+ if (--argc < 1) goto bad;
+ keymatexportlen=atoi(*(++argv));
+ if (keymatexportlen == 0) goto bad;
+ }
else
{
BIO_printf(bio_err,"unknown option %s\n",*argv);
@@ -1900,6 +1916,7 @@ static void print_stuff(BIO *bio, SSL *s, int full)
#ifndef OPENSSL_NO_COMP
const COMP_METHOD *comp, *expansion;
#endif
+ unsigned char *exportedkeymat;
if (full)
{
@@ -2045,6 +2062,30 @@ static void print_stuff(BIO *bio, SSL *s, int full)
}
SSL_SESSION_print(bio,SSL_get_session(s));
+ if (keymatexportlabel != NULL) {
+ BIO_printf(bio, "Keying material exporter:\n");
+ BIO_printf(bio, " Label: '%s'\n", keymatexportlabel);
+ BIO_printf(bio, " Length: %i bytes\n", keymatexportlen);
+ exportedkeymat = OPENSSL_malloc(keymatexportlen);
+ if (exportedkeymat != NULL) {
+ i = SSL_export_keying_material(s, exportedkeymat,
+ keymatexportlen,
+ keymatexportlabel,
+ strlen(keymatexportlabel),
+ NULL, 0, 0);
+ if (i != keymatexportlen) {
+ BIO_printf(bio,
+ " Error: return value %i\n", i);
+ } else {
+ BIO_printf(bio, " Keying material: ");
+ for (i=0; i<keymatexportlen; i++)
+ BIO_printf(bio, "%02X",
+ exportedkeymat[i]);
+ BIO_printf(bio, "\n");
+ }
+ OPENSSL_free(exportedkeymat);
+ }
+ }
BIO_printf(bio,"---\n");
if (peer != NULL)
X509_free(peer);
diff --git a/apps/s_server.c b/apps/s_server.c
index e462c9951a..59e16ec348 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -297,6 +297,9 @@ static int no_resume_ephemeral = 0;
static int s_msg=0;
static int s_quiet=0;
+static char *keymatexportlabel=NULL;
+static int keymatexportlen=20;
+
static int hack=0;
#ifndef OPENSSL_NO_ENGINE
static char *engine_id=NULL;
@@ -548,6 +551,8 @@ static void sv_usage(void)
# endif
BIO_printf(bio_err," -use_srtp profiles - Offer SRTP key management with a colon-separated profile list");
#endif
+ BIO_printf(bio_err," -keymatexport label - Export keying material using label\n");
+ BIO_printf(bio_err," -keymatexportlen len - Export len bytes of keying material (default 20)\n");
}
static int local_argc=0;
@@ -1332,6 +1337,17 @@ int MAIN(int argc, char *argv[])
if (--argc < 1) goto bad;
srtp_profiles = *(++argv);
}
+ else if (strcmp(*argv,"-keymatexport") == 0)
+ {
+ if (--argc < 1) goto bad;
+ keymatexportlabel= *(++argv);
+ }
+ else if (strcmp(*argv,"-keymatexportlen") == 0)
+ {
+ if (--argc < 1) goto bad;
+ keymatexportlen=atoi(*(++argv));
+ if (keymatexportlen == 0) goto bad;
+ }
else
{
BIO_printf(bio_err,"unknown option %s\n",*argv);
@@ -2354,6 +2370,8 @@ static int init_ssl_connection(SSL *con)
#ifndef OPENSSL_NO_KRB5
char *client_princ;
#endif
+ unsigned char *exportedkeymat;
+
if ((i=SSL_accept(con)) <= 0)
{
@@ -2425,6 +2443,32 @@ static int init_ssl_connection(SSL *con)
#endif /* OPENSSL_NO_KRB5 */
BIO_printf(bio_s_out, "Secure Renegotiation IS%s supported\n",
SSL_get_secure_renegotiation_support(con) ? "" : " NOT");
+ if (keymatexportlabel != NULL) {
+ BIO_printf(bio_s_out, "Keying material exporter:\n");
+ BIO_printf(bio_s_out, " Label: '%s'\n", keymatexportlabel);
+ BIO_printf(bio_s_out, " Length: %i bytes\n",
+ keymatexportlen);
+ exportedkeymat = OPENSSL_malloc(keymatexportlen);
+ if (exportedkeymat != NULL) {
+ i = SSL_export_keying_material(con, exportedkeymat,
+ keymatexportlen,
+ keymatexportlabel,
+ strlen(keymatexportlabel),
+ NULL, 0, 0);
+ if (i != keymatexportlen) {
+ BIO_printf(bio_s_out,
+ " Error: return value %i\n", i);
+ } else {
+ BIO_printf(bio_s_out, " Keying material: ");
+ for (i=0; i<keymatexportlen; i++)
+ BIO_printf(bio_s_out, "%02X",
+ exportedkeymat[i]);
+ BIO_printf(bio_s_out, "\n");
+ }
+ OPENSSL_free(exportedkeymat);
+ }
+ }
+
return(1);
}
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index c3b77c889b..a94290a834 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -82,6 +82,7 @@ SSL3_ENC_METHOD DTLSv1_enc_data={
TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
tls1_alert_code,
+ tls1_export_keying_material,
};
long dtls1_default_timeout(void)
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index a81c80ddab..3dcf50efed 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -2904,6 +2904,9 @@ SSL3_ENC_METHOD SSLv3_enc_data={
SSL3_MD_CLIENT_FINISHED_CONST,4,
SSL3_MD_SERVER_FINISHED_CONST,4,
ssl3_alert_code,
+ (int (*)(SSL *, unsigned char *, unsigned int, const char *,
+ unsigned int, const unsigned char *, unsigned int,
+ int use_context))ssl_undefined_function,
};
long ssl3_default_timeout(void)
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 9d46d6b0c0..ffbe6114a4 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -2259,6 +2259,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_CHANGE_CIPHER_STATE 209
#define SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT 274
#define SSL_F_TLS1_ENC 210
+#define SSL_F_TLS1_EXPORT_KEYING_MATERIAL 312
#define SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT 275
#define SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT 276
#define SSL_F_TLS1_PRF 284
@@ -2513,6 +2514,7 @@ void ERR_load_SSL_strings(void);
#define SSL_R_TLSV1_UNRECOGNIZED_NAME 1112
#define SSL_R_TLSV1_UNSUPPORTED_EXTENSION 1110
#define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER 232
+#define SSL_R_TLS_ILLEGAL_EXPORTER_LABEL 367
#define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST 157
#define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233
#define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG 234
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index b899dcb008..0426aaff5f 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -277,6 +277,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_TLS1_CHANGE_CIPHER_STATE), "TLS1_CHANGE_CIPHER_STATE"},
{ERR_FUNC(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT), "TLS1_CHECK_SERVERHELLO_TLSEXT"},
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
+{ERR_FUNC(SSL_F_TLS1_EXPORT_KEYING_MATERIAL), "TLS1_EXPORT_KEYING_MATERIAL"},
{ERR_FUNC(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT), "TLS1_PREPARE_CLIENTHELLO_TLSEXT"},
{ERR_FUNC(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT), "TLS1_PREPARE_SERVERHELLO_TLSEXT"},
{ERR_FUNC(SSL_F_TLS1_PRF), "tls1_prf"},
@@ -534,6 +535,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
{ERR_REASON(SSL_R_TLSV1_UNRECOGNIZED_NAME),"tlsv1 unrecognized name"},
{ERR_REASON(SSL_R_TLSV1_UNSUPPORTED_EXTENSION),"tlsv1 unsupported extension"},
{ERR_REASON(SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER),"tls client cert req with anon cipher"},
+{ERR_REASON(SSL_R_TLS_ILLEGAL_EXPORTER_LABEL),"tls illegal exporter label"},
{ERR_REASON(SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST),"tls invalid ecpointformat list"},
{ERR_REASON(SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST),"tls peer did not respond with certificate list"},
{ERR_REASON(SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG),"tls rsa encrypted value length is wrong"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 14664cfe59..df784479aa 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -177,7 +177,10 @@ SSL3_ENC_METHOD ssl3_undef_enc_method={
0, /* client_finished_label_len */
NULL, /* server_finished_label */
0, /* server_finished_label_len */
- (int (*)(int))ssl_undefined_function
+ (int (*)(int))ssl_undefined_function,
+ (int (*)(SSL *, unsigned char *, unsigned int, const char *,
+ unsigned int, const unsigned char *, unsigned int,
+ int use_context))ssl_undefined_function,
};
int SSL_clear(SSL *s)
@@ -1627,6 +1630,17 @@ void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, int (*cb) (SSL *s, unsigned
# endif
#endif
+int SSL_export_keying_material(SSL *s, unsigned char *out, int olen,
+ char *label, int llen, unsigned char *p, int plen, int use_context)
+ {
+ if (s->version < TLS1_VERSION)
+ return -1;
+
+ return s->method->ssl3_enc->export_keying_material(s, out, olen, label,
+ llen, p, plen,
+ use_context);
+ }
+
static unsigned long ssl_session_hash(const SSL_SESSION *a)
{
unsigned long l;
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index e5eec19c49..bda365d323 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -569,6 +569,10 @@ typedef struct ssl3_enc_method
const char *server_finished_label;
int server_finished_label_len;
int (*alert_value)(int);
+ int (*export_keying_material)(SSL *, unsigned char *, unsigned int,
+ const char *, unsigned int,
+ const unsigned char *, unsigned int,
+ int use_context);
} SSL3_ENC_METHOD;
#ifndef OPENSSL_NO_COMP
@@ -1055,6 +1059,9 @@ int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *p);
int tls1_mac(SSL *ssl, unsigned char *md, int snd);
int tls1_generate_master_secret(SSL *s, unsigned char *out,
unsigned char *p, int len);
+int tls1_export_keying_material(SSL *s, unsigned char *out, unsigned int olen,
+ const char *label, unsigned int llen, const unsigned char *p,
+ unsigned int plen, int use_context);
int tls1_alert_code(int code);
int ssl3_alert_code(int code);
int ssl_ok(SSL *s);
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 3452b25c45..b9d0dd3757 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -1119,6 +1119,95 @@ int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
return(SSL3_MASTER_SECRET_SIZE);
}
+int tls1_export_keying_material(SSL *s, unsigned char *out, unsigned int olen,
+ const char *label, unsigned int llen, const unsigned char *context,
+ unsigned int contextlen, int use_context)
+ {
+ unsigned char *buff;
+ unsigned char *val;
+ unsigned int vallen, currentvalpos, rv;
+
+#ifdef KSSL_DEBUG
+ printf ("tls1_export_keying_material(%p, %p,%d, %s,%d, %p,%d)\n", s, out,olen, label,llen, p,plen);
+#endif /* KSSL_DEBUG */
+
+ buff = OPENSSL_malloc(olen);
+ if (buff == NULL) goto err2;
+
+ /* construct PRF arguments
+ * we construct the PRF argument ourself rather than passing separate
+ * values into the TLS PRF to ensure that the concatenation of values
+ * does not create a prohibited label.
+ */
+ vallen = llen + SSL3_RANDOM_SIZE * 2;
+ if (use_context)
+ {
+ vallen += 2 + contextlen;
+ }
+
+ val = OPENSSL_malloc(vallen);
+ if (val == NULL) goto err2;
+ currentvalpos = 0;
+ memcpy(val + currentvalpos, (unsigned char *) label, llen);
+ currentvalpos += llen;
+ memcpy(val + currentvalpos, s->s3->client_random, SSL3_RANDOM_SIZE);
+ currentvalpos += SSL3_RANDOM_SIZE;
+ memcpy(val + currentvalpos, s->s3->server_random, SSL3_RANDOM_SIZE);
+ currentvalpos += SSL3_RANDOM_SIZE;
+
+ if (use_context)
+ {
+ val[currentvalpos] = (contextlen << 8) & 0xff;
+ currentvalpos++;
+ val[currentvalpos] = contextlen & 0xff;
+ currentvalpos++;
+ if ((contextlen > 0) || (context != NULL))
+ {
+ memcpy(val + currentvalpos, context, contextlen);
+ }
+ }
+
+ /* disallow prohibited labels
+ * note that SSL3_RANDOM_SIZE > max(prohibited label len) =
+ * 15, so size of val > max(prohibited label len) = 15 and the
+ * comparisons won't have buffer overflow
+ */
+ if (bcmp(val, TLS_MD_CLIENT_FINISH_CONST,
+ TLS_MD_CLIENT_FINISH_CONST_SIZE) == 0) goto err1;
+ if (bcmp(val, TLS_MD_SERVER_FINISH_CONST,
+ TLS_MD_SERVER_FINISH_CONST_SIZE) == 0) goto err1;
+ if (bcmp(val, TLS_MD_MASTER_SECRET_CONST,
+ TLS_MD_MASTER_SECRET_CONST_SIZE) == 0) goto err1;
+ if (bcmp(val, TLS_MD_KEY_EXPANSION_CONST,
+ TLS_MD_KEY_EXPANSION_CONST_SIZE) == 0) goto err1;
+
+ tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
+ val, vallen,
+ NULL, 0,
+ NULL, 0,
+ NULL, 0,
+ NULL, 0,
+ s->session->master_key,s->session->master_key_length,
+ out,buff,olen);
+
+#ifdef KSSL_DEBUG
+ printf ("tls1_export_keying_material() complete\n");
+#endif /* KSSL_DEBUG */
+ rv = olen;
+ goto ret;
+err1:
+ SSLerr(SSL_F_TLS1_EXPORT_KEYING_MATERIAL, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL);
+ rv = 0;
+ goto ret;
+err2:
+ SSLerr(SSL_F_TLS1_EXPORT_KEYING_MATERIAL, ERR_R_MALLOC_FAILURE);
+ rv = 0;
+ret:
+ if (buff != NULL) OPENSSL_free(buff);
+ if (val != NULL) OPENSSL_free(val);
+ return(rv);
+ }
+
int tls1_alert_code(int code)
{
switch (code)
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 473bd94b3f..7b54dc9cd1 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -136,6 +136,7 @@ SSL3_ENC_METHOD TLSv1_enc_data={
TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
tls1_alert_code,
+ tls1_export_keying_material,
};
long tls1_default_timeout(void)
diff --git a/ssl/tls1.h b/ssl/tls1.h
index f443bb13ef..545383a5ee 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -262,8 +262,10 @@ extern "C" {
#define TLSEXT_MAXLEN_host_name 255
-const char *SSL_get_servername(const SSL *s, const int type) ;
-int SSL_get_servername_type(const SSL *s) ;
+const char *SSL_get_servername(const SSL *s, const int type);
+int SSL_get_servername_type(const SSL *s);
+int SSL_export_keying_material(SSL *s, unsigned char *out, int olen,
+ char *label, int llen, unsigned char *p, int plen, int use_context);
#define SSL_set_tlsext_host_name(s,name) \
SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name)