Make i2r_sctlist static.
[openssl.git] / ssl / t1_lib.c
index 8b7cce65f308963191cb582294b3458e4093587c..27621cdf066c4f8fcb786c5fd012099fe72abaa5 100644 (file)
  */
 
 #include <stdio.h>
+#include <time.h>
+#include <openssl/bio.h>
+#include <openssl/bn.h>
 #include <openssl/objects.h>
 #include <openssl/evp.h>
 #include <openssl/hmac.h>
@@ -539,7 +542,7 @@ int tls1_set_curves(unsigned char **pext, size_t *pextlen,
        return 1;
        }
 
-#define MAX_CURVELIST  25
+#define MAX_CURVELIST  28
 
 typedef struct
        {
@@ -1089,7 +1092,7 @@ void ssl_set_client_disabled(SSL *s)
        c->valid = 1;
        }
 
-unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
+unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit, int *al)
        {
        int extdatalen=0;
        unsigned char *ret = p;
@@ -1108,7 +1111,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
 
                        alg_k = c->algorithm_mkey;
                        alg_a = c->algorithm_auth;
-                       if ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)
+                       if ((alg_k & (SSL_kECDHE|SSL_kECDHr|SSL_kECDHe)
                                || (alg_a & SSL_aECDSA)))
                                {
                                using_ecc = 1;
@@ -1453,7 +1456,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                                {
                                int cb_retval = 0;
                                cb_retval = record->fn1(s, record->ext_type,
-                                                       &out, &outlen,
+                                                       &out, &outlen, al,
                                                        record->arg);
                                if (cb_retval == 0)
                                        return NULL; /* error */
@@ -1472,17 +1475,30 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
        s2n(TLSEXT_TYPE_encrypt_then_mac,ret);
        s2n(0,ret);
 #endif
-#ifdef TLSEXT_TYPE_wtf
-       {
-       /* Work out length which would be used in the TLS record:
-        * NB this should ALWAYS appear after all other extensions.
+#ifdef TLSEXT_TYPE_padding
+       /* Add padding to workaround bugs in F5 terminators.
+        * See https://tools.ietf.org/html/draft-agl-tls-padding-02
+        *
+        * NB: because this code works out the length of all existing
+        * extensions it MUST always appear last.
         */
-       int hlen = ret - (unsigned char *)s->init_buf->data - 3;
+       {
+       int hlen = ret - (unsigned char *)s->init_buf->data;
+       /* The code in s23_clnt.c to build ClientHello messages includes the
+        * 5-byte record header in the buffer, while the code in s3_clnt.c does
+        * not. */
+       if (s->state == SSL23_ST_CW_CLNT_HELLO_A)
+               hlen -= 5;
        if (hlen > 0xff && hlen < 0x200)
                {
                hlen = 0x200 - hlen;
-               s2n(TLSEXT_TYPE_wtf,ret);
-               s2n(hlen,ret);
+               if (hlen >= 4)
+                       hlen -= 4;
+               else
+                       hlen = 0;
+
+               s2n(TLSEXT_TYPE_padding, ret);
+               s2n(hlen, ret);
                memset(ret, 0, hlen);
                ret += hlen;
                }
@@ -1496,17 +1512,19 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
        return ret;
        }
 
-unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
+unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit, int *al)
        {
        int extdatalen=0;
        unsigned char *ret = p;
+       size_t i;
+       custom_srv_ext_record *record;
 #ifndef OPENSSL_NO_NEXTPROTONEG
        int next_proto_neg_seen;
 #endif
 #ifndef OPENSSL_NO_EC
        unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
        unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
-       int using_ecc = (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA);
+       int using_ecc = (alg_k & (SSL_kECDHE|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA);
        using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
 #endif
        /* don't add extensions for SSLv3, unless doing secure renegotiation */
@@ -1683,45 +1701,30 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
                }
 #endif
 
-       /* If custom types were sent in ClientHello, add ServerHello responses */
-       if (s->s3->tlsext_custom_types_count)
+       for (i = 0; i < s->ctx->custom_srv_ext_records_count; i++)
                {
-               size_t i;
+               const unsigned char *out = NULL;
+               unsigned short outlen = 0;
+               int cb_retval = 0;
 
-               for (i = 0; i < s->s3->tlsext_custom_types_count; i++)
-                       {
-                       size_t j;
-                       custom_srv_ext_record *record;
+               record = &s->ctx->custom_srv_ext_records[i];
 
-                       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;
-                                       }
-                               }
-                       }
+               /* NULL callback or -1 omits extension */
+               if (!record->fn2)
+                       continue;
+               cb_retval = record->fn2(s, record->ext_type,
+                                                               &out, &outlen, al,
+                                                               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;
                }
 #ifdef TLSEXT_TYPE_encrypt_then_mac
        if (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC)
@@ -1936,12 +1939,12 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
                }
 
        /* Clear observed custom extensions */
-       s->s3->tlsext_custom_types_count = 0;
-       if (s->s3->tlsext_custom_types != NULL)
+       s->s3->serverinfo_client_tlsext_custom_types_count = 0;
+       if (s->s3->serverinfo_client_tlsext_custom_types != NULL)
                {
-               OPENSSL_free(s->s3->tlsext_custom_types);
-               s->s3->tlsext_custom_types = NULL;
-               }               
+               OPENSSL_free(s->s3->serverinfo_client_tlsext_custom_types);
+               s->s3->serverinfo_client_tlsext_custom_types = NULL;
+               }
 
 #ifndef OPENSSL_NO_HEARTBEATS
        s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
