Implement the Opaque PRF Input TLS extension
authorBodo Möller <bodo@openssl.org>
Fri, 21 Sep 2007 06:54:24 +0000 (06:54 +0000)
committerBodo Möller <bodo@openssl.org>
Fri, 21 Sep 2007 06:54:24 +0000 (06:54 +0000)
(draft-rescorla-tls-opaque-prf-input-00.txt), and do some cleanups and
bugfixes on the way.  In particular, this fixes the buffer bounds
checks in ssl_add_clienthello_tlsext() and in ssl_add_serverhello_tlsext().

Note that the opaque PRF Input TLS extension is not compiled by default;
see CHANGES.

16 files changed:
CHANGES
apps/s_cb.c
apps/s_client.c
apps/s_server.c
ssl/s23_clnt.c
ssl/s3_clnt.c
ssl/s3_lib.c
ssl/ssl.h
ssl/ssl3.h
ssl/ssl_err.c
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/ssltest.c
ssl/t1_enc.c
ssl/t1_lib.c
ssl/tls1.h

diff --git a/CHANGES b/CHANGES
index 106f98f..dddc1ea 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,64 @@
 
  Changes between 0.9.8f and 0.9.9  [xx XXX xxxx]
 
+  *) Implement Opaque PRF Input TLS extension as specified in
+     draft-rescorla-tls-opaque-prf-input-00.txt.  Since this is not an
+     official specification yet and no extension type assignment by
+     IANA exists, this extension (for now) will have to be explicitly
+     enabled when building OpenSSL by providing the extension number
+     to use.  For example, specify an option
+
+         -DTLSEXT_TYPE_opaque_prf_input=0x9527
+
+     to the "config" or "Configure" script to enable the extension,
+     assuming extension number 0x9527 (which is a completely arbitrary
+     and unofficial assignment based on the MD5 hash of the Internet
+     Draft).  Note that by doing so, you potentially lose
+     interoperability with other TLS implementations since these might
+     be using the same extension number for other purposes.
+
+     SSL_set_tlsext_opaque_prf_input(ssl, src, len) is used to set the
+     opaque PRF input value to use in the handshake.  This will create
+     an interal copy of the length-'len' string at 'src', and will
+     return non-zero for success.
+
+     To get more control and flexibility, provide a callback function
+     by using
+
+          SSL_CTX_set_tlsext_opaque_prf_input_callback(ctx, cb)
+          SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(ctx, arg)
+
+     where
+
+          int (*cb)(SSL *, void *peerinput, size_t len, void *arg);
+          void *arg;
+
+     Callback function 'cb' will be called in handshakes, and is
+     expected to use SSL_set_tlsext_opaque_prf_input() as appropriate.
+     Argument 'arg' is for application purposes (the value as given to
+     SSL_CTX_set_tlsext_opaque_prf_input_callback_arg() will directly
+     be provided to the callback function).  The callback function
+     has to return non-zero to report success: usually 1 to use opaque
+     PRF input just if possible, or 2 to enforce use of the opaque PRF
+     input.  In the latter case, the library will abort the handshake
+     if opaque PRF input is not successfully negotiated.
+
+     Arguments 'peerinput' and 'len' given to the callback function
+     will always be NULL and 0 in the case of a client.  A server will
+     see the client's opaque PRF input through these variables if
+     available (NULL and 0 otherwise).  Note that if the server
+     provides an opaque PRF input, the length must be the same as the
+     length of the client's opaque PRF input.
+
+     Note that the callback function will only be called when creating
+     a new session (session resumption can resume whatever was
+     previously negotiated), and will not be called in SSL 2.0
+     handshakes; thus, SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) or
+     SSL_set_options(ssl, SSL_OP_NO_SSLv2) is especially recommended
+     for applications that need to enforce opaque PRF input.
+
+     [Bodo Moeller]
+
   *) Update ssl code to support digests other than SHA1+MD5 for handshake
      MAC. 
 
index 0366cc8..dc50ff5 100644 (file)
@@ -638,6 +638,11 @@ void MS_CALLBACK tlsext_cb(SSL *s, int client_server, int type,
                extname = "server ticket";
                break;
 
+#ifdef TLSEXT_TYPE_opaque_prf_input
+               case TLSEXT_TYPE_opaque_prf_input:
+               extname = "opaque PRF input";
+               break;
+#endif
 
                default:
                extname = "unknown";
index 44c5356..eae1287 100644 (file)
@@ -859,6 +859,11 @@ bad:
                }
 #endif /* OPENSSL_NO_KRB5  */
 /*     SSL_set_cipher_list(con,"RC4-MD5"); */
+#if 0
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       SSL_set_tlsext_opaque_prf_input(con, "Test client", 1);
+#endif
+#endif
 
 re_start:
 
@@ -1073,11 +1078,13 @@ re_start:
                        if (in_init)
                                {
                                in_init=0;
+#if 0 /* This test doesn't really work as intended (needs to be fixed) */
 #ifndef OPENSSL_NO_TLSEXT
                                if (servername != NULL && !SSL_session_reused(con))
                                        {
                                        BIO_printf(bio_c_out,"Server did %sacknowledge servername extension.\n",tlsextcbp.ack?"":"not ");
                                        }
+#endif
 #endif
                                if (sess_out)
                                        {
index 328fcaf..0cfdf6a 100644 (file)
@@ -1575,6 +1575,11 @@ static int sv_body(char *hostname, int s, unsigned char *context)
                                                 strlen((char *)context));
        }
        SSL_clear(con);
+#if 0
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       SSL_set_tlsext_opaque_prf_input(con, "Test server", 1);
+#endif
+#endif
 
        if (SSL_version(con) == DTLS1_VERSION)
                {
index 1181d05..c500a93 100644 (file)
@@ -277,6 +277,19 @@ static int ssl23_client_hello(SSL *s)
                version = SSL2_VERSION;
                }
 
