Add support for application defined signature algorithms for use with
[openssl.git] / ssl / s3_srvr.c
index 53b3515..6ae2c4d 100644 (file)
 #define NETSCAPE_HANG_BUG
 
 #include <stdio.h>
-#include <openssl/crypto.h>
 #include "ssl_locl.h"
 #include "kssl_lcl.h"
 #include <openssl/buffer.h>
@@ -181,7 +180,7 @@ static const SSL_METHOD *ssl3_get_server_method(int ver)
        }
 
 #ifndef OPENSSL_NO_SRP
-static int ssl_check_srp_ext_ClientHello(SSL *s,int *al)
+static int ssl_check_srp_ext_ClientHello(SSL *s, int *al)
        {
        int ret = SSL_ERROR_NONE;
 
@@ -298,6 +297,7 @@ int ssl3_accept(SSL *s)
 
                        s->init_num=0;
                        s->s3->flags &= ~SSL3_FLAGS_SGC_RESTART_DONE;
+                       s->s3->flags &= ~TLS1_FLAGS_SKIP_CERT_VERIFY;
 
                        if (s->state != SSL_ST_RENEGOTIATE)
                                {
@@ -402,9 +402,30 @@ int ssl3_accept(SSL *s)
                                        s->state=SSL3_ST_SW_CHANGE_A;
 #endif
                        else
-                               s->state=SSL3_ST_SW_CERT_A;
-                       s->init_num=0;
+#ifndef OPENSSL_NO_TLSEXT
+                               s->state = SSL3_ST_SW_SUPPLEMENTAL_DATA_A;
+#else
+                       s->state = SSL3_ST_SW_CERT_A;
+#endif
+                       s->init_num = 0;
+                       break;
+
+#ifndef OPENSSL_NO_TLSEXT
+               case SSL3_ST_SW_SUPPLEMENTAL_DATA_A:
+               case SSL3_ST_SW_SUPPLEMENTAL_DATA_B:
+                       /* We promised to send an audit proof in the hello. */
+                       if (s->s3->tlsext_authz_promised_to_client)
+                               {
+                               ret = tls1_send_server_supplemental_data(s);
+                               if (ret <= 0) goto end;
+                               }
+                       else
+                               skip = 1;
+
+                       s->state = SSL3_ST_SW_CERT_A;
+                       s->init_num = 0;
                        break;
+#endif
 
                case SSL3_ST_SW_CERT_A:
                case SSL3_ST_SW_CERT_B:
@@ -478,7 +499,7 @@ int ssl3_accept(SSL *s)
                            /* SRP: send ServerKeyExchange */
                            || (alg_k & SSL_kSRP)
 #endif
-                           || (alg_k & (SSL_kDHr|SSL_kDHd|SSL_kEDH))
+                           || (alg_k & SSL_kEDH)
                            || (alg_k & SSL_kEECDH)
                            || ((alg_k & SSL_kRSA)
                                && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
@@ -872,14 +893,6 @@ int ssl3_check_client_hello(SSL *s)
        int ok;
        long n;
 
-       /* We only allow the client to restart the handshake once per
-        * negotiation. */
-       if (s->s3->flags & SSL3_FLAGS_SGC_RESTART_DONE)
-               {
-               SSLerr(SSL_F_SSL3_CHECK_CLIENT_HELLO, SSL_R_MULTIPLE_SGC_RESTARTS);
-               return -1;
-               }
-
        /* this function is called when we really expect a Certificate message,
         * so permit appropriate message length */
        n=s->method->ssl_get_message(s,
@@ -892,6 +905,13 @@ int ssl3_check_client_hello(SSL *s)
        s->s3->tmp.reuse_message = 1;
        if (s->s3->tmp.message_type == SSL3_MT_CLIENT_HELLO)
                {
+               /* We only allow the client to restart the handshake once per
+                * negotiation. */
+               if (s->s3->flags & SSL3_FLAGS_SGC_RESTART_DONE)
+                       {
+                       SSLerr(SSL_F_SSL3_CHECK_CLIENT_HELLO, SSL_R_MULTIPLE_SGC_RESTARTS);
+                       return -1;
+                       }
                /* Throw away what we have done so far in the current handshake,
                 * which will now be aborted. (A full SSL_clear would be too much.) */
 #ifndef OPENSSL_NO_DH
@@ -916,7 +936,7 @@ int ssl3_check_client_hello(SSL *s)
 
 int ssl3_get_client_hello(SSL *s)
        {
-       int i,j,ok,al,ret= -1;
+       int i,j,ok,al=SSL_AD_INTERNAL_ERROR,ret= -1;
        unsigned int cookie_len;
        long n;
        unsigned long id;
@@ -1177,16 +1197,11 @@ int ssl3_get_client_hello(SSL *s)
        /* TLS extensions*/
        if (s->version >= SSL3_VERSION)
                {
-               if (!ssl_parse_clienthello_tlsext(s,&p,d,n, &al))
+               if (!ssl_parse_clienthello_tlsext(s,&p,d,n))
                        {
-                       /* 'al' set by ssl_parse_clienthello_tlsext */
                        SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLSEXT);
-                       goto f_err;
-                       }
-               }
-               if (ssl_check_clienthello_tlsext(s) <= 0) {
-                       SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
                        goto err;
+                       }
                }
 
        /* Check if we want to use external pre-shared secret for this
@@ -1201,7 +1216,6 @@ int ssl3_get_client_hello(SSL *s)
                l2n(Time,pos);
                if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
                        {
-                       al=SSL_AD_INTERNAL_ERROR;
                        goto f_err;
                        }
        }
@@ -1256,7 +1270,6 @@ int ssl3_get_client_hello(SSL *s)
                /* Can't disable compression */
                if (s->options & SSL_OP_NO_COMPRESSION)
                        {
-                       al=SSL_AD_INTERNAL_ERROR;
                        SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INCONSISTENT_COMPRESSION);
                        goto f_err;
                        }
@@ -1272,7 +1285,6 @@ int ssl3_get_client_hello(SSL *s)
                        }
                if (s->s3->tmp.new_compression == NULL)
                        {
-                       al=SSL_AD_INTERNAL_ERROR;
                        SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INVALID_COMPRESSION_ALGORITHM);
                        goto f_err;
                        }
@@ -1321,7 +1333,6 @@ int ssl3_get_client_hello(SSL *s)
         */
        if (s->session->compress_meth != 0)
                {
-               al=SSL_AD_INTERNAL_ERROR;
                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INCONSISTENT_COMPRESSION);
                goto f_err;
                }
