Followup on RT3334 fix: make sure that a directory that's the empty
[openssl.git] / ssl / s23_clnt.c
index 0f2e19e135ce1eb02133b99cea1e21ff153357d0..2b93c639dd25402c905e70956c8599e0569b237b 100644 (file)
@@ -269,12 +269,35 @@ static int ssl23_no_ssl2_ciphers(SSL *s)
        return 1;
        }
 
+/* Fill a ClientRandom or ServerRandom field of length len. Returns <= 0
+ * on failure, 1 on success. */
+int ssl_fill_hello_random(SSL *s, int server, unsigned char *result, int len)
+       {
+       int send_time = 0;
+
+       if (len < 4)
+               return 0;
+       if (server)
+               send_time = (s->mode & SSL_MODE_SEND_SERVERHELLO_TIME) != 0;
+       else
+               send_time = (s->mode & SSL_MODE_SEND_CLIENTHELLO_TIME) != 0;
+       if (send_time)
+               {
+               unsigned long Time = (unsigned long)time(NULL);
+               unsigned char *p = result;
+               l2n(Time, p);
+               return RAND_pseudo_bytes(p, len-4);
+               }
+       else
+               return RAND_pseudo_bytes(result, len);
+       }
+
 static int ssl23_client_hello(SSL *s)
        {
        unsigned char *buf;
        unsigned char *p,*d;
        int i,ch_len;
-       unsigned long Time,l;
+       unsigned long l;
        int ssl2_compat;
        int version = 0, version_major, version_minor;
 #ifndef OPENSSL_NO_COMP
@@ -282,34 +305,51 @@ static int ssl23_client_hello(SSL *s)
        SSL_COMP *comp;
 #endif
        int ret;
+       unsigned long mask, options = s->options;
 
-       ssl2_compat = (s->options & SSL_OP_NO_SSLv2) ? 0 : 1;
+       ssl2_compat = (options & SSL_OP_NO_SSLv2) ? 0 : 1;
 
        if (ssl2_compat && ssl23_no_ssl2_ciphers(s))
                ssl2_compat = 0;
-#ifndef OPENSSL_NO_TLS1_2_CLIENT
-       if (!(s->options & SSL_OP_NO_TLSv1_2))
-               {
-               version = TLS1_2_VERSION;
-               }
-       else
+
+       /*
+        * SSL_OP_NO_X disables all protocols above X *if* there are
+        * some protocols below X enabled. This is required in order
+        * to maintain "version capability" vector contiguous. So
+        * that if application wants to disable TLS1.0 in favour of
+        * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the
+        * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3|SSL_OP_NO_SSLv2.
+        */
+       mask =  SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1
+#if !defined(OPENSSL_NO_SSL3)
+               |SSL_OP_NO_SSLv3
 #endif
-       if (!(s->options & SSL_OP_NO_TLSv1_1))
-               {
+#if !defined(OPENSSL_NO_SSL2)
+               |(ssl2_compat?SSL_OP_NO_SSLv2:0)
+#endif
+               ;
+#if !defined(OPENSSL_NO_TLS1_2_CLIENT)
+       version = TLS1_2_VERSION;
+
+       if ((options & SSL_OP_NO_TLSv1_2) && (options & mask) != mask)
                version = TLS1_1_VERSION;
-               }
-       else if (!(s->options & SSL_OP_NO_TLSv1))
-               {
+#else
+       version = TLS1_1_VERSION;
+#endif
+       mask &= ~SSL_OP_NO_TLSv1_1;
+       if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask)
                version = TLS1_VERSION;
-               }
-       else if (!(s->options & SSL_OP_NO_SSLv3))
-               {
+       mask &= ~SSL_OP_NO_TLSv1;
+#if !defined(OPENSSL_NO_SSL3)
+       if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask)
                version = SSL3_VERSION;
-               }
-       else if (!(s->options & SSL_OP_NO_SSLv2))
-               {
+       mask &= ~SSL_OP_NO_SSLv3;
+#endif
+#if !defined(OPENSSL_NO_SSL2)
+       if ((options & SSL_OP_NO_SSLv3) && (options & mask) != mask)
                version = SSL2_VERSION;
-               }
+#endif
+
 #ifndef OPENSSL_NO_TLSEXT
        if (version != SSL2_VERSION)
                {
@@ -338,9 +378,7 @@ static int ssl23_client_hello(SSL *s)
 #endif
 
                p=s->s3->client_random;
-               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, 0, p, SSL3_RANDOM_SIZE) <= 0)
                        return -1;
 
                if (version == TLS1_2_VERSION)