check return value of RAND_pseudo_bytes; backport from the stable branch
[openssl.git] / ssl / s3_srvr.c
index a2f5b843db48847e68b0f29266c1801645dc5d64..7bb68e083d68aef0a6cc73f30206e2752cfbeae5 100644 (file)
@@ -56,7 +56,7 @@
  * [including the GNU Public Licence.]
  */
 /* ====================================================================
- * Copyright (c) 1998-2003 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1998-2005 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include <openssl/objects.h>
 #include <openssl/evp.h>
 #include <openssl/x509.h>
+#include <openssl/dh.h>
+#include <openssl/bn.h>
+#ifndef OPENSSL_NO_KRB5
 #include <openssl/krb5_asn.h>
+#endif
 #include <openssl/md5.h>
-#include "cryptlib.h"
 
 static SSL_METHOD *ssl3_get_server_method(int ver);
-static int ssl3_get_client_hello(SSL *s);
-static int ssl3_check_client_hello(SSL *s);
-static int ssl3_send_server_hello(SSL *s);
-static int ssl3_send_server_key_exchange(SSL *s);
-static int ssl3_send_certificate_request(SSL *s);
-static int ssl3_send_server_done(SSL *s);
-static int ssl3_get_client_key_exchange(SSL *s);
-static int ssl3_get_client_certificate(SSL *s);
-static int ssl3_get_cert_verify(SSL *s);
-static int ssl3_send_hello_request(SSL *s);
 
 #ifndef OPENSSL_NO_ECDH
 static int nid2curve_id(int nid);
@@ -456,10 +449,11 @@ int ssl3_accept(SSL *s)
                        if (ret == 2)
                                s->state = SSL3_ST_SR_CLNT_HELLO_C;
                        else {
-                               /* could be sent for a DH cert, even if we
-                                * have not asked for it :-) */
-                               ret=ssl3_get_client_certificate(s);
-                               if (ret <= 0) goto end;
+                               if (s->s3->tmp.cert_request)
+                                       {
+                                       ret=ssl3_get_client_certificate(s);
+                                       if (ret <= 0) goto end;
+                                       }
                                s->init_num=0;
                                s->state=SSL3_ST_SR_KEY_EXCH_A;
                        }
@@ -625,7 +619,7 @@ end:
        return(ret);
        }
 
-static int ssl3_send_hello_request(SSL *s)
+int ssl3_send_hello_request(SSL *s)
        {
        unsigned char *p;
 
@@ -647,14 +641,14 @@ static int ssl3_send_hello_request(SSL *s)
        return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
        }
 