@@ -1683,7 +1694,14 @@ int ssl3_send_server_key_exchange(SSL *s)
                        const EC_GROUP *group;
 
                        ecdhp=cert->ecdh_tmp;
-                       if ((ecdhp == NULL) && (s->cert->ecdh_tmp_cb != NULL))
+                       if (s->cert->ecdh_tmp_auto)
+                               {
+                               /* Get NID of first shared curve */
+                               int nid = tls1_shared_curve(s, 0);
+                               if (nid != NID_undef)
+                                       ecdhp = EC_KEY_new_by_curve_name(nid);
+                               }
+                       else if ((ecdhp == NULL) && s->cert->ecdh_tmp_cb)
                                {
                                ecdhp=s->cert->ecdh_tmp_cb(s,
                                      SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
@@ -1708,7 +1726,9 @@ int ssl3_send_server_key_exchange(SSL *s)
                                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
                                goto err;
                                }
-                       if ((ecdh = EC_KEY_dup(ecdhp)) == NULL)
+                       if (s->cert->ecdh_tmp_auto)
+                               ecdh = ecdhp;
+                       else if ((ecdh = EC_KEY_dup(ecdhp)) == NULL)
                                {
                                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
                                goto err;
@@ -2046,7 +2066,7 @@ int ssl3_send_certificate_request(SSL *s)
 
                if (TLS1_get_version(s) >= TLS1_2_VERSION)
                        {
-                       nl = tls12_get_req_sig_algs(s, p + 2);
+                       nl = tls12_get_sig_algs(s, p + 2);
                        s2n(nl, p);
                        p += nl + 2;
                        n += nl + 2;
@@ -2132,7 +2152,7 @@ int ssl3_get_client_key_exchange(SSL *s)
 #endif
 #ifndef OPENSSL_NO_DH
        BIGNUM *pub=NULL;
-       DH *dh_srvr;
+       DH *dh_srvr, *dh_clnt = NULL;
 #endif
 #ifndef OPENSSL_NO_KRB5
        KSSL_ERR kssl_err;
@@ -2266,8 +2286,13 @@ int ssl3_get_client_key_exchange(SSL *s)
 #ifndef OPENSSL_NO_DH
                if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
                {
-               n2s(p,i);
-               if (n != i+2)
+               int idx = -1;
+               EVP_PKEY *skey = NULL;
+               if (n)
+                       n2s(p,i);
+               else
+                       i = 0;
+               if (n && n != i+2)
                        {
                        if (!(s->options & SSL_OP_SSLEAY_080_CLIENT_DH_BUG))
                                {
@@ -2280,26 +2305,52 @@ int ssl3_get_client_key_exchange(SSL *s)
                                i=(int)n;
                                }
                        }
-
-               if (n == 0L) /* the parameters are in the cert */
+               if (alg_k & SSL_kDHr)
+                       idx = SSL_PKEY_DH_RSA;
+               else if (alg_k & SSL_kDHd)
+                       idx = SSL_PKEY_DH_DSA;
+               if (idx >= 0)
+                       {
+                       skey = s->cert->pkeys[idx].privatekey;
+                       if ((skey == NULL) ||
+                               (skey->type != EVP_PKEY_DH) ||
+                               (skey->pkey.dh == NULL))
+                               {
+                               al=SSL_AD_HANDSHAKE_FAILURE;
+                               SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_RSA_CERTIFICATE);
+                               goto f_err;
+                               }
+                       dh_srvr = skey->pkey.dh;
+                       }
+               else if (s->s3->tmp.dh == NULL)
                        {
                        al=SSL_AD_HANDSHAKE_FAILURE;
-                       SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_DECODE_DH_CERTS);
+                       SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
                        goto f_err;
                        }
                else
+                       dh_srvr=s->s3->tmp.dh;
+
+               if (n == 0L)
                        {
-                       if (s->s3->tmp.dh == NULL)
+                       /* Get pubkey from cert */
+                       EVP_PKEY *clkey=X509_get_pubkey(s->session->peer);
+                       if (clkey)
+                               {
+                               if (EVP_PKEY_cmp_parameters(clkey, skey) == 1)
+                                       dh_clnt = EVP_PKEY_get1_DH(clkey);
+                               }
+                       if (dh_clnt == NULL)
                                {
                                al=SSL_AD_HANDSHAKE_FAILURE;
                                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
                                goto f_err;
                                }
-                       else
-                               dh_srvr=s->s3->tmp.dh;
+                       EVP_PKEY_free(clkey);
+                       pub = dh_clnt->pub_key;
                        }
-
-               pub=BN_bin2bn(p,i,NULL);
+               else
+                       pub=BN_bin2bn(p,i,NULL);
                if (pub == NULL)
                        {
                        SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BN_LIB);
@@ -2317,13 +2368,17 @@ int ssl3_get_client_key_exchange(SSL *s)
 
                DH_free(s->s3->tmp.dh);
                s->s3->tmp.dh=NULL;
-
-               BN_clear_free(pub);
+               if (dh_clnt)
+                       DH_free(dh_clnt);
+               else
+                       BN_clear_free(pub);
                pub=NULL;
                s->session->master_key_length=
                        s->method->ssl3_enc->generate_master_secret(s,
                                s->session->master_key,p,i);
                OPENSSL_cleanse(p,i);
+               if (dh_clnt)
+                       return 2;
                }
        else
 #endif
@@ -2941,7 +2996,7 @@ int ssl3_get_cert_verify(SSL *s)
        if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_VERIFY)
                {
                s->s3->tmp.reuse_message=1;
-               if ((peer != NULL) && (type | EVP_PKT_SIGN))
+               if ((peer != NULL) && (type & EVP_PKT_SIGN))
                        {
                        al=SSL_AD_UNEXPECTED_MESSAGE;
                        SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_MISSING_VERIFY_MESSAGE);
@@ -3328,12 +3383,12 @@ err:
 int ssl3_send_server_certificate(SSL *s)
        {
        unsigned long l;
-       X509 *x;
+       CERT_PKEY *cpk;
 
        if (s->state == SSL3_ST_SW_CERT_A)
                {
-               x=ssl_get_server_send_cert(s);
-               if (x == NULL)
+               cpk=ssl_get_server_send_pkey(s);
+               if (cpk == NULL)
                        {
                        /* VRS: allow null cert if auth == KRB5 */
                        if ((s->s3->tmp.new_cipher->algorithm_auth != SSL_aKRB5) ||
@@ -3344,7 +3399,7 @@ int ssl3_send_server_certificate(SSL *s)
                                }
                        }
 
-               l=ssl3_output_cert_chain(s,x);
+               l=ssl3_output_cert_chain(s,cpk);
                s->state=SSL3_ST_SW_CERT_B;
                s->init_num=(int)l;
                s->init_off=0;
@@ -3527,7 +3582,7 @@ int ssl3_send_cert_status(SSL *s)
        return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
        }
 
-# ifndef OPENSSL_NO_NPN
+# ifndef OPENSSL_NO_NEXTPROTONEG
 /* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It
  * sets the next_proto member in s if found */
 int ssl3_get_next_proto(SSL *s)
@@ -3594,4 +3649,99 @@ int ssl3_get_next_proto(SSL *s)
        return 1;
        }
 # endif
+
+int tls1_send_server_supplemental_data(SSL *s)
+       {
+       size_t length = 0;
+       const unsigned char *authz, *orig_authz;
+       unsigned char *p;
+       size_t authz_length, i;
+
+       if (s->state != SSL3_ST_SW_SUPPLEMENTAL_DATA_A)
+               return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+
+       orig_authz = authz = ssl_get_authz_data(s, &authz_length);
+       if (authz == NULL)
+               {
+               /* This should never occur. */
+               return 0;
+               }
+
+       /* First we walk over the authz data to see how long the handshake
+        * message will be. */
+       for (i = 0; i < authz_length; i++)
+               {
+               unsigned short len;
+               unsigned char type;
+
+               type = *(authz++);
+               n2s(authz, len);
+               /* n2s increments authz by 2*/
+               i += 2;
+
+               if (memchr(s->s3->tlsext_authz_client_types,
+                          type,
+                          s->s3->tlsext_authz_client_types_len) != NULL)
+                       length += 1 /* authz type */ + 2 /* length */ + len;
+
+               authz += len;
+               i += len;
+               }
+
+       length += 1 /* handshake type */ +
+                 3 /* handshake length */ +
+                 3 /* supplemental data length */ +
+                 2 /* supplemental entry type */ +
+                 2 /* supplemental entry length */;
+
+       if (!BUF_MEM_grow_clean(s->init_buf, length))
+               {
+               SSLerr(SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB);
+               return 0;
+               }
+
+       p = (unsigned char *)s->init_buf->data;
+       *(p++) = SSL3_MT_SUPPLEMENTAL_DATA;
+       /* Handshake length */
+       l2n3(length - 4, p);
+       /* Length of supplemental data */
+       l2n3(length - 7, p);
+       /* Supplemental data type */
+       s2n(TLSEXT_SUPPLEMENTALDATATYPE_authz_data, p);
+       /* Its length */
+       s2n(length - 11, p);
+
+       authz = orig_authz;
+
+       /* Walk over the authz again and append the selected elements. */
+       for (i = 0; i < authz_length; i++)
+               {
+               unsigned short len;
+               unsigned char type;
+
+               type = *(authz++);
+               n2s(authz, len);
+               /* n2s increments authz by 2 */
+               i += 2;
+
+               if (memchr(s->s3->tlsext_authz_client_types,
+                          type,
+                          s->s3->tlsext_authz_client_types_len) != NULL)
+                       {
+                       *(p++) = type;
+                       s2n(len, p);
+                       memcpy(p, authz, len);
+                       p += len;
+                       }
+
+               authz += len;
+               i += len;
+               }
+
+       s->state = SSL3_ST_SW_SUPPLEMENTAL_DATA_B;
+       s->init_num = length;
+       s->init_off = 0;
+
+       return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+       }
 #endif