correct error codes
[openssl.git] / ssl / t1_lib.c
index 1c0164aeeddb509f3ce4ed40518b26658792015c..e120a87fc2bb78dc3a9f50833606e7baa16ac677 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;
@@ -201,33 +202,41 @@ static int nid_list[] =
                NID_secp521r1  /* secp521r1 (25) */     
        };
 
-static int pref_list[] =
+
+static const unsigned char ecformats_default[] = 
        {
-               NID_sect571r1, /* sect571r1 (14) */ 
-               NID_sect571k1, /* sect571k1 (13) */ 
-               NID_secp521r1, /* secp521r1 (25) */     
-               NID_sect409k1, /* sect409k1 (11) */ 
-               NID_sect409r1, /* sect409r1 (12) */
-               NID_secp384r1, /* secp384r1 (24) */
-               NID_sect283k1, /* sect283k1 (9) */
-               NID_sect283r1, /* sect283r1 (10) */ 
-               NID_secp256k1, /* secp256k1 (22) */ 
-               NID_X9_62_prime256v1, /* secp256r1 (23) */ 
-               NID_sect239k1, /* sect239k1 (8) */ 
-               NID_sect233k1, /* sect233k1 (6) */
-               NID_sect233r1, /* sect233r1 (7) */ 
-               NID_secp224k1, /* secp224k1 (20) */ 
-               NID_secp224r1, /* secp224r1 (21) */
-               NID_sect193r1, /* sect193r1 (4) */ 
-               NID_sect193r2, /* sect193r2 (5) */ 
-               NID_secp192k1, /* secp192k1 (18) */
-               NID_X9_62_prime192v1, /* secp192r1 (19) */ 
-               NID_sect163k1, /* sect163k1 (1) */
-               NID_sect163r1, /* sect163r1 (2) */
-               NID_sect163r2, /* sect163r2 (3) */
-               NID_secp160k1, /* secp160k1 (15) */
-               NID_secp160r1, /* secp160r1 (16) */ 
-               NID_secp160r2, /* secp160r2 (17) */ 
+       TLSEXT_ECPOINTFORMAT_uncompressed,
+       TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime,
+       TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2
+       };
+
+static const unsigned char eccurves_default[] =
+       {
+               0,14, /* sect571r1 (14) */ 
+               0,13, /* sect571k1 (13) */ 
+               0,25, /* secp521r1 (25) */      
+               0,11, /* sect409k1 (11) */ 
+               0,12, /* sect409r1 (12) */
+               0,24, /* secp384r1 (24) */
+               0,9,  /* sect283k1 (9) */
+               0,10, /* sect283r1 (10) */ 
+               0,22, /* secp256k1 (22) */ 
+               0,23, /* secp256r1 (23) */ 
+               0,8,  /* sect239k1 (8) */ 
+               0,6,  /* sect233k1 (6) */
+               0,7,  /* sect233r1 (7) */ 
+               0,20, /* secp224k1 (20) */ 
+               0,21, /* secp224r1 (21) */
+               0,4,  /* sect193r1 (4) */ 
+               0,5,  /* sect193r2 (5) */ 
+               0,18, /* secp192k1 (18) */
+               0,19, /* secp192r1 (19) */ 
+               0,1,  /* sect163k1 (1) */
+               0,2,  /* sect163r1 (2) */
+               0,3,  /* sect163r2 (3) */
+               0,15, /* secp160k1 (15) */
+               0,16, /* secp160r1 (16) */ 
+               0,17, /* secp160r2 (17) */ 
        };
 
 int tls1_ec_curve_id2nid(int curve_id)
@@ -298,6 +307,278 @@ int tls1_ec_nid2curve_id(int nid)
                return 0;
                }
        }