@@ -2277,8 +2280,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
                                return 0;
                                }
                        }
-               else if (type == TLSEXT_TYPE_status_request
-                        && s->ctx->tlsext_status_cb)
+               else if (type == TLSEXT_TYPE_status_request)
                        {
                
                        if (size < 5) 
@@ -2464,35 +2466,8 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
                                record = &s->ctx->custom_srv_ext_records[i];
                                if (type == record->ext_type)
                                        {
-                                       size_t j;
-
-                                       /* Error on duplicate TLS Extensions */
-                                       for (j = 0; j < s->s3->tlsext_custom_types_count; j++)
-                                               {
-                                               if (type == s->s3->tlsext_custom_types[j])
-                                                       {
-                                                       *al = TLS1_AD_DECODE_ERROR;
-                                                       return 0;
-                                                       }
-                                               }
-
-                                       /* NULL callback still notes the extension */ 
                                        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;
                                        }                                               
                                }
                        }
@@ -3124,7 +3099,7 @@ int ssl_check_serverhello_tlsext(SSL *s)
        unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
        if ((s->tlsext_ecpointformatlist != NULL) && (s->tlsext_ecpointformatlist_length > 0) && 
            (s->session->tlsext_ecpointformatlist != NULL) && (s->session->tlsext_ecpointformatlist_length > 0) && 
-           ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA)))
+           ((alg_k & (SSL_kECDHE|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA)))
                {
                /* we are using an ECC cipher */
                size_t i;
@@ -4460,3 +4435,126 @@ int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain)
        }
 
 #endif