-static int ssl3_check_client_hello(SSL *s)
+int ssl3_check_client_hello(SSL *s)
        {
        int ok;
        long n;
 
        /* this function is called when we really expect a Certificate message,
         * so permit appropriate message length */
-       n=ssl3_get_message(s,
+       n=s->method->ssl_get_message(s,
                SSL3_ST_SR_CERT_A,
                SSL3_ST_SR_CERT_B,
                -1,
@@ -680,9 +674,10 @@ static int ssl3_check_client_hello(SSL *s)
        return 1;
 }
 
-static int ssl3_get_client_hello(SSL *s)
+int ssl3_get_client_hello(SSL *s)
        {
        int i,j,ok,al,ret= -1;
+       unsigned int cookie_len;
        long n;
        unsigned long id;
        unsigned char *p,*d,*q;
@@ -701,7 +696,7 @@ static int ssl3_get_client_hello(SSL *s)
                s->first_packet=1;
                s->state=SSL3_ST_SR_CLNT_HELLO_B;
                }
-       n=ssl3_get_message(s,
+       n=s->method->ssl_get_message(s,
                SSL3_ST_SR_CLNT_HELLO_B,
                SSL3_ST_SR_CLNT_HELLO_C,
                SSL3_MT_CLIENT_HELLO,
@@ -766,6 +761,68 @@ static int ssl3_get_client_hello(SSL *s)
                }
 
        p+=j;
+
+       if (SSL_version(s) == DTLS1_VERSION)
+               {
+               /* cookie stuff */
+               cookie_len = *(p++);
+
+               if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
+                       s->d1->send_cookie == 0)
+                       {
+                       /* HelloVerifyMessage has already been sent */
+                       if ( cookie_len != s->d1->cookie_len)
+                               {
+                               al = SSL_AD_HANDSHAKE_FAILURE;
+                               SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
+                               goto f_err;
+                               }
+                       }
+
+               /* 
+                * The ClientHello may contain a cookie even if the
+                * HelloVerify message has not been sent--make sure that it
+                * does not cause an overflow.
+                */
+               if ( cookie_len > sizeof(s->d1->rcvd_cookie))
+                       {
+                       /* too much data */
+                       al = SSL_AD_DECODE_ERROR;
+                       SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
+                       goto f_err;
+                       }
+
+               /* verify the cookie if appropriate option is set. */
+               if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
+                       cookie_len > 0)
+                       {
+                       memcpy(s->d1->rcvd_cookie, p, cookie_len);
+
+                       if ( s->ctx->app_verify_cookie_cb != NULL)
+                               {
+                               if ( s->ctx->app_verify_cookie_cb(s, s->d1->rcvd_cookie,
+                                       cookie_len) == 0)
+                                       {
+                                       al=SSL_AD_HANDSHAKE_FAILURE;
+                                       SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, 
+                                               SSL_R_COOKIE_MISMATCH);
+                                       goto f_err;
+                                       }
+                               /* else cookie verification succeeded */
+                               }
+                       else if ( memcmp(s->d1->rcvd_cookie, s->d1->cookie, 
+                                                 s->d1->cookie_len) != 0) /* default verification */
+                               {
+                                       al=SSL_AD_HANDSHAKE_FAILURE;
+                                       SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, 
+                                               SSL_R_COOKIE_MISMATCH);
+                                       goto f_err;
+                               }
+                       }
+
+               p += cookie_len;
+               }
+
        n2s(p,i);
        if ((i == 0) && (j != 0))
                {
@@ -815,8 +872,7 @@ static int ssl3_get_client_hello(SSL *s)
                        if ((s->options & SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG) && (sk_SSL_CIPHER_num(ciphers) == 1))
                                {
                                /* Very bad for multi-threading.... */
-                               s->session->cipher=sk_SSL_CIPHER_value(ciphers,
-                                                                      0);
+                               s->session->cipher=sk_SSL_CIPHER_value(ciphers, 0);
                                }
                        else
                                {
@@ -883,6 +939,9 @@ static int ssl3_get_client_hello(SSL *s)
                }
 
        /* TLS does not mind if there is extra stuff */
+#if 0   /* SSL 3.0 does not mind either, so we should disable this test
+         * (was enabled in 0.9.6d through 0.9.6j and 0.9.7 through 0.9.7b,
+         * in earlier SSLeay/OpenSSL releases this test existed but was buggy) */
        if (s->version == SSL3_VERSION)
                {
                if (p < (d+n))
@@ -894,6 +953,7 @@ static int ssl3_get_client_hello(SSL *s)
                        goto f_err;
                        }
                }
+#endif
 
        /* Given s->session->ciphers and SSL_get_ciphers, we must
         * pick a cipher */
@@ -975,7 +1035,7 @@ err:
        return(ret);
        }
 
-static int ssl3_send_server_hello(SSL *s)
+int ssl3_send_server_hello(SSL *s)
        {
        unsigned char *buf;
        unsigned char *p,*d;
@@ -988,7 +1048,8 @@ static int ssl3_send_server_hello(SSL *s)
                p=s->s3->server_random;
                Time=time(NULL);                        /* Time */
                l2n(Time,p);
-               RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-sizeof(Time));
+               if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
+                       return -1;
                /* Do the message type and length last */
                d=p= &(buf[4]);
 
@@ -1011,7 +1072,7 @@ static int ssl3_send_server_hello(SSL *s)
                        s->session->session_id_length=0;
 
                sl=s->session->session_id_length;
-               if (sl > sizeof s->session->session_id)
+               if (sl > (int)sizeof(s->session->session_id))
                        {
                        SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
                        return -1;
@@ -1046,7 +1107,7 @@ static int ssl3_send_server_hello(SSL *s)
        return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
        }
 
-static int ssl3_send_server_done(SSL *s)
+int ssl3_send_server_done(SSL *s)
        {
        unsigned char *p;
 
@@ -1070,7 +1131,7 @@ static int ssl3_send_server_done(SSL *s)
        return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
        }
 
-static int ssl3_send_server_key_exchange(SSL *s)
+int ssl3_send_server_key_exchange(SSL *s)
        {
 #ifndef OPENSSL_NO_RSA
        unsigned char *q;
@@ -1229,7 +1290,7 @@ static int ssl3_send_server_key_exchange(SSL *s)
                                }
                        if (!EC_KEY_up_ref(ecdhp))
                                {
-                               SSLerr(SSL_F_SSL3_CTRL,ERR_R_ECDH_LIB);
+                               SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
                                goto err;
                                }
                        ecdh = ecdhp;
@@ -1489,7 +1550,7 @@ err:
        return(-1);
        }
 