+       if (version != SSL2_VERSION)
+               {
+               /* have to disable SSL 2.0 compatibility if we need TLS extensions */
+
+               if (s->tlsext_hostname != NULL)
+                       ssl2_compat = 0;
+               
+#ifdef TLSEXT_TYPE_opaque_prf_input
+               if (s->ctx->tlsext_opaque_prf_input_callback != 0 || s->tlsext_opaque_prf_input != NULL)
+                       ssl2_compat = 0;
+#endif
+               }
+
        buf=(unsigned char *)s->init_buf->data;
        if (s->state == SSL23_ST_CW_CLNT_HELLO_A)
                {
@@ -420,6 +433,12 @@ static int ssl23_client_hello(SSL *s)
                        *(p++)=0; /* Add the NULL method */
 
 #ifndef OPENSSL_NO_TLSEXT
+                       /* TLS extensions*/
+                       if (ssl_prepare_clienthello_tlsext(s) <= 0)
+                               {
+                               SSLerr(SSL_F_SSL23_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+                               return -1;
+                               }
                        if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
                                {
                                SSLerr(SSL_F_SSL23_CLIENT_HELLO,ERR_R_INTERNAL_ERROR);
index 2d1b1a5..f8f43eb 100644 (file)
@@ -656,7 +656,9 @@ int ssl3_client_hello(SSL *s)
                        }
 #endif
                *(p++)=0; /* Add the NULL method */
+
 #ifndef OPENSSL_NO_TLSEXT
+               /* TLS extensions*/
                if (ssl_prepare_clienthello_tlsext(s) <= 0)
                        {
                        SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
@@ -853,6 +855,7 @@ int ssl3_get_server_hello(SSL *s)
                s->s3->tmp.new_compression=comp;
                }
 #endif
+
 #ifndef OPENSSL_NO_TLSEXT
        /* TLS extensions*/
        if (s->version > SSL3_VERSION)
@@ -1768,7 +1771,7 @@ int ssl3_get_new_session_ticket(SSL *s)
        if (ticklen + 6 != n)
                {
                al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
-               SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
+               SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
                goto f_err;
                }
        if (s->session->tlsext_tick)
@@ -1779,7 +1782,7 @@ int ssl3_get_new_session_ticket(SSL *s)
        s->session->tlsext_tick = OPENSSL_malloc(ticklen);
        if (!s->session->tlsext_tick)
                {
-               SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
+               SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
                goto err;
                }
        memcpy(s->session->tlsext_tick, p, ticklen);
index b2d1fef..476d27a 100644 (file)
@@ -2083,6 +2083,13 @@ void ssl3_free(SSL *s)
        if(s == NULL)
            return;
 
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       if (s->s3->client_opaque_prf_input != NULL)
+               OPENSSL_free(s->s3->client_opaque_prf_input);
+       if (s->s3->server_opaque_prf_input != NULL)
+               OPENSSL_free(s->s3->server_opaque_prf_input);
+#endif
+
        ssl3_cleanup_key_block(s);
        if (s->s3->rbuf.buf != NULL)
                OPENSSL_free(s->s3->rbuf.buf);
@@ -2115,6 +2122,15 @@ void ssl3_clear(SSL *s)
        unsigned char *rp,*wp;
        size_t rlen, wlen;
 
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       if (s->s3->client_opaque_prf_input != NULL)
+               OPENSSL_free(s->s3->client_opaque_prf_input);
+       s->s3->client_opaque_prf_input = NULL;
+       if (s->s3->server_opaque_prf_input != NULL)
+               OPENSSL_free(s->s3->server_opaque_prf_input);
+       s->s3->server_opaque_prf_input = NULL;
+#endif
+
        ssl3_cleanup_key_block(s);
        if (s->s3->tmp.ca_names != NULL)
                sk_X509_NAME_pop_free(s->s3->tmp.ca_names,X509_NAME_free);
@@ -2337,11 +2353,33 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
                        SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE);
                        return 0;
                        }
-               s->options |= SSL_OP_NO_SSLv2; /* can't use extension w/ SSL 2.0 format */
                break;
        case SSL_CTRL_SET_TLSEXT_DEBUG_ARG:
                s->tlsext_debug_arg=parg;
+               ret = 1;
                break;
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT:
+               if (larg > 12288) /* actual internal limit is 2^16 for the complete hello message
+                                  * (including the cert chain and everything) */
+                       {
+                       SSLerr(SSL_F_SSL3_CTRL, SSL_R_OPAQUE_PRF_INPUT_TOO_LONG);
+                       break;
+                       }
+               if (s->tlsext_opaque_prf_input != NULL)
+                       OPENSSL_free(s->tlsext_opaque_prf_input);
+               s->tlsext_opaque_prf_input = BUF_memdup(parg, (size_t)larg);
+               if (s->tlsext_opaque_prf_input != NULL)
+                       {
+                       s->tlsext_opaque_prf_input_len = (size_t)larg;
+                       ret = 1;
+                       }
+               else
+                       s->tlsext_opaque_prf_input_len = 0;
+               break;
+#endif
+
 #endif /* !OPENSSL_NO_TLSEXT */
        default:
                break;
@@ -2562,7 +2600,15 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
                        }
                return 1;
                }
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG:
+               ctx->tlsext_opaque_prf_input_callback_arg = parg;
+               return 1;
+#endif
+
 #endif /* !OPENSSL_NO_TLSEXT */
+
        /* A Thawte special :-) */
        case SSL_CTRL_EXTRA_CHAIN_CERT:
                if (ctx->extra_certs == NULL)