+/* Get curves list, if "sess" is set return client curves otherwise
+ * preferred list
+ */
+static void tls1_get_curvelist(SSL *s, int sess,
+                                       const unsigned char **pcurves,
+                                       size_t *pcurveslen)
+       {
+       if (sess)
+               {
+               *pcurves = s->session->tlsext_ellipticcurvelist;
+               *pcurveslen = s->session->tlsext_ellipticcurvelist_length;
+               }
+       else
+               {
+               *pcurves = s->tlsext_ellipticcurvelist;
+               *pcurveslen = s->tlsext_ellipticcurvelist_length;
+               }
+       /* If not set use default: for now static structure */
+       if (!*pcurves)
+               {
+               *pcurves = eccurves_default;
+               *pcurveslen = sizeof(eccurves_default);
+               }
+       }
+
+/* Return nth shared curve. If nmatch == -1 return number of
+ * matches.
+ */
+
+int tls1_shared_curve(SSL *s, int nmatch)
+       {
+       const unsigned char *pref, *supp;
+       size_t preflen, supplen, i, j;
+       int k;
+       /* Can't do anything on client side */
+       if (s->server == 0)
+               return -1;
+       tls1_get_curvelist(s, !!(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE),
+                               &supp, &supplen);
+       tls1_get_curvelist(s, !(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE),
+                               &pref, &preflen);
+       preflen /= 2;
+       supplen /= 2;
+       k = 0;
+       for (i = 0; i < preflen; i++, pref+=2)
+               {
+               const unsigned char *tsupp = supp;
+               for (j = 0; j < supplen; j++, tsupp+=2)
+                       {
+                       if (pref[0] == tsupp[0] && pref[1] == tsupp[1])
+                               {
+                               if (nmatch == k)
+                                       {
+                                       int id = (pref[0] << 8) | pref[1];
+                                       return tls1_ec_curve_id2nid(id);
+                                       }
+                               k++;
+                               }
+                       }
+               }
+       if (nmatch == -1)
+               return k;
+       return 0;
+       }
+
+int tls1_set_curves(unsigned char **pext, size_t *pextlen,
+                       int *curves, size_t ncurves)
+       {
+       unsigned char *clist, *p;
+       size_t i;
+       /* Bitmap of curves included to detect duplicates: only works
+        * while curve ids < 32 
+        */
+       unsigned long dup_list = 0;
+       clist = OPENSSL_malloc(ncurves * 2);
+       if (!clist)
+               return 0;
+       for (i = 0, p = clist; i < ncurves; i++)
+               {
+               unsigned long idmask;
+               int id;
+               id = tls1_ec_nid2curve_id(curves[i]);
+               idmask = 1L << id;
+               if (!id || (dup_list & idmask))
+                       {
+                       OPENSSL_free(clist);
+                       return 0;
+                       }
+               dup_list |= idmask;
+               s2n(id, p);
+               }
+       if (*pext)
+               OPENSSL_free(*pext);
+       *pext = clist;
+       *pextlen = ncurves * 2;
+       return 1;
+       }
+
+#define MAX_CURVELIST  25
+
+typedef struct
+       {
+       size_t nidcnt;
+       int nid_arr[MAX_CURVELIST];
+       } nid_cb_st;
+
+static int nid_cb(const char *elem, int len, void *arg)
+       {
+       nid_cb_st *narg = arg;
+       size_t i;
+       int nid;
+       char etmp[20];
+       if (narg->nidcnt == MAX_CURVELIST)
+               return 0;
+       if (len > (int)(sizeof(etmp) - 1))
+               return 0;
+       memcpy(etmp, elem, len);
+       etmp[len] = 0;
+       nid = EC_curve_nist2nid(etmp);
+       if (nid == NID_undef)
+               nid = OBJ_sn2nid(etmp);
+       if (nid == NID_undef)
+               nid = OBJ_ln2nid(etmp);
+       if (nid == NID_undef)
+               return 0;
+       for (i = 0; i < narg->nidcnt; i++)
+               if (narg->nid_arr[i] == nid)
+                       return 0;
+       narg->nid_arr[narg->nidcnt++] = nid;
+       return 1;
+       }
+/* Set curves based on a colon separate list */
+int tls1_set_curves_list(unsigned char **pext, size_t *pextlen, 
+                               const char *str)
+       {
+       nid_cb_st ncb;
+       ncb.nidcnt = 0;
+       if (!CONF_parse_list(str, ':', 1, nid_cb, &ncb))
+               return 0;
+       return tls1_set_curves(pext, pextlen, ncb.nid_arr, ncb.nidcnt);
+       }
+/* For an EC key set TLS id and required compression based on parameters */
+static int tls1_set_ec_id(unsigned char *curve_id, unsigned char *comp_id,
+                               EC_KEY *ec)
+       {
+       int is_prime, id;
+       const EC_GROUP *grp;
+       const EC_POINT *pt;
+       const EC_METHOD *meth;
+       if (!ec)
+               return 0;
+       /* Determine if it is a prime field */
+       grp = EC_KEY_get0_group(ec);
+        pt = EC_KEY_get0_public_key(ec);
+       if (!grp || !pt)
+               return 0;
+        meth = EC_GROUP_method_of(grp);
+       if (!meth)
+               return 0;
+        if (EC_METHOD_get_field_type(meth) == NID_X9_62_prime_field)
+               is_prime = 1;
+       else
+               is_prime = 0;
+       /* Determine curve ID */
+       id = EC_GROUP_get_curve_name(grp);
+       id = tls1_ec_nid2curve_id(id);
+       /* If we have an ID set it, otherwise set arbitrary explicit curve */
+       if (id)
+               {
+               curve_id[0] = 0;
+               curve_id[1] = (unsigned char)id;
+               }
+       else
+               {
+               curve_id[0] = 0xff;
+               if (is_prime)
+                       curve_id[1] = 0x01;
+               else
+                       curve_id[1] = 0x02;
+               }
+       if (comp_id)
+               {
+               if (EC_KEY_get_conv_form(ec) == POINT_CONVERSION_COMPRESSED)
+                       {
+                       if (is_prime)
+                               *comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
+                       else
+                               *comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
+                       }
+               else
+                       *comp_id = TLSEXT_ECPOINTFORMAT_uncompressed;
+               }
+       return 1;
+       }
+/* Check an EC key is compatible with extensions */
+static int tls1_check_ec_key(SSL *s,
+                       unsigned char *curve_id, unsigned char *comp_id)
+       {
+       const unsigned char *p;
+       size_t plen, i;
+       int j;
+       /* If point formats extension present check it, otherwise everything
+        * is supported (see RFC4492).
+        */
+       if (comp_id && s->session->tlsext_ecpointformatlist)
+               {
+               p = s->session->tlsext_ecpointformatlist;
+               plen = s->session->tlsext_ecpointformatlist_length;
+               for (i = 0; i < plen; i++, p++)
+                       {
+                       if (*comp_id == *p)
+                               break;
+                       }
+               if (i == plen)
+                       return 0;
+               }
+       /* Check curve is consistent with client and server preferences */
+       for (j = 0; j <= 1; j++)
+               {
+               tls1_get_curvelist(s, j, &p, &plen);
+               for (i = 0; i < plen; i+=2, p+=2)
+                       {
+                       if (p[0] == curve_id[0] && p[1] == curve_id[1])
+                               break;
+                       }
+               if (i == plen)
+                       return 0;
+               }
+       return 1;
+       }
+/* Check EC server key is compatible with client extensions */
+int tls1_check_ec_server_key(SSL *s)
+       {
+       int rv;
+       CERT_PKEY *cpk = s->cert->pkeys + SSL_PKEY_ECC;
+       EVP_PKEY *pkey;
+       unsigned char comp_id, curve_id[2];
+       if (!cpk->x509 || !cpk->privatekey)
+               return 0;
+       pkey = X509_get_pubkey(cpk->x509);
+       if (!pkey)
+               return 0;
+       rv = tls1_set_ec_id(curve_id, &comp_id, pkey->pkey.ec);
+       EVP_PKEY_free(pkey);
+       if (!rv)
+               return 0;
+       return tls1_check_ec_key(s, curve_id, &comp_id);
+       }
+/* Check EC temporary key is compatible with client extensions */
+int tls1_check_ec_tmp_key(SSL *s)
+       {
+       unsigned char curve_id[2];
+       EC_KEY *ec = s->cert->ecdh_tmp;
+       if (s->cert->ecdh_tmp_auto)
+               {
+               /* Need a shared curve */
+               if (tls1_shared_curve(s, 0))
+                       return 1;
+               else return 0;
+               }
+       if (!ec)
+               {
+               if (s->cert->ecdh_tmp_cb)
+                       return 1;
+               else
+                       return 0;
+               }
+       if (!tls1_set_ec_id(curve_id, NULL, ec))
+               return 1;
+       return tls1_check_ec_key(s, curve_id, NULL);
+       }
+
 #endif /* OPENSSL_NO_EC */
 
 #ifndef OPENSSL_NO_TLSEXT
