Add a bunch of SSL_xxx() functions for configuring the temporary RSA and DH
[openssl.git] / ssl / ssl_lib.c
index c9a228519951651109e1d91301a66897467eb879..55f862fbe03a725a7969f8a21a478192b954e84a 100644 (file)
@@ -77,30 +77,37 @@ SSL3_ENC_METHOD ssl3_undef_enc_method={
        ssl_undefined_function,
        };
 
-void SSL_clear(s)
+int SSL_clear(s)
 SSL *s;
        {
        int state;
 
-       if (s->method == NULL) return;
+       if (s->method == NULL)
+               {
+               SSLerr(SSL_F_SSL_CLEAR,SSL_R_NO_METHOD_SPECIFIED);
+               return(0);
+               }
 
        s->error=0;
        s->hit=0;
+       s->shutdown=0;
 
+#if 0
        /* This is set if we are doing dynamic renegotiation so keep
         * the old cipher.  It is sort of a SSL_clear_lite :-) */
-       if (s->new_session) return;
+       if (s->new_session) return(1);
+#endif
 
        state=s->state; /* Keep to check if we throw away the session-id */
        s->type=0;
 
+       s->state=SSL_ST_BEFORE|((s->server)?SSL_ST_ACCEPT:SSL_ST_CONNECT);
+
        s->version=s->method->version;
+       s->client_version=s->version;
        s->rwstate=SSL_NOTHING;
-       s->state=SSL_ST_BEFORE;
        s->rstate=SSL_ST_READ_HEADER;
-       s->read_ahead=s->ctx->default_read_ahead;
-
-/*     s->shutdown=(SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); */
+       s->read_ahead=s->ctx->read_ahead;
 
        if (s->init_buf != NULL)
                {
@@ -116,10 +123,22 @@ SSL *s;
                s->session=NULL;
                }
 
-       s->shutdown=(SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
        s->first_packet=0;
 
-       s->method->ssl_clear(s);
+#if 1
+       /* Check to see if we were changed into a different method, if
+        * so, revert back if we are not doing session-id reuse. */
+       if ((s->session == NULL) && (s->method != s->ctx->method))
+               {
+               s->method->ssl_free(s);
+               s->method=s->ctx->method;
+               if (!s->method->ssl_new(s))
+                       return(0);
+               }
+       else
+#endif
+               s->method->ssl_clear(s);
+       return(1);
        }
 
 /* Used to change an SSL_CTXs default SSL method type */
@@ -169,7 +188,7 @@ SSL_CTX *ctx;
                }
        else
                s->cert=NULL;
-       s->verify_mode=ctx->default_verify_mode;
+       s->verify_mode=ctx->verify_mode;
        s->verify_callback=ctx->default_verify_callback;
        CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
        s->ctx=ctx;
@@ -187,6 +206,7 @@ SSL_CTX *ctx;
 
        s->quiet_shutdown=ctx->quiet_shutdown;
        s->references=1;
+       s->server=(ctx->method->ssl_accept == ssl_undefined_function)?0:1;
        s->options=ctx->options;
        SSL_clear(s);
 
@@ -251,11 +271,6 @@ SSL *s;
 
        ssl_clear_cipher_ctx(s);
 
-       if (s->expand != NULL)
-               COMP_CTX_free(s->expand);
-       if (s->compress != NULL)
-               COMP_CTX_free(s->compress);
-
        if (s->cert != NULL) ssl_cert_free(s->cert);
        /* Free up if allocated */
 
@@ -402,7 +417,7 @@ SSL *s;
 int SSL_CTX_get_verify_mode(ctx)
 SSL_CTX *ctx;
        {
-       return(ctx->default_verify_mode);
+       return(ctx->verify_mode);
        }
 
 int (*SSL_CTX_get_verify_callback(ctx))()