@@ -2612,6 +2658,13 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
        case SSL_CTRL_SET_TLSEXT_SERVERNAME_CB:
                ctx->tlsext_servername_callback=(int (*)(SSL *,int *,void *))fp;
                break;
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB:
+               ctx->tlsext_opaque_prf_input_callback = (int (*)(SSL *,void *, size_t, void *))fp;
+               break;
+#endif
+
 #endif
        default:
                return(0);
index a2669f9..ec42280 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -799,7 +799,12 @@ struct ssl_ctx_st
        unsigned char tlsext_tick_key_name[16];
        unsigned char tlsext_tick_hmac_key[16];
        unsigned char tlsext_tick_aes_key[16];
+
+       /* draft-rescorla-tls-opaque-prf-input-00.txt information */
+       int (*tlsext_opaque_prf_input_callback)(SSL *, void *peerinput, size_t len, void *arg);
+       void *tlsext_opaque_prf_input_callback_arg;
 #endif
+
 #ifndef OPENSSL_NO_PSK
        char *psk_identity_hint;
        unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, char *identity,
@@ -1086,11 +1091,16 @@ struct ssl_st
        size_t tlsext_ellipticcurvelist_length;
        unsigned char *tlsext_ellipticcurvelist; /* our list */
 #endif /* OPENSSL_NO_EC */
+
+       /* draft-rescorla-tls-opaque-prf-input-00.txt information to be used for handshakes */
+       void *tlsext_opaque_prf_input;
+       size_t tlsext_opaque_prf_input_len;
+
        SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
 #define session_ctx initial_ctx
 #else
 #define session_ctx ctx
-#endif
+#endif /* OPENSSL_NO_TLSEXT */
        };
 
 #ifdef __cplusplus
@@ -1304,6 +1314,9 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
 #define SSL_CTRL_SET_TLSEXT_DEBUG_ARG          57
 #define SSL_CTRL_GET_TLSEXT_TICKET_KEYS                58
 #define SSL_CTRL_SET_TLSEXT_TICKET_KEYS                59
+#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT   60
+#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB        61
+#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG 62
 #endif
 
 #define SSL_session_reused(ssl) \
@@ -2009,6 +2022,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_NULL_SSL_METHOD_PASSED                    196
 #define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED           197
 #define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE             297
+#define SSL_R_OPAQUE_PRF_INPUT_TOO_LONG                         327
 #define SSL_R_PACKET_LENGTH_TOO_LONG                    198
 #define SSL_R_PARSE_TLSEXT                              227
 #define SSL_R_PATH_TOO_LONG                             270
index 0543cb2..29cd3da 100644 (file)
@@ -443,6 +443,14 @@ typedef struct ssl3_state_st
 
        int in_read_app_data;
 
+       /* Opaque PRF input as used for the current handshake.
+        * These fields are used only if TLSEXT_TYPE_opaque_prf_input is defined
+        * (otherwise, they are merely present to improve binary compatibility) */
+       void *client_opaque_prf_input;
+       size_t client_opaque_prf_input_len;
+       void *server_opaque_prf_input;
+       size_t server_opaque_prf_input_len;
+
        struct  {
                /* actually only needs to be 16+20 */
                unsigned char cert_verify_md[EVP_MAX_MD_SIZE*2];
index 18a64e9..3121e0e 100644 (file)
@@ -249,13 +249,13 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE),   "SSL_use_RSAPrivateKey_file"},
 {ERR_FUNC(SSL_F_SSL_VERIFY_CERT_CHAIN),        "SSL_VERIFY_CERT_CHAIN"},
 {ERR_FUNC(SSL_F_SSL_WRITE),    "SSL_write"},
-{ERR_FUNC(SSL_F_TLS1_CERT_VERIFY_MAC), "tls1_cert_verify_mac"},
+{ERR_FUNC(SSL_F_TLS1_CERT_VERIFY_MAC), "TLS1_CERT_VERIFY_MAC"},
 {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_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"},
+{ERR_FUNC(SSL_F_TLS1_PRF),     "TLS1_PRF"},
 {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
 {ERR_FUNC(SSL_F_WRITE_PENDING),        "WRITE_PENDING"},
 {0,NULL}
@@ -399,6 +399,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_NULL_SSL_METHOD_PASSED),"null ssl method passed"},
 {ERR_REASON(SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),"old session cipher not returned"},
 {ERR_REASON(SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE),"only tls allowed in fips mode"},
+{ERR_REASON(SSL_R_OPAQUE_PRF_INPUT_TOO_LONG),"opaque PRF input too long"},
 {ERR_REASON(SSL_R_PACKET_LENGTH_TOO_LONG),"packet length too long"},
 {ERR_REASON(SSL_R_PARSE_TLSEXT)          ,"parse tlsext"},
 {ERR_REASON(SSL_R_PATH_TOO_LONG)         ,"path too long"},
index 575cf7c..00a93ee 100644 (file)
@@ -542,6 +542,7 @@ void SSL_free(SSL *s)
        if (s->tlsext_ecpointformatlist) OPENSSL_free(s->tlsext_ecpointformatlist);
        if (s->tlsext_ellipticcurvelist) OPENSSL_free(s->tlsext_ellipticcurvelist);
 #endif /* OPENSSL_NO_EC */
+       if (s->tlsext_opaque_prf_input) OPENSSL_free(s->tlsext_opaque_prf_input);
 #endif
 
        if (s->client_CA != NULL)
index 2f8f0f8..50a8acc 100644 (file)
 #define SSL_SSLV3              0x00000002L
 #define SSL_TLSV1              SSL_SSLV3       /* for now */
 
