diff options
author | Ben Laurie <ben@openssl.org> | 2011-11-15 23:50:52 +0000 |
---|---|---|
committer | Ben Laurie <ben@openssl.org> | 2011-11-15 23:50:52 +0000 |
commit | e0af04056cafff7cbfd2f4426cd0b44700a374a4 (patch) | |
tree | a8d2b07974989368206df6302fd9d13d67aa7c92 | |
parent | 333f926d677d12e42279274c525c7b9af52ece8c (diff) | |
download | openssl-e0af04056cafff7cbfd2f4426cd0b44700a374a4.tar.gz |
Add TLS exporter.
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | apps/s_client.c | 41 | ||||
-rw-r--r-- | apps/s_server.c | 44 | ||||
-rw-r--r-- | ssl/d1_lib.c | 1 | ||||
-rw-r--r-- | ssl/s3_lib.c | 3 | ||||
-rw-r--r-- | ssl/ssl.h | 2 | ||||
-rw-r--r-- | ssl/ssl_err.c | 2 | ||||
-rw-r--r-- | ssl/ssl_lib.c | 16 | ||||
-rw-r--r-- | ssl/ssl_locl.h | 7 | ||||
-rw-r--r-- | ssl/t1_enc.c | 89 | ||||
-rw-r--r-- | ssl/t1_lib.c | 1 | ||||
-rw-r--r-- | ssl/tls1.h | 6 |
12 files changed, 212 insertions, 3 deletions
@@ -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) @@ -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) |