PR: 2739
[openssl.git] / ssl / t1_lib.c
index 032319bd7660db4f0221976abbb5171153052161..57d1107e4034564e22d71c73cd3125d14143efc4 100644 (file)
 #include <openssl/evp.h>
 #include <openssl/hmac.h>
 #include <openssl/ocsp.h>
+#include <openssl/rand.h>
 #include "ssl_locl.h"
 
 const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT;
@@ -136,6 +137,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)
@@ -430,25 +432,29 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
         }
 
 #ifndef OPENSSL_NO_SRP
-#define MIN(x,y) (((x)<(y))?(x):(y))
-       /* we add SRP username the first time only if we have one! */
+       /* Add SRP username if there is one */
        if (s->srp_ctx.login != NULL)
-               {/* Add TLS extension SRP username to the Client Hello message */
-               int login_len = MIN(strlen(s->srp_ctx.login) + 1, 255);
-               long lenmax; 
+               { /* Add TLS extension SRP username to the Client Hello message */
 
-               if ((lenmax = limit - ret - 5) < 0) return NULL; 
-               if (login_len > lenmax) return NULL;
-               if (login_len > 255)
+               int login_len = strlen(s->srp_ctx.login);       
+               if (login_len > 255 || login_len == 0)
                        {
                        SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
                        return NULL;
-                       }
+                       } 
+
+               /* check for enough space.
+                  4 for the srp type type and entension length
+                  1 for the srp user identity
+                  + srp user identity length 
+               */
+               if ((limit - ret - 5 - login_len) < 0) return NULL; 
+
+               /* fill in the extension */
                s2n(TLSEXT_TYPE_srp,ret);
                s2n(login_len+1,ret);
-
-               (*ret++) = (unsigned char) MIN(strlen(s->srp_ctx.login), 254);
-               memcpy(ret, s->srp_ctx.login, MIN(strlen(s->srp_ctx.login), 254));
+               (*ret++) = (unsigned char) login_len;
+               memcpy(ret, s->srp_ctx.login, login_len);
                ret+=login_len;
                }
 #endif
@@ -617,6 +623,20 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                        i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret);
                }
 
+#ifndef OPENSSL_NO_HEARTBEATS
+       /* Add Heartbeat extension */
+       s2n(TLSEXT_TYPE_heartbeat,ret);
+       s2n(1,ret);
+       /* Set mode:
+        * 1: peer may send requests
+        * 2: peer not allowed to send requests
+        */
+       if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS)
+               *(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+       else
+               *(ret++) = SSL_TLSEXT_HB_ENABLED;
+#endif
+
 #ifndef OPENSSL_NO_NEXTPROTONEG
        if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len)
                {
@@ -629,6 +649,25 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                }
 #endif
 
+        if(SSL_get_srtp_profiles(s))
+                {
+                int el;
+
+                ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0);
+                
+                if((limit - p - 4 - el) < 0) return NULL;
+
+                s2n(TLSEXT_TYPE_use_srtp,ret);
+                s2n(el,ret);
+
+                if(ssl_add_clienthello_use_srtp_ext(s, ret, &el, el))
+                       {
+                       SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+                       return NULL;
+                       }
+                ret += el;
+                }
+
        if ((extdatalen = ret-p-2)== 0) 
                return p;
 
@@ -741,6 +780,26 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
                ret += sol;
                }
 #endif
+
+        if(s->srtp_profile)
+                {
+                int el;
+
+                ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0);
+                
+                if((limit - p - 4 - el) < 0) return NULL;
+
+                s2n(TLSEXT_TYPE_use_srtp,ret);
+                s2n(el,ret);
+
+                if(ssl_add_serverhello_use_srtp_ext(s, ret, &el, el))
+                       {
+                       SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+                       return NULL;
+                       }
+                ret+=el;
+                }
+
        if (((s->s3->tmp.new_cipher->id & 0xFFFF)==0x80 || (s->s3->tmp.new_cipher->id & 0xFFFF)==0x81) 
                && (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG))
                { const unsigned char cryptopro_ext[36] = {
@@ -756,6 +815,24 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
 
                }
 
+#ifndef OPENSSL_NO_HEARTBEATS
+       /* Add Heartbeat extension if we've received one */
+       if (s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED)
+               {
+               s2n(TLSEXT_TYPE_heartbeat,ret);
+               s2n(1,ret);
+               /* Set mode:
+                * 1: peer may send requests
+                * 2: peer not allowed to send requests
+                */
+               if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS)
+                       *(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+               else
+                       *(ret++) = SSL_TLSEXT_HB_ENABLED;
+
+               }
+#endif
+
 #ifndef OPENSSL_NO_NEXTPROTONEG
        next_proto_neg_seen = s->s3->next_proto_neg_seen;
        s->s3->next_proto_neg_seen = 0;
@@ -796,6 +873,14 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
 
        s->servername_done = 0;
        s->tlsext_status_type = -1;
+#ifndef OPENSSL_NO_NEXTPROTONEG
+       s->s3->next_proto_neg_seen = 0;
+#endif
+
+#ifndef OPENSSL_NO_HEARTBEATS
+       s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
+                              SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
+#endif
 
        if (data >= (d+n-2))
                goto ri_check;
@@ -926,13 +1011,25 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
 #ifndef OPENSSL_NO_SRP
                else if (type == TLSEXT_TYPE_srp)
                        {
-                       if (size > 0)
+                       if (size <= 0 || ((len = data[0])) != (size -1))
                                {
-                               len = data[0];
-                               if ((s->srp_ctx.login = OPENSSL_malloc(len+1)) == NULL)
-                                       return -1;
-                               memcpy(s->srp_ctx.login, &data[1], len);
-                               s->srp_ctx.login[len]='\0';  
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               }
+                       if (s->srp_ctx.login != NULL)
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               }
+                       if ((s->srp_ctx.login = OPENSSL_malloc(len+1)) == NULL)
+                               return -1;
+                       memcpy(s->srp_ctx.login, &data[1], len);
+                       s->srp_ctx.login[len]='\0';
+  
+                       if (strlen(s->srp_ctx.login) != len) 
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
                                }
                        }
 #endif
