summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Laurie <ben@openssl.org>2011-11-15 23:51:22 +0000
committerBen Laurie <ben@openssl.org>2011-11-15 23:51:22 +0000
commitb1d7429186658934e4ca8b7913c3640ef4426e45 (patch)
treebaa81aec5fc88283adf9389c7903eab77772dddc
parent060a38a2c06145df02d04af20e31bacf30f192e2 (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 c8f8c88d19..24d29d1206 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,9 @@
Changes between 1.0.0f and 1.0.1 [xx XXX xxxx]
+ *) 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 94e03c9c00..0a0fcf836a 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 14cffa6fa9..e89b888888 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -293,6 +293,9 @@ static int cert_status_cb(SSL *s, void *arg);
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;
@@ -543,6 +546,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;
@@ -1315,6 +1320,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);
@@ -2324,6 +2340,8 @@ static int init_ssl_connection(SSL *con)
const unsigned char *next_proto_neg;
unsigned next_proto_neg_len;
#endif
+ unsigned char *exportedkeymat;
+
if ((i=SSL_accept(con)) <= 0)
{
@@ -2395,6 +2413,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 a6778c213a..6a8ef84935 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 77a0c3c158..a2803e23ab 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -2244,6 +2244,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
@@ -2498,6 +2499,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 a61cd1f0dc..d5be942144 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -176,7 +176,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)
@@ -1624,6 +1627,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 4d6ffd9f39..48ee110d5f 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -571,6 +571,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
@@ -1057,6 +1061,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 030c0c1131..f33a93197b 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)