@@ -623,7 +638,22 @@ int cmd;
 long larg;
 char *parg;
        {
-       return(s->method->ssl_ctrl(s,cmd,larg,parg));
+       long l;
+
+       switch (cmd)
+               {
+       case SSL_CTRL_GET_READ_AHEAD:
+               return(s->read_ahead);
+       case SSL_CTRL_SET_READ_AHEAD:
+               l=s->read_ahead;
+               s->read_ahead=larg;
+               return(l);
+       case SSL_CTRL_OPTIONS:
+               return(s->options|=larg);
+       default:
+               return(s->method->ssl_ctrl(s,cmd,larg,parg));
+               }
+       return(0);
        }
 
 long SSL_CTX_ctrl(ctx,cmd,larg,parg)
@@ -632,7 +662,60 @@ int cmd;
 long larg;
 char *parg;
        {
-       return(ctx->method->ssl_ctx_ctrl(ctx,cmd,larg,parg));
+       long l;
+
+       switch (cmd)
+               {
+       case SSL_CTRL_GET_READ_AHEAD:
+               return(ctx->read_ahead);
+       case SSL_CTRL_SET_READ_AHEAD:
+               l=ctx->read_ahead;
+               ctx->read_ahead=larg;
+               return(l);
+
+       case SSL_CTRL_SET_SESS_CACHE_SIZE:
+               l=ctx->session_cache_size;
+               ctx->session_cache_size=larg;
+               return(l);
+       case SSL_CTRL_GET_SESS_CACHE_SIZE:
+               return(ctx->session_cache_size);
+       case SSL_CTRL_SET_SESS_CACHE_MODE:
+               l=ctx->session_cache_mode;
+               ctx->session_cache_mode=larg;
+               return(l);
+       case SSL_CTRL_GET_SESS_CACHE_MODE:
+               return(ctx->session_cache_mode);
+
+       case SSL_CTRL_SESS_NUMBER:
+               return(ctx->sessions->num_items);
+       case SSL_CTRL_SESS_CONNECT:
+               return(ctx->stats.sess_connect);
+       case SSL_CTRL_SESS_CONNECT_GOOD:
+               return(ctx->stats.sess_connect_good);
+       case SSL_CTRL_SESS_CONNECT_RENEGOTIATE:
+               return(ctx->stats.sess_connect_renegotiate);
+       case SSL_CTRL_SESS_ACCEPT:
+               return(ctx->stats.sess_accept);
+       case SSL_CTRL_SESS_ACCEPT_GOOD:
+               return(ctx->stats.sess_accept_good);
+       case SSL_CTRL_SESS_ACCEPT_RENEGOTIATE:
+               return(ctx->stats.sess_accept_renegotiate);
+       case SSL_CTRL_SESS_HIT:
+               return(ctx->stats.sess_hit);
+       case SSL_CTRL_SESS_CB_HIT:
+               return(ctx->stats.sess_cb_hit);
+       case SSL_CTRL_SESS_MISSES:
+               return(ctx->stats.sess_miss);
+       case SSL_CTRL_SESS_TIMEOUTS:
+               return(ctx->stats.sess_timeout);
+       case SSL_CTRL_SESS_CACHE_FULL:
+               return(ctx->stats.sess_cache_full);
+       case SSL_CTRL_OPTIONS:
+               return(ctx->options|=larg);
+       default:
+               return(ctx->method->ssl_ctx_ctrl(ctx,cmd,larg,parg));
+               }
+       return(0);
        }
 
 int ssl_cipher_id_cmp(a,b)
@@ -903,17 +986,7 @@ SSL_METHOD *meth;
        ret->remove_session_cb=NULL;
        ret->get_session_cb=NULL;
 
-       ret->sess_connect=0;
-       ret->sess_connect_good=0;
-       ret->sess_accept=0;
-       ret->sess_accept_renegotiate=0;
-       ret->sess_connect_renegotiate=0;
-       ret->sess_accept_good=0;
-       ret->sess_miss=0;
-       ret->sess_timeout=0;
-       ret->sess_cache_full=0;
-       ret->sess_hit=0;
-       ret->sess_cb_hit=0;
+       memset((char *)&ret->stats,0,sizeof(ret->stats));
 
        ret->references=1;
        ret->quiet_shutdown=0;
@@ -929,8 +1002,8 @@ SSL_METHOD *meth;
        ret->app_verify_callback=NULL;
        ret->app_verify_arg=NULL;
 