@@ -1167,6 +1264,12 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                sdata = data;
                                if (dsize > 0)
                                        {
+                                       if (s->tlsext_ocsp_exts)
+                                               {
+                                               sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
+                                                                          X509_EXTENSION_free);
+                                               }
+
                                        s->tlsext_ocsp_exts =
                                                d2i_X509_EXTENSIONS(NULL,
                                                        &sdata, dsize);
@@ -1184,6 +1287,23 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                else
                                        s->tlsext_status_type = -1;
                        }
+#ifndef OPENSSL_NO_HEARTBEATS
+               else if (type == TLSEXT_TYPE_heartbeat)
+                       {
+                       switch(data[0])
+                               {
+                               case 0x01:      /* Client allows us to send HB requests */
+                                                       s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+                                                       break;
+                               case 0x02:      /* Client doesn't accept HB requests */
+                                                       s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+                                                       s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+                                                       break;
+                               default:        *al = SSL_AD_ILLEGAL_PARAMETER;
+                                                       return 0;
+                               }
+                       }
+#endif
 #ifndef OPENSSL_NO_NEXTPROTONEG
                else if (type == TLSEXT_TYPE_next_proto_neg &&
                         s->s3->tmp.finish_md_len == 0)
@@ -1208,6 +1328,13 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
 #endif
 
                /* session ticket processed earlier */
+               else if (type == TLSEXT_TYPE_use_srtp)
+                        {
+                       if(ssl_parse_clienthello_use_srtp_ext(s, data, size,
+                                                             al))
+                               return 0;
+                        }
+
                data+=size;
                }
                                
@@ -1258,6 +1385,15 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
        int tlsext_servername = 0;
        int renegotiate_seen = 0;
 
+#ifndef OPENSSL_NO_NEXTPROTONEG
+       s->s3->next_proto_neg_seen = 0;
+#endif
+
+#ifndef OPENSSL_NO_HEARTBEATS
+       s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
+                              SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
+#endif
+
        if (data >= (d+n-2))
                goto ri_check;
 
@@ -1384,7 +1520,8 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                        s->tlsext_status_expected = 1;
                        }
 #ifndef OPENSSL_NO_NEXTPROTONEG
-               else if (type == TLSEXT_TYPE_next_proto_neg)
+               else if (type == TLSEXT_TYPE_next_proto_neg &&
+                        s->s3->tmp.finish_md_len == 0)
                        {
                        unsigned char *selected;
                        unsigned char selected_len;
@@ -1414,6 +1551,7 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                }
                        memcpy(s->next_proto_negotiated, selected, selected_len);
                        s->next_proto_negotiated_len = selected_len;
+                       s->s3->next_proto_neg_seen = 1;
                        }
 #endif
                else if (type == TLSEXT_TYPE_renegotiate)
@@ -1422,6 +1560,30 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                return 0;
                        renegotiate_seen = 1;
                        }
+#ifndef OPENSSL_NO_HEARTBEATS
+               else if (type == TLSEXT_TYPE_heartbeat)
+                       {
+                       switch(data[0])
+                               {
+                               case 0x01:      /* Server allows us to send HB requests */
+                                                       s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+                                                       break;
+                               case 0x02:      /* Server doesn't accept HB requests */
+                                                       s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+                                                       s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+                                                       break;
+                               default:        *al = SSL_AD_ILLEGAL_PARAMETER;
+                                                       return 0;
+                               }
+                       }
+#endif
+               else if (type == TLSEXT_TYPE_use_srtp)
+                        {
+                        if(ssl_parse_serverhello_use_srtp_ext(s, data, size,
+                                                             al))
+                                return 0;
+                        }
+
                data+=size;             
                }
 
