Support retries in certificate callback
[openssl.git] / ssl / s3_srvr.c
index 28d5bed483f853770c380ebfac3405e36672cce7..29459f0490e50ae1d8d52a74f81177cf14b2ef63 100644 (file)
@@ -352,12 +352,11 @@ int ssl3_accept(SSL *s)
                case SSL3_ST_SR_CLNT_HELLO_B:
                case SSL3_ST_SR_CLNT_HELLO_C:
 
-                       if (s->rwstate != SSL_X509_LOOKUP)
-                       {
-                               ret=ssl3_get_client_hello(s);
-                               if (ret <= 0) goto end;
-                       }
+                       ret=ssl3_get_client_hello(s);
+                       if (ret <= 0) goto end;
 #ifndef OPENSSL_NO_SRP
+                       s->state = SSL3_ST_SR_CLNT_HELLO_D;
+               case SSL3_ST_SR_CLNT_HELLO_D:
                        {
                        int al;
                        if ((ret = ssl_check_srp_ext_ClientHello(s,&al))  < 0)
@@ -413,14 +412,8 @@ int ssl3_accept(SSL *s)
 #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;
+                       ret = tls1_send_server_supplemental_data(s, &skip);
+                       if (ret <= 0) goto end;
 
                        s->state = SSL3_ST_SW_CERT_A;
                        s->init_num = 0;
@@ -499,8 +492,8 @@ int ssl3_accept(SSL *s)
                            /* SRP: send ServerKeyExchange */
                            || (alg_k & SSL_kSRP)
 #endif
-                           || (alg_k & SSL_kEDH)
-                           || (alg_k & SSL_kEECDH)
+                           || (alg_k & SSL_kDHE)
+                           || (alg_k & SSL_kECDHE)
                            || ((alg_k & SSL_kRSA)
                                && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
                                    || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
@@ -595,7 +588,16 @@ int ssl3_accept(SSL *s)
 
                        s->state=s->s3->tmp.next_state;
                        break;
-
+#ifndef OPENSSL_NO_TLSEXT
+               case SSL3_ST_SR_SUPPLEMENTAL_DATA_A:
+               case SSL3_ST_SR_SUPPLEMENTAL_DATA_B:
+                       ret=tls1_get_client_supplemental_data(s);
+                       if (ret <= 0) goto end;
+                       s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
+                       s->state=SSL3_ST_SW_FLUSH;
+                       s->init_num=0;
+                       break;
+#endif
                case SSL3_ST_SR_CERT_A:
                case SSL3_ST_SR_CERT_B:
                        /* Check for second client hello (MS SGC) */
@@ -604,6 +606,10 @@ int ssl3_accept(SSL *s)
                                goto end;
                        if (ret == 2)
                                s->state = SSL3_ST_SR_CLNT_HELLO_C;
+#ifndef OPENSSL_NO_TLSEXT
+                       else if (ret == 3)
+                               s->state = SSL3_ST_SR_SUPPLEMENTAL_DATA_A;
+#endif
                        else {
                                if (s->s3->tmp.cert_request)
                                        {
@@ -894,6 +900,10 @@ int ssl3_check_client_hello(SSL *s)
                &ok);
        if (!ok) return((int)n);
        s->s3->tmp.reuse_message = 1;
+#ifndef OPENSSL_NO_TLSEXT
+       if (s->s3->tmp.message_type == SSL3_MT_SUPPLEMENTAL_DATA)
+               return 3;
+#endif
        if (s->s3->tmp.message_type == SSL3_MT_CLIENT_HELLO)
                {
                /* We only allow the client to restart the handshake once per
@@ -939,6 +949,9 @@ int ssl3_get_client_hello(SSL *s)
 #endif
        STACK_OF(SSL_CIPHER) *ciphers=NULL;
 
+       if (s->state == SSL3_ST_SR_CLNT_HELLO_C)
+               goto retry_cert;
+
        /* We do this so that we will respond with our native type.
         * If we are TLSv1 and we get SSLv3, we will respond with TLSv1,
         * This down switching should be handled by a different method.
@@ -967,12 +980,13 @@ int ssl3_get_client_hello(SSL *s)
        s->client_version=(((int)p[0])<<8)|(int)p[1];
        p+=2;
 
-       if ((SSL_IS_DTLS(s) && s->client_version > s->version
-                       && s->method->version != DTLS_ANY_VERSION) ||
-           (!SSL_IS_DTLS(s) && s->client_version < s->version))
+       if (SSL_IS_DTLS(s)  ?   (s->client_version > s->version &&
+                                s->method->version != DTLS_ANY_VERSION)
+                           :   (s->client_version < s->version))
                {
                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER);
-               if ((s->client_version>>8) == SSL3_VERSION_MAJOR)
+               if ((s->client_version>>8) == SSL3_VERSION_MAJOR &&
+                       !s->enc_write_ctx && !s->write_hash)
                        {
                        /* similar to ssl3_get_record, send alert using remote version number */
                        s->version = s->client_version;
@@ -1235,12 +1249,9 @@ int ssl3_get_client_hello(SSL *s)
         * server_random before calling tls_session_secret_cb in order to allow
         * SessionTicket processing to use it in key derivation. */
        {
-               unsigned long Time;
                unsigned char *pos;
-               Time=(unsigned long)time(NULL);                 /* Time */
                pos=s->s3->server_random;
-               l2n(Time,pos);
-               if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
+               if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE) <= 0)
                        {
                        goto f_err;
                        }
@@ -1385,12 +1396,22 @@ int ssl3_get_client_hello(SSL *s)
                        }
                ciphers=NULL;
                /* Let cert callback update server certificates if required */
-               if (s->cert->cert_cb
-                       && s->cert->cert_cb(s, s->cert->cert_cb_arg) <= 0)
+               retry_cert:             
+               if (s->cert->cert_cb)
                        {
-                       al=SSL_AD_INTERNAL_ERROR;
-                       SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CERT_CB_ERROR);
-                       goto f_err;
+                       int rv = s->cert->cert_cb(s, s->cert->cert_cb_arg);
+                       if (rv == 0)
+                               {
+                               al=SSL_AD_INTERNAL_ERROR;
+                               SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CERT_CB_ERROR);
+                               goto f_err;
+                               }
+                       if (rv < 0)
+                               {
+                               s->rwstate=SSL_X509_LOOKUP;
+                               return -1;
+                               }
+                       s->rwstate = SSL_NOTHING;
                        }
                c=ssl3_choose_cipher(s,s->session->ciphers,
                                     SSL_get_ciphers(s));
