Cleanup of custom extension stuff.
[openssl.git] / ssl / t1_lib.c
index 1d2615bde1a47bbb1e918e9977a466c88e3220a2..8bed38d6d4718290bb7b0ec83a115ef9bfb0ba89 100644 (file)
@@ -140,6 +140,49 @@ SSL3_ENC_METHOD TLSv1_enc_data={
        TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
        tls1_alert_code,
        tls1_export_keying_material,
+       0,
+       SSL3_HM_HEADER_LENGTH,
+       ssl3_set_handshake_header,
+       ssl3_handshake_write
+       };
+
+SSL3_ENC_METHOD TLSv1_1_enc_data={
+       tls1_enc,
+       tls1_mac,
+       tls1_setup_key_block,
+       tls1_generate_master_secret,
+       tls1_change_cipher_state,
+       tls1_final_finish_mac,
+       TLS1_FINISH_MAC_LENGTH,
+       tls1_cert_verify_mac,
+       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,
+       SSL_ENC_FLAG_EXPLICIT_IV,
+       SSL3_HM_HEADER_LENGTH,
+       ssl3_set_handshake_header,
+       ssl3_handshake_write
+       };
+
+SSL3_ENC_METHOD TLSv1_2_enc_data={
+       tls1_enc,
+       tls1_mac,
+       tls1_setup_key_block,
+       tls1_generate_master_secret,
+       tls1_change_cipher_state,
+       tls1_final_finish_mac,
+       TLS1_FINISH_MAC_LENGTH,
+       tls1_cert_verify_mac,
+       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,
+       SSL_ENC_FLAG_EXPLICIT_IV|SSL_ENC_FLAG_SIGALGS|SSL_ENC_FLAG_SHA256_PRF
+               |SSL_ENC_FLAG_TLS1_2_CIPHERS,
+       SSL3_HM_HEADER_LENGTH,
+       ssl3_set_handshake_header,
+       ssl3_handshake_write
        };
 
 long tls1_default_timeout(void)
@@ -966,8 +1009,8 @@ void ssl_set_client_disabled(SSL *s)
        int have_rsa = 0, have_dsa = 0, have_ecdsa = 0;
        c->mask_a = 0;
        c->mask_k = 0;
-       /* If less than TLS 1.2 don't allow TLS 1.2 only ciphers */
-       if (TLS1_get_client_version(s) < TLS1_2_VERSION)
+       /* Don't allow TLS 1.2 only ciphers if we don't suppport them */
+       if (!SSL_CLIENT_USE_TLS1_2_CIPHERS(s))
                c->mask_ssl = SSL_TLSV1_2;
        else
                c->mask_ssl = 0;
@@ -1053,7 +1096,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
 #ifndef OPENSSL_NO_EC
        /* See if we support any ECC ciphersuites */
        int using_ecc = 0;
-       if (s->version != DTLS1_VERSION && s->version >= TLS1_VERSION)
+       if (s->version >= TLS1_VERSION || SSL_IS_DTLS(s))
                {
                int i;
                unsigned long alg_k, alg_a;
@@ -1255,7 +1298,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                }
                skip_ext:
 
-       if (TLS1_get_client_version(s) >= TLS1_2_VERSION)
+       if (SSL_USE_SIGALGS(s))
                {
                size_t salglen;
                const unsigned char *salg;
@@ -1270,8 +1313,7 @@ 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 &&
-           s->version != DTLS1_VERSION)
+       if (s->s3->client_opaque_prf_input != NULL)
                {
                size_t col = s->s3->client_opaque_prf_input_len;
                
@@ -1288,8 +1330,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                }
 #endif
 
-       if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
-           s->version != DTLS1_VERSION)
+       if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
                {
                int i;
                long extlen, idlen, itmp;
@@ -1389,13 +1430,11 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
        /* 1 byte for the list (we only support audit proofs) */
        if (s->ctx->tlsext_authz_server_audit_proof_cb != NULL)
                {
-               size_t lenmax;
                 const unsigned short ext_len = 2;
                 const unsigned char list_len = 1;
 
                if (limit < ret + 6)
                        return NULL;
-               lenmax = limit - ret - 6;
 
                s2n(TLSEXT_TYPE_server_authz, ret);
                 /* Extension length: 2 bytes */
@@ -1404,6 +1443,40 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                *(ret++) = TLSEXT_AUTHZDATAFORMAT_audit_proof;
                }
 
+       /* Add custom TLS Extensions to ClientHello */
+       if (s->ctx->custom_cli_ext_records_count)
+               {
+               size_t i;
+               custom_cli_ext_record* record;
+
+               for (i = 0; i < s->ctx->custom_cli_ext_records_count; i++)
+                       {
+                       const unsigned char* out = NULL;
+                       unsigned short outlen = 0;
+
+                       record = &s->ctx->custom_cli_ext_records[i];
+                       /* NULL callback sends empty extension */ 
+                       /* -1 from callback omits extension */
+                       if (record->fn1)
+                               {
+                               int cb_retval = 0;
+                               cb_retval = record->fn1(s, record->ext_type,
+                                                       &out, &outlen,
+                                                       record->arg);
+                               if (cb_retval == 0)
+                                       return NULL; /* error */
+                               if (cb_retval == -1)
+                                       continue; /* skip this extension */
+                               }
+                       if (limit < ret + 4 + outlen)
+                               return NULL;
+                       s2n(record->ext_type, ret);
+                       s2n(outlen, ret);
+                       memcpy(ret, out, outlen);
+                       ret += outlen;
+                       }
+               }
+
        if ((extdatalen = ret-p-2) == 0)
                return p;
 
@@ -1463,7 +1536,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
         }
 
 #ifndef OPENSSL_NO_EC
