Add client cert engine to SSL routines.
[openssl.git] / ssl / d1_clnt.c
index d2340c8a3e02dc1132f4d99dfeb86cef5ae37db1..f4e9df9810a1810587e45d32711109f9f6355dca 100644 (file)
@@ -4,7 +4,7 @@
  * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
  */
 /* ====================================================================
- * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1999-2007 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/md5.h>
+#include <openssl/bn.h>
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
 
-static SSL_METHOD *dtls1_get_client_method(int ver);
+static const SSL_METHOD *dtls1_get_client_method(int ver);
 static int dtls1_get_hello_verify(SSL *s);
 
-static SSL_METHOD *dtls1_get_client_method(int ver)
+static const SSL_METHOD *dtls1_get_client_method(int ver)
        {
        if (ver == DTLS1_VERSION)
                return(DTLSv1_client_method());
@@ -132,33 +136,15 @@ static SSL_METHOD *dtls1_get_client_method(int ver)
                return(NULL);
        }
 
-SSL_METHOD *DTLSv1_client_method(void)
-       {
-       static int init=1;
-       static SSL_METHOD DTLSv1_client_data;
-
-       if (init)
-               {
-               CRYPTO_w_lock(CRYPTO_LOCK_SSL_METHOD);
-
-               if (init)
-                       {
-                       memcpy((char *)&DTLSv1_client_data,(char *)dtlsv1_base_method(),
-                               sizeof(SSL_METHOD));
-                       DTLSv1_client_data.ssl_connect=dtls1_connect;
-                       DTLSv1_client_data.get_ssl_method=dtls1_get_client_method;
-                       init=0;
-                       }
-               
-               CRYPTO_w_unlock(CRYPTO_LOCK_SSL_METHOD);
-               }
-       return(&DTLSv1_client_data);
-       }
+IMPLEMENT_dtls1_meth_func(DTLSv1_client_method,
+                       ssl_undefined_function,
+                       dtls1_connect,
+                       dtls1_get_client_method)
 
 int dtls1_connect(SSL *s)
        {
        BUF_MEM *buf=NULL;
-       unsigned long Time=time(NULL),l;
+       unsigned long Time=(unsigned long)time(NULL);
        long num1;
        void (*cb)(const SSL *ssl,int type,int val)=NULL;
        int ret= -1;
@@ -228,17 +214,21 @@ int dtls1_connect(SSL *s)
 
                        /* don't push the buffering BIO quite yet */
 
-                       ssl3_init_finished_mac(s);
-
                        s->state=SSL3_ST_CW_CLNT_HELLO_A;
                        s->ctx->stats.sess_connect++;
                        s->init_num=0;
+                       /* mark client_random uninitialized */
+                       memset(s->s3->client_random,0,sizeof(s->s3->client_random));
                        break;
 
                case SSL3_ST_CW_CLNT_HELLO_A:
                case SSL3_ST_CW_CLNT_HELLO_B:
 
                        s->shutdown=0;
+
+                       /* every DTLS ClientHello resets Finished MAC */
+                       ssl3_init_finished_mac(s);
+
                        ret=dtls1_client_hello(s);
                        if (ret <= 0) goto end;
 
@@ -288,7 +278,7 @@ int dtls1_connect(SSL *s)
                case SSL3_ST_CR_CERT_A:
                case SSL3_ST_CR_CERT_B:
                        /* Check if it is anon DH */