@@ -2099,7 +2261,7 @@ static tls12_lookup tls12_sig[] = {
 #ifndef OPENSSL_NO_RSA
        {EVP_PKEY_RSA, TLSEXT_signature_rsa},
 #endif
-#ifndef OPENSSL_NO_RSA
+#ifndef OPENSSL_NO_DSA
        {EVP_PKEY_DSA, TLSEXT_signature_dsa},
 #endif
 #ifndef OPENSSL_NO_ECDSA
@@ -2133,6 +2295,8 @@ static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen)
 int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk, const EVP_MD *md)
        {
        int sig_id, md_id;
+       if (!md)
+               return 0;
        md_id = tls12_find_id(EVP_MD_type(md), tls12_md,
                                sizeof(tls12_md)/sizeof(tls12_lookup));
        if (md_id == -1)
@@ -2267,3 +2431,148 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
        }
 
 #endif
+
+#ifndef OPENSSL_NO_HEARTBEATS
+int
+tls1_process_heartbeat(SSL *s)
+       {
+       unsigned char *p = &s->s3->rrec.data[0], *pl;
+       unsigned short hbtype;
+       unsigned int payload;
+       unsigned int padding = 16; /* Use minimum padding */
+
+       /* Read type and payload length first */
+       hbtype = *p++;
+       n2s(p, payload);
+       pl = p;
+
+       if (s->msg_callback)
+               s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
+                       &s->s3->rrec.data[0], s->s3->rrec.length,
+                       s, s->msg_callback_arg);
+
+       if (hbtype == TLS1_HB_REQUEST)
+               {
+               unsigned char *buffer, *bp;
+               int r;
+
+               /* Allocate memory for the response, size is 1 bytes
+                * message type, plus 2 bytes payload length, plus
+                * payload, plus padding
+                */
+               buffer = OPENSSL_malloc(1 + 2 + payload + padding);
+               bp = buffer;
+               
+               /* Enter response type, length and copy payload */
+               *bp++ = TLS1_HB_RESPONSE;
+               s2n(payload, bp);
+               memcpy(bp, pl, payload);
+               bp += payload;
+               /* Random padding */
+               RAND_pseudo_bytes(bp, padding);
+
+               r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
+
+               if (r >= 0 && s->msg_callback)
+                       s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+                               buffer, 3 + payload + padding,
+                               s, s->msg_callback_arg);
+
+               OPENSSL_free(buffer);
+
+               if (r < 0)
+                       return r;
+               }
+       else if (hbtype == TLS1_HB_RESPONSE)
+               {
+               unsigned int seq;
+               
+               /* We only send sequence numbers (2 bytes unsigned int),
+                * and 16 random bytes, so we just try to read the
+                * sequence number */
+               n2s(pl, seq);
+               
+               if (payload == 18 && seq == s->tlsext_hb_seq)
+                       {
+                       s->tlsext_hb_seq++;
+                       s->tlsext_hb_pending = 0;
+                       }
+               }
+
+       return 0;
+       }
+
+int
+tls1_heartbeat(SSL *s)
+       {
+       unsigned char *buf, *p;
+       int ret;
+       unsigned int payload = 18; /* Sequence number + random bytes */
+       unsigned int padding = 16; /* Use minimum padding */
+
+       /* Only send if peer supports and accepts HB requests... */
+       if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) ||
+           s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS)
+               {
+               SSLerr(SSL_F_TLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT);
+               return -1;
+               }
+
+       /* ...and there is none in flight yet... */
+       if (s->tlsext_hb_pending)
+               {
+               SSLerr(SSL_F_TLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PENDING);
+               return -1;
+               }
+               
+       /* ...and no handshake in progress. */
+       if (SSL_in_init(s) || s->in_handshake)
+               {
+               SSLerr(SSL_F_TLS1_HEARTBEAT,SSL_R_UNEXPECTED_MESSAGE);
+               return -1;
+               }
+               
+       /* Check if padding is too long, payload and padding
+        * must not exceed 2^14 - 3 = 16381 bytes in total.
+        */
+       OPENSSL_assert(payload + padding <= 16381);
+
+       /* Create HeartBeat message, we just use a sequence number
+        * as payload to distuingish different messages and add
+        * some random stuff.
+        *  - Message Type, 1 byte
+        *  - Payload Length, 2 bytes (unsigned int)
+        *  - Payload, the sequence number (2 bytes uint)
+        *  - Payload, random bytes (16 bytes uint)
+        *  - Padding
+        */
+       buf = OPENSSL_malloc(1 + 2 + payload + padding);
+       p = buf;
+       /* Message Type */
+       *p++ = TLS1_HB_REQUEST;
+       /* Payload length (18 bytes here) */
+       s2n(payload, p);
+       /* Sequence number */
+       s2n(s->tlsext_hb_seq, p);
+       /* 16 random bytes */
+       RAND_pseudo_bytes(p, 16);
+       p += 16;
+       /* Random padding */
+       RAND_pseudo_bytes(p, padding);
+
+       ret = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding);
+       if (ret >= 0)
+               {
+               if (s->msg_callback)
+                       s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+                               buf, 3 + payload + padding,
+                               s, s->msg_callback_arg);
+
+               s->tlsext_hb_pending = 1;
+               }
+               
+       OPENSSL_free(buf);
+
+       return ret;
+       }
+#endif