-/* Bits for algorithm2 (handshake digests) */
+
+/* Bits for algorithm2 (handshake digests and other extra flags) */
 
 #define SSL_HANDSHAKE_MAC_MD5 0x10
 #define SSL_HANDSHAKE_MAC_SHA 0x20
 #define SSL_HANDSHAKE_MAC_GOST94 0x40
 #define SSL_HANDSHAKE_MAC_DEFAULT (SSL_HANDSHAKE_MAC_MD5 | SSL_HANDSHAKE_MAC_SHA)
 
-
 /* When adding new digest in the ssl_ciph.c and increment SSM_MD_NUM_IDX
  * make sure to update this constant too */
 #define SSL_MAX_DIGEST 4
 
-
 #define TLS1_PRF_DGST_SHIFT 8
 #define TLS1_PRF_MD5 (SSL_HANDSHAKE_MAC_MD5 << TLS1_PRF_DGST_SHIFT)
 #define TLS1_PRF_SHA1 (SSL_HANDSHAKE_MAC_SHA << TLS1_PRF_DGST_SHIFT)
 #define TLS1_PRF_GOST94 (SSL_HANDSHAKE_MAC_GOST94 << TLS1_PRF_DGST_SHIFT)
 #define TLS1_PRF (TLS1_PRF_MD5 | TLS1_PRF_SHA1)