-       if (using_ecc && s->version != DTLS1_VERSION)
+       if (using_ecc)
                {
                const unsigned char *plist;
                size_t plistlen;
@@ -1506,8 +1579,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
                }
 
 #ifdef TLSEXT_TYPE_opaque_prf_input
-       if (s->s3->server_opaque_prf_input != NULL &&
-           s->version != DTLS1_VERSION)
+       if (s->s3->server_opaque_prf_input != NULL)
                {
                size_t sol = s->s3->server_opaque_prf_input_len;
                
@@ -1671,6 +1743,47 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
                        }
                }
 
+       /* If custom types were sent in ClientHello, add ServerHello responses */
+       if (s->s3->tlsext_custom_types_count)
+               {
+               size_t i;
+
+               for (i = 0; i < s->s3->tlsext_custom_types_count; i++)
+                       {
+                       size_t j;
+                       custom_srv_ext_record *record;
+
+                       for (j = 0; j < s->ctx->custom_srv_ext_records_count; j++)
+                               {
+                               record = &s->ctx->custom_srv_ext_records[j];
+                               if (s->s3->tlsext_custom_types[i] == record->ext_type)
+                                       {
+                                       const unsigned char *out = NULL;
+                                       unsigned short outlen = 0;
+                                       int cb_retval = 0;
+
+                                       /* NULL callback or -1 omits extension */
+                                       if (!record->fn2)
+                                               break;
+                                       cb_retval = record->fn2(s, record->ext_type,
+                                                               &out, &outlen,
+                                                               record->arg);
+                                       if (cb_retval == 0)
+                                               return NULL; /* error */
+                                       if (cb_retval == -1)
+                                               break; /* skip this extension */
+                                       if (limit < ret + 4 + outlen)
+                                               return NULL;
+                                       s2n(record->ext_type, ret);
+                                       s2n(outlen, ret);
+                                       memcpy(ret, out, outlen);
+                                       ret += outlen;
+                                       break;
+                                       }
+                               }
+                       }
+               }
+
        if ((extdatalen = ret-p-2)== 0) 
                return p;
 
@@ -1869,8 +1982,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
 #endif
 
 #ifndef OPENSSL_NO_EC
-               else if (type == TLSEXT_TYPE_ec_point_formats &&
-                    s->version != DTLS1_VERSION)
+               else if (type == TLSEXT_TYPE_ec_point_formats)
                        {
                        unsigned char *sdata = data;
                        int ecpointformatlist_length = *(sdata++);
@@ -1905,8 +2017,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
                        fprintf(stderr,"\n");
 #endif
                        }
-               else if (type == TLSEXT_TYPE_elliptic_curves &&
-                    s->version != DTLS1_VERSION)
+               else if (type == TLSEXT_TYPE_elliptic_curves)
                        {
                        unsigned char *sdata = data;
                        int ellipticcurvelist_length = (*(sdata++) << 8);
@@ -1944,8 +2055,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
                        }
 #endif /* OPENSSL_NO_EC */
 #ifdef TLSEXT_TYPE_opaque_prf_input
-               else if (type == TLSEXT_TYPE_opaque_prf_input &&
-                    s->version != DTLS1_VERSION)
+               else if (type == TLSEXT_TYPE_opaque_prf_input)
                        {
                        unsigned char *sdata = data;
 
@@ -2020,8 +2130,8 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
                                return 0;
                                }
                        }
-               else if (type == TLSEXT_TYPE_status_request &&
-                        s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
+               else if (type == TLSEXT_TYPE_status_request
+                        && s->ctx->tlsext_status_cb)
                        {
                
                        if (size < 5) 
@@ -2239,6 +2349,54 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
                                }
                        }
 
