Add TLS exporter.
authorBen Laurie <ben@openssl.org>
Tue, 15 Nov 2011 23:50:52 +0000 (23:50 +0000)
committerBen Laurie <ben@openssl.org>
Tue, 15 Nov 2011 23:50:52 +0000 (23:50 +0000)
12 files changed:
CHANGES
apps/s_client.c
apps/s_server.c
ssl/d1_lib.c
ssl/s3_lib.c
ssl/ssl.h
ssl/ssl_err.c
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/t1_enc.c
ssl/t1_lib.c
ssl/tls1.h

diff --git a/CHANGES b/CHANGES
index 927b9e7..142dc80 100644 (file)
--- a/CHANGES
+++ b/CHANGES
      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]
 
index 5527dc2..1621a01 100644 (file)
@@ -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);
index e462c99..59e16ec 100644 (file)
@@ -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);
        }
 
index c3b77c8..a94290a 100644 (file)
@@ -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)
index a81c80d..3dcf50e 100644 (file)
@@ -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)
index 9d46d6b..ffbe611 100644 (file)
--- 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
index b899dcb..0426aaf 100644 (file)
@@ -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"},
index 14664cf..df78447 100644 (file)
@@ -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;
index e5eec19..bda365d 100644 (file)
@@ -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);
index 3452b25..b9d0dd3 100644 (file)
@@ -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)
index 473bd94..7b54dc9 100644 (file)
@@ -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)
index f443bb1..545383a 100644 (file)
@@ -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)