+
+/* Stream MAC for GOST ciphersuites from cryptopro draft
+ * (currently this also goes into algorithm2) */
+#define TLS1_STREAM_MAC 0x04
+
+
+
 /*
  * Export and cipher strength information. For each cipher we have to decide
  * whether it is exportable or not. This information is likely to change
index 0be921f..83a571d 100644 (file)
@@ -422,6 +422,25 @@ static void lock_dbg_cb(int mode, int type, const char *file, int line)
                }
        }
 
+#ifdef TLSEXT_TYPE_opaque_prf_input
+struct cb_info_st { void *input; size_t len; int ret; };
+struct cb_info_st co1 = { "C", 1, 1 }; /* try to negotiate oqaque PRF input */
+struct cb_info_st co2 = { "C", 1, 2 }; /* insist on oqaque PRF input */
+struct cb_info_st so1 = { "S", 1, 1 }; /* try to negotiate oqaque PRF input */
+struct cb_info_st so2 = { "S", 1, 2 }; /* insist on oqaque PRF input */
+
+int opaque_prf_input_cb(SSL *ssl, void *peerinput, size_t len, void *arg_)
+       {
+       struct cb_info_st *arg = arg_;
+
+       if (arg == NULL)
+               return 1;
+       
+       if (!SSL_set_tlsext_opaque_prf_input(ssl, arg->input, arg->len))
+               return 0;
+       return arg->ret;
+       }
+#endif
 
 int main(int argc, char *argv[])
        {
@@ -836,6 +855,13 @@ bad:
        SSL_CTX_set_tmp_rsa_callback(s_ctx,tmp_rsa_cb);
 #endif
 
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       SSL_CTX_set_tlsext_opaque_prf_input_callback(c_ctx, opaque_prf_input_cb);
+       SSL_CTX_set_tlsext_opaque_prf_input_callback(s_ctx, opaque_prf_input_cb);
+       SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(c_ctx, &co1); /* or &co2 or NULL */
+       SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(s_ctx, &so1); /* or &so2 or NULL */
+#endif
+
        if (!SSL_CTX_use_certificate_file(s_ctx,server_cert,SSL_FILETYPE_PEM))
                {
                ERR_print_errors(bio_err);
index 80cfe44..3509f62 100644 (file)
 #include <openssl/hmac.h>
 #include <openssl/md5.h>
 
+/* seed1 through seed5 are virtually concatenated */
 static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
-                       int sec_len, unsigned char *seed, int seed_len,
+                       int sec_len,
+                       const void *seed1, int seed1_len,
+                       const void *seed2, int seed2_len,
+                       const void *seed3, int seed3_len,
+                       const void *seed4, int seed4_len,
+                       const void *seed5, int seed5_len,
                        unsigned char *out, int olen)
        {
        int chunk,n;
@@ -159,7 +165,11 @@ static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
        HMAC_CTX_init(&ctx_tmp);
        HMAC_Init_ex(&ctx,sec,sec_len,md, NULL);
        HMAC_Init_ex(&ctx_tmp,sec,sec_len,md, NULL);
-       HMAC_Update(&ctx,seed,seed_len);
+       if (seed1 != NULL) HMAC_Update(&ctx,seed1,seed1_len);
+       if (seed2 != NULL) HMAC_Update(&ctx,seed2,seed2_len);
+       if (seed3 != NULL) HMAC_Update(&ctx,seed3,seed3_len);
+       if (seed4 != NULL) HMAC_Update(&ctx,seed4,seed4_len);
+       if (seed5 != NULL) HMAC_Update(&ctx,seed5,seed5_len);
        HMAC_Final(&ctx,A1,&A1_len);
 
        n=0;
@@ -169,7 +179,11 @@ static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
                HMAC_Init_ex(&ctx_tmp,NULL,0,NULL,NULL); /* re-init */
                HMAC_Update(&ctx,A1,A1_len);
                HMAC_Update(&ctx_tmp,A1,A1_len);
-               HMAC_Update(&ctx,seed,seed_len);
+               if (seed1 != NULL) HMAC_Update(&ctx,seed1,seed1_len);
+               if (seed2 != NULL) HMAC_Update(&ctx,seed2,seed2_len);
+               if (seed3 != NULL) HMAC_Update(&ctx,seed3,seed3_len);
+               if (seed4 != NULL) HMAC_Update(&ctx,seed4,seed4_len);
+               if (seed5 != NULL) HMAC_Update(&ctx,seed5,seed5_len);
 
                if (olen > chunk)
                        {
@@ -190,9 +204,15 @@ static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
        OPENSSL_cleanse(A1,sizeof(A1));
        }
 
+/* seed1 through seed5 are virtually concatenated */
 static void tls1_PRF(long digest_mask,
-                    unsigned char *label, int label_len,
-                    const unsigned char *sec, int slen, unsigned char *out1,
+                    const void *seed1, int seed1_len,
+                    const void *seed2, int seed2_len,
+                    const void *seed3, int seed3_len,
+                    const void *seed4, int seed4_len,
+                    const void *seed5, int seed5_len,
+                    const unsigned char *sec, int slen,
+                    unsigned char *out1,
                     unsigned char *out2, int olen)
        {
        int len,i,idx,count;
@@ -200,7 +220,7 @@ static void tls1_PRF(long digest_mask,
        long m;
        const EVP_MD *md;
 
-       /* Count number of digests and divide sec evenly */
+       /* Count number of digests and partition sec evenly */
        count=0;
        for (idx=0;ssl_get_handshake_digest(idx,&m,&md);idx++) {
                if ((m<<TLS1_PRF_DGST_SHIFT) & digest_mask) count++;
@@ -215,7 +235,9 @@ static void tls1_PRF(long digest_mask,
                                SSL_R_UNSUPPORTED_DIGEST_TYPE);
                                return;                         
                        }
-                       tls1_P_hash(md ,S1,len+(slen&1),label,label_len,out2,olen);
+                       tls1_P_hash(md ,S1,len+(slen&1),
+                                   seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,seed4,seed4_len,seed5,seed5_len,
+                                   out2,olen);
                        S1+=len;
                        for (i=0; i<olen; i++)
                        {
@@ -228,20 +250,11 @@ static void tls1_PRF(long digest_mask,
 static void tls1_generate_key_block(SSL *s, unsigned char *km,
             unsigned char *tmp, int num)
        {
-       unsigned char *p;
-       unsigned char buf[SSL3_RANDOM_SIZE*2+
-               TLS_MD_MAX_CONST_SIZE];
-       p=buf;
-
-       memcpy(p,TLS_MD_KEY_EXPANSION_CONST,
-               TLS_MD_KEY_EXPANSION_CONST_SIZE);
-       p+=TLS_MD_KEY_EXPANSION_CONST_SIZE;
-       memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
-       p+=SSL3_RANDOM_SIZE;
-       memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE);
-       p+=SSL3_RANDOM_SIZE;
-
-       tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,(int)(p-buf),
+       tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
+                TLS_MD_KEY_EXPANSION_CONST,TLS_MD_KEY_EXPANSION_CONST_SIZE,
+                s->s3->server_random,SSL3_RANDOM_SIZE,
+                s->s3->client_random,SSL3_RANDOM_SIZE,
+                NULL,0,NULL,0,
                 s->session->master_key,s->session->master_key_length,
                 km,tmp,num);
 #ifdef KSSL_DEBUG
@@ -261,8 +274,7 @@ int tls1_change_cipher_state(SSL *s, int which)
        {
        static const unsigned char empty[]="";
        unsigned char *p,*key_block,*mac_secret;
-       unsigned char *exp_label,buf[TLS_MD_MAX_CONST_SIZE+
-               SSL3_RANDOM_SIZE*2];
+       unsigned char *exp_label;
        unsigned char tmp1[EVP_MAX_KEY_LENGTH];
        unsigned char tmp2[EVP_MAX_KEY_LENGTH];
        unsigned char iv1[EVP_MAX_IV_LENGTH*2];
@@ -443,29 +455,22 @@ printf("which = %04X\nmac key=",which);
                /* In here I set both the read and write key/iv to the
                 * same value since only the correct one will be used :-).
                 */
-               p=buf;
-               memcpy(p,exp_label,exp_label_len);
-               p+=exp_label_len;
-               memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE);
-               p+=SSL3_RANDOM_SIZE;
-               memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
-               p+=SSL3_RANDOM_SIZE;
-               tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,(int)(p-buf),key,j,
-                        tmp1,tmp2,EVP_CIPHER_key_length(c));
+               tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
+                        exp_label,exp_label_len,
+                        s->s3->client_random,SSL3_RANDOM_SIZE,
+                        s->s3->server_random,SSL3_RANDOM_SIZE,
+                        NULL,0,NULL,0,
+                        key,j,tmp1,tmp2,EVP_CIPHER_key_length(c));
                key=tmp1;
 
                if (k > 0)
                        {
-                       p=buf;
-                       memcpy(p,TLS_MD_IV_BLOCK_CONST,
-                               TLS_MD_IV_BLOCK_CONST_SIZE);
-                       p+=TLS_MD_IV_BLOCK_CONST_SIZE;
-                       memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE);
-                       p+=SSL3_RANDOM_SIZE;
-                       memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
-                       p+=SSL3_RANDOM_SIZE;
-                       tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,p-buf,empty,0,
-                                iv1,iv2,k*2);
+                       tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
+                                TLS_MD_IV_BLOCK_CONST,TLS_MD_IV_BLOCK_CONST_SIZE,
+                                s->s3->client_random,SSL3_RANDOM_SIZE,
+                                s->s3->server_random,SSL3_RANDOM_SIZE,
+                                NULL,0,NULL,0,
+                                empty,0,iv1,iv2,k*2);
                        if (client_write)
                                iv=iv1;
                        else
@@ -767,35 +772,51 @@ int tls1_final_finish_mac(SSL *s,
        {
        unsigned int i;
        EVP_MD_CTX ctx;
-       unsigned char buf[TLS_MD_MAX_CONST_SIZE+MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
+       unsigned char buf[2*EVP_MAX_MD_SIZE];
        unsigned char *q,buf2[12];
        int idx;
        long mask;
+       int err=0;
        const EVP_MD *md; 
 
        q=buf;
-       memcpy(q,str,slen);
-       q+=slen;
 
        EVP_MD_CTX_init(&ctx);
 
        if (s->s3->handshake_buffer) 
                ssl3_digest_cached_records(s);
 
-       for (idx=0;ssl_get_handshake_digest(idx,&mask,&md);idx++) {
-               if (mask & s->s3->tmp.new_cipher->algorithm2) {
-                       EVP_MD_CTX_copy_ex(&ctx,s->s3->handshake_dgst[idx]);
-                       EVP_DigestFinal_ex(&ctx,q,&i);
-                       q+=i;
+       for (idx=0;ssl_get_handshake_digest(idx,&mask,&md);idx++)
+               {
+               if (mask & s->s3->tmp.new_cipher->algorithm2)
+                       {
+                       int hashsize = EVP_MD_size(md);
+                       if ((size_t)hashsize > (sizeof buf - (size_t)(q-buf)))
+                               {
+                               /* internal error: 'buf' is too small for this cipersuite! */
+                               err = 1;
+                               }
+                       else
+                               {
+                               EVP_MD_CTX_copy_ex(&ctx,s->s3->handshake_dgst[idx]);
+                               EVP_DigestFinal_ex(&ctx,q,&i);
+                               if (i != hashsize) /* can't really happen */
+                                       err = 1;
+                               q+=i;
+                               }
+                       }
                }
-       }
-
-       tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,(int)(q-buf),
-               s->session->master_key,s->session->master_key_length,
-               out,buf2,sizeof buf2);
+               
+       tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
+                str,slen, buf,(int)(q-buf), NULL,0, NULL,0, NULL,0,
+                s->session->master_key,s->session->master_key_length,
+                out,buf2,sizeof buf2);
        EVP_MD_CTX_cleanup(&ctx);
 
-       return sizeof buf2;
+       if (err)
+               return 0;
+       else
+               return sizeof buf2;
        }
 
 int tls1_mac(SSL *ssl, unsigned char *md, int send)
@@ -876,23 +897,35 @@ printf("rec=");
 int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
             int len)
        {
-       unsigned char buf[SSL3_RANDOM_SIZE*2+TLS_MD_MASTER_SECRET_CONST_SIZE];
        unsigned char buff[SSL_MAX_MASTER_KEY_LENGTH];
+       const void *co = NULL, *so = NULL;
+       int col = 0, sol = NULL;
 
 #ifdef KSSL_DEBUG
        printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len);
 #endif /* KSSL_DEBUG */
 
-       /* Setup the stuff to munge */
-       memcpy(buf,TLS_MD_MASTER_SECRET_CONST,
-               TLS_MD_MASTER_SECRET_CONST_SIZE);
-       memcpy(&(buf[TLS_MD_MASTER_SECRET_CONST_SIZE]),
-               s->s3->client_random,SSL3_RANDOM_SIZE);
-       memcpy(&(buf[SSL3_RANDOM_SIZE+TLS_MD_MASTER_SECRET_CONST_SIZE]),
-               s->s3->server_random,SSL3_RANDOM_SIZE);
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       if (s->s3->client_opaque_prf_input != NULL && s->s3->server_opaque_prf_input != NULL &&
+           s->s3->client_opaque_prf_input_len > 0 &&
+           s->s3->client_opaque_prf_input_len == s->s3->server_opaque_prf_input_len)
+               {
+               co = s->s3->client_opaque_prf_input;
+               col = s->s3->server_opaque_prf_input_len;
+               so = s->s3->server_opaque_prf_input;
+               sol = s->s3->client_opaque_prf_input_len; /* must be same as col (see draft-rescorla-tls-opaque-prf-input-00.txt, section 3.1) */
+               }
+#endif
+
        tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
-               buf,TLS_MD_MASTER_SECRET_CONST_SIZE+SSL3_RANDOM_SIZE*2,p,len,
+               TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE,
+               s->s3->client_random,SSL3_RANDOM_SIZE,
+               co, col,
+               s->s3->server_random,SSL3_RANDOM_SIZE,
+               so, sol,
+               p,len,
                s->session->master_key,buff,sizeof buff);