-       ret->default_read_ahead=0;
-       ret->default_verify_mode=SSL_VERIFY_NONE;
+       ret->read_ahead=0;
+       ret->verify_mode=SSL_VERIFY_NONE;
        ret->default_verify_callback=NULL;
        if ((ret->default_cert=ssl_cert_new()) == NULL)
                goto err;
@@ -974,6 +1047,7 @@ SSL_METHOD *meth;
        CRYPTO_new_ex_data(ssl_ctx_meth,(char *)ret,&ret->ex_data);
 
        ret->extra_certs=NULL;
+       ret->comp_methods=SSL_COMP_get_compression_methods();
 
        return(ret);
 err:
@@ -1021,6 +1095,8 @@ SSL_CTX *a;
                sk_pop_free(a->client_CA,X509_NAME_free);
        if (a->extra_certs != NULL)
                sk_pop_free(a->extra_certs,X509_free);
+       if (a->comp_methods != NULL)
+               sk_pop_free(a->comp_methods,free);
        Free((char *)a);
        }
 
@@ -1049,52 +1125,55 @@ int (*cb)(int, X509_STORE_CTX *);
 int (*cb)();
 #endif
        {
-       ctx->default_verify_mode=mode;
+       ctx->verify_mode=mode;
        ctx->default_verify_callback=cb;
        /* This needs cleaning up EAY EAY EAY */
        X509_STORE_set_verify_cb_func(ctx->cert_store,cb);
        }
 
-void ssl_set_cert_masks(c)
+void ssl_set_cert_masks(c,cipher)
 CERT *c;
