diff options
author | Bodo Möller <bodo@openssl.org> | 2002-08-09 08:56:08 +0000 |
---|---|---|
committer | Bodo Möller <bodo@openssl.org> | 2002-08-09 08:56:08 +0000 |
commit | ea262260469e49149cb10b25a87dfd6ad3fbb4ba (patch) | |
tree | 7032110f80ba1888d7b3047cfbacd2d46e4fb67c /ssl/ssl_lib.c | |
parent | 17f627931780f000b8dd47fe030c52cc0fa93ef5 (diff) | |
download | openssl-ea262260469e49149cb10b25a87dfd6ad3fbb4ba.zip openssl-ea262260469e49149cb10b25a87dfd6ad3fbb4ba.tar.gz openssl-ea262260469e49149cb10b25a87dfd6ad3fbb4ba.tar.bz2 |
ECC ciphersuite support
Submitted by: Douglas Stebila <douglas.stebila@sun.com>
(Authors: Vipul Gupta and Sumit Gupta, Sun Microsystems Laboratories)
Diffstat (limited to 'ssl/ssl_lib.c')
-rw-r--r-- | ssl/ssl_lib.c | 177 |
1 files changed, 173 insertions, 4 deletions
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index ab172ae..b50fc46 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -110,7 +110,11 @@ * Hudson (tjh@cryptsoft.com). * */ - +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ #ifdef REF_CHECK # include <assert.h> @@ -1467,6 +1471,10 @@ void ssl_set_cert_masks(CERT *c, SSL_CIPHER *cipher) int rsa_enc_export,dh_rsa_export,dh_dsa_export; int rsa_tmp_export,dh_tmp_export,kl; unsigned long mask,emask; + int have_ecc_cert, have_ecdh_tmp, ecdh_ok, ecdsa_ok, ecc_pkey_size; + X509 *x = NULL; + EVP_PKEY *ecc_pkey = NULL; + int signature_nid = 0; if (c == NULL) return; @@ -1487,6 +1495,9 @@ void ssl_set_cert_masks(CERT *c, SSL_CIPHER *cipher) dh_tmp=dh_tmp_export=0; #endif +#ifndef OPENSSL_NO_ECDH + have_ecdh_tmp=(c->ecdh_tmp != NULL || c->ecdh_tmp_cb != NULL); +#endif cpk= &(c->pkeys[SSL_PKEY_RSA_ENC]); rsa_enc= (cpk->x509 != NULL && cpk->privatekey != NULL); rsa_enc_export=(rsa_enc && EVP_PKEY_size(cpk->privatekey)*8 <= kl); @@ -1501,7 +1512,8 @@ void ssl_set_cert_masks(CERT *c, SSL_CIPHER *cipher) /* FIX THIS EAY EAY EAY */ dh_dsa= (cpk->x509 != NULL && cpk->privatekey != NULL); dh_dsa_export=(dh_dsa && EVP_PKEY_size(cpk->privatekey)*8 <= kl); - + cpk= &(c->pkeys[SSL_PKEY_ECC]); + have_ecc_cert= (cpk->x509 != NULL && cpk->privatekey != NULL); mask=0; emask=0; @@ -1541,7 +1553,7 @@ void ssl_set_cert_masks(CERT *c, SSL_CIPHER *cipher) if (rsa_enc || rsa_sign) { mask|=SSL_aRSA; - emask|=SSL_aRSA; + mask|=SSL_aRSA; } if (dsa_sign) @@ -1558,11 +1570,131 @@ void ssl_set_cert_masks(CERT *c, SSL_CIPHER *cipher) emask|=SSL_kKRB5|SSL_aKRB5; #endif + /* An ECC certificate may be usable for ECDH and/or + * ECDSA cipher suites depending on the key usage extension. + */ + if (have_ecc_cert) + { + /* This call populates extension flags (ex_flags) */ + x = (c->pkeys[SSL_PKEY_ECC]).x509; + X509_check_purpose(x, -1, 0); + ecdh_ok = (x->ex_flags & EXFLAG_KUSAGE) ? + (x->ex_kusage & X509v3_KU_KEY_AGREEMENT) : 1; + ecdsa_ok = (x->ex_flags & EXFLAG_KUSAGE) ? + (x->ex_kusage & X509v3_KU_DIGITAL_SIGNATURE) : 1; + ecc_pkey = X509_get_pubkey(x); + ecc_pkey_size = (ecc_pkey != NULL) ? + EVP_PKEY_bits(ecc_pkey) : 0; + EVP_PKEY_free(ecc_pkey); + if ((x->sig_alg) && (x->sig_alg->algorithm)) + signature_nid = OBJ_obj2nid(x->sig_alg->algorithm); +#ifndef OPENSSL_NO_ECDH + if (ecdh_ok) + { + if ((signature_nid == NID_md5WithRSAEncryption) || + (signature_nid == NID_md4WithRSAEncryption) || + (signature_nid == NID_md2WithRSAEncryption)) + { + mask|=SSL_kECDH|SSL_aRSA; + if (ecc_pkey_size <= 163) + emask|=SSL_kECDH|SSL_aRSA; + } + if (signature_nid == NID_ecdsa_with_SHA1) + { + mask|=SSL_kECDH|SSL_aECDSA; + if (ecc_pkey_size <= 163) + emask|=SSL_kECDH|SSL_aECDSA; + } + } +#endif +#ifndef OPENSSL_NO_ECDSA + if (ecdsa_ok) + { + mask|=SSL_aECDSA; + emask|=SSL_aECDSA; + } +#endif + } + +#ifndef OPENSSL_NO_ECDH + if (have_ecdh_tmp) + { + mask|=SSL_kECDHE; + emask|=SSL_kECDHE; + } +#endif c->mask=mask; c->export_mask=emask; c->valid=1; } +/* This handy macro borrowed from crypto/x509v3/v3_purp.c */ +#define ku_reject(x, usage) \ + (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage))) + +int check_srvr_ecc_cert_and_alg(X509 *x, SSL_CIPHER *cs) + { + unsigned long alg = cs->algorithms; + EVP_PKEY *pkey = NULL; + int keysize = 0; + int signature_nid = 0; + + if (SSL_C_IS_EXPORT(cs)) + { + /* ECDH key length in export ciphers must be <= 163 bits */ + pkey = X509_get_pubkey(x); + if (pkey == NULL) return 0; + keysize = EVP_PKEY_bits(pkey); + EVP_PKEY_free(pkey); + if (keysize > 163) return 0; + } + + /* This call populates the ex_flags field correctly */ + X509_check_purpose(x, -1, 0); + if ((x->sig_alg) && (x->sig_alg->algorithm)) + signature_nid = OBJ_obj2nid(x->sig_alg->algorithm); + if (alg & SSL_kECDH) + { + /* key usage, if present, must allow key agreement */ + if (ku_reject(x, X509v3_KU_KEY_AGREEMENT)) + { + printf("ECC cert not authorized for key agreement\n"); + return 0; + } + if (alg & SSL_aECDSA) + { + /* signature alg must be ECDSA */ + if (signature_nid != NID_ecdsa_with_SHA1) + { + printf("ECC cert not signed w/ ECDSA\n"); + return 0; + } + } + if (alg & SSL_aRSA) + { + /* signature alg must be RSA */ + if ((signature_nid != NID_md5WithRSAEncryption) && + (signature_nid != NID_md4WithRSAEncryption) && + (signature_nid != NID_md2WithRSAEncryption)) + { + printf("ECC cert not signed w/ RSA\n"); + return 0; + } + } + } + else if (alg & SSL_aECDSA) + { + /* key usage, if present, must allow signing */ + if (ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE)) + { + printf("ECC cert not authorized for signature\n"); + return 0; + } + } + + return 1; /* all checks are ok */ + } + /* THIS NEEDS CLEANING UP */ X509 *ssl_get_server_send_cert(SSL *s) { @@ -1577,7 +1709,26 @@ X509 *ssl_get_server_send_cert(SSL *s) mask=is_export?c->export_mask:c->mask; kalg=alg&(SSL_MKEY_MASK|SSL_AUTH_MASK); - if (kalg & SSL_kDHr) + if (kalg & SSL_kECDH) + { + /* we don't need to look at SSL_kECDHE + * since no certificate is needed for + * anon ECDH and for authenticated + * ECDHE, the check for the auth + * algorithm will set i correctly + * NOTE: For ECDH-RSA, we need an ECC + * not an RSA cert but for ECDHE-RSA + * we need an RSA cert. Placing the + * checks for SSL_kECDH before RSA + * checks ensures the correct cert is chosen. + */ + i=SSL_PKEY_ECC; + } + else if (kalg & SSL_aECDSA) + { + i=SSL_PKEY_ECC; + } + else if (kalg & SSL_kDHr) i=SSL_PKEY_DH_RSA; else if (kalg & SSL_kDHd) i=SSL_PKEY_DH_DSA; @@ -1601,6 +1752,7 @@ X509 *ssl_get_server_send_cert(SSL *s) return(NULL); } if (c->pkeys[i].x509 == NULL) return(NULL); + return(c->pkeys[i].x509); } @@ -1624,6 +1776,9 @@ EVP_PKEY *ssl_get_sign_pkey(SSL *s,SSL_CIPHER *cipher) else return(NULL); } + else if ((alg & SSL_aECDSA) && + (c->pkeys[SSL_PKEY_ECC].privatekey != NULL)) + return(c->pkeys[SSL_PKEY_ECC].privatekey); else /* if (alg & SSL_aNULL) */ { SSLerr(SSL_F_SSL_GET_SIGN_PKEY,ERR_R_INTERNAL_ERROR); @@ -2271,6 +2426,20 @@ void SSL_set_tmp_dh_callback(SSL *ssl,DH *(*dh)(SSL *ssl,int is_export, } #endif +#ifndef OPENSSL_NO_ECDH +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 (*)())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 (*)())ecdh); + } +#endif + void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)) { |