+
 #ifdef KSSL_DEBUG
        printf ("tls1_generate_master_secret() complete\n");
 #endif /* KSSL_DEBUG */
index b5eab2c..0c78414 100644 (file)
@@ -284,8 +284,8 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                   + hostname length 
                */
                   
-               if ((lenmax = limit - p - 9) < 0 
-               || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax) 
+               if ((lenmax = limit - ret - 9) < 0 
+                   || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax) 
                        return NULL;
                        
                /* extension type and length */
@@ -300,15 +300,15 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                s2n(size_str,ret);
                memcpy(ret, s->tlsext_hostname, size_str);
                ret+=size_str;
-
                }
+
 #ifndef OPENSSL_NO_EC
        if (s->tlsext_ecpointformatlist != NULL)
                {
                /* Add TLS extension ECPointFormats to the ClientHello message */
                long lenmax; 
 
-               if ((lenmax = limit - p - 5) < 0) return NULL; 
+               if ((lenmax = limit - ret - 5) < 0) return NULL; 
                if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
                if (s->tlsext_ecpointformatlist_length > 255)
                        {
@@ -327,7 +327,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                /* Add TLS extension EllipticCurves to the ClientHello message */
                long lenmax; 
 
-               if ((lenmax = limit - p - 6) < 0) return NULL; 
+               if ((lenmax = limit - ret - 6) < 0) return NULL; 
                if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL;
                if (s->tlsext_ellipticcurvelist_length > 65532)
                        {
@@ -359,8 +359,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                /* Check for enough room 2 for extension type, 2 for len
                 * rest for ticket
                 */
-               if (limit - p - 4 - ticklen < 0)
-                       return NULL;
+               if ((long)(limit - ret - 4 - ticklen) < 0) return NULL;
                s2n(TLSEXT_TYPE_session_ticket,ret); 
                s2n(ticklen,ret);
                if (ticklen)
@@ -370,6 +369,24 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                        }
                }
 
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       if (s->s3->client_opaque_prf_input != NULL)
+               {
+               size_t col = s->s3->client_opaque_prf_input_len;
+               
+               if ((long)(limit - ret - 6 - col < 0))
+                       return NULL;
+               if (col > 0xFFFD) /* can't happen */
+                       return NULL;
+
+               s2n(TLSEXT_TYPE_opaque_prf_input, ret); 
+               s2n(col + 2, ret);
+               s2n(col, ret);
+               memcpy(ret, s->s3->client_opaque_prf_input, col);
+               ret += col;
+               }
+#endif
+
        if ((extdatalen = ret-p-2)== 0) 
                return p;
 
@@ -387,7 +404,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
 
        if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL)
                { 
-               if (limit - p - 4 < 0) return NULL; 
+               if ((long)(limit - ret - 4) < 0) return NULL; 
 
                s2n(TLSEXT_TYPE_server_name,ret);
                s2n(0,ret);
@@ -398,7 +415,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
                /* Add TLS extension ECPointFormats to the ServerHello message */
                long lenmax; 
 
-               if ((lenmax = limit - p - 5) < 0) return NULL; 
+               if ((lenmax = limit - ret - 5) < 0) return NULL; 
                if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
                if (s->tlsext_ecpointformatlist_length > 255)
                        {
@@ -419,11 +436,29 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
        if (s->tlsext_ticket_expected
                && !(SSL_get_options(s) & SSL_OP_NO_TICKET)) 
                { 
-               if (limit - p - 4 < 0) return NULL; 
+               if ((long)(limit - ret - 4) < 0) return NULL; 
                s2n(TLSEXT_TYPE_session_ticket,ret);
                s2n(0,ret);
                }
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       if (s->s3->server_opaque_prf_input != NULL)
+               {
+               size_t sol = s->s3->server_opaque_prf_input_len;
                
+               if ((long)(limit - ret - 6 - sol) < 0)
+                       return NULL;
+               if (sol > 0xFFFD) /* can't happen */
+                       return NULL;
+
+               s2n(TLSEXT_TYPE_opaque_prf_input, ret); 
+               s2n(sol + 2, ret);
+               s2n(sol, ret);
+               memcpy(ret, s->s3->server_opaque_prf_input, sol);
+               ret += sol;
+               }
+#endif
+
        if ((extdatalen = ret-p-2)== 0) 
                return p;
 
@@ -610,6 +645,35 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
 #endif
                        }
 #endif /* OPENSSL_NO_EC */
+#ifdef TLSEXT_TYPE_opaque_prf_input
+               else if (type == TLSEXT_TYPE_opaque_prf_input)
+                       {
+                       unsigned char *sdata = data;
+
+                       if (size < 2)
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               }
+                       n2s(sdata, s->s3->client_opaque_prf_input_len);
+                       if (s->s3->client_opaque_prf_input_len != size - 2)
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               }
+
+                       if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
+                               OPENSSL_free(s->s3->client_opaque_prf_input);
+
+                       s->s3->client_opaque_prf_input = BUF_memdup(sdata, s->s3->client_opaque_prf_input_len);
+                       if (s->s3->client_opaque_prf_input == NULL)
+                               {
+                               *al = TLS1_AD_INTERNAL_ERROR;
+                               return 0;
+                               }
+                       }
+#endif
+
                /* session ticket processed earlier */
                data+=size;
                }