@@ -1405,7 +1426,7 @@ int ssl3_get_client_hello(SSL *s)
                /* check whether we should disable session resumption */
                if (s->not_resumable_session_cb != NULL)
                        s->session->not_resumable=s->not_resumable_session_cb(s,
-                               ((c->algorithm_mkey & (SSL_kEDH | SSL_kEECDH)) != 0));
+                               ((c->algorithm_mkey & (SSL_kDHE | SSL_kECDHE)) != 0));
                if (s->session->not_resumable)
                        /* do not send a session ticket */
                        s->tlsext_ticket_expected = 0;
@@ -1485,19 +1506,13 @@ int ssl3_send_server_hello(SSL *s)
        unsigned char *p,*d;
        int i,sl;
        unsigned long l;
-#ifdef OPENSSL_NO_TLSEXT
-       unsigned long Time;
-#endif
 
        if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
                {
                buf=(unsigned char *)s->init_buf->data;
 #ifdef OPENSSL_NO_TLSEXT
                p=s->s3->server_random;
-               /* Generate server_random if it was not needed previously */
-               Time=(unsigned long)time(NULL);                 /* Time */
-               l2n(Time,p);
-               if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
+               if (ssl_fill_hello_random(s, 1, p, SSL3_RANDOM_SIZE) <= 0)
                        return -1;
 #endif
                /* Do the message type and length last */
@@ -1660,7 +1675,7 @@ int ssl3_send_server_key_exchange(SSL *s)
                else
 #endif
 #ifndef OPENSSL_NO_DH
-                       if (type & SSL_kEDH)
+                       if (type & SSL_kDHE)
                        {
                        dhp=cert->dh_tmp;
                        if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
@@ -1716,7 +1731,7 @@ int ssl3_send_server_key_exchange(SSL *s)
                else 
 #endif
 #ifndef OPENSSL_NO_ECDH
-                       if (type & SSL_kEECDH)
+                       if (type & SSL_kECDHE)
                        {
                        const EC_GROUP *group;
 
@@ -1932,7 +1947,7 @@ int ssl3_send_server_key_exchange(SSL *s)
                        }
 
 #ifndef OPENSSL_NO_ECDH
-               if (type & SSL_kEECDH
+               if (type & SSL_kECDHE
                        {
                        /* XXX: For now, we only support named (not generic) curves.
                         * In this situation, the serverKeyExchange message has:
@@ -2104,12 +2119,12 @@ int ssl3_send_certificate_request(SSL *s)
                                {
                                name=sk_X509_NAME_value(sk,i);
                                j=i2d_X509_NAME(name,NULL);
-                               if (!BUF_MEM_grow_clean(buf,4+n+j+2))
+                               if (!BUF_MEM_grow_clean(buf,SSL_HM_HEADER_LENGTH(s)+n+j+2))
                                        {
                                        SSLerr(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST,ERR_R_BUF_LIB);
                                        goto err;
                                        }
-                               p=(unsigned char *)&(buf->data[4+n]);
+                               p = ssl_handshake_start(s) + n;
                                if (!(s->options & SSL_OP_NETSCAPE_CA_DN_BUG))
                                        {
                                        s2n(j,p);
@@ -2343,7 +2358,7 @@ int ssl3_get_client_key_exchange(SSL *s)
        else
 #endif
 #ifndef OPENSSL_NO_DH
-               if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+               if (alg_k & (SSL_kDHE|SSL_kDHr|SSL_kDHd))
                {
                int idx = -1;
                EVP_PKEY *skey = NULL;
@@ -2635,7 +2650,7 @@ int ssl3_get_client_key_exchange(SSL *s)
 #endif /* OPENSSL_NO_KRB5 */
 
 #ifndef OPENSSL_NO_ECDH
-               if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
+               if (alg_k & (SSL_kECDHE|SSL_kECDHr|SSL_kECDHe))
                {
                int ret = 1;
                int field_size = 0;
@@ -2688,7 +2703,7 @@ int ssl3_get_client_key_exchange(SSL *s)
                        {
                        /* Client Publickey was in Client Certificate */
 
-                        if (alg_k & SSL_kEECDH)
+                        if (alg_k & SSL_kECDHE)
                                 {
                                 al=SSL_AD_HANDSHAKE_FAILURE;
                                 SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY);
@@ -3686,98 +3701,153 @@ int ssl3_get_next_proto(SSL *s)
        }
 # endif
 
-int tls1_send_server_supplemental_data(SSL *s)
+int tls1_send_server_supplemental_data(SSL *s, int *skip)
        {
-       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;
+       if (s->ctx->srv_supp_data_records_count)
+               {
+               unsigned char *p = NULL;
+               unsigned char *size_loc = NULL;
+               srv_supp_data_record *record = NULL;
+               size_t length = 0;
+               size_t i = 0;
+
+               for (i = 0; i < s->ctx->srv_supp_data_records_count; i++)
+                       {
+                       const unsigned char *out = NULL;
+                       unsigned short outlen = 0;
+                       int cb_retval = 0;
+                       record = &s->ctx->srv_supp_data_records[i];
+
+                       /* NULL callback or -1 omits supp data entry */
+                       if (!record->fn1)
+                               continue;
+                       cb_retval = record->fn1(s, record->supp_data_type,
+                       &out, &outlen,
+                       record->arg);
+                       if (cb_retval == -1)
+                               continue; /* skip this supp data entry */
+                       if (cb_retval == 0)
+                               {
+                               SSLerr(SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB);
+                               return 0;
+                               }
+                       if (outlen == 0 || TLSEXT_MAXLEN_supplemental_data < outlen + 4 + length)
+                               {
+                               SSLerr(SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB);
+                               return 0;
+                               }
+                       /* write supp data entry...
+                        * if first entry, write handshake message type
+                        * jump back to write length at end */
+                       if (length == 0)
+                               {
+                               /* 1 byte message type + 3 bytes for
+                                * message length */
+                               if (!BUF_MEM_grow_clean(s->init_buf, 4))
+                                       {
+                                       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;
+                               /* hold on to length field to update later */
+                               size_loc = p;
+                               /* skip over handshake length field (3
+                                * bytes) and supp_data length field
+                                * (3 bytes) */
+                               p += 3 + 3;
+                               length += 1 +3 +3;
+                               }
+                       /* 2 byte supp data type + 2 byte length + outlen */
+                       if (!BUF_MEM_grow(s->init_buf, outlen + 4))
+                               {
+                               SSLerr(SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB);
+                               return 0;
+                               }
+                       s2n(record->supp_data_type, p);
+                       s2n(outlen, p);
+                       memcpy(p, out, outlen);
+                       /* update length to supp data type (2 bytes) +
+                        * supp data length (2 bytes) + supp data */
+                       length += (outlen + 4);
+                       p += outlen;
+                       }
+               if (length > 0)
+                       {
+                       /* write handshake length */
+                       l2n3(length - 4, size_loc);
+                       /* supp_data length */
+                       l2n3(length - 7, size_loc);
+                       s->state = SSL3_ST_SW_SUPPLEMENTAL_DATA_B;
+                       s->init_num = length;
+                       s->init_off = 0;
+
+                       return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+                       }
+               }
+
+       /* no supp data message sent */
+       *skip = 1;
+       s->init_num = 0;
+       s->init_off = 0;
+       return 1;
+       }
 
-               type = *(authz++);
-               n2s(authz, len);
-               /* n2s increments authz by 2*/
-               i += 2;
+int tls1_get_client_supplemental_data(SSL *s)
+       {
+       int al = 0;
+       int cb_retval = 0;
+       int ok;
+       long n;
+       const unsigned char *p, *d;
+       unsigned short supp_data_entry_type = 0;
+       unsigned long supp_data_entry_len = 0;
+       unsigned long supp_data_len = 0;
+       size_t i = 0;
 
-               if (memchr(s->s3->tlsext_authz_client_types,
-                          type,
-                          s->s3->tlsext_authz_client_types_len) != NULL)
-                       length += 1 /* authz type */ + 2 /* length */ + len;
+       n=s->method->ssl_get_message(s,
+       SSL3_ST_SR_SUPPLEMENTAL_DATA_A,
+       SSL3_ST_SR_SUPPLEMENTAL_DATA_B,
+       SSL3_MT_SUPPLEMENTAL_DATA,
+       /* use default limit */
+       TLSEXT_MAXLEN_supplemental_data,
+       &ok);
 
-               authz += len;
-               i += len;
-               }
+       if (!ok) return((int)n);
 
-       length += 1 /* handshake type */ +
-                 3 /* handshake length */ +
-                 3 /* supplemental data length */ +
-                 2 /* supplemental entry type */ +
-                 2 /* supplemental entry length */;
+       p = (unsigned char *)s->init_msg;
+       d = p;
 
-       if (!BUF_MEM_grow_clean(s->init_buf, length))
+       /* The message cannot be empty */
+       if (n < 3)
                {
-               SSLerr(SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB);
-               return 0;
+               al = SSL_AD_DECODE_ERROR;
+               SSLerr(SSL_F_TLS1_GET_CLIENT_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
+               goto f_err;
                }
-
-       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++)
+       n2l3(p, supp_data_len);
+       while (p<d+supp_data_len)
                {
-               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)
+               n2s(p, supp_data_entry_type);
+               n2s(p, supp_data_entry_len);
+               /* if there is a callback for this supp data type, send it */
+               for (i=0; i < s->ctx->srv_supp_data_records_count; i++)
                        {
-                       *(p++) = type;
-                       s2n(len, p);
-                       memcpy(p, authz, len);
-                       p += len;
+                       if (s->ctx->srv_supp_data_records[i].supp_data_type == supp_data_entry_type && s->ctx->srv_supp_data_records[i].fn2)
+                               {
+                               cb_retval = s->ctx->srv_supp_data_records[i].fn2(s, supp_data_entry_type, p, supp_data_entry_len, &al, s->ctx->srv_supp_data_records[i].arg);
+                               if (cb_retval == 0)
+                                       {
+                                       SSLerr(SSL_F_TLS1_GET_CLIENT_SUPPLEMENTAL_DATA, ERR_R_SSL_LIB);
+                                       goto f_err;
+                                       }
+                               }
                        }
-
-               authz += len;
-               i += len;
+               p+=supp_data_entry_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);
+       return 1;
+f_err:
+       ssl3_send_alert(s,SSL3_AL_FATAL,al);
+       return -1;
        }
 #endif