@@ -363,6 +644,30 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
        {
        int extdatalen=0;
        unsigned char *ret = p;
+#ifndef OPENSSL_NO_EC
+       /* See if we support any ECC ciphersuites */
+       int using_ecc = 0;
+       if (s->version != DTLS1_VERSION && s->version >= TLS1_VERSION)
+               {
+               int i;
+               unsigned long alg_k, alg_a;
+               STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
+
+               for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++)
+                       {
+                       SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
+
+                       alg_k = c->algorithm_mkey;
+                       alg_a = c->algorithm_auth;
+                       if ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)
+                               || (alg_a & SSL_aECDSA)))
+                               {
+                               using_ecc = 1;
+                               break;
+                               }
+                       }
+               }
+#endif
 
        /* don't add extensions for SSLv3 unless doing secure renegotiation */
        if (s->client_version == SSL3_VERSION
@@ -431,75 +736,88 @@ 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
 
 #ifndef OPENSSL_NO_EC
-       if (s->tlsext_ecpointformatlist != NULL &&
-           s->version != DTLS1_VERSION)
+       if (using_ecc)
                {
                /* Add TLS extension ECPointFormats to the ClientHello message */
                long lenmax; 
+               const unsigned char *plist;
+               size_t plistlen;
+               /* If we have a custom point format list use it otherwise
+                * use default */
+               plist = s->tlsext_ecpointformatlist;
+               if (plist)
+                       plistlen = s->tlsext_ecpointformatlist_length;
+               else
+                       {
+                       plist = ecformats_default;
+                       plistlen = sizeof(ecformats_default);
+                       }
 
                if ((lenmax = limit - ret - 5) < 0) return NULL; 
-               if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
-               if (s->tlsext_ecpointformatlist_length > 255)
+               if (plistlen > (size_t)lenmax) return NULL;
+               if (plistlen > 255)
                        {
                        SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
                        return NULL;
                        }
                
                s2n(TLSEXT_TYPE_ec_point_formats,ret);
-               s2n(s->tlsext_ecpointformatlist_length + 1,ret);
-               *(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length;
-               memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
-               ret+=s->tlsext_ecpointformatlist_length;
-               }
-       if (s->tlsext_ellipticcurvelist != NULL &&
-           s->version != DTLS1_VERSION)
-               {
+               s2n(plistlen + 1,ret);
+               *(ret++) = (unsigned char)plistlen ;
+               memcpy(ret, plist, plistlen);
+               ret+=plistlen;
+
                /* Add TLS extension EllipticCurves to the ClientHello message */
-               long lenmax; 
+               plist = s->tlsext_ellipticcurvelist;
+               tls1_get_curvelist(s, 0, &plist, &plistlen);
 
                if ((lenmax = limit - ret - 6) < 0) return NULL; 
-               if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL;
-               if (s->tlsext_ellipticcurvelist_length > 65532)
+               if (plistlen > (size_t)lenmax) return NULL;
+               if (plistlen > 65532)
                        {
                        SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
                        return NULL;
                        }
                
                s2n(TLSEXT_TYPE_elliptic_curves,ret);
-               s2n(s->tlsext_ellipticcurvelist_length + 2, ret);
+               s2n(plistlen + 2, ret);
 
                /* NB: draft-ietf-tls-ecc-12.txt uses a one-byte prefix for
                 * elliptic_curve_list, but the examples use two bytes.
                 * http://www1.ietf.org/mail-archive/web/tls/current/msg00538.html
                 * resolves this to two bytes.
                 */
-               s2n(s->tlsext_ellipticcurvelist_length, ret);
-               memcpy(ret, s->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist_length);
-               ret+=s->tlsext_ellipticcurvelist_length;
+               s2n(plistlen, ret);
+               memcpy(ret, plist, plistlen);
+               ret+=plistlen;
                }
 #endif /* OPENSSL_NO_EC */
 
@@ -539,7 +857,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                }
                skip_ext:
 
-       if (TLS1_get_version(s) >= TLS1_2_VERSION)
+       if (TLS1_get_client_version(s) >= TLS1_2_VERSION)
                {
                if ((size_t)(limit - ret) < sizeof(tls12_sigalgs) + 6)
                        return NULL; 
@@ -618,6 +936,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)
                {
@@ -796,6 +1128,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;
@@ -825,8 +1175,8 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
        return ret;
        }
 
-int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
-       {
+static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al) 
+       {       
        unsigned short type;
        unsigned short size;
        unsigned short len;
@@ -840,6 +1190,11 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
        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;
        n2s(data,len);
@@ -969,13 +1324,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
@@ -1210,6 +1577,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);
@@ -1227,6 +1600,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)
@@ -1271,7 +1661,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
                {
                *al = SSL_AD_HANDSHAKE_FAILURE;
-               SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT,
+               SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT,
                                SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
                return 0;
                }