@@ -694,6 +758,35 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                }
                        s->tlsext_ticket_expected = 1;
                        }
+#ifdef TLSEXT_TYPE_opaque_prf_input
+               else if (type == TLSEXT_TYPE_opaque_prf_input)
+                       {
+                       unsigned char *sdata = data;
+
+                       if (size < 2)
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               }
+                       n2s(sdata, s->s3->server_opaque_prf_input_len);
+                       if (s->s3->server_opaque_prf_input_len != size - 2)
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               }
+                       
+                       if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
+                               OPENSSL_free(s->s3->server_opaque_prf_input);
+                       s->s3->server_opaque_prf_input = BUF_memdup(sdata, s->s3->server_opaque_prf_input_len);
+
+                       if (s->s3->server_opaque_prf_input == NULL)
+                               {
+                               *al = TLS1_AD_INTERNAL_ERROR;
+                               return 0;
+                               }
+                       }
+#endif
+
                data+=size;             
                }
 
@@ -780,6 +873,38 @@ int ssl_prepare_clienthello_tlsext(SSL *s)
                        s2n(i,j);
                }
 #endif /* OPENSSL_NO_EC */
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       {
+               int r = 1;
+       
+               if (s->ctx->tlsext_opaque_prf_input_callback != 0)
+                       {
+                       r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
+                       if (!r)
+                               return -1;
+                       }
+
+               if (s->tlsext_opaque_prf_input != NULL)
+                       {
+                       if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
+                               OPENSSL_free(s->s3->client_opaque_prf_input);
+
+                       s->s3->client_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
+                       if (s->s3->client_opaque_prf_input == NULL)
+                               {
+                               SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+                               return -1;
+                               }
+                       s->s3->client_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
+                       }
+
+               if (r == 2)
+                       /* at callback's request, insist on receiving an appropriate server opaque PRF input */
+                       s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
+       }
+#endif
+
        return 1;
        }
 
@@ -810,6 +935,7 @@ int ssl_prepare_serverhello_tlsext(SSL *s)
                s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
                }
 #endif /* OPENSSL_NO_EC */
+
        return 1;
        }
 