+               /* If this ClientHello extension was unhandled and this is 
+                * a nonresumed connection, check whether the extension is a 
+                * custom TLS Extension (has a custom_srv_ext_record), and if
+                * so call the callback and record the extension number so that
+                * an appropriate ServerHello may be later returned.
+                */
+               else if (!s->hit && s->ctx->custom_srv_ext_records_count)
+                       {
+                       custom_srv_ext_record *record;
+
+                       for (i=0; i < s->ctx->custom_srv_ext_records_count; i++)
+                               {
+                               record = &s->ctx->custom_srv_ext_records[i];
+                               if (type == record->ext_type)
+                                       {
+                                       /* Error on duplicate TLS Extensions */
+                                       size_t j;
+
+                                       for (j = 0; j < s->s3->tlsext_custom_types_count; j++)
+                                               {
+                                               if (s->s3->tlsext_custom_types[j] == type)
+                                                       {
+                                                       *al = TLS1_AD_DECODE_ERROR;
+                                                       return 0;
+                                                       }
+                                               }
+
+                                       /* Callback */
+                                       if (record->fn1 && !record->fn1(s, type, data, size, al, record->arg))
+                                               return 0;
+                                               
+                                       /* Add the (non-duplicated) entry */
+                                       s->s3->tlsext_custom_types_count++;
+                                       s->s3->tlsext_custom_types = OPENSSL_realloc(
+                                                       s->s3->tlsext_custom_types,
+                                                       s->s3->tlsext_custom_types_count*2);
+                                       if (s->s3->tlsext_custom_types == NULL)
+                                               {
+                                               s->s3->tlsext_custom_types = 0;
+                                               *al = TLS1_AD_INTERNAL_ERROR;
+                                               return 0;
+                                               }
+                                       s->s3->tlsext_custom_types[
+                                                       s->s3->tlsext_custom_types_count-1] = type;
+                                       }                                               
+                               }
+                       }
+
                data+=size;
                }
 
@@ -2351,8 +2509,7 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char
                        }
 
 #ifndef OPENSSL_NO_EC
-               else if (type == TLSEXT_TYPE_ec_point_formats &&
-                    s->version != DTLS1_VERSION)
+               else if (type == TLSEXT_TYPE_ec_point_formats)
                        {
                        unsigned char *sdata = data;
                        int ecpointformatlist_length = *(sdata++);
@@ -2398,8 +2555,7 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char
                        s->tlsext_ticket_expected = 1;
                        }
 #ifdef TLSEXT_TYPE_opaque_prf_input
-               else if (type == TLSEXT_TYPE_opaque_prf_input &&
-                    s->version != DTLS1_VERSION)
+               else if (type == TLSEXT_TYPE_opaque_prf_input)
                        {
                        unsigned char *sdata = data;
 
@@ -2429,8 +2585,7 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char
                                }
                        }
 #endif
-               else if (type == TLSEXT_TYPE_status_request &&
-                        s->version != DTLS1_VERSION)
+               else if (type == TLSEXT_TYPE_status_request)
                        {
                        /* MUST be empty and only sent if we've requested
                         * a status request message.
@@ -2546,6 +2701,26 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char
 
                        s->s3->tlsext_authz_server_promised = 1;
                        }
+
+               /* If this extension type was not otherwise handled, but 
+                * matches a custom_cli_ext_record, then send it to the c
+                * callback */
+               else if (s->ctx->custom_cli_ext_records_count)
+                       {
+                       size_t i;
+                       custom_cli_ext_record* record;
+
+                       for (i = 0; i < s->ctx->custom_cli_ext_records_count; i++)
+                               {
+                               record = &s->ctx->custom_cli_ext_records[i];
+                               if (record->ext_type == type)
+                                       {
+                                       if (record->fn2 && !record->fn2(s, type, data, size, al, record->arg))
+                                               return 0;
+                                       break;
+                                       }
+                               }                       
+                       }
  
                data += size;
                }
@@ -2991,7 +3166,7 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
        if (p >= limit)
                return -1;
        /* Skip past DTLS cookie */
-       if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
+       if (SSL_IS_DTLS(s))
                {
                i = *(p++);
                p+= i;
@@ -3127,7 +3302,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
        HMAC_Update(&hctx, etick, eticklen);
        HMAC_Final(&hctx, tick_hmac, NULL);
        HMAC_CTX_cleanup(&hctx);
-       if (memcmp(tick_hmac, etick + eticklen, mlen))
+       if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen))
                return 2;
        /* Attempt to decrypt session data */
        /* Move p after IV to start of encrypted ticket, update length */
@@ -3418,8 +3593,8 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
        const EVP_MD *md;
        CERT *c = s->cert;
        TLS_SIGALGS *sigptr;
-       /* Extension ignored for TLS versions below 1.2 */
-       if (TLS1_get_version(s) < TLS1_2_VERSION)
+       /* Extension ignored for inappropriate versions */
+       if (!SSL_USE_SIGALGS(s))
                return 1;
        /* Should never happen */
        if (!c)