-                       if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
+                       if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL))
                                {
                                ret=ssl3_get_server_certificate(s);
                                if (ret <= 0) goto end;
@@ -349,7 +339,6 @@ int dtls1_connect(SSL *s)
                case SSL3_ST_CW_KEY_EXCH_B:
                        ret=dtls1_send_client_key_exchange(s);
                        if (ret <= 0) goto end;
-                       l=s->s3->tmp.new_cipher->algorithms;
                        /* EAY EAY EAY need to check for DH fix cert
                         * sent back */
                        /* For TLS, cert_req is set to 2, so a cert chain
@@ -385,11 +374,15 @@ int dtls1_connect(SSL *s)
                        s->init_num=0;
 
                        s->session->cipher=s->s3->tmp.new_cipher;
+#ifdef OPENSSL_NO_COMP
+                       s->session->compress_meth=0;
+#else
                        if (s->s3->tmp.new_compression == NULL)
                                s->session->compress_meth=0;
                        else
                                s->session->compress_meth=
                                        s->s3->tmp.new_compression->id;
+#endif
                        if (!s->method->ssl3_enc->setup_key_block(s))
                                {
                                ret= -1;
@@ -432,6 +425,8 @@ int dtls1_connect(SSL *s)
                                s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
                                }
                        s->init_num=0;
+                       /* mark client_random uninitialized */
+                       memset (s->s3->client_random,0,sizeof(s->s3->client_random));
                        break;
 
                case SSL3_ST_CR_FINISHED_A:
@@ -537,7 +532,7 @@ int dtls1_client_hello(SSL *s)
        {
        unsigned char *buf;
        unsigned char *p,*d;
-       int i,j;
+       unsigned int i,j;
        unsigned long Time,l;
        SSL_COMP *comp;
 
@@ -554,9 +549,16 @@ int dtls1_client_hello(SSL *s)
                /* else use the pre-loaded session */
 
                p=s->s3->client_random;
-               Time=time(NULL);                        /* Time */
-               l2n(Time,p);
-               RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-sizeof(Time));
+
+               /* if client_random is initialized, reuse it, we are
+                * required to use same upon reply to HelloVerify */
+               for (i=0;p[i]=='\0' && i<sizeof(s->s3->client_random);i++) ;
+               if (i==sizeof(s->s3->client_random))
+                       {
+                       Time=(unsigned long)time(NULL); /* Time */
+                       l2n(Time,p);
+                       RAND_pseudo_bytes(p,sizeof(s->s3->client_random)-4);
+                       }
 
                /* Do the message type and length last */
                d=p= &(buf[DTLS1_HM_HEADER_LENGTH]);
@@ -597,7 +599,7 @@ int dtls1_client_hello(SSL *s)
                p += s->d1->cookie_len;
 
                /* Ciphers supported */
-               i=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),&(p[2]));
+               i=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),&(p[2]),0);
                if (i == 0)
                        {
                        SSLerr(SSL_F_DTLS1_CLIENT_HELLO,SSL_R_NO_CIPHERS_AVAILABLE);
@@ -694,7 +696,7 @@ int dtls1_send_client_key_exchange(SSL *s)
        {
        unsigned char *p,*d;
        int n;
-       unsigned long l;
+       unsigned long alg_k;
 #ifndef OPENSSL_NO_RSA
        unsigned char *q;
        EVP_PKEY *pkey=NULL;
@@ -707,13 +709,13 @@ int dtls1_send_client_key_exchange(SSL *s)
                {
                d=(unsigned char *)s->init_buf->data;
                p= &(d[DTLS1_HM_HEADER_LENGTH]);
-
-               l=s->s3->tmp.new_cipher->algorithms;
+               
+               alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
 
                 /* Fool emacs indentation */
                 if (0) {}
 #ifndef OPENSSL_NO_RSA
-               else if (l & SSL_kRSA)
+               else if (alg_k & SSL_kRSA)
                        {
                        RSA *rsa;
                        unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
@@ -742,7 +744,7 @@ int dtls1_send_client_key_exchange(SSL *s)
                        s->session->master_key_length=sizeof tmp_buf;
 
                        q=p;
-                       /* Fix buf for TLS and beyond */
+                       /* Fix buf for TLS and [incidentally] DTLS */
                        if (s->version > SSL3_VERSION)
                                p+=2;
                        n=RSA_public_encrypt(sizeof tmp_buf,
@@ -757,7 +759,7 @@ int dtls1_send_client_key_exchange(SSL *s)
                                goto err;
                                }
 
-                       /* Fix buf for TLS and beyond */
+                       /* Fix buf for TLS and [incidentally] DTLS */
                        if (s->version > SSL3_VERSION)
                                {
                                s2n(n,q);
@@ -772,7 +774,7 @@ int dtls1_send_client_key_exchange(SSL *s)
                        }
 #endif
 #ifndef OPENSSL_NO_KRB5
-               else if (l & SSL_kKRB5)
+               else if (alg_k & SSL_kKRB5)
                         {
                         krb5_error_code        krb5rc;
                         KSSL_CTX       *kssl_ctx = s->kssl_ctx;
@@ -791,7 +793,7 @@ int dtls1_send_client_key_exchange(SSL *s)
 
 #ifdef KSSL_DEBUG
                         printf("ssl3_send_client_key_exchange(%lx & %lx)\n",
-                                l, SSL_kKRB5);
+                                alg_k, SSL_kKRB5);
 #endif /* KSSL_DEBUG */
 
                        authp = NULL;
@@ -904,7 +906,7 @@ int dtls1_send_client_key_exchange(SSL *s)
                         }
 #endif
 #ifndef OPENSSL_NO_DH
-               else if (l & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+               else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
                        {
                        DH *dh_srvr,*dh_clnt;
 
@@ -1009,14 +1011,16 @@ int dtls1_send_client_verify(SSL *s)
                p= &(d[DTLS1_HM_HEADER_LENGTH]);
                pkey=s->cert->key->privatekey;
 
-               s->method->ssl3_enc->cert_verify_mac(s,&(s->s3->finish_dgst2),
+               s->method->ssl3_enc->cert_verify_mac(s,
+               NID_sha1,
                        &(data[MD5_DIGEST_LENGTH]));
 
 #ifndef OPENSSL_NO_RSA
                if (pkey->type == EVP_PKEY_RSA)
                        {
                        s->method->ssl3_enc->cert_verify_mac(s,
-                               &(s->s3->finish_dgst1),&(data[0]));
+                               NID_md5,
+                               &(data[0]));
                        if (RSA_sign(NID_md5_sha1, data,
                                         MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH,
                                        &(p[2]), &u, pkey->pkey.rsa) <= 0 )
@@ -1092,8 +1096,7 @@ int dtls1_send_client_certificate(SSL *s)
                 * ssl->rwstate=SSL_X509_LOOKUP; return(-1);
                 * We then get retied later */
                i=0;
-               if (s->ctx->client_cert_cb != NULL)
-                       i=s->ctx->client_cert_cb(s,&(x509),&(pkey));
+               i = ssl_do_client_cert_cb(s, &x509, &pkey);
                if (i < 0)
                        {
                        s->rwstate=SSL_X509_LOOKUP;