-static int ssl3_send_certificate_request(SSL *s)
+int ssl3_send_certificate_request(SSL *s)
        {
        unsigned char *p,*d;
        int i,j,nl,off,n;
@@ -1569,6 +1630,7 @@ static int ssl3_send_certificate_request(SSL *s)
                s->init_num += 4;
 #endif
 
+               s->state = SSL3_ST_SW_CERT_REQ_B;
                }
 
        /* SSL3_ST_SW_CERT_REQ_B */
@@ -1579,18 +1641,20 @@ err:
 
 
 static const int KDF1_SHA1_len = 20;
-static void *KDF1_SHA1(void *in, size_t inlen, void *out, size_t outlen)
+static void *KDF1_SHA1(const void *in, size_t inlen, void *out, size_t *outlen)
        {
 #ifndef OPENSSL_NO_SHA
-       if (outlen != SHA_DIGEST_LENGTH)
+       if (*outlen < SHA_DIGEST_LENGTH)
                return NULL;
+       else
+               *outlen = SHA_DIGEST_LENGTH;
        return SHA1(in, inlen, out);
 #else
        return NULL;
 #endif
        }
 
-static int ssl3_get_client_key_exchange(SSL *s)
+int ssl3_get_client_key_exchange(SSL *s)
        {
        int i,al,ok;
        long n;
@@ -1615,7 +1679,7 @@ static int ssl3_get_client_key_exchange(SSL *s)
        BN_CTX *bn_ctx = NULL; 
 #endif
 
-       n=ssl3_get_message(s,
+       n=s->method->ssl_get_message(s,
                SSL3_ST_SR_KEY_EXCH_A,
                SSL3_ST_SR_KEY_EXCH_B,
                SSL3_MT_CLIENT_KEY_EXCHANGE,
@@ -1684,7 +1748,7 @@ static int ssl3_get_client_key_exchange(SSL *s)
                if (i != SSL_MAX_MASTER_KEY_LENGTH)
                        {
                        al=SSL_AD_DECODE_ERROR;
-                       SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT);
+                       /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT); */
                        }
 
                if ((al == -1) && !((p[0] == (s->client_version>>8)) && (p[1] == (s->client_version & 0xff))))
@@ -1700,30 +1764,29 @@ static int ssl3_get_client_key_exchange(SSL *s)
                                (p[0] == (s->version>>8)) && (p[1] == (s->version & 0xff))))
                                {
                                al=SSL_AD_DECODE_ERROR;
-                               SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_PROTOCOL_VERSION_NUMBER);
-                               goto f_err;
+                               /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_PROTOCOL_VERSION_NUMBER); */
+
+                               /* The Klima-Pokorny-Rosa extension of Bleichenbacher's attack
+                                * (http://eprint.iacr.org/2003/052/) exploits the version
+                                * number check as a "bad version oracle" -- an alert would
+                                * reveal that the plaintext corresponding to some ciphertext
+                                * made up by the adversary is properly formatted except
+                                * that the version number is wrong.  To avoid such attacks,
+                                * we should treat this just like any other decryption error. */
                                }
                        }
 
                if (al != -1)
                        {
-#if 0
-                       goto f_err;
-#else
                        /* Some decryption failure -- use random value instead as countermeasure
                         * against Bleichenbacher's attack on PKCS #1 v1.5 RSA padding
-                        * (see RFC 2246, section 7.4.7.1).
-                        * But note that due to length and protocol version checking, the
-                        * attack is impractical anyway (see section 5 in D. Bleichenbacher:
-                        * "Chosen Ciphertext Attacks Against Protocols Based on the RSA
-                        * Encryption Standard PKCS #1", CRYPTO '98, LNCS 1462, pp. 1-12).
-                        */
+                        * (see RFC 2246, section 7.4.7.1). */
                        ERR_clear_error();
                        i = SSL_MAX_MASTER_KEY_LENGTH;
                        p[0] = s->client_version >> 8;
                        p[1] = s->client_version & 0xff;
-                       RAND_pseudo_bytes(p+2, i-2); /* should be RAND_bytes, but we cannot work around a failure */
-#endif
+                       if (RAND_pseudo_bytes(p+2, i-2) <= 0) /* should be RAND_bytes, but we cannot work around a failure */
+                               goto err;
                        }
        
                s->session->master_key_length=
@@ -1843,8 +1906,8 @@ static int ssl3_get_client_key_exchange(SSL *s)
                        goto err;
                        }
 
-               if (n != enc_ticket.length + authenticator.length +
-                                               enc_pms.length + 6)
+               if (n != (long)(enc_ticket.length + authenticator.length +
+                                               enc_pms.length + 6))
                        {
                        SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
                                SSL_R_DATA_LENGTH_TOO_LONG);
