From ea262260469e49149cb10b25a87dfd6ad3fbb4ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bodo=20M=C3=B6ller?= Date: Fri, 9 Aug 2002 08:56:08 +0000 Subject: ECC ciphersuite support Submitted by: Douglas Stebila (Authors: Vipul Gupta and Sumit Gupta, Sun Microsystems Laboratories) --- ssl/s3_both.c | 22 +++ ssl/s3_clnt.c | 441 +++++++++++++++++++++++++++++++++++++++++++++++++- ssl/s3_lib.c | 499 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- ssl/s3_srvr.c | 492 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- ssl/ssl.h | 56 +++++-- ssl/ssl3.h | 17 +- ssl/ssl_algs.c | 3 + ssl/ssl_cert.c | 31 +++- ssl/ssl_ciph.c | 29 +++- ssl/ssl_err.c | 8 + ssl/ssl_lib.c | 177 +++++++++++++++++++- ssl/ssl_locl.h | 79 ++++++--- ssl/ssltest.c | 67 +++++++- ssl/tls1.h | 107 ++++++++++++- 14 files changed, 1953 insertions(+), 75 deletions(-) (limited to 'ssl') diff --git a/ssl/s3_both.c b/ssl/s3_both.c index 8864366f59..a5588360e5 100644 --- a/ssl/s3_both.c +++ b/ssl/s3_both.c @@ -108,6 +108,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. + */ #include #include @@ -520,6 +525,23 @@ int ssl_cert_type(X509 *x, EVP_PKEY *pkey) else ret= -1; } } +#ifndef OPENSSL_NO_EC + /* XXX: Structurally, there is no distinction between + * ECDSA and ECDH public keys (both are ECPoints). + * So EVP_PKEY_ECDSA should really be renamed EVP_PKEY_ECC + * (or similar). As for ECC certificates, additional + * information (e.g. in the optional key usage X509v3 + * extension) could be used when available to distinguish + * between ECDH and ECDSA certificates. For now, we do not + * make that distinction here. Instead, we shift the burden + * of checking for appropriate key usage to the SSL code + * responsible for sending/processing ECC certificates. + */ + else if (i == EVP_PKEY_ECDSA) + { + ret = SSL_PKEY_ECC; + } +#endif else ret= -1; diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 2b58482484..74e1e529f8 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -108,6 +108,32 @@ * Hudson (tjh@cryptsoft.com). * */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * In addition, Sun covenants to all licensees who provide a reciprocal + * covenant with respect to their own patents if any, not to sue under + * current and future patent claims necessarily infringed by the making, + * using, practicing, selling, offering for sale and/or otherwise + * disposing of the Contribution as delivered hereunder + * (or portions thereof), provided that such covenant shall not apply: + * 1) for code that a licensee deletes from the Contribution; + * 2) separates from the Contribution; or + * 3) for infringements caused by: + * i) the modification of the Contribution or + * ii) the combination of the Contribution with other software or + * devices where such combination causes the infringement. + * + * ECC cipher suite support in OpenSSL originally written by + * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. + * + */ #include #include "ssl_locl.h" @@ -131,6 +157,12 @@ static int ssl3_send_client_key_exchange(SSL *s); static int ssl3_get_key_exchange(SSL *s); static int ssl3_get_server_certificate(SSL *s); static int ssl3_check_cert_and_algorithm(SSL *s); + +#ifndef OPENSSL_NO_ECDH +static int curve_id2nid(int curve_id); +int check_srvr_ecc_cert_and_alg(X509 *x, SSL_CIPHER *cs); +#endif + static SSL_METHOD *ssl3_get_client_method(int ver) { if (ver == SSL3_VERSION) @@ -262,7 +294,7 @@ int ssl3_connect(SSL *s) case SSL3_ST_CR_CERT_A: case SSL3_ST_CR_CERT_B: - /* Check if it is anon DH */ + /* Check if it is anon DH/ECDH */ if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL)) { ret=ssl3_get_server_certificate(s); @@ -329,6 +361,13 @@ int ssl3_connect(SSL *s) * sent back */ /* For TLS, cert_req is set to 2, so a cert chain * of nothing is sent, but no verify packet is sent */ + /* XXX: For now, we do not support client + * authentication in ECDH cipher suites with + * ECDH (rather than ECDSA) certificates. + * We need to skip the certificate verify + * message when client's ECDH public key is sent + * inside the client certificate. + */ if (s->s3->tmp.cert_req == 1) { s->state=SSL3_ST_CW_CERT_VRFY_A; @@ -944,6 +983,13 @@ static int ssl3_get_key_exchange(SSL *s) #ifndef OPENSSL_NO_DH DH *dh=NULL; #endif +#ifndef OPENSSL_NO_ECDH + EC_KEY *ecdh = NULL; + BN_CTX *bn_ctx = NULL; + EC_POINT *srvr_ecpoint = NULL; + int curve_nid = 0; + int encoded_pt_len = 0; +#endif /* use same message size as in ssl3_get_certificate_request() * as ServerKeyExchange message may be skipped */ @@ -979,6 +1025,13 @@ static int ssl3_get_key_exchange(SSL *s) DH_free(s->session->sess_cert->peer_dh_tmp); s->session->sess_cert->peer_dh_tmp=NULL; } +#endif +#ifndef OPENSSL_NO_ECDH + if (s->session->sess_cert->peer_ecdh_tmp) + { + EC_KEY_free(s->session->sess_cert->peer_ecdh_tmp); + s->session->sess_cert->peer_ecdh_tmp=NULL; + } #endif } else @@ -1121,6 +1174,101 @@ static int ssl3_get_key_exchange(SSL *s) goto f_err; } #endif /* !OPENSSL_NO_DH */ + +#ifndef OPENSSL_NO_ECDH + else if (alg & SSL_kECDHE) + { + if ((ecdh=EC_KEY_new()) == NULL) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Extract elliptic curve parameters and the + * server's ephemeral ECDH public key. + * Keep accumulating lengths of various components in + * param_len and make sure it never exceeds n. + */ + + /* XXX: For now we only support named (not generic) curves + * and the ECParameters in this case is just two bytes. + */ + param_len=2; + if ((param_len > n) || + (*p != NAMED_CURVE_TYPE) || + ((curve_nid = curve_id2nid(*(p + 1))) == 0)) + { + al=SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS); + goto f_err; + } + + if (!(ecdh->group=EC_GROUP_new_by_nid(curve_nid))) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_EC_LIB); + goto err; + } + + if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && + (EC_GROUP_get_degree(ecdh->group) > 163)) + { + al=SSL_AD_EXPORT_RESTRICTION; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER); + goto f_err; + } + + p+=2; + + /* Next, get the encoded ECPoint */ + if (((srvr_ecpoint = EC_POINT_new(ecdh->group)) == NULL) || + ((bn_ctx = BN_CTX_new()) == NULL)) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE); + goto err; + } + + encoded_pt_len = *p; /* length of encoded point */ + p+=1; + param_len += (1 + encoded_pt_len); + if ((param_len > n) || + (EC_POINT_oct2point(ecdh->group, srvr_ecpoint, + p, encoded_pt_len, bn_ctx) == 0)) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_ECPOINT); + goto f_err; + } + + n-=param_len; + p+=encoded_pt_len; + + /* The ECC/TLS specification does not mention + * the use of DSA to sign ECParameters in the server + * key exchange message. We do support RSA and ECDSA. + */ + if (0) ; +#ifndef OPENSSL_NO_RSA + else if (alg & SSL_aRSA) + pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); +#endif +#ifndef OPENSSL_NO_ECDSA + else if (alg & SSL_aECDSA) + pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_ECC].x509); +#endif + /* else anonymous ECDH, so no certificate or pkey. */ + ecdh->pub_key = srvr_ecpoint; + s->session->sess_cert->peer_ecdh_tmp=ecdh; + ecdh=NULL; + BN_CTX_free(bn_ctx); + srvr_ecpoint = NULL; + } + else if (alg & SSL_kECDH) + { + al=SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } +#endif /* !OPENSSL_NO_ECDH */ if (alg & SSL_aFZA) { al=SSL_AD_HANDSHAKE_FAILURE; @@ -1131,7 +1279,6 @@ static int ssl3_get_key_exchange(SSL *s) /* p points to the next byte, there are 'n' bytes left */ - /* if it was signed, check the signature */ if (pkey != NULL) { @@ -1200,6 +1347,24 @@ static int ssl3_get_key_exchange(SSL *s) } } else +#endif +#ifndef OPENSSL_NO_ECDSA + if (pkey->type == EVP_PKEY_ECDSA) + { + /* let's do ECDSA */ + EVP_VerifyInit_ex(&md_ctx,EVP_ecdsa(), NULL); + EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); + EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); + EVP_VerifyUpdate(&md_ctx,param,param_len); + if (!EVP_VerifyFinal(&md_ctx,p,(int)n,pkey)) + { + /* bad signature */ + al=SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SIGNATURE); + goto f_err; + } + } + else #endif { SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); @@ -1235,6 +1400,12 @@ err: #ifndef OPENSSL_NO_DH if (dh != NULL) DH_free(dh); +#endif +#ifndef OPENSSL_NO_ECDH + BN_CTX_free(bn_ctx); + EC_POINT_free(srvr_ecpoint); + if (ecdh != NULL) + EC_KEY_free(ecdh); #endif EVP_MD_CTX_cleanup(&md_ctx); return(-1); @@ -1423,6 +1594,14 @@ static int ssl3_send_client_key_exchange(SSL *s) #ifndef OPENSSL_NO_KRB5 KSSL_ERR kssl_err; #endif /* OPENSSL_NO_KRB5 */ +#ifndef OPENSSL_NO_ECDH + EC_KEY *clnt_ecdh = NULL; + EC_POINT *srvr_ecpoint = NULL; + EVP_PKEY *srvr_pub_pkey = NULL; + unsigned char *encodedPoint = NULL; + int encoded_pt_len = 0; + BN_CTX * bn_ctx = NULL; +#endif if (s->state == SSL3_ST_CW_KEY_EXCH_A) { @@ -1680,10 +1859,180 @@ static int ssl3_send_client_key_exchange(SSL *s) /* perhaps clean things up a bit EAY EAY EAY EAY*/ } #endif + +#ifndef OPENSSL_NO_ECDH + else if ((l & SSL_kECDH) || (l & SSL_kECDHE)) + { + EC_GROUP *srvr_group = NULL; + int ecdh_clnt_cert = 0; + + /* Did we send out the client's + * ECDH share for use in premaster + * computation as part of client certificate? + * If so, set ecdh_clnt_cert to 1. + */ + if ((l & SSL_kECDH) && (s->cert != NULL)) + { + /* XXX: For now, we do not support client + * authentication using ECDH certificates. + * To add such support, one needs to add + * code that checks for appropriate + * conditions and sets ecdh_clnt_cert to 1. + * For example, the cert have an ECC + * key on the same curve as the server's + * and the key should be authorized for + * key agreement. + * + * One also needs to add code in ssl3_connect + * to skip sending the certificate verify + * message. + * + * if ((s->cert->key->privatekey != NULL) && + * (s->cert->key->privatekey->type == + * EVP_PKEY_ECC) && ...) + * ecdh_clnt_cert = 1; + */ + } + + if (s->session->sess_cert->peer_ecdh_tmp != NULL) + { + srvr_group = s->session->sess_cert-> \ + peer_ecdh_tmp->group; + srvr_ecpoint = s->session->sess_cert-> \ + peer_ecdh_tmp->pub_key; + } + else + { + /* Get the Server Public Key from Cert */ + srvr_pub_pkey = X509_get_pubkey(s->session-> \ + sess_cert->peer_pkeys[SSL_PKEY_ECC].x509); + if ((srvr_pub_pkey == NULL) || + (srvr_pub_pkey->type != EVP_PKEY_ECDSA) || + (srvr_pub_pkey->pkey.eckey == NULL)) + { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + srvr_group = srvr_pub_pkey->pkey.eckey->group; + srvr_ecpoint = + srvr_pub_pkey->pkey.eckey->pub_key; + } + + if ((srvr_group == NULL) || (srvr_ecpoint == NULL)) + { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if ((clnt_ecdh=EC_KEY_new()) == NULL) + { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE); + goto err; + } + + clnt_ecdh->group = srvr_group; + if (ecdh_clnt_cert) + { + /* Reuse key info from our certificate + * We only need our private key to perform + * the ECDH computation. + */ + clnt_ecdh->priv_key = BN_dup(s->cert->key-> \ + privatekey->pkey.eckey->priv_key); + } + else + { + /* Generate a new ECDH key pair */ + if (!(EC_KEY_generate_key(clnt_ecdh))) + { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); + goto err; + } + } + + /* use the 'p' output buffer for the ECDH key, but + * make sure to clear it out afterwards + */ + + n=ECDH_compute_key(p, srvr_ecpoint, clnt_ecdh); + if (n <= 0) + { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_ECDH_LIB); + goto err; + } + + /* generate master key from the result */ + s->session->master_key_length = s->method->ssl3_enc \ + -> generate_master_secret(s, + s->session->master_key, + p, n); + + memset(p, 0, n); /* clean up */ + + if (ecdh_clnt_cert) + { + /* Send empty client key exch message */ + n = 0; + } + else + { + /* First check the size of encoding and + * allocate memory accordingly. + */ + encoded_pt_len = + EC_POINT_point2oct(clnt_ecdh->group, + clnt_ecdh->pub_key, + POINT_CONVERSION_UNCOMPRESSED, + NULL, 0, NULL); + + encodedPoint = (unsigned char *) + OPENSSL_malloc(encoded_pt_len * + sizeof(unsigned char)); + bn_ctx = BN_CTX_new(); + if ((encodedPoint == NULL) || + (bn_ctx == NULL)) + { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Encode the public key */ + n = EC_POINT_point2oct(clnt_ecdh->group, + clnt_ecdh->pub_key, + POINT_CONVERSION_UNCOMPRESSED, + encodedPoint, encoded_pt_len, bn_ctx); + + *p = n; /* length of encoded point */ + /* Encoded point will be copied here */ + p += 1; + /* copy the point */ + memcpy((unsigned char *)p, encodedPoint, n); + /* increment n to account for length field */ + n += 1; + } + + /* Free allocated memory */ + BN_CTX_free(bn_ctx); + if (encodedPoint != NULL) OPENSSL_free(encodedPoint); + if (clnt_ecdh != NULL) + { + /* group is shared */ + clnt_ecdh->group = NULL; + EC_KEY_free(clnt_ecdh); + } + EVP_PKEY_free(srvr_pub_pkey); + } +#endif /* !OPENSSL_NO_ECDH */ else { - ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE); - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); + ssl3_send_alert(s, SSL3_AL_FATAL, + SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); goto err; } @@ -1699,6 +2048,17 @@ static int ssl3_send_client_key_exchange(SSL *s) /* SSL3_ST_CW_KEY_EXCH_B */ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); err: +#ifndef OPENSSL_NO_ECDH + BN_CTX_free(bn_ctx); + if (encodedPoint != NULL) OPENSSL_free(encodedPoint); + if (clnt_ecdh != NULL) + { + /* group is shared */ + clnt_ecdh->group = NULL; + EC_KEY_free(clnt_ecdh); + } + EVP_PKEY_free(srvr_pub_pkey); +#endif return(-1); } @@ -1756,6 +2116,23 @@ static int ssl3_send_client_verify(SSL *s) n=j+2; } else +#endif +#ifndef OPENSSL_NO_ECDSA + if (pkey->type == EVP_PKEY_ECDSA) + { + if (!ECDSA_sign(pkey->save_type, + &(data[MD5_DIGEST_LENGTH]), + SHA_DIGEST_LENGTH,&(p[2]), + (unsigned int *)&j,pkey->pkey.eckey)) + { + SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, + ERR_R_ECDSA_LIB); + goto err; + } + s2n(j,p); + n=j+2; + } + else #endif { SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_INTERNAL_ERROR); @@ -1888,6 +2265,21 @@ static int ssl3_check_cert_and_algorithm(SSL *s) /* This is the passed certificate */ idx=sc->peer_cert_type; +#ifndef OPENSSL_NO_ECDH + if (idx == SSL_PKEY_ECC) + { + if (check_srvr_ecc_cert_and_alg(sc->peer_pkeys[idx].x509, + s->s3->tmp.new_cipher) == 0) + { /* check failed */ + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_BAD_ECC_CERT); + goto f_err; + } + else + { + return 1; + } + } +#endif pkey=X509_get_pubkey(sc->peer_pkeys[idx].x509); i=X509_certificate_type(sc->peer_pkeys[idx].x509,pkey); EVP_PKEY_free(pkey); @@ -1973,3 +2365,44 @@ err: return(0); } + +#ifndef OPENSSL_NO_ECDH +/* This is the complement of nid2curve_id in s3_srvr.c. */ +static int curve_id2nid(int curve_id) +{ + /* ECC curves from draft-ietf-tls-ecc-01.txt (Mar 15, 2001) */ + static int nid_list[26] = + { + 0, + NID_sect163k1, /* sect163k1 (1) */ + NID_sect163r1, /* sect163r1 (2) */ + NID_sect163r2, /* sect163r2 (3) */ + NID_sect193r1, /* sect193r1 (4) */ + NID_sect193r2, /* sect193r2 (5) */ + NID_sect233k1, /* sect233k1 (6) */ + NID_sect233r1, /* sect233r1 (7) */ + NID_sect239k1, /* sect239k1 (8) */ + NID_sect283k1, /* sect283k1 (9) */ + NID_sect283r1, /* sect283r1 (10) */ + NID_sect409k1, /* sect409k1 (11) */ + NID_sect409r1, /* sect409r1 (12) */ + NID_sect571k1, /* sect571k1 (13) */ + NID_sect571r1, /* sect571r1 (14) */ + NID_secp160k1, /* secp160k1 (15) */ + NID_secp160r1, /* secp160r1 (16) */ + NID_secp160r2, /* secp160r2 (17) */ + NID_secp192k1, /* secp192k1 (18) */ + NID_X9_62_prime192v1, /* secp192r1 (19) */ + NID_secp224k1, /* secp224k1 (20) */ + NID_secp224r1, /* secp224r1 (21) */ + NID_secp256k1, /* secp256k1 (22) */ + NID_X9_62_prime256v1, /* secp256r1 (23) */ + NID_secp384r1, /* secp384r1 (24) */ + NID_secp521r1 /* secp521r1 (25) */ + }; + + if ((curve_id < 1) || (curve_id > 25)) return 0; + + return nid_list[curve_id]; +} +#endif diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 14b2f13ae2..40730ca11d 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -108,6 +108,32 @@ * Hudson (tjh@cryptsoft.com). * */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * In addition, Sun covenants to all licensees who provide a reciprocal + * covenant with respect to their own patents if any, not to sue under + * current and future patent claims necessarily infringed by the making, + * using, practicing, selling, offering for sale and/or otherwise + * disposing of the Contribution as delivered hereunder + * (or portions thereof), provided that such covenant shall not apply: + * 1) for code that a licensee deletes from the Contribution; + * 2) separates from the Contribution; or + * 3) for infringements caused by: + * i) the modification of the Contribution or + * ii) the combination of the Contribution with other software or + * devices where such combination causes the infringement. + * + * ECC cipher suite support in OpenSSL originally written by + * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. + * + */ #include #include @@ -871,6 +897,356 @@ OPENSSL_GLOBAL SSL_CIPHER ssl3_ciphers[]={ SSL_ALL_STRENGTHS, }, +#ifndef OPENSSL_NO_ECDH + /* Cipher 47 */ + { + 1, + TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA, + TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA, + SSL_kECDH|SSL_aECDSA|SSL_eNULL|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP, + 0, + 0, + 0, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 48 */ + { + 1, + TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA, + TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA, + SSL_kECDH|SSL_aECDSA|SSL_RC4|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP, + 0, + 128, + 128, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 49 */ + { + 1, + TLS1_TXT_ECDH_ECDSA_WITH_DES_CBC_SHA, + TLS1_CK_ECDH_ECDSA_WITH_DES_CBC_SHA, + SSL_kECDH|SSL_aECDSA|SSL_DES|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP|SSL_LOW, + 0, + 56, + 56, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 4A */ + { + 1, + TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA, + TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA, + SSL_kECDH|SSL_aECDSA|SSL_3DES|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + 0, + 168, + 168, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 4B */ + { + 1, + TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + SSL_kECDH|SSL_aECDSA|SSL_AES|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP|SSL_MEDIUM, + 0, + 128, + 128, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 4C */ + { + 1, + TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + SSL_kECDH|SSL_aECDSA|SSL_AES|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + 0, + 256, + 256, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 5B */ + /* XXX NOTE: The ECC/TLS draft has a bug and reuses 4B for this */ + { + 1, + TLS1_TXT_ECDH_ECDSA_EXPORT_WITH_RC4_40_SHA, + TLS1_CK_ECDH_ECDSA_EXPORT_WITH_RC4_40_SHA, + SSL_kECDH|SSL_aECDSA|SSL_RC4|SSL_SHA|SSL_TLSV1, + SSL_EXPORT|SSL_EXP40, + 0, + 40, + 128, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 5C */ + /* XXX NOTE: The ECC/TLS draft has a bug and reuses 4C for this */ + { + 1, + TLS1_TXT_ECDH_ECDSA_EXPORT_WITH_RC4_56_SHA, + TLS1_CK_ECDH_ECDSA_EXPORT_WITH_RC4_56_SHA, + SSL_kECDH|SSL_aECDSA|SSL_RC4|SSL_SHA|SSL_TLSV1, + SSL_EXPORT|SSL_EXP56, + 0, + 56, + 128, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 4D */ + { + 1, + TLS1_TXT_ECDH_RSA_WITH_NULL_SHA, + TLS1_CK_ECDH_RSA_WITH_NULL_SHA, + SSL_kECDH|SSL_aRSA|SSL_eNULL|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP, + 0, + 0, + 0, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 4E */ + { + 1, + TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA, + TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA, + SSL_kECDH|SSL_aRSA|SSL_RC4|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP, + 0, + 128, + 128, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 4F */ + { + 1, + TLS1_TXT_ECDH_RSA_WITH_DES_CBC_SHA, + TLS1_CK_ECDH_RSA_WITH_DES_CBC_SHA, + SSL_kECDH|SSL_aRSA|SSL_DES|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP|SSL_LOW, + 0, + 56, + 56, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 50 */ + { + 1, + TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA, + TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA, + SSL_kECDH|SSL_aRSA|SSL_3DES|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + 0, + 168, + 168, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 51 */ + { + 1, + TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA, + SSL_kECDH|SSL_aRSA|SSL_AES|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP|SSL_MEDIUM, + 0, + 128, + 128, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 52 */ + { + 1, + TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA, + TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA, + SSL_kECDH|SSL_aRSA|SSL_AES|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + 0, + 256, + 256, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 53 */ + { + 1, + TLS1_TXT_ECDH_RSA_EXPORT_WITH_RC4_40_SHA, + TLS1_CK_ECDH_RSA_EXPORT_WITH_RC4_40_SHA, + SSL_kECDH|SSL_aRSA|SSL_RC4|SSL_SHA|SSL_TLSV1, + SSL_EXPORT|SSL_EXP40, + 0, + 40, + 128, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 54 */ + { + 1, + TLS1_TXT_ECDH_RSA_EXPORT_WITH_RC4_56_SHA, + TLS1_CK_ECDH_RSA_EXPORT_WITH_RC4_56_SHA, + SSL_kECDH|SSL_aRSA|SSL_RC4|SSL_SHA|SSL_TLSV1, + SSL_EXPORT|SSL_EXP56, + 0, + 56, + 128, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 55 */ + { + 1, + TLS1_TXT_ECDH_anon_WITH_NULL_SHA, + TLS1_CK_ECDH_anon_WITH_NULL_SHA, + SSL_kECDHE|SSL_aNULL|SSL_eNULL|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP, + 0, + 0, + 0, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 56 */ + { + 1, + TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA, + TLS1_CK_ECDH_anon_WITH_RC4_128_SHA, + SSL_kECDHE|SSL_aNULL|SSL_RC4|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP, + 0, + 128, + 128, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 57 */ + { + 1, + TLS1_TXT_ECDH_anon_WITH_DES_CBC_SHA, + TLS1_CK_ECDH_anon_WITH_DES_CBC_SHA, + SSL_kECDHE|SSL_aNULL|SSL_DES|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP|SSL_LOW, + 0, + 56, + 56, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 58 */ + { + 1, + TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA, + TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA, + SSL_kECDHE|SSL_aNULL|SSL_3DES|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + 0, + 168, + 168, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 59 */ + { + 1, + TLS1_TXT_ECDH_anon_EXPORT_WITH_DES_40_CBC_SHA, + TLS1_CK_ECDH_anon_EXPORT_WITH_DES_40_CBC_SHA, + SSL_kECDHE|SSL_aNULL|SSL_DES|SSL_SHA|SSL_TLSV1, + SSL_EXPORT|SSL_EXP40, + 0, + 40, + 56, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 5A */ + { + 1, + TLS1_TXT_ECDH_anon_EXPORT_WITH_RC4_40_SHA, + TLS1_CK_ECDH_anon_EXPORT_WITH_RC4_40_SHA, + SSL_kECDHE|SSL_aNULL|SSL_RC4|SSL_SHA|SSL_TLSV1, + SSL_EXPORT|SSL_EXP40, + 0, + 40, + 128, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 77 XXX: ECC ciphersuites offering forward secrecy + * are not yet specified in the ECC/TLS draft but our code + * allows them to be implemented very easily. To add such + * a cipher suite, one needs to add two constant definitions + * to tls1.h and a new structure in this file as shown below. We + * illustrate the process for the made-up cipher + * ECDHE-ECDSA-AES128-SHA. + */ + { + 1, + TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + SSL_kECDHE|SSL_aECDSA|SSL_AES|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP|SSL_MEDIUM, + 0, + 128, + 128, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + + /* Cipher 78 XXX: Another made-up ECC cipher suite that + * offers forward secrecy (ECDHE-RSA-AES128-SHA). + */ + { + 1, + TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, + SSL_kECDHE|SSL_aRSA|SSL_AES|SSL_SHA|SSL_TLSV1, + SSL_NOT_EXP|SSL_MEDIUM, + 0, + 128, + 128, + SSL_ALL_CIPHERS, + SSL_ALL_STRENGTHS, + }, + +#endif /* !OPENSSL_NO_ECDH */ + /* end of list */ }; @@ -982,6 +1358,11 @@ void ssl3_free(SSL *s) if (s->s3->tmp.dh != NULL) DH_free(s->s3->tmp.dh); #endif +#ifndef OPENSSL_NO_ECDH + if (s->s3->tmp.ecdh != NULL) + EC_KEY_free(s->s3->tmp.ecdh); +#endif + if (s->s3->tmp.ca_names != NULL) sk_X509_NAME_pop_free(s->s3->tmp.ca_names,X509_NAME_free); EVP_MD_CTX_cleanup(&s->s3->finish_dgst1); @@ -1009,6 +1390,10 @@ void ssl3_clear(SSL *s) if (s->s3->tmp.dh != NULL) DH_free(s->s3->tmp.dh); #endif +#ifndef OPENSSL_NO_ECDH + if (s->s3->tmp.ecdh != NULL) + EC_KEY_free(s->s3->tmp.ecdh); +#endif rp = s->s3->rbuf.buf; wp = s->s3->wbuf.buf; @@ -1147,6 +1532,44 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) } break; #endif +#ifndef OPENSSL_NO_ECDH + case SSL_CTRL_SET_TMP_ECDH: + { + EC_KEY *ecdh = NULL; + + if (parg == NULL) + { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_PASSED_NULL_PARAMETER); + return(ret); + } + if (!EC_KEY_up_ref((EC_KEY *)parg)) + { + SSLerr(SSL_F_SSL3_CTRL,ERR_R_ECDH_LIB); + return(ret); + } + ecdh = (EC_KEY *)parg; + if (!(s->options & SSL_OP_SINGLE_ECDH_USE)) + { + if (!EC_KEY_generate_key(ecdh)) + { + EC_KEY_free(ecdh); + SSLerr(SSL_F_SSL3_CTRL,ERR_R_ECDH_LIB); + return(ret); + } + } + if (s->cert->ecdh_tmp != NULL) + EC_KEY_free(s->cert->ecdh_tmp); + s->cert->ecdh_tmp = ecdh; + ret = 1; + } + break; + case SSL_CTRL_SET_TMP_ECDH_CB: + { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return(ret); + } + break; +#endif /* !OPENSSL_NO_ECDH */ default: break; } @@ -1190,6 +1613,13 @@ long ssl3_callback_ctrl(SSL *s, int cmd, void (*fp)()) s->cert->dh_tmp_cb = (DH *(*)(SSL *, int, int))fp; } break; +#endif +#ifndef OPENSSL_NO_ECDH + case SSL_CTRL_SET_TMP_ECDH_CB: + { + s->cert->ecdh_tmp_cb = (EC_KEY *(*)(SSL *, int, int))fp; + } + break; #endif default: break; @@ -1283,6 +1713,47 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) } break; #endif +#ifndef OPENSSL_NO_ECDH + case SSL_CTRL_SET_TMP_ECDH: + { + EC_KEY *ecdh = NULL; + + if (parg == NULL) + { + SSLerr(SSL_F_SSL3_CTX_CTRL,ERR_R_ECDH_LIB); + return 0; + } + if (!EC_KEY_up_ref((EC_KEY *)parg)) + { + SSLerr(SSL_F_SSL3_CTRL,ERR_R_ECDH_LIB); + return 0; + } + ecdh = (EC_KEY *)parg; + if (!(ctx->options & SSL_OP_SINGLE_ECDH_USE)) + { + if (!EC_KEY_generate_key(ecdh)) + { + EC_KEY_free(ecdh); + SSLerr(SSL_F_SSL3_CTX_CTRL,ERR_R_ECDH_LIB); + return 0; + } + } + + if (cert->ecdh_tmp != NULL) + { + EC_KEY_free(cert->ecdh_tmp); + } + cert->ecdh_tmp = ecdh; + return 1; + } + /* break; */ + case SSL_CTRL_SET_TMP_ECDH_CB: + { + SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return(0); + } + break; +#endif /* !OPENSSL_NO_ECDH */ /* A Thawte special :-) */ case SSL_CTRL_EXTRA_CHAIN_CERT: if (ctx->extra_certs == NULL) @@ -1320,6 +1791,13 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)()) cert->dh_tmp_cb = (DH *(*)(SSL *, int, int))fp; } break; +#endif +#ifndef OPENSSL_NO_ECDH + case SSL_CTRL_SET_TMP_ECDH_CB: + { + cert->ecdh_tmp_cb = (EC_KEY *(*)(SSL *, int, int))fp; + } + break; #endif default: return(0); @@ -1465,7 +1943,6 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, } if (!ok) continue; - j=sk_SSL_CIPHER_find(allow,c); if (j >= 0) { @@ -1510,6 +1987,26 @@ int ssl3_get_req_cert_type(SSL *s, unsigned char *p) #ifndef OPENSSL_NO_DSA p[ret++]=SSL3_CT_DSS_SIGN; #endif +#ifndef OPENSSL_NO_ECDH + /* We should ask for fixed ECDH certificates only + * for SSL_kECDH (and not SSL_kECDHE) + */ + if ((alg & SSL_kECDH) && (s->version >= TLS1_VERSION)) + { + p[ret++]=TLS_CT_RSA_FIXED_ECDH; + p[ret++]=TLS_CT_ECDSA_FIXED_ECDH; + } +#endif + +#ifndef OPENSSL_NO_ECDSA + /* ECDSA certs can be used with RSA cipher suites as well + * so we don't need to check for SSL_kECDH or SSL_kECDHE + */ + if (s->version >= TLS1_VERSION) + { + p[ret++]=TLS_CT_ECDSA_SIGN; + } +#endif return(ret); } diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 20d716fb1b..d26790a017 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -108,11 +108,36 @@ * Hudson (tjh@cryptsoft.com). * */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * In addition, Sun covenants to all licensees who provide a reciprocal + * covenant with respect to their own patents if any, not to sue under + * current and future patent claims necessarily infringed by the making, + * using, practicing, selling, offering for sale and/or otherwise + * disposing of the Contribution as delivered hereunder + * (or portions thereof), provided that such covenant shall not apply: + * 1) for code that a licensee deletes from the Contribution; + * 2) separates from the Contribution; or + * 3) for infringements caused by: + * i) the modification of the Contribution or + * ii) the combination of the Contribution with other software or + * devices where such combination causes the infringement. + * + * ECC cipher suite support in OpenSSL originally written by + * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. + * + */ #define REUSE_CIPHER_BUG #define NETSCAPE_HANG_BUG - #include #include "ssl_locl.h" #include "kssl_lcl.h" @@ -137,6 +162,10 @@ static int ssl3_get_client_certificate(SSL *s); static int ssl3_get_cert_verify(SSL *s); static int ssl3_send_hello_request(SSL *s); +#ifndef OPENSSL_NO_ECDH +static int nid2curve_id(int nid); +#endif + static SSL_METHOD *ssl3_get_server_method(int ver) { if (ver == SSL3_VERSION) @@ -300,7 +329,7 @@ int ssl3_accept(SSL *s) case SSL3_ST_SW_CERT_A: case SSL3_ST_SW_CERT_B: - /* Check if it is anon DH */ + /* Check if it is anon DH or anon ECDH */ if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL)) { ret=ssl3_send_server_certificate(s); @@ -331,9 +360,18 @@ int ssl3_accept(SSL *s) else s->s3->tmp.use_rsa_tmp=0; + /* only send if a DH key exchange, fortezza or - * RSA but we have a sign only certificate */ + * RSA but we have a sign only certificate + * + * For ECC ciphersuites, we send a serverKeyExchange + * message only if the cipher suite is either + * ECDH-anon or ECDHE. In other cases, the + * server certificate contains the server's + * public key for key exchange. + */ if (s->s3->tmp.use_rsa_tmp + || (l & SSL_kECDHE) || (l & (SSL_DH|SSL_kFZA)) || ((l & SSL_kRSA) && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL @@ -436,19 +474,33 @@ int ssl3_accept(SSL *s) case SSL3_ST_SR_KEY_EXCH_A: case SSL3_ST_SR_KEY_EXCH_B: ret=ssl3_get_client_key_exchange(s); - if (ret <= 0) goto end; - s->state=SSL3_ST_SR_CERT_VRFY_A; - s->init_num=0; - - /* We need to get hashes here so if there is - * a client cert, it can be verified */ - s->method->ssl3_enc->cert_verify_mac(s, - &(s->s3->finish_dgst1), - &(s->s3->tmp.cert_verify_md[0])); - s->method->ssl3_enc->cert_verify_mac(s, - &(s->s3->finish_dgst2), - &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH])); + if (ret <= 0) + goto end; + if (ret == 2) + { + /* For the ECDH ciphersuites when + * the client sends its ECDH pub key in + * a certificate, the CertificateVerify + * message is not sent. + */ + s->state=SSL3_ST_SR_FINISHED_A; + s->init_num = 0; + } + else + { + s->state=SSL3_ST_SR_CERT_VRFY_A; + s->init_num=0; + /* We need to get hashes here so if there is + * a client cert, it can be verified + */ + s->method->ssl3_enc->cert_verify_mac(s, + &(s->s3->finish_dgst1), + &(s->s3->tmp.cert_verify_md[0])); + s->method->ssl3_enc->cert_verify_mac(s, + &(s->s3->finish_dgst2), + &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH])); + } break; case SSL3_ST_SR_CERT_VRFY_A: @@ -1035,6 +1087,13 @@ static int ssl3_send_server_key_exchange(SSL *s) #endif #ifndef OPENSSL_NO_DH DH *dh=NULL,*dhp; +#endif +#ifndef OPENSSL_NO_ECDH + EC_KEY *ecdh=NULL, *ecdhp; + unsigned char *encodedPoint = NULL; + int encodedlen = 0; + int curve_id = 0; + BN_CTX *bn_ctx = NULL; #endif EVP_PKEY *pkey; unsigned char *p,*d; @@ -1144,6 +1203,131 @@ static int ssl3_send_server_key_exchange(SSL *s) } else #endif +#ifndef OPENSSL_NO_ECDH + if (type & SSL_kECDHE) + { + ecdhp=cert->ecdh_tmp; + if ((ecdhp == NULL) && (s->cert->ecdh_tmp_cb != NULL)) + { + ecdhp=s->cert->ecdh_tmp_cb(s, + SSL_C_IS_EXPORT(s->s3->tmp.new_cipher), + SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)); + } + if (ecdhp == NULL) + { + al=SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY); + goto f_err; + } + + if (s->s3->tmp.ecdh != NULL) + { + EC_KEY_free(s->s3->tmp.ecdh); + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* Duplicate the ECDH structure. */ + if (ecdhp == NULL) + { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB); + goto err; + } + if (!EC_KEY_up_ref(ecdhp)) + { + SSLerr(SSL_F_SSL3_CTRL,ERR_R_ECDH_LIB); + goto err; + } + ecdh = ecdhp; + + s->s3->tmp.ecdh=ecdh; + if ((ecdh->pub_key == NULL) || + (ecdh->priv_key == NULL) || + (s->options & SSL_OP_SINGLE_ECDH_USE)) + { + if(!EC_KEY_generate_key(ecdh)) + { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB); + goto err; + } + } + + if ((ecdh->group == NULL) || + (ecdh->pub_key == NULL) || + (ecdh->priv_key == NULL)) + { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB); + goto err; + } + + if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && + (EC_GROUP_get_degree(ecdh->group) > 163)) + { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER); + goto err; + } + + /* XXX: For now, we only support ephemeral ECDH + * keys over named (not generic) curves. For + * supported named curves, curve_id is non-zero. + */ + if ((curve_id = + nid2curve_id(EC_GROUP_get_nid(ecdh->group))) + == 0) + { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNSUPPORTED_ELLIPTIC_CURVE); + goto err; + } + + /* Encode the public key. + * First check the size of encoding and + * allocate memory accordingly. + */ + encodedlen = EC_POINT_point2oct(ecdh->group, + ecdh->pub_key, + POINT_CONVERSION_UNCOMPRESSED, + NULL, 0, NULL); + + encodedPoint = (unsigned char *) + OPENSSL_malloc(encodedlen*sizeof(unsigned char)); + bn_ctx = BN_CTX_new(); + if ((encodedPoint == NULL) || (bn_ctx == NULL)) + { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE); + goto err; + } + + + encodedlen = EC_POINT_point2oct(ecdh->group, + ecdh->pub_key, + POINT_CONVERSION_UNCOMPRESSED, + encodedPoint, encodedlen, bn_ctx); + + if (encodedlen == 0) + { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB); + goto err; + } + + BN_CTX_free(bn_ctx); bn_ctx=NULL; + + /* XXX: For now, we only support named (not + * generic) curves in ECDH ephemeral key exchanges. + * In this situation, we need three additional bytes + * to encode the entire ServerECDHParams + * structure. + */ + n = 3 + encodedlen; + + /* We'll generate the serverKeyExchange message + * explicitly so we can set these to NULLs + */ + r[0]=NULL; + r[1]=NULL; + r[2]=NULL; + } + else +#endif /* !OPENSSL_NO_ECDH */ { al=SSL_AD_HANDSHAKE_FAILURE; SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE); @@ -1186,6 +1370,29 @@ static int ssl3_send_server_key_exchange(SSL *s) p+=nr[i]; } +#ifndef OPENSSL_NO_ECDH + if (type & SSL_kECDHE) + { + /* XXX: For now, we only support named (not generic) curves. + * In this situation, the serverKeyExchange message has: + * [1 byte CurveType], [1 byte CurveName] + * [1 byte length of encoded point], followed by + * the actual encoded point itself + */ + *p = NAMED_CURVE_TYPE; + p += 1; + *p = curve_id; + p += 1; + *p = encodedlen; + p += 1; + memcpy((unsigned char*)p, + (unsigned char *)encodedPoint, + encodedlen); + OPENSSL_free(encodedPoint); + p += encodedlen; + } +#endif + /* not anonymous */ if (pkey != NULL) { @@ -1237,6 +1444,25 @@ static int ssl3_send_server_key_exchange(SSL *s) n+=i+2; } else +#endif +#if !defined(OPENSSL_NO_ECDSA) + if (pkey->type == EVP_PKEY_ECDSA) + { + /* let's do ECDSA */ + EVP_SignInit_ex(&md_ctx,EVP_ecdsa(), NULL); + EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); + EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); + EVP_SignUpdate(&md_ctx,&(d[4]),n); + if (!EVP_SignFinal(&md_ctx,&(p[2]), + (unsigned int *)&i,pkey)) + { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_ECDSA); + goto err; + } + s2n(i,p); + n+=i+2; + } + else #endif { /* Is this error check actually needed? */ @@ -1261,6 +1487,10 @@ static int ssl3_send_server_key_exchange(SSL *s) f_err: ssl3_send_alert(s,SSL3_AL_FATAL,al); err: +#ifndef OPENSSL_NO_ECDH + if (encodedPoint != NULL) OPENSSL_free(encodedPoint); + BN_CTX_free(bn_ctx); +#endif EVP_MD_CTX_cleanup(&md_ctx); return(-1); } @@ -1371,6 +1601,13 @@ static int ssl3_get_client_key_exchange(SSL *s) KSSL_ERR kssl_err; #endif /* OPENSSL_NO_KRB5 */ +#ifndef OPENSSL_NO_ECDH + EC_KEY *srvr_ecdh = NULL; + EVP_PKEY *clnt_pub_pkey = NULL; + EC_POINT *clnt_ecpoint = NULL; + BN_CTX *bn_ctx = NULL; +#endif + n=ssl3_get_message(s, SSL3_ST_SR_KEY_EXCH_A, SSL3_ST_SR_KEY_EXCH_B, @@ -1711,6 +1948,138 @@ static int ssl3_get_client_key_exchange(SSL *s) } else #endif /* OPENSSL_NO_KRB5 */ + +#ifndef OPENSSL_NO_ECDH + if ((l & SSL_kECDH) || (l & SSL_kECDHE)) + { + int ret = 1; + + /* initialize structures for server's ECDH key pair */ + if ((srvr_ecdh = EC_KEY_new()) == NULL) + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Let's get server private key and group information */ + if (l & SSL_kECDH) + { + /* use the certificate */ + srvr_ecdh->group = s->cert->key->privatekey-> \ + pkey.eckey->group; + srvr_ecdh->priv_key = s->cert->key->privatekey-> \ + pkey.eckey->priv_key; + } + else + { + /* use the ephermeral values we saved when + * generating the ServerKeyExchange msg. + */ + srvr_ecdh->group = s->s3->tmp.ecdh->group; + srvr_ecdh->priv_key = s->s3->tmp.ecdh->priv_key; + } + + /* Let's get client's public key */ + if ((clnt_ecpoint = EC_POINT_new(srvr_ecdh->group)) + == NULL) + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (n == 0L) + { + /* Client Publickey was in Client Certificate */ + + if (l & SSL_kECDHE) + { + al=SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY); + goto f_err; + } + if (((clnt_pub_pkey=X509_get_pubkey(s->session->peer)) + == NULL) || + (clnt_pub_pkey->type != EVP_PKEY_ECDSA)) + { + /* XXX: For now, we do not support client + * authentication using ECDH certificates + * so this branch (n == 0L) of the code is + * never executed. When that support is + * added, we ought to ensure the key + * received in the certificate is + * authorized for key agreement. + * ECDH_compute_key implicitly checks that + * the two ECDH shares are for the same + * group. + */ + al=SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_UNABLE_TO_DECODE_ECDH_CERTS); + goto f_err; + } + + EC_POINT_copy(clnt_ecpoint, + clnt_pub_pkey->pkey.eckey->pub_key); + ret = 2; /* Skip certificate verify processing */ + } + else + { + /* Get client's public key from encoded point + * in the ClientKeyExchange message. + */ + if ((bn_ctx = BN_CTX_new()) == NULL) + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Get encoded point length */ + i = *p; + p += 1; + if (EC_POINT_oct2point(srvr_ecdh->group, + clnt_ecpoint, p, i, bn_ctx) == 0) + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_EC_LIB); + goto err; + } + /* p is pointing to somewhere in the buffer + * currently, so set it to the start + */ + p=(unsigned char *)s->init_buf->data; + } + + /* Compute the shared pre-master secret */ + i = ECDH_compute_key(p, clnt_ecpoint, srvr_ecdh); + if (i <= 0) + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_ECDH_LIB); + goto err; + } + + EVP_PKEY_free(clnt_pub_pkey); + EC_POINT_free(clnt_ecpoint); + if (srvr_ecdh != NULL) + { + srvr_ecdh->priv_key = NULL; + srvr_ecdh->group = NULL; + EC_KEY_free(srvr_ecdh); + } + BN_CTX_free(bn_ctx); + + /* Compute the master secret */ + s->session->master_key_length = s->method->ssl3_enc-> \ + generate_master_secret(s, s->session->master_key, p, i); + + memset(p, 0, i); + return (ret); + } + else +#endif { al=SSL_AD_HANDSHAKE_FAILURE; SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, @@ -1721,8 +2090,19 @@ static int ssl3_get_client_key_exchange(SSL *s) return(1); f_err: ssl3_send_alert(s,SSL3_AL_FATAL,al); -#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_RSA) +#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_ECDH) err: +#endif +#ifndef NO_OPENSSL_ECDH + EVP_PKEY_free(clnt_pub_pkey); + EC_POINT_free(clnt_ecpoint); + if (srvr_ecdh != NULL) + { + srvr_ecdh->priv_key = NULL; + srvr_ecdh->group = NULL; + EC_KEY_free(srvr_ecdh); + } + BN_CTX_free(bn_ctx); #endif return(-1); } @@ -1846,6 +2226,23 @@ static int ssl3_get_cert_verify(SSL *s) } } else +#endif +#ifndef OPENSSL_NO_ECDSA + if (pkey->type == EVP_PKEY_ECDSA) + { + j=ECDSA_verify(pkey->save_type, + &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]), + SHA_DIGEST_LENGTH,p,i,pkey->pkey.eckey); + if (j <= 0) + { + /* bad signature */ + al=SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + SSL_R_BAD_ECDSA_SIGNATURE); + goto f_err; + } + } + else #endif { SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,ERR_R_INTERNAL_ERROR); @@ -2047,3 +2444,66 @@ int ssl3_send_server_certificate(SSL *s) /* SSL3_ST_SW_CERT_B */ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); } + + +#ifndef OPENSSL_NO_ECDH +/* This is the complement of curve_id2nid in s3_clnt.c. */ +static int nid2curve_id(int nid) +{ + /* ECC curves from draft-ietf-tls-ecc-01.txt (Mar 15, 2001) */ + switch (nid) { + case NID_sect163k1: /* sect163k1 (1) */ + return 1; + case NID_sect163r1: /* sect163r1 (2) */ + return 2; + case NID_sect163r2: /* sect163r2 (3) */ + return 3; + case NID_sect193r1: /* sect193r1 (4) */ + return 4; + case NID_sect193r2: /* sect193r2 (5) */ + return 5; + case NID_sect233k1: /* sect233k1 (6) */ + return 6; + case NID_sect233r1: /* sect233r1 (7) */ + return 7; + case NID_sect239k1: /* sect239k1 (8) */ + return 8; + case NID_sect283k1: /* sect283k1 (9) */ + return 9; + case NID_sect283r1: /* sect283r1 (10) */ + return 10; + case NID_sect409k1: /* sect409k1 (11) */ + return 11; + case NID_sect409r1: /* sect409r1 (12) */ + return 12; + case NID_sect571k1: /* sect571k1 (13) */ + return 13; + case NID_sect571r1: /* sect571r1 (14) */ + return 14; + case NID_secp160k1: /* secp160k1 (15) */ + return 15; + case NID_secp160r1: /* secp160r1 (16) */ + return 16; + case NID_secp160r2: /* secp160r2 (17) */ + return 17; + case NID_secp192k1: /* secp192k1 (18) */ + return 18; + case NID_X9_62_prime192v1: /* secp192r1 (19) */ + return 19; + case NID_secp224k1: /* secp224k1 (20) */ + return 20; + case NID_secp224r1: /* secp224r1 (21) */ + return 21; + case NID_secp256k1: /* secp256k1 (22) */ + return 22; + case NID_X9_62_prime256v1: /* secp256r1 (23) */ + return 23; + case NID_secp384r1: /* secp384r1 (24) */ + return 24; + case NID_secp521r1: /* secp521r1 (25) */ + return 25; + default: + return 0; + } +} +#endif diff --git a/ssl/ssl.h b/ssl/ssl.h index e9d1e896d7..49e3c52c9c 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -161,6 +161,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. + */ #ifndef HEADER_SSL_H #define HEADER_SSL_H @@ -265,6 +270,7 @@ extern "C" { #define SSL_TXT_SSLV3 "SSLv3" #define SSL_TXT_TLSV1 "TLSv1" #define SSL_TXT_ALL "ALL" +#define SSL_TXT_ECC "ECCdraft" /* ECC ciphersuites are not yet official */ /* * COMPLEMENTOF* definitions. These identifiers are used to (de-select) @@ -470,6 +476,8 @@ typedef struct ssl_session_st /* As server, disallow session resumption on renegotiation */ #define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000L +/* If set, always create a new key when using tmp_ecdh parameters */ +#define SSL_OP_SINGLE_ECDH_USE 0x00080000L /* If set, always create a new key when using tmp_dh parameters */ #define SSL_OP_SINGLE_DH_USE 0x00100000L /* Set to always use the tmp_rsa key when doing RSA operations, @@ -1074,19 +1082,21 @@ size_t SSL_get_peer_finished(SSL *s, void *buf, size_t count); #define SSL_CTRL_NEED_TMP_RSA 1 #define SSL_CTRL_SET_TMP_RSA 2 #define SSL_CTRL_SET_TMP_DH 3 -#define SSL_CTRL_SET_TMP_RSA_CB 4 -#define SSL_CTRL_SET_TMP_DH_CB 5 - -#define SSL_CTRL_GET_SESSION_REUSED 6 -#define SSL_CTRL_GET_CLIENT_CERT_REQUEST 7 -#define SSL_CTRL_GET_NUM_RENEGOTIATIONS 8 -#define SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS 9 -#define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS 10 -#define SSL_CTRL_GET_FLAGS 11 -#define SSL_CTRL_EXTRA_CHAIN_CERT 12 - -#define SSL_CTRL_SET_MSG_CALLBACK 13 -#define SSL_CTRL_SET_MSG_CALLBACK_ARG 14 +#define SSL_CTRL_SET_TMP_ECDH 4 +#define SSL_CTRL_SET_TMP_RSA_CB 5 +#define SSL_CTRL_SET_TMP_DH_CB 6 +#define SSL_CTRL_SET_TMP_ECDH_CB 7 + +#define SSL_CTRL_GET_SESSION_REUSED 8 +#define SSL_CTRL_GET_CLIENT_CERT_REQUEST 9 +#define SSL_CTRL_GET_NUM_RENEGOTIATIONS 10 +#define SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS 11 +#define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS 12 +#define SSL_CTRL_GET_FLAGS 13 +#define SSL_CTRL_EXTRA_CHAIN_CERT 14 + +#define SSL_CTRL_SET_MSG_CALLBACK 15 +#define SSL_CTRL_SET_MSG_CALLBACK_ARG 16 /* Stats */ #define SSL_CTRL_SESS_NUMBER 20 @@ -1129,6 +1139,8 @@ size_t SSL_get_peer_finished(SSL *s, void *buf, size_t count); SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa) #define SSL_CTX_set_tmp_dh(ctx,dh) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_DH,0,(char *)dh) +#define SSL_CTX_set_tmp_ecdh(ctx,ecdh) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh) #define SSL_need_tmp_RSA(ssl) \ SSL_ctrl(ssl,SSL_CTRL_NEED_TMP_RSA,0,NULL) @@ -1136,6 +1148,8 @@ size_t SSL_get_peer_finished(SSL *s, void *buf, size_t count); SSL_ctrl(ssl,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa) #define SSL_set_tmp_dh(ssl,dh) \ SSL_ctrl(ssl,SSL_CTRL_SET_TMP_DH,0,(char *)dh) +#define SSL_set_tmp_ecdh(ssl,ecdh) \ + SSL_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh) #define SSL_CTX_add_extra_chain_cert(ctx,x509) \ SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509) @@ -1445,6 +1459,14 @@ void SSL_set_tmp_dh_callback(SSL *ssl, DH *(*dh)(SSL *ssl,int is_export, int keylength)); #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)); +void SSL_set_tmp_ecdh_callback(SSL *ssl, + EC_KEY *(*ecdh)(SSL *ssl,int is_export, + int keylength)); +#endif #ifndef OPENSSL_NO_COMP int SSL_COMP_add_compression_method(int id,COMP_METHOD *cm); @@ -1619,6 +1641,9 @@ void ERR_load_SSL_strings(void); #define SSL_R_BAD_DH_P_LENGTH 110 #define SSL_R_BAD_DIGEST_LENGTH 111 #define SSL_R_BAD_DSA_SIGNATURE 112 +#define SSL_R_BAD_ECC_CERT 1117 +#define SSL_R_BAD_ECDSA_SIGNATURE 1112 +#define SSL_R_BAD_ECPOINT 1113 #define SSL_R_BAD_HELLO_REQUEST 105 #define SSL_R_BAD_LENGTH 271 #define SSL_R_BAD_MAC_DECODE 113 @@ -1659,6 +1684,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 1109 #define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG 148 #define SSL_R_DIGEST_CHECK_FAILED 149 +#define SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER 1119 #define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 150 #define SSL_R_ERROR_GENERATING_TMP_RSA_KEY 1092 #define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 151 @@ -1699,6 +1725,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_MISSING_RSA_ENCRYPTING_CERT 169 #define SSL_R_MISSING_RSA_SIGNING_CERT 170 #define SSL_R_MISSING_TMP_DH_KEY 171 +#define SSL_R_MISSING_TMP_ECDH_KEY 1114 #define SSL_R_MISSING_TMP_RSA_KEY 172 #define SSL_R_MISSING_TMP_RSA_PKEY 173 #define SSL_R_MISSING_VERIFY_MESSAGE 174 @@ -1796,8 +1823,10 @@ void ERR_load_SSL_strings(void); #define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG 234 #define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER 235 #define SSL_R_UNABLE_TO_DECODE_DH_CERTS 236 +#define SSL_R_UNABLE_TO_DECODE_ECDH_CERTS 1115 #define SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY 237 #define SSL_R_UNABLE_TO_FIND_DH_PARAMETERS 238 +#define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 1116 #define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS 239 #define SSL_R_UNABLE_TO_FIND_SSL_METHOD 240 #define SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES 241 @@ -1818,6 +1847,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_UNKNOWN_STATE 255 #define SSL_R_UNSUPPORTED_CIPHER 256 #define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM 257 +#define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 1118 #define SSL_R_UNSUPPORTED_OPTION 1091 #define SSL_R_UNSUPPORTED_PROTOCOL 258 #define SSL_R_UNSUPPORTED_SSL_VERSION 259 diff --git a/ssl/ssl3.h b/ssl/ssl3.h index 8fd6951d77..59211fef70 100644 --- a/ssl/ssl3.h +++ b/ssl/ssl3.h @@ -108,6 +108,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. + */ #ifndef HEADER_SSL3_H #define HEADER_SSL3_H @@ -285,7 +290,12 @@ typedef struct ssl3_buffer_st #define SSL3_CT_RSA_EPHEMERAL_DH 5 #define SSL3_CT_DSS_EPHEMERAL_DH 6 #define SSL3_CT_FORTEZZA_DMS 20 -#define SSL3_CT_NUMBER 7 +/* SSL3_CT_NUMBER is used to size arrays and it must be large + * enough to contain all of the cert types defined either for + * SSLv3 and TLSv1. + */ +#define SSL3_CT_NUMBER 7 + #define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS 0x0001 #define SSL3_FLAGS_DELAY_CLIENT_FINISHED 0x0002 @@ -370,6 +380,11 @@ typedef struct ssl3_state_st #ifndef OPENSSL_NO_DH DH *dh; #endif + +#ifndef OPENSSL_NO_ECDH + EC_KEY *ecdh; /* holds short lived ECDH key */ +#endif + /* used when SSL_ST_FLUSH_DATA is entered */ int next_state; diff --git a/ssl/ssl_algs.c b/ssl/ssl_algs.c index 3d1299ee7b..7c8a451fc5 100644 --- a/ssl/ssl_algs.c +++ b/ssl/ssl_algs.c @@ -100,6 +100,9 @@ int SSL_library_init(void) EVP_add_digest_alias(SN_dsaWithSHA1,SN_dsaWithSHA1_2); EVP_add_digest_alias(SN_dsaWithSHA1,"DSS1"); EVP_add_digest_alias(SN_dsaWithSHA1,"dss1"); +#endif +#ifndef OPENSSL_NO_ECDSA + EVP_add_digest(EVP_ecdsa()); #endif /* If you want support for phased out ciphers, add the following */ #if 0 diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index 263a1dc34d..c6dbc94d65 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -103,6 +103,11 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== */ +/* ==================================================================== + * 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. + */ #include @@ -234,6 +239,15 @@ CERT *ssl_cert_dup(CERT *cert) ret->dh_tmp_cb = cert->dh_tmp_cb; #endif +#ifndef OPENSSL_NO_ECDH + if (cert->ecdh_tmp) + { + EC_KEY_up_ref(cert->ecdh_tmp); + ret->ecdh_tmp = cert->ecdh_tmp; + } + ret->ecdh_tmp_cb = cert->ecdh_tmp_cb; +#endif + for (i = 0; i < SSL_PKEY_NUM; i++) { if (cert->pkeys[i].x509 != NULL) @@ -268,7 +282,11 @@ CERT *ssl_cert_dup(CERT *cert) case SSL_PKEY_DH_DSA: /* We have a DH key. */ break; - + + case SSL_PKEY_ECC: + /* We have an ECC key */ + break; + default: /* Can't happen. */ SSLerr(SSL_F_SSL_CERT_DUP, SSL_R_LIBRARY_BUG); @@ -294,6 +312,10 @@ err: if (ret->dh_tmp != NULL) DH_free(ret->dh_tmp); #endif +#ifndef OPENSSL_NO_ECDH + if (ret->ecdh_tmp != NULL) + EC_KEY_free(ret->ecdh_tmp); +#endif for (i = 0; i < SSL_PKEY_NUM; i++) { @@ -333,6 +355,9 @@ void ssl_cert_free(CERT *c) #ifndef OPENSSL_NO_DH if (c->dh_tmp) DH_free(c->dh_tmp); #endif +#ifndef OPENSSL_NO_ECDH + if (c->ecdh_tmp) EC_KEY_free(c->ecdh_tmp); +#endif for (i=0; ipeer_dh_tmp != NULL) DH_free(sc->peer_dh_tmp); #endif +#ifndef OPENSSL_NO_ECDH + if (sc->peer_ecdh_tmp != NULL) + EC_KEY_free(sc->peer_ecdh_tmp); +#endif OPENSSL_free(sc); } diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c index 37f58886a6..0660275422 100644 --- a/ssl/ssl_ciph.c +++ b/ssl/ssl_ciph.c @@ -55,7 +55,11 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ - +/* ==================================================================== + * 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. + */ #include #include #include @@ -101,18 +105,20 @@ typedef struct cipher_order_st static const SSL_CIPHER cipher_aliases[]={ /* Don't include eNULL unless specifically enabled. */ - {0,SSL_TXT_ALL, 0,SSL_ALL & ~SSL_eNULL, SSL_ALL ,0,0,0,SSL_ALL,SSL_ALL}, /* must be first */ - {0,SSL_TXT_CMPALL,0,SSL_eNULL,0,0,0,0,SSL_ENC_MASK,0}, /* COMPLEMENT OF ALL */ + /* Don't include ECC in ALL because these ciphers are not yet official. */ + {0,SSL_TXT_ALL, 0,SSL_ALL & ~SSL_eNULL & ~SSL_kECDH & ~SSL_kECDHE, SSL_ALL ,0,0,0,SSL_ALL,SSL_ALL}, /* must be first */ + /* TODO: COMPLEMENT OF ALL and COMPLEMENT OF DEFAULT do not have ECC cipher suites handled properly. */ + {0,SSL_TXT_CMPALL,0,SSL_eNULL,0,0,0,0,SSL_ENC_MASK,0}, /* COMPLEMENT OF ALL */ {0,SSL_TXT_CMPDEF,0,SSL_ADH, 0,0,0,0,SSL_AUTH_MASK,0}, - {0,SSL_TXT_kKRB5,0,SSL_kKRB5,0,0,0,0,SSL_MKEY_MASK,0}, /* VRS Kerberos5 */ + {0,SSL_TXT_kKRB5,0,SSL_kKRB5,0,0,0,0,SSL_MKEY_MASK,0}, /* VRS Kerberos5 */ {0,SSL_TXT_kRSA,0,SSL_kRSA, 0,0,0,0,SSL_MKEY_MASK,0}, {0,SSL_TXT_kDHr,0,SSL_kDHr, 0,0,0,0,SSL_MKEY_MASK,0}, {0,SSL_TXT_kDHd,0,SSL_kDHd, 0,0,0,0,SSL_MKEY_MASK,0}, {0,SSL_TXT_kEDH,0,SSL_kEDH, 0,0,0,0,SSL_MKEY_MASK,0}, {0,SSL_TXT_kFZA,0,SSL_kFZA, 0,0,0,0,SSL_MKEY_MASK,0}, {0,SSL_TXT_DH, 0,SSL_DH, 0,0,0,0,SSL_MKEY_MASK,0}, + {0,SSL_TXT_ECC, 0,(SSL_kECDH|SSL_kECDHE), 0,0,0,0,SSL_MKEY_MASK,0}, {0,SSL_TXT_EDH, 0,SSL_EDH, 0,0,0,0,SSL_MKEY_MASK|SSL_AUTH_MASK,0}, - {0,SSL_TXT_aKRB5,0,SSL_aKRB5,0,0,0,0,SSL_AUTH_MASK,0}, /* VRS Kerberos5 */ {0,SSL_TXT_aRSA,0,SSL_aRSA, 0,0,0,0,SSL_AUTH_MASK,0}, {0,SSL_TXT_aDSS,0,SSL_aDSS, 0,0,0,0,SSL_AUTH_MASK,0}, @@ -314,7 +320,9 @@ static unsigned long ssl_cipher_get_disabled(void) #ifdef OPENSSL_NO_KRB5 mask |= SSL_kKRB5|SSL_aKRB5; #endif - +#ifdef OPENSSL_NO_ECDH + mask |= SSL_kECDH|SSL_kECDHE; +#endif #ifdef SSL_FORBID_ENULL mask |= SSL_eNULL; #endif @@ -916,7 +924,7 @@ char *SSL_CIPHER_description(SSL_CIPHER *cipher, char *buf, int len) pkl=SSL_C_EXPORT_PKEYLENGTH(cipher); kl=SSL_C_EXPORT_KEYLENGTH(cipher); exp=is_export?" export":""; - + if (alg & SSL_SSLV2) ver="SSLv2"; else if (alg & SSL_SSLV3) @@ -945,6 +953,10 @@ char *SSL_CIPHER_description(SSL_CIPHER *cipher, char *buf, int len) case SSL_kEDH: kx=is_export?(pkl == 512 ? "DH(512)" : "DH(1024)"):"DH"; break; + case SSL_kECDH: + case SSL_kECDHE: + kx=is_export?"ECDH(<=163)":"ECDH"; + break; default: kx="unknown"; } @@ -968,6 +980,9 @@ char *SSL_CIPHER_description(SSL_CIPHER *cipher, char *buf, int len) case SSL_aNULL: au="None"; break; + case SSL_aECDSA: + au="ECDSA"; + break; default: au="unknown"; break; diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 7067a745f3..18aea72f13 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -227,6 +227,9 @@ static ERR_STRING_DATA SSL_str_reasons[]= {SSL_R_BAD_DH_P_LENGTH ,"bad dh p length"}, {SSL_R_BAD_DIGEST_LENGTH ,"bad digest length"}, {SSL_R_BAD_DSA_SIGNATURE ,"bad dsa signature"}, +{SSL_R_BAD_ECC_CERT ,"bad ecc cert"}, +{SSL_R_BAD_ECDSA_SIGNATURE ,"bad ecdsa signature"}, +{SSL_R_BAD_ECPOINT ,"bad ecpoint"}, {SSL_R_BAD_HELLO_REQUEST ,"bad hello request"}, {SSL_R_BAD_LENGTH ,"bad length"}, {SSL_R_BAD_MAC_DECODE ,"bad mac decode"}, @@ -267,6 +270,7 @@ static ERR_STRING_DATA SSL_str_reasons[]= {SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC,"decryption failed or bad record mac"}, {SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG ,"dh public value length is wrong"}, {SSL_R_DIGEST_CHECK_FAILED ,"digest check failed"}, +{SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER ,"ecgroup too large for cipher"}, {SSL_R_ENCRYPTED_LENGTH_TOO_LONG