Add TLS exporter.
authorBen Laurie <ben@openssl.org>
Tue, 15 Nov 2011 23:51:22 +0000 (23:51 +0000)
committerBen Laurie <ben@openssl.org>
Tue, 15 Nov 2011 23:51:22 +0000 (23:51 +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 c8f8c88d192e06782fcb45bcb3676188e506e145..24d29d120697816d1aa10717d0e1364e7e955d0a 100644 (file)
--- 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]
 
index 94e03c9c000f271e9b7e04a864d9c79f9ca93f3f..0a0fcf836a01434ba2ea3b77e3ec7148bcac95c2 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 14cffa6fa9e36649bc501147d8158b05f4f7ca4c..e89b888888bf6bfc8dd642d1d03212e36cebc485 100644 (file)
@@ -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);
        }
 
index c3b77c889bd8c4417b048842ba54b9e2b6ce7148..a94290a834f70cc61d58153a65bbd4257f7cab83 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 a6778c213a119fed2f33903a945c83ec841dc9cd..6a8ef84935c5ad74ab04b1552908591057713f70 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 77a0c3c15829788cdbe61eb688ffe9d6dd15eea3..a2803e23abf5b42fcc1d2537608d7fae14c9e103 100644 (file)
--- 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
index b899dcb008d772150e27a389f32104ccc37dc614..0426aaff5fe8a96e89b6614ce5f28cef83c8e09e 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 a61cd1f0dc1179444e7f589ec4d076089270a884..d5be942144e587aa45c6867ead27a6d58fb766ab 100644 (file)
@@ -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;
index 4d6ffd9f3987f96ea33cb33e3201d7abc57608cc..48ee110d5f079b30cc47c0c16a298856ae980999 100644 (file)
@@ -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);
index 3452b25c456f0ee33235c3833e2ee6ae8bce6b72..b9d0dd3757c37b127923e1f8d24b3672abba0c3e 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 030c0c113150e999afc5813b49aa62b4deea06cc..f33a93197becfdb80fed423dcda5821822430a7a 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 f443bb13eff4edb432dce92c5bef2a490de156c4..545383a5eedf52ea3beabacabe605f72b8de8f49 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)