+
+/* RFC6962 Signed Certificate Timestamp List X.509 extension parser */
+static int i2r_sctlist(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *oct,
+                      BIO *out, int indent)
+       {
+       BN_ULLONG timestamp;
+       struct tm tm1;
+       time_t unix_epoch = 0;
+       unsigned char* data = oct->data;
+       char month[4];
+       unsigned short listlen, sctlen = 0, fieldlen;
+       int signhash_nid;
+
+       if (oct->length < 2)
+               return 0;
+       n2s(data, listlen);
+       if (listlen != oct->length - 2)
+               return 0;
+
+       while (listlen > 0)
+               {
+               if (listlen < 2)
+                       return 0;
+               n2s(data, sctlen);
+               listlen -= 2;
+
+               if ((sctlen < 1) || (sctlen > listlen))
+                       return 0;
+               listlen -= sctlen;
+
+               BIO_printf(out, "%*sSigned Certificate Timestamp:", indent,
+                          "");
+
+               if (*data == 0)         /* SCT v1 */
+                       {
+                       /* Fixed-length header:
+                        *              struct {
+                        * (1 byte)       Version sct_version;
+                        * (32 bytes)     LogID id;
+                        * (8 bytes)      uint64 timestamp;
+                        * (2 bytes + ?)  CtExtensions extensions;
+                        */
+                       if (sctlen < 43)
+                               return 0;
+                       sctlen -= 43;
+
+                       BIO_printf(out, "\n%*sVersion   : v1(0)", indent + 4,
+                                  "");
+
+                       BIO_printf(out, "\n%*sLog ID    : ", indent + 4, "");
+                       BIO_hex_string(out, indent + 16, 16, data + 1, 32);
+
+                       data += 33;
+                       n2l8(data, timestamp);
+                       OPENSSL_gmtime(&unix_epoch, &tm1);
+                       OPENSSL_gmtime_adj(&tm1, timestamp / 86400000,
+                                          (timestamp % 86400000) / 1000);
+                       strftime(month, 4, "%b", &tm1);
+                       BIO_printf(out, "\n%*sTimestamp : ", indent + 4, "");
+                       BIO_printf(out, "%s %2d %02d:%02d:%02d.%03u %d UTC",
+                                  month, tm1.tm_mday, tm1.tm_hour,
+                                  tm1.tm_min, tm1.tm_sec,
+                                  (unsigned int)(timestamp % 1000),
+                                  tm1.tm_year + 1900);
+
+                       n2s(data, fieldlen);
+                       if (sctlen < fieldlen)
+                               return 0;
+                       sctlen -= fieldlen;
+                       BIO_printf(out, "\n%*sExtensions: ", indent + 4, "");
+                       if (fieldlen == 0)
+                               BIO_printf(out, "none");
+                       else
+                               BIO_hex_string(out, indent + 16, 16, data,
+                                              fieldlen);
+                       data += fieldlen;
+
+                       /* digitally-signed struct header:
+                        * (1 byte) Hash algorithm
+                        * (1 byte) Signature algorithm
+                        * (2 bytes + ?) Signature
+                        */
+                       if (sctlen < 4)
+                               return 0;
+                       sctlen -= 4;
+
+                       tls1_lookup_sigalg(NULL, NULL, &signhash_nid, data);
+                       data += 2;
+                       n2s(data, fieldlen);
+                       if (sctlen != fieldlen)
+                               return 0;
+                       BIO_printf(out, "\n%*sSignature : ", indent + 4, "");
+                       BIO_printf(out, "%s", OBJ_nid2ln(signhash_nid));
+                       BIO_printf(out, "\n%*s            ", indent + 4, "");
+                       BIO_hex_string(out, indent + 16, 16, data, fieldlen);
+                       if (listlen > 0) BIO_printf(out, "\n");
+                       data += fieldlen;
+                       }
+               }
+
+       return 1;
+       }
+
+static X509V3_EXT_METHOD ext_method_ct_precert_scts =
+       {
+       NID_ct_precert_scts, 0, ASN1_ITEM_ref(ASN1_OCTET_STRING),
+       0, 0, 0, 0, 0, 0, 0, 0, (X509V3_EXT_I2R)i2r_sctlist, NULL, NULL
+       };
+
+static X509V3_EXT_METHOD ext_method_ct_cert_scts =
+       {
+       NID_ct_cert_scts, 0, ASN1_ITEM_ref(ASN1_OCTET_STRING),
+       0, 0, 0, 0, 0, 0, 0, 0, (X509V3_EXT_I2R)i2r_sctlist, NULL, NULL
+       };
+
+int X509V3_EXT_add_rfc6962(void)
+       {
+       if (!X509V3_EXT_add(&ext_method_ct_precert_scts))
+               return 0;
+       if (!X509V3_EXT_add(&ext_method_ct_cert_scts))
+               return 0;
+       return 1;
+       }