@@ -832,6 +958,62 @@ int ssl_check_clienthello_tlsext(SSL *s)
        else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)             
                ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
 
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       {
+               /* This sort of belongs into ssl_prepare_serverhello_tlsext(),
+                * but we might be sending an alert in response to the client hello,
+                * so this has to happen here in ssl_check_clienthello_tlsext(). */
+
+               int r = 1;
+       
+               if (s->ctx->tlsext_opaque_prf_input_callback != 0)
+                       {
+                       r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
+                       if (!r)
+                               {
+                               ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+                               al = SSL_AD_INTERNAL_ERROR;
+                               goto err;
+                               }
+                       }
+
+               if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
+                       OPENSSL_free(s->s3->server_opaque_prf_input);
+               s->s3->server_opaque_prf_input = NULL;
+
+               if (s->tlsext_opaque_prf_input != NULL)
+                       {
+                       if (s->s3->client_opaque_prf_input != NULL &&
+                               s->s3->client_opaque_prf_input_len == s->tlsext_opaque_prf_input_len)
+                               {
+                               /* can only use this extension if we have a server opaque PRF input
+                                * of the same length as the client opaque PRF input! */
+
+                               s->s3->server_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
+                               if (s->s3->server_opaque_prf_input == NULL)
+                                       {
+                                       ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+                                       al = SSL_AD_INTERNAL_ERROR;
+                                       goto err;
+                                       }
+                               s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
+                               }
+                       }
+
+               if (r == 2 && s->s3->server_opaque_prf_input == NULL)
+                       {
+                       /* The callback wants to enforce use of the extension,
+                        * but we can't do that with the client opaque PRF input;
+                        * abort the handshake.
+                        */
+                       ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+                       al = SSL_AD_HANDSHAKE_FAILURE;
+                       }
+       }
+#endif
+
+ err:
        switch (ret)
                {
                case SSL_TLSEXT_ERR_ALERT_FATAL:
@@ -895,6 +1077,29 @@ int ssl_check_serverhello_tlsext(SSL *s)
        else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)             
                ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
 
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       if (s->s3->server_opaque_prf_input_len > 0)
+               {
+               /* This case may indicate that we, as a client, want to insist on using opaque PRF inputs.
+                * So first verify that we really have a value from the server too. */
+
+               if (s->s3->server_opaque_prf_input == NULL)
+                       {
+                       ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+                       al = SSL_AD_HANDSHAKE_FAILURE;
+                       }
+               
+               /* Anytime the server *has* sent an opaque PRF input, we need to check
+                * that we have a client opaque PRF input of the same size. */
+               if (s->s3->client_opaque_prf_input == NULL ||
+                   s->s3->client_opaque_prf_input_len != s->s3->server_opaque_prf_input_len)
+                       {
+                       ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+                       al = SSL_AD_ILLEGAL_PARAMETER;
+                       }
+               }
+#endif
+
        switch (ret)
                {
                case SSL_TLSEXT_ERR_ALERT_FATAL:
index f55ab3d..cac8d0e 100644 (file)
@@ -183,16 +183,23 @@ extern "C" {
 #define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114
 #define TLS1_AD_UNKNOWN_PSK_IDENTITY   115     /* fatal */
 
-/* ExtensionType values from RFC 3546 */
+/* ExtensionType values from RFC3546 / RFC4366 */
 #define TLSEXT_TYPE_server_name                        0
 #define TLSEXT_TYPE_max_fragment_length                1
 #define TLSEXT_TYPE_client_certificate_url     2
 #define TLSEXT_TYPE_trusted_ca_keys            3
 #define TLSEXT_TYPE_truncated_hmac             4
 #define TLSEXT_TYPE_status_request             5
+/* ExtensionType values from RFC4492 */
 #define TLSEXT_TYPE_elliptic_curves            10
 #define TLSEXT_TYPE_ec_point_formats           11
 #define TLSEXT_TYPE_session_ticket             35
+/* ExtensionType value from draft-rescorla-tls-opaque-prf-input-00.txt */
+#if 0 /* will have to be provided externally for now ,
+       * i.e. build with -DTLSEXT_TYPE_opaque_prf_input=38183
+       * using whatever extension number you'd like to try */
+# define TLSEXT_TYPE_opaque_prf_input          ?? */
+#endif
 
 /* NameType value from RFC 3546 */
 #define TLSEXT_NAMETYPE_host_name 0
@@ -235,6 +242,14 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
        SSL_CTX_ctrl((ctx),SSL_CTRL_GET_TLXEXT_TICKET_KEYS,(keylen),(keys))
 #define SSL_CTX_set_tlsext_ticket_keys(ctx, keys, keylen) \
        SSL_CTX_ctrl((ctx),SSL_CTRL_SET_TLXEXT_TICKET_KEYS,(keylen),(keys))
+
+#define SSL_set_tlsext_opaque_prf_input(s, src, len) \
+SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT, len, src)
+#define SSL_CTX_set_tlsext_opaque_prf_input_callback(ctx, cb) \
+SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB, (void (*)(void))cb)
+#define SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(ctx, arg) \
+SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG, 0, arg)
+
 #endif
 
 /* PSK ciphersuites from 4279 */
@@ -416,10 +431,6 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
 #define TLS1_TXT_DHE_RSA_WITH_SEED_SHA                  "DHE-RSA-SEED-SHA"
 #define TLS1_TXT_ADH_WITH_SEED_SHA                      "ADH-SEED-SHA"
 
-/* Flags for SSL_CIPHER.algorithm2 field */
-/* Stream MAC for GOST ciphersuites from cryptopro draft */
-#define TLS1_STREAM_MAC 0x04
-
 
 #define TLS_CT_RSA_SIGN                        1
 #define TLS_CT_DSS_SIGN                        2