@@ -1279,6 +1669,23 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
        return 1;
        }
 
+int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n) 
+       {
+       int al = -1;
+       if (ssl_scan_clienthello_tlsext(s, p, d, n, &al) <= 0) 
+               {
+               ssl3_send_alert(s,SSL3_AL_FATAL,al); 
+               return 0;
+               }
+
+       if (ssl_check_clienthello_tlsext(s) <= 0) 
+               {
+               SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT,SSL_R_CLIENTHELLO_TLSEXT);
+               return 0;
+               }
+       return 1;
+}
+
 #ifndef OPENSSL_NO_NEXTPROTONEG
 /* ssl_next_proto_validate validates a Next Protocol Negotiation block. No
  * elements of zero length are allowed and the set of elements must exactly fill
@@ -1312,6 +1719,11 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
        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;
 
@@ -1478,6 +1890,23 @@ 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,
@@ -1542,59 +1971,6 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
 
 int ssl_prepare_clienthello_tlsext(SSL *s)
        {
-#ifndef OPENSSL_NO_EC
-       /* If we are client and using an elliptic curve cryptography cipher suite, send the point formats 
-        * and elliptic curves we support.
-        */
-       int using_ecc = 0;
-       int i;
-       unsigned char *j;
-       unsigned long alg_k, alg_a;
-       STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
-
-       for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++)
-               {
-               SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
-
-               alg_k = c->algorithm_mkey;
-               alg_a = c->algorithm_auth;
-               if ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe) || (alg_a & SSL_aECDSA)))
-                       {
-                       using_ecc = 1;
-                       break;
-                       }
-               }
-       using_ecc = using_ecc && (s->version >= TLS1_VERSION);
-       if (using_ecc)
-               {
-               if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist);
-               if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL)
-                       {
-                       SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
-                       return -1;
-                       }
-               s->tlsext_ecpointformatlist_length = 3;
-               s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed;
-               s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
-               s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
-
-               /* we support all named elliptic curves in draft-ietf-tls-ecc-12 */
-               if (s->tlsext_ellipticcurvelist != NULL) OPENSSL_free(s->tlsext_ellipticcurvelist);
-               s->tlsext_ellipticcurvelist_length = sizeof(pref_list)/sizeof(pref_list[0]) * 2;
-               if ((s->tlsext_ellipticcurvelist = OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL)
-                       {
-                       s->tlsext_ellipticcurvelist_length = 0;
-                       SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
-                       return -1;
-                       }
-               for (i = 0, j = s->tlsext_ellipticcurvelist; (unsigned int)i <
-                               sizeof(pref_list)/sizeof(pref_list[0]); i++)
-                       {
-                       int id = tls1_ec_nid2curve_id(pref_list[i]);
-                       s2n(id,j);
-                       }
-               }
-#endif /* OPENSSL_NO_EC */
 
 #ifdef TLSEXT_TYPE_opaque_prf_input
        {
@@ -2142,32 +2518,18 @@ typedef struct
        } tls12_lookup;
 
 static tls12_lookup tls12_md[] = {
-#ifndef OPENSSL_NO_MD5
        {NID_md5, TLSEXT_hash_md5},
-#endif
-#ifndef OPENSSL_NO_SHA
        {NID_sha1, TLSEXT_hash_sha1},
-#endif
-#ifndef OPENSSL_NO_SHA256
        {NID_sha224, TLSEXT_hash_sha224},
        {NID_sha256, TLSEXT_hash_sha256},
-#endif
-#ifndef OPENSSL_NO_SHA512
        {NID_sha384, TLSEXT_hash_sha384},
        {NID_sha512, TLSEXT_hash_sha512}
-#endif
 };
 
 static tls12_lookup tls12_sig[] = {
-#ifndef OPENSSL_NO_RSA
        {EVP_PKEY_RSA, TLSEXT_signature_rsa},
-#endif
-#ifndef OPENSSL_NO_RSA
        {EVP_PKEY_DSA, TLSEXT_signature_dsa},
-#endif
-#ifndef OPENSSL_NO_ECDSA
        {EVP_PKEY_EC, TLSEXT_signature_ecdsa}
-#endif
 };
 
 static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen)
