New CMS tests.
[openssl.git] / ssl / t1_lib.c
index 8cb018d65e7ff166e02800229268fc62be23af71..07cb0966461e23797f1ecfc103849ce24f1b9e99 100644 (file)
@@ -1010,7 +1010,7 @@ void ssl_set_client_disabled(SSL *s)
        c->mask_a = 0;
        c->mask_k = 0;
        /* Don't allow TLS 1.2 only ciphers if we don't suppport them */
-       if (!SSL_USE_TLS1_2_CIPHERS(s))
+       if (!SSL_CLIENT_USE_TLS1_2_CIPHERS(s))
                c->mask_ssl = SSL_TLSV1_2;
        else
                c->mask_ssl = 0;
@@ -1443,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;
 
@@ -1709,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;
 
@@ -2274,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)
+                                       {
+                                       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;
+                                       }                                               
+                               }
+                       }
+
                data+=size;
                }
 
@@ -2578,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;
                }