@@ -1860,7 +1923,7 @@ static int ssl3_get_client_key_exchange(SSL *s)
                         if (kssl_err.text)
                                 printf("kssl_err text= %s\n", kssl_err.text);
 #endif /* KSSL_DEBUG */
-                        SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+                        SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
                                 kssl_err.reason);
                         goto err;
                         }
@@ -1877,14 +1940,14 @@ static int ssl3_get_client_key_exchange(SSL *s)
                         if (kssl_err.text)
                                 printf("kssl_err text= %s\n", kssl_err.text);
 #endif /* KSSL_DEBUG */
-                        SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+                        SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
                                 kssl_err.reason);
                         goto err;
                        }
 
                if ((krb5rc = kssl_validate_times(authtime, &ttimes)) != 0)
                        {
-                       SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, krb5rc);
+                       SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, krb5rc);
                         goto err;
                        }
 
@@ -1960,6 +2023,7 @@ static int ssl3_get_client_key_exchange(SSL *s)
                if ((l & SSL_kECDH) || (l & SSL_kECDHE))
                {
                int ret = 1;
+               int field_size = 0;
 
                 /* initialize structures for server's ECDH key pair */
                if ((srvr_ecdh = EC_KEY_new()) == NULL) 
@@ -2060,7 +2124,21 @@ static int ssl3_get_client_key_exchange(SSL *s)
                         }
 
                /* Compute the shared pre-master secret */
-                i = ECDH_compute_key(p, KDF1_SHA1_len, clnt_ecpoint, srvr_ecdh, KDF1_SHA1);
+               field_size = EC_GROUP_get_degree(srvr_ecdh->group);
+               if (field_size <= 0)
+                       {
+                       SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, 
+                              ERR_R_ECDH_LIB);
+                       goto err;
+                       }
+               /* If field size is not more than 24 octets, then use SHA-1 hash of result;
+                * otherwise, use result (see section 4.8 of draft-ietf-tls-ecc-03.txt;
+                * this is new with this version of the Internet Draft).
+                */
+               if (field_size <= 24 * 8)
+                   i = ECDH_compute_key(p, KDF1_SHA1_len, clnt_ecpoint, srvr_ecdh, KDF1_SHA1);
+               else
+                   i = ECDH_compute_key(p, (field_size+7)/8, clnt_ecpoint, srvr_ecdh, NULL);
                 if (i <= 0)
                         {
                         SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
@@ -2114,7 +2192,7 @@ err:
        return(-1);
        }
 
-static int ssl3_get_cert_verify(SSL *s)
+int ssl3_get_cert_verify(SSL *s)
        {
        EVP_PKEY *pkey=NULL;
        unsigned char *p;
@@ -2123,7 +2201,7 @@ static int ssl3_get_cert_verify(SSL *s)
        int type=0,i,j;
        X509 *peer;
 
-       n=ssl3_get_message(s,
+       n=s->method->ssl_get_message(s,
                SSL3_ST_SR_CERT_VRFY_A,
                SSL3_ST_SR_CERT_VRFY_B,
                -1,
@@ -2269,15 +2347,16 @@ end:
        return(ret);
        }
 
-static int ssl3_get_client_certificate(SSL *s)
+int ssl3_get_client_certificate(SSL *s)
        {
        int i,ok,al,ret= -1;
        X509 *x=NULL;
        unsigned long l,nc,llen,n;
-       unsigned char *p,*d,*q;
+       const unsigned char *p,*q;
+       unsigned char *d;
        STACK_OF(X509) *sk=NULL;
 
-       n=ssl3_get_message(s,
+       n=s->method->ssl_get_message(s,
                SSL3_ST_SR_CERT_A,
                SSL3_ST_SR_CERT_B,
                -1,
@@ -2312,7 +2391,7 @@ static int ssl3_get_client_certificate(SSL *s)
                SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_WRONG_MESSAGE_TYPE);
                goto f_err;
                }
-       d=p=(unsigned char *)s->init_msg;
+       p=d=(unsigned char *)s->init_msg;
 
        if ((sk=sk_X509_new_null()) == NULL)
                {
@@ -2457,7 +2536,8 @@ int ssl3_send_server_certificate(SSL *s)
 /* This is the complement of curve_id2nid in s3_clnt.c. */
 static int nid2curve_id(int nid)
 {
-       /* ECC curves from draft-ietf-tls-ecc-01.txt (Mar 15, 2001) */
+       /* ECC curves from draft-ietf-tls-ecc-01.txt (Mar 15, 2001)
+        * (no changes in draft-ietf-tls-ecc-03.txt [June 2003]) */
        switch (nid) {
        case NID_sect163k1: /* sect163k1 (1) */
                return 1;