@@ -2180,22 +2542,23 @@ static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen)
                }
        return -1;
        }
-#if 0
+
 static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen)
        {
        size_t i;
        for (i = 0; i < tlen; i++)
                {
-               if (table[i].id == id)
+               if ((table[i].id) == id)
                        return table[i].nid;
                }
-       return -1;
+       return NID_undef;
        }
-#endif
 
 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)
@@ -2257,6 +2620,7 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
        int i, idx;
        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)
                return 1;
@@ -2269,11 +2633,26 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
        c->pkeys[SSL_PKEY_RSA_ENC].digest = NULL;
        c->pkeys[SSL_PKEY_ECC].digest = NULL;
 
-       for (i = 0; i < dsize; i += 2)
-               {
-               unsigned char hash_alg = data[i], sig_alg = data[i+1];
+       if (c->sigalgs)
+               OPENSSL_free(c->sigalgs);
+       c->sigalgs = OPENSSL_malloc((dsize/2) * sizeof(TLS_SIGALGS));
+       if (!c->sigalgs)
+               return 0;
+       c->sigalgslen = dsize/2;
 
-               switch(sig_alg)
+       for (i = 0, sigptr = c->sigalgs; i < dsize; i += 2, sigptr++)
+               {
+               sigptr->rhash = data[i];
+               sigptr->rsign = data[i + 1];
+               sigptr->hash_nid = tls12_find_nid(sigptr->rhash, tls12_md,
+                                       sizeof(tls12_md)/sizeof(tls12_lookup));
+               sigptr->sign_nid = tls12_find_nid(sigptr->rsign, tls12_sig,
+                                       sizeof(tls12_sig)/sizeof(tls12_lookup));
+               if (!OBJ_find_sigid_by_algs(&sigptr->signandhash_nid,
+                                               sigptr->hash_nid,
+                                               sigptr->sign_nid))
+                       sigptr->signandhash_nid = NID_undef;
+               switch(sigptr->rsign)
                        {
 #ifndef OPENSSL_NO_RSA
                        case TLSEXT_signature_rsa:
@@ -2296,7 +2675,7 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
 
                if (c->pkeys[idx].digest == NULL)
                        {
-                       md = tls12_get_hash(hash_alg);
+                       md = tls12_get_hash(sigptr->rhash);
                        if (md)
                                {
                                c->pkeys[idx].digest = md;
@@ -2330,3 +2709,175 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
        }
 
 #endif
+
+int SSL_get_sigalgs(SSL *s, int idx,
+                       int *psign, int *phash, int *psignandhash,
+                       unsigned char *rsig, unsigned char *rhash)
+       {
+       if (s->cert->sigalgs == NULL)
+               return 0;
+       if (idx >= 0)
+               {
+               TLS_SIGALGS *psig;
+               if (idx >= (int)s->cert->sigalgslen)
+                       return 0;
+               psig = s->cert->sigalgs + idx;
+               if (psign)
+                       *psign = psig->sign_nid;
+               if (phash)
+                       *phash = psig->hash_nid;
+               if (psignandhash)
+                       *psignandhash = psig->signandhash_nid;
+               if (rsig)
+                       *rsig = psig->rsign;
+               if (rhash)
+                       *rhash = psig->rhash;
+               }
+       return s->cert->sigalgslen;
+       }
+       
+
+#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