Remove SSL_{CTX_}set_ecdh_auto() and always enable ECDH
[openssl.git] / ssl / ssl_lib.c
index 270a908a3ec4e63e8758922d6d8e3d8fe3677bb3..ea2acce96a12c03b2c63507d2748729ad0392763 100644 (file)
@@ -176,7 +176,6 @@ SSL3_ENC_METHOD ssl3_undef_enc_method = {
     (int (*)(SSL *, const char *, int, unsigned char *))
         ssl_undefined_function,
     0,                          /* finish_mac_length */
-    (int (*)(SSL *, int, unsigned char *))ssl_undefined_function,
     NULL,                       /* client_finished_label */
     0,                          /* client_finished_label_len */
     NULL,                       /* server_finished_label */
@@ -191,6 +190,11 @@ struct ssl_async_args {
     SSL *s;
     void *buf;
     int num;
+    int type;
+    union {
+        int (*func1)(SSL *, void *, int);
+        int (*func2)(SSL *, const void *, int);
+    } f;
 };
 
 static void clear_ciphers(SSL *s)
@@ -934,61 +938,29 @@ int SSL_waiting_for_async(SSL *s)
 int SSL_get_async_wait_fd(SSL *s)
 {
     if (!s->job)
-        return 0;
+        return -1;
 
     return ASYNC_get_wait_fd(s->job);
 }
 
-static int ssl_accept_intern(void *vargs)
-{
-    struct ssl_async_args *args;
-    SSL *s;
-
-    args = (struct ssl_async_args *)vargs;
-    s = args->s;
-
-    return s->method->ssl_accept(s);
-}
-
 int SSL_accept(SSL *s)
 {
-    int ret;
-    struct ssl_async_args args;
-
-    if (s->handshake_func == 0)
+    if (s->handshake_func == 0) {
         /* Not properly initialized yet */
         SSL_set_accept_state(s);
-
-    args.s = s;
-
-    if((s->mode & SSL_MODE_ASYNC) && !ASYNC_in_job()) {
-        switch(ASYNC_start_job(&s->job, &ret, ssl_accept_intern, &args,
-            sizeof(struct ssl_async_args))) {
-        case ASYNC_ERR:
-            SSLerr(SSL_F_SSL_ACCEPT, SSL_R_FAILED_TO_INIT_ASYNC);
-            return -1;
-        case ASYNC_PAUSE:
-            return -1;
-        case ASYNC_FINISH:
-            s->job = NULL;
-            return ret;
-        default:
-            SSLerr(SSL_F_SSL_ACCEPT, ERR_R_INTERNAL_ERROR);
-            /* Shouldn't happen */
-            return -1;
-        }
-    } else {
-        return s->method->ssl_accept(s);
     }
+
+    return SSL_do_handshake(s);
 }
 
 int SSL_connect(SSL *s)
 {
-    if (s->handshake_func == 0)
+    if (s->handshake_func == 0) {
         /* Not properly initialized yet */
         SSL_set_connect_state(s);
+    }
 
-    return (s->method->ssl_connect(s));
+    return SSL_do_handshake(s);
 }
 
 long SSL_get_default_timeout(const SSL *s)
@@ -996,8 +968,30 @@ long SSL_get_default_timeout(const SSL *s)
     return (s->method->get_timeout());
 }
 
+static int ssl_start_async_job(SSL *s, struct ssl_async_args *args,
+                          int (*func)(void *)) {
+    int ret;
+    switch(ASYNC_start_job(&s->job, &ret, func, args,
+        sizeof(struct ssl_async_args))) {
+    case ASYNC_ERR:
+        s->rwstate = SSL_NOTHING;
+        SSLerr(SSL_F_SSL_START_ASYNC_JOB, SSL_R_FAILED_TO_INIT_ASYNC);
+        return -1;
+    case ASYNC_PAUSE:
+        s->rwstate = SSL_ASYNC_PAUSED;
+        return -1;
+    case ASYNC_FINISH:
+        s->job = NULL;
+        return ret;
+    default:
+        s->rwstate = SSL_NOTHING;
+        SSLerr(SSL_F_SSL_START_ASYNC_JOB, ERR_R_INTERNAL_ERROR);
+        /* Shouldn't happen */
+        return -1;
+    }
+}
 
-static int ssl_read_intern(void *vargs)
+static int ssl_io_intern(void *vargs)
 {
     struct ssl_async_args *args;
     SSL *s;
@@ -1008,15 +1002,14 @@ static int ssl_read_intern(void *vargs)
     s = args->s;
     buf = args->buf;
     num = args->num;
-
-    return s->method->ssl_read(s, buf, num);
+    if (args->type == 1)
+        return args->f.func1(s, buf, num);
+    else
+        return args->f.func2(s, buf, num);
 }
 
 int SSL_read(SSL *s, void *buf, int num)
 {
-    int ret;
-    struct ssl_async_args args;
-
     if (s->handshake_func == 0) {
         SSLerr(SSL_F_SSL_READ, SSL_R_UNINITIALIZED);
         return -1;
@@ -1027,29 +1020,16 @@ int SSL_read(SSL *s, void *buf, int num)
         return (0);
     }
 
-    args.s = s;
-    args.buf = buf;
-    args.num = num;
-
-    if((s->mode & SSL_MODE_ASYNC) && !ASYNC_in_job()) {
-        switch(ASYNC_start_job(&s->job, &ret, ssl_read_intern, &args,
-            sizeof(struct ssl_async_args))) {
-        case ASYNC_ERR:
-            s->rwstate = SSL_NOTHING;
-            SSLerr(SSL_F_SSL_READ, SSL_R_FAILED_TO_INIT_ASYNC);
-            return -1;
-        case ASYNC_PAUSE:
-            s->rwstate = SSL_ASYNC_PAUSED;
-            return -1;
-        case ASYNC_FINISH:
-            s->job = NULL;
-            return ret;
-        default:
-            s->rwstate = SSL_NOTHING;
-            SSLerr(SSL_F_SSL_READ, ERR_R_INTERNAL_ERROR);
-            /* Shouldn't happen */
-            return -1;
-        }
+    if((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
+        struct ssl_async_args args;
+
+        args.s = s;
+        args.buf = buf;
+        args.num = num;
+        args.type = 1;
+        args.f.func1 = s->method->ssl_read;
+
+        return ssl_start_async_job(s, &args, ssl_io_intern);
     } else {
         return s->method->ssl_read(s, buf, num);
     }
@@ -1065,30 +1045,23 @@ int SSL_peek(SSL *s, void *buf, int num)
     if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
         return (0);
     }
-    return (s->method->ssl_peek(s, buf, num));
-}
-
-static int ssl_write_intern(void *vargs)
-{
-    struct ssl_async_args *args;
-    SSL *s;
-    const void *buf;
-    int num;
+    if((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
+        struct ssl_async_args args;
 
-    args = (struct ssl_async_args *)vargs;
-    s = args->s;
-    buf = args->buf;
-    num = args->num;
+        args.s = s;
+        args.buf = buf;
+        args.num = num;
+        args.type = 1;
+        args.f.func1 = s->method->ssl_peek;
 
-    return s->method->ssl_write(s, buf, num);
+        return ssl_start_async_job(s, &args, ssl_io_intern);
+    } else {
+        return s->method->ssl_peek(s, buf, num);
+    }
 }
 
-
 int SSL_write(SSL *s, const void *buf, int num)
 {
-    int ret;
-    struct ssl_async_args args;
-
     if (s->handshake_func == 0) {
         SSLerr(SSL_F_SSL_WRITE, SSL_R_UNINITIALIZED);
         return -1;
@@ -1100,29 +1073,16 @@ int SSL_write(SSL *s, const void *buf, int num)
         return (-1);
     }
 
-    args.s = s;
-    args.buf = (void *) buf;
-    args.num = num;
-
-    if((s->mode & SSL_MODE_ASYNC) && !ASYNC_in_job()) {
-        switch(ASYNC_start_job(&s->job, &ret, ssl_write_intern, &args,
-            sizeof(struct ssl_async_args))) {
-        case ASYNC_ERR:
-            s->rwstate = SSL_NOTHING;
-            SSLerr(SSL_F_SSL_WRITE, SSL_R_FAILED_TO_INIT_ASYNC);
-            return -1;
-        case ASYNC_PAUSE:
-            s->rwstate = SSL_ASYNC_PAUSED;
-            return -1;
-        case ASYNC_FINISH:
-            s->job = NULL;
-            return ret;
-        default:
-            s->rwstate = SSL_NOTHING;
-            SSLerr(SSL_F_SSL_WRITE, ERR_R_INTERNAL_ERROR);
-            /* Shouldn't happen */
-            return -1;
-        }
+    if((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
+        struct ssl_async_args args;
+
+        args.s = s;
+        args.buf = (void *)buf;
+        args.num = num;
+        args.type = 2;
+        args.f.func2 = s->method->ssl_write;
+
+        return ssl_start_async_job(s, &args, ssl_io_intern);
     } else {
         return s->method->ssl_write(s, buf, num);
     }
@@ -2050,7 +2010,7 @@ void ssl_set_masks(SSL *s, const SSL_CIPHER *cipher)
     unsigned long mask_k, mask_a, emask_k, emask_a;
 #ifndef OPENSSL_NO_EC
     int have_ecc_cert, ecdsa_ok, ecc_pkey_size;
-    int have_ecdh_tmp, ecdh_ok;
+    int ecdh_ok;
     X509 *x = NULL;
     EVP_PKEY *ecc_pkey = NULL;
     int pk_nid = 0, md_nid = 0;
@@ -2076,9 +2036,6 @@ void ssl_set_masks(SSL *s, const SSL_CIPHER *cipher)
     dh_tmp = dh_tmp_export = 0;
 #endif
 
-#ifndef OPENSSL_NO_EC
-    have_ecdh_tmp = (c->ecdh_tmp || c->ecdh_tmp_cb || c->ecdh_tmp_auto);
-#endif
     cpk = &(c->pkeys[SSL_PKEY_RSA_ENC]);
     rsa_enc = pvalid[SSL_PKEY_RSA_ENC] & CERT_PKEY_VALID;
     rsa_enc_export = (rsa_enc && EVP_PKEY_size(cpk->privatekey) * 8 <= kl);
@@ -2103,16 +2060,28 @@ void ssl_set_masks(SSL *s, const SSL_CIPHER *cipher)
 
 #ifdef CIPHER_DEBUG
     fprintf(stderr,
-            "rt=%d rte=%d dht=%d ecdht=%d re=%d ree=%d rs=%d ds=%d dhr=%d dhd=%d\n",
-            rsa_tmp, rsa_tmp_export, dh_tmp, have_ecdh_tmp, rsa_enc,
+            "rt=%d rte=%d dht=%d re=%d ree=%d rs=%d ds=%d dhr=%d dhd=%d\n",
+            rsa_tmp, rsa_tmp_export, dh_tmp, rsa_enc,
             rsa_enc_export, rsa_sign, dsa_sign, dh_rsa, dh_dsa);
 #endif
 
+#ifndef OPENSSL_NO_GOST
+    cpk = &(c->pkeys[SSL_PKEY_GOST12_512]);
+    if (cpk->x509 != NULL && cpk->privatekey != NULL) {
+        mask_k |= SSL_kGOST;
+        mask_a |= SSL_aGOST12;
+    }
+    cpk = &(c->pkeys[SSL_PKEY_GOST12_256]);
+    if (cpk->x509 != NULL && cpk->privatekey != NULL) {
+        mask_k |= SSL_kGOST;
+        mask_a |= SSL_aGOST12;
+    }
     cpk = &(c->pkeys[SSL_PKEY_GOST01]);
     if (cpk->x509 != NULL && cpk->privatekey != NULL) {
         mask_k |= SSL_kGOST;
         mask_a |= SSL_aGOST01;
     }
+#endif
 
     if (rsa_enc || (rsa_tmp && rsa_sign))
         mask_k |= SSL_kRSA;
@@ -2197,10 +2166,8 @@ void ssl_set_masks(SSL *s, const SSL_CIPHER *cipher)
 #endif
 
 #ifndef OPENSSL_NO_EC
-    if (have_ecdh_tmp) {
-        mask_k |= SSL_kECDHE;
-        emask_k |= SSL_kECDHE;
-    }
+    mask_k |= SSL_kECDHE;
+    emask_k |= SSL_kECDHE;
 #endif
 
 #ifndef OPENSSL_NO_PSK
@@ -2294,6 +2261,16 @@ static int ssl_get_server_cert_index(const SSL *s)
     idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
     if (idx == SSL_PKEY_RSA_ENC && !s->cert->pkeys[SSL_PKEY_RSA_ENC].x509)
         idx = SSL_PKEY_RSA_SIGN;
+    if (idx == SSL_PKEY_GOST_EC) {
+        if (s->cert->pkeys[SSL_PKEY_GOST12_512].x509)
+            idx = SSL_PKEY_GOST12_512;
+        else if (s->cert->pkeys[SSL_PKEY_GOST12_256].x509)
+            idx = SSL_PKEY_GOST12_256;
+        else if (s->cert->pkeys[SSL_PKEY_GOST01].x509)
+            idx = SSL_PKEY_GOST01;
+        else
+            idx = -1;
+    }
     if (idx == -1)
         SSLerr(SSL_F_SSL_GET_SERVER_CERT_INDEX, ERR_R_INTERNAL_ERROR);
     return idx;
@@ -2534,21 +2511,40 @@ int SSL_get_error(const SSL *s, int i)
     return (SSL_ERROR_SYSCALL);
 }
 
+static int ssl_do_handshake_intern(void *vargs)
+{
+    struct ssl_async_args *args;
+    SSL *s;
+
+    args = (struct ssl_async_args *)vargs;
+    s = args->s;
+
+    return s->handshake_func(s);
+}
+
 int SSL_do_handshake(SSL *s)
 {
     int ret = 1;
 
     if (s->handshake_func == NULL) {
         SSLerr(SSL_F_SSL_DO_HANDSHAKE, SSL_R_CONNECTION_TYPE_NOT_SET);
-        return (-1);
+        return -1;
     }
 
     s->method->ssl_renegotiate_check(s);
 
     if (SSL_in_init(s) || SSL_in_before(s)) {
-        ret = s->handshake_func(s);
+        if((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
+            struct ssl_async_args args;
+
+            args.s = s;
+
+            ret = ssl_start_async_job(s, &args, ssl_do_handshake_intern);
+        } else {
+            ret = s->handshake_func(s);
+        }
     }
-    return (ret);
+    return ret;
 }
 
 void SSL_set_accept_state(SSL *s)
@@ -3041,13 +3037,6 @@ size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
     return outlen;
 }
 
-int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
-                         CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
-{
-    return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, argl, argp,
-                                   new_func, dup_func, free_func);
-}
-
 int SSL_set_ex_data(SSL *s, int idx, void *arg)
 {
     return (CRYPTO_set_ex_data(&s->ex_data, idx, arg));
@@ -3058,14 +3047,6 @@ void *SSL_get_ex_data(const SSL *s, int idx)
     return (CRYPTO_get_ex_data(&s->ex_data, idx));
 }
 
-int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
-                             CRYPTO_EX_dup *dup_func,
-                             CRYPTO_EX_free *free_func)
-{
-    return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, argl, argp,
-                                   new_func, dup_func, free_func);
-}
-
 int SSL_CTX_set_ex_data(SSL_CTX *s, int idx, void *arg)
 {
     return (CRYPTO_set_ex_data(&s->ex_data, idx, arg));
@@ -3156,23 +3137,6 @@ void SSL_set_tmp_dh_callback(SSL *ssl, DH *(*dh) (SSL *ssl, int is_export,
 }
 #endif
 
-#ifndef OPENSSL_NO_EC
-void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx,
-                                   EC_KEY *(*ecdh) (SSL *ssl, int is_export,
-                                                    int keylength))
-{
-    SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TMP_ECDH_CB,
-                          (void (*)(void))ecdh);
-}
-
-void SSL_set_tmp_ecdh_callback(SSL *ssl,
-                               EC_KEY *(*ecdh) (SSL *ssl, int is_export,
-                                                int keylength))
-{
-    SSL_callback_ctrl(ssl, SSL_CTRL_SET_TMP_ECDH_CB, (void (*)(void))ecdh);
-}
-#endif
-
 #ifndef OPENSSL_NO_PSK
 int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint)
 {
@@ -3334,27 +3298,17 @@ void ssl_clear_hash_ctx(EVP_MD_CTX **hash)
 /* Retrieve handshake hashes */
 int ssl_handshake_hash(SSL *s, unsigned char *out, int outlen)
 {
-    unsigned char *p = out;
-    int idx, ret = 0;
-    long mask;
     EVP_MD_CTX ctx;
-    const EVP_MD *md;
+    EVP_MD_CTX *hdgst = s->s3->handshake_dgst;
+    int ret = EVP_MD_CTX_size(hdgst);
     EVP_MD_CTX_init(&ctx);
-    for (idx = 0; ssl_get_handshake_digest(idx, &mask, &md); idx++) {
-        if (mask & ssl_get_algorithm2(s)) {
-            int hashsize = EVP_MD_size(md);
-            EVP_MD_CTX *hdgst = s->s3->handshake_dgst[idx];
-            if (!hdgst || hashsize < 0 || hashsize > outlen)
-                goto err;
-            if (!EVP_MD_CTX_copy_ex(&ctx, hdgst))
-                goto err;
-            if (!EVP_DigestFinal_ex(&ctx, p, NULL))
-                goto err;
-            p += hashsize;
-            outlen -= hashsize;
-        }
+    if (ret < 0 || ret > outlen) {
+        ret = 0;
+        goto err;
     }
-    ret = p - out;
+    if (!EVP_MD_CTX_copy_ex(&ctx, hdgst)
+        || EVP_DigestFinal_ex(&ctx, out, NULL) <= 0)
+        ret = 0;
  err:
     EVP_MD_CTX_cleanup(&ctx);
     return ret;