+SSL_CIPHER *cipher;
        {
        CERT_PKEY *cpk;
        int rsa_enc,rsa_tmp,rsa_sign,dh_tmp,dh_rsa,dh_dsa,dsa_sign;
        int rsa_enc_export,dh_rsa_export,dh_dsa_export;
-       int rsa_tmp_export,dh_tmp_export;
+       int rsa_tmp_export,dh_tmp_export,kl;
        unsigned long mask,emask;
 
        if ((c == NULL) || (c->valid)) return;
 
+       kl=SSL_C_EXPORT_PKEYLENGTH(cipher);
+
 #ifndef NO_RSA
-       rsa_tmp=((c->rsa_tmp != NULL) || (c->rsa_tmp_cb != NULL))?1:0;
-       rsa_tmp_export=((c->rsa_tmp_cb != NULL) ||
-               (rsa_tmp && (RSA_size(c->rsa_tmp)*8 <= 512)))?1:0;
+       rsa_tmp=(c->rsa_tmp != NULL || c->rsa_tmp_cb != NULL);
+       rsa_tmp_export=(c->rsa_tmp_cb != NULL ||
+               (rsa_tmp && RSA_size(c->rsa_tmp)*8 <= kl));
 #else
        rsa_tmp=rsa_tmp_export=0;
 #endif
 #ifndef NO_DH
-       dh_tmp=((c->dh_tmp != NULL) || (c->dh_tmp_cb != NULL))?1:0;
-       dh_tmp_export=((c->dh_tmp_cb != NULL) ||
-               (dh_tmp && (DH_size(c->dh_tmp)*8 <= 512)))?1:0;
+       dh_tmp=(c->dh_tmp != NULL || c->dh_tmp_cb != NULL);
+       dh_tmp_export=(c->dh_tmp_cb != NULL ||
+               (dh_tmp && DH_size(c->dh_tmp)*8 <= kl));
 #else
        dh_tmp=dh_tmp_export=0;
 #endif
 
        cpk= &(c->pkeys[SSL_PKEY_RSA_ENC]);
-       rsa_enc= ((cpk->x509 != NULL) && (cpk->privatekey != NULL))?1:0;
-       rsa_enc_export=(rsa_enc && (EVP_PKEY_size(cpk->privatekey)*8 <= 512))?1:0;
+       rsa_enc= (cpk->x509 != NULL && cpk->privatekey != NULL);
+       rsa_enc_export=(rsa_enc && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
        cpk= &(c->pkeys[SSL_PKEY_RSA_SIGN]);
-       rsa_sign=((cpk->x509 != NULL) && (cpk->privatekey != NULL))?1:0;
+       rsa_sign=(cpk->x509 != NULL && cpk->privatekey != NULL);
        cpk= &(c->pkeys[SSL_PKEY_DSA_SIGN]);
-       dsa_sign=((cpk->x509 != NULL) && (cpk->privatekey != NULL))?1:0;
+       dsa_sign=(cpk->x509 != NULL && cpk->privatekey != NULL);
        cpk= &(c->pkeys[SSL_PKEY_DH_RSA]);
-       dh_rsa=  ((cpk->x509 != NULL) && (cpk->privatekey != NULL))?1:0;
-       dh_rsa_export=(dh_rsa && (EVP_PKEY_size(cpk->privatekey)*8 <= 512))?1:0;
+       dh_rsa=  (cpk->x509 != NULL && cpk->privatekey != NULL);
+       dh_rsa_export=(dh_rsa && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
        cpk= &(c->pkeys[SSL_PKEY_DH_DSA]);
 /* FIX THIS EAY EAY EAY */
-       dh_dsa=  ((cpk->x509 != NULL) && (cpk->privatekey != NULL))?1:0;
-       dh_dsa_export=(dh_dsa && (EVP_PKEY_size(cpk->privatekey)*8 <= 512))?1:0;
+       dh_dsa=  (cpk->x509 != NULL && cpk->privatekey != NULL);
+       dh_dsa_export=(dh_dsa && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
 
        mask=0;
        emask=0;
@@ -1163,10 +1242,10 @@ SSL *s;
        int i,export;
 
        c=s->cert;
-       ssl_set_cert_masks(c);
+       ssl_set_cert_masks(c,s->s3->tmp.new_cipher);
        alg=s->s3->tmp.new_cipher->algorithms;
-       export=(alg & SSL_EXPORT)?1:0;
-       mask=(export)?c->export_mask:c->mask;
+       export=SSL_IS_EXPORT(alg);
+       mask=export?c->export_mask:c->mask;
        kalg=alg&(SSL_MKEY_MASK|SSL_AUTH_MASK);
 
        if      (kalg & SSL_kDHr)
@@ -1246,8 +1325,8 @@ int mode;
                ((i & mode) == mode))
                {
                if (  (((mode & SSL_SESS_CACHE_CLIENT)
-                       ?s->ctx->sess_connect_good
-                       :s->ctx->sess_accept_good) & 0xff) == 0xff)
+                       ?s->ctx->stats.sess_connect_good
+                       :s->ctx->stats.sess_accept_good) & 0xff) == 0xff)
                        {
                        SSL_CTX_flush_sessions(s->ctx,time(NULL));
                        }
@@ -1294,12 +1373,20 @@ SSL *s;
 int i;
        {
        int reason;
+       unsigned long l;
        BIO *bio;
 
        if (i > 0) return(SSL_ERROR_NONE);
 
-       if (ERR_peek_error() != 0)
-               return(SSL_ERROR_SSL);
+       /* Make things return SSL_ERROR_SYSCALL when doing SSL_do_handshake
+        * etc, where we do encode the error */
+       if ((l=ERR_peek_error()) != 0)
+               {
+               if (ERR_GET_LIB(l) == ERR_LIB_SYS)
+                       return(SSL_ERROR_SYSCALL);
+               else
+                       return(SSL_ERROR_SSL);
+               }
 
        if ((i < 0) && SSL_want_read(s))
                {
@@ -1381,6 +1468,7 @@ SSL *s;
 void SSL_set_accept_state(s)
 SSL *s;
        {
+       s->server=1;
        s->shutdown=0;
        s->state=SSL_ST_ACCEPT|SSL_ST_BEFORE;
        s->handshake_func=s->method->ssl_accept;
@@ -1391,6 +1479,7 @@ SSL *s;
 void SSL_set_connect_state(s)
 SSL *s;
        {
+       s->server=0;
        s->shutdown=0;
        s->state=SSL_ST_CONNECT|SSL_ST_BEFORE;
        s->handshake_func=s->method->ssl_connect;
@@ -1498,6 +1587,7 @@ SSL *s;
        ret->shutdown=s->shutdown;
        ret->state=s->state;
        ret->handshake_func=s->handshake_func;
+       ret->server=s->server;
 
        if (0)
                {
@@ -1523,6 +1613,16 @@ SSL *s;
                 Free(s->enc_write_ctx);
                 s->enc_write_ctx=NULL;
                 }
+       if (s->expand != NULL)
+               {
+               COMP_CTX_free(s->expand);
+               s->expand=NULL;
+               }
+       if (s->compress != NULL)
+               {
+               COMP_CTX_free(s->compress);
+               s->compress=NULL;
+               }
        }
 
 /* Fix this function so that it takes an optional type parameter */
@@ -1590,6 +1690,26 @@ int push;
                }
        return(1);
        }
+
+void ssl_free_wbio_buffer(s)
+SSL *s;
+       {
+       BIO *under;
+
+       if (s->bbio == NULL) return;
+
+       if (s->bbio == s->wbio)
+               {
+               /* remove buffering */
+               under=BIO_pop(s->wbio);
+               if (under != NULL)
+                       s->wbio=under;
+               else
+                       abort(); /* ok */
+               }
+       BIO_free(s->bbio);
+       s->bbio=NULL;
+       }
        
 void SSL_CTX_set_quiet_shutdown(ctx,mode)
 SSL_CTX *ctx;
@@ -1705,12 +1825,12 @@ void (*free_func)();
 int SSL_set_ex_data(s,idx,arg)
 SSL *s;
 int idx;
-char *arg;
+void *arg;
        {
        return(CRYPTO_set_ex_data(&s->ex_data,idx,arg));
        }
 
-char *SSL_get_ex_data(s,idx)
+void *SSL_get_ex_data(s,idx)
 SSL *s;
 int idx;
        {
@@ -1732,12 +1852,12 @@ void (*free_func)();
 int SSL_CTX_set_ex_data(s,idx,arg)
 SSL_CTX *s;
 int idx;
-char *arg;
+void *arg;
        {
        return(CRYPTO_set_ex_data(&s->ex_data,idx,arg));
        }
 
-char *SSL_CTX_get_ex_data(s,idx)
+void *SSL_CTX_get_ex_data(s,idx)
 SSL_CTX *s;
 int idx;
        {
@@ -1750,12 +1870,43 @@ SSL *s;
        return(1);
        }
 
-void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,RSA *(*cb)(SSL *ssl,int export))
+X509_STORE *SSL_CTX_get_cert_store(ctx)
+SSL_CTX *ctx;
+       {
+       return(ctx->cert_store);
+       }
+
+void SSL_CTX_set_cert_store(ctx,store)
+SSL_CTX *ctx;
+X509_STORE *store;
+       {
+       if (ctx->cert_store != NULL)
+               X509_STORE_free(ctx->cert_store);
+       ctx->cert_store=store;
+       }
+
+int SSL_want(s)
+SSL *s;
+       {
+       return(s->rwstate);
+       }
+
+void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,RSA *(*cb)(SSL *ssl,int export,
+                                                         int keylength))
     { SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_RSA_CB,0,(char *)cb); }
 
-void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,DH *(*dh)(SSL *ssl,int export))
+void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,DH *(*dh)(SSL *ssl,int export,
+                                                       int keylength))
     { SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_DH_CB,0,(char *)dh); }
 
+void SSL_set_tmp_rsa_callback(SSL *ssl,RSA *(*cb)(SSL *ssl,int export,
+                                                         int keylength))
+    { SSL_ctrl(ssl,SSL_CTRL_SET_TMP_RSA_CB,0,(char *)cb); }
+
+void SSL_set_tmp_dh_callback(SSL *ssl,DH *(*dh)(SSL *ssl,int export,
+                                                       int keylength))
+    { SSL_ctrl(ssl,SSL_CTRL_SET_TMP_DH_CB,0,(char *)dh); }
+
 #if defined(_WINDLL) && defined(WIN16)
 #include "../crypto/bio/bss_file.c"
 #endif