diff options
author | Bodo Möller <bodo@openssl.org> | 2002-08-09 12:56:08 +0400 |
---|---|---|
committer | Bodo Möller <bodo@openssl.org> | 2002-08-09 12:56:08 +0400 |
commit | ea262260469e49149cb10b25a87dfd6ad3fbb4ba (patch) | |
tree | 7032110f80ba1888d7b3047cfbacd2d46e4fb67c /ssl | |
parent | 17f627931780f000b8dd47fe030c52cc0fa93ef5 (diff) |
ECC ciphersuite support
Submitted by: Douglas Stebila <douglas.stebila@sun.com>
(Authors: Vipul Gupta and Sumit Gupta, Sun Microsystems Laboratories)
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/s3_both.c | 22 | ||||
-rw-r--r-- | ssl/s3_clnt.c | 441 | ||||
-rw-r--r-- | ssl/s3_lib.c | 499 | ||||
-rw-r--r-- | ssl/s3_srvr.c | 492 | ||||
-rw-r--r-- | ssl/ssl.h | 56 | ||||
-rw-r--r-- | ssl/ssl3.h | 17 | ||||
-rw-r--r-- | ssl/ssl_algs.c | 3 | ||||
-rw-r--r-- | ssl/ssl_cert.c | 31 | ||||
-rw-r--r-- | ssl/ssl_ciph.c | 29 | ||||
-rw-r--r-- | ssl/ssl_err.c | 8 | ||||
-rw-r--r-- | ssl/ssl_lib.c | 177 | ||||
-rw-r--r-- | ssl/ssl_locl.h | 79 | ||||
-rw-r--r-- | ssl/ssltest.c | 67 | ||||
-rw-r--r-- | ssl/tls1.h | 107 |
14 files changed, 1953 insertions, 75 deletions
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 <limits.h> #include <string.h> @@ -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 <stdio.h> #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 */ @@ -980,6 +1026,13 @@ static int ssl3_get_key_exchange(SSL *s) 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) { @@ -1201,6 +1348,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); goto err; @@ -1236,6 +1401,12 @@ err: 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); } @@ -1757,6 +2117,23 @@ static int ssl3_send_client_verify(SSL *s) } 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); goto err; @@ -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 <stdio.h> #include <openssl/objects.h> @@ -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; } @@ -1191,6 +1614,13 @@ long ssl3_callback_ctrl(SSL *s, int cmd, void (*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) @@ -1321,6 +1792,13 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*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 <stdio.h> #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: @@ -1036,6 +1088,13 @@ static int ssl3_send_server_key_exchange(SSL *s) #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; int al,i; @@ -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) { @@ -1238,6 +1445,25 @@ static int ssl3_send_server_key_exchange(SSL *s) } 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? */ al=SSL_AD_HANDSHAKE_FAILURE; @@ -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,9 +2090,20 @@ 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); } @@ -1847,6 +2227,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); al=SSL_AD_UNSUPPORTED_CERTIFICATE; @@ -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 @@ -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 @@ -101,6 +101,9 @@ int SSL_library_init(void) 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 EVP_add_digest(EVP_sha()); 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 <stdio.h> @@ -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; i<SSL_PKEY_NUM; i++) { @@ -439,6 +464,10 @@ void ssl_sess_cert_free(SESS_CERT *sc) if (sc->peer_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 <stdio.h> #include <openssl/objects.h> #include <openssl/comp.h> @@ -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 ,"encrypted length too long"}, {SSL_R_ERROR_GENERATING_TMP_RSA_KEY ,"error generating tmp rsa key"}, {SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST ,"error in received cipher list"}, @@ -307,6 +311,7 @@ static ERR_STRING_DATA SSL_str_reasons[]= {SSL_R_MISSING_RSA_ENCRYPTING_CERT ,"missing rsa encrypting cert"}, {SSL_R_MISSING_RSA_SIGNING_CERT ,"missing rsa signing cert"}, {SSL_R_MISSING_TMP_DH_KEY ,"missing tmp dh key"}, +{SSL_R_MISSING_TMP_ECDH_KEY ,"missing tmp ecdh key"}, {SSL_R_MISSING_TMP_RSA_KEY ,"missing tmp rsa key"}, {SSL_R_MISSING_TMP_RSA_PKEY ,"missing tmp rsa pkey"}, {SSL_R_MISSING_VERIFY_MESSAGE ,"missing verify message"}, @@ -404,8 +409,10 @@ static ERR_STRING_DATA SSL_str_reasons[]= {SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG,"tls rsa encrypted value length is wrong"}, {SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER ,"tried to use unsupported cipher"}, {SSL_R_UNABLE_TO_DECODE_DH_CERTS ,"unable to decode dh certs"}, +{SSL_R_UNABLE_TO_DECODE_ECDH_CERTS ,"unable to decode ecdh certs"}, {SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY ,"unable to extract public key"}, {SSL_R_UNABLE_TO_FIND_DH_PARAMETERS ,"unable to find dh parameters"}, +{SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS ,"unable to find ecdh parameters"}, {SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS,"unable to find public key parameters"}, {SSL_R_UNABLE_TO_FIND_SSL_METHOD ,"unable to find ssl method"}, {SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES ,"unable to load ssl2 md5 routines"}, @@ -426,6 +433,7 @@ static ERR_STRING_DATA SSL_str_reasons[]= {SSL_R_UNKNOWN_STATE ,"unknown state"}, {SSL_R_UNSUPPORTED_CIPHER ,"unsupported cipher"}, {SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM ,"unsupported compression algorithm"}, +{SSL_R_UNSUPPORTED_ELLIPTIC_CURVE ,"unsupported elliptic curve"}, {SSL_R_UNSUPPORTED_OPTION ,"unsupported option"}, {SSL_R_UNSUPPORTED_PROTOCOL ,"unsupported protocol"}, {SSL_R_UNSUPPORTED_SSL_VERSION ,"unsupported ssl version"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index ab172aeaec..b50fc463d1 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)) { diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index dd6c7a7323..a990bb1ba5 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.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_SSL_LOCL_H #define HEADER_SSL_LOCL_H @@ -227,52 +232,56 @@ * that the different entities within are mutually exclusive: * ONLY ONE BIT PER MASK CAN BE SET AT A TIME. */ -#define SSL_MKEY_MASK 0x0000003FL +#define SSL_MKEY_MASK 0x000000FFL #define SSL_kRSA 0x00000001L /* RSA key exchange */ #define SSL_kDHr 0x00000002L /* DH cert RSA CA cert */ #define SSL_kDHd 0x00000004L /* DH cert DSA CA cert */ #define SSL_kFZA 0x00000008L #define SSL_kEDH 0x00000010L /* tmp DH key no DH cert */ #define SSL_kKRB5 0x00000020L /* Kerberos5 key exchange */ +#define SSL_kECDH 0x00000040L /* ECDH w/ long-term keys */ +#define SSL_kECDHE 0x00000080L /* ephemeral ECDH */ #define SSL_EDH (SSL_kEDH|(SSL_AUTH_MASK^SSL_aNULL)) -#define SSL_AUTH_MASK 0x00000FC0L -#define SSL_aRSA 0x00000040L /* Authenticate with RSA */ -#define SSL_aDSS 0x00000080L /* Authenticate with DSS */ +#define SSL_AUTH_MASK 0x00007F00L +#define SSL_aRSA 0x00000100L /* Authenticate with RSA */ +#define SSL_aDSS 0x00000200L /* Authenticate with DSS */ #define SSL_DSS SSL_aDSS -#define SSL_aFZA 0x00000100L -#define SSL_aNULL 0x00000200L /* no Authenticate, ADH */ -#define SSL_aDH 0x00000400L /* no Authenticate, ADH */ -#define SSL_aKRB5 0x00000800L /* Authenticate with KRB5 */ +#define SSL_aFZA 0x00000400L +#define SSL_aNULL 0x00000800L /* no Authenticate, ADH */ +#define SSL_aDH 0x00001000L /* no Authenticate, ADH */ +#define SSL_aKRB5 0x00002000L /* Authenticate with KRB5 */ +#define SSL_aECDSA 0x00004000L /* Authenticate with ECDSA */ #define SSL_NULL (SSL_eNULL) #define SSL_ADH (SSL_kEDH|SSL_aNULL) #define SSL_RSA (SSL_kRSA|SSL_aRSA) #define SSL_DH (SSL_kDHr|SSL_kDHd|SSL_kEDH) +#define SSL_ECDH (SSL_kECDH|SSL_kECDHE) #define SSL_FZA (SSL_aFZA|SSL_kFZA|SSL_eFZA) #define SSL_KRB5 (SSL_kKRB5|SSL_aKRB5) -#define SSL_ENC_MASK 0x0087F000L -#define SSL_DES 0x00001000L -#define SSL_3DES 0x00002000L -#define SSL_RC4 0x00004000L -#define SSL_RC2 0x00008000L -#define SSL_IDEA 0x00010000L -#define SSL_eFZA 0x00020000L -#define SSL_eNULL 0x00040000L -#define SSL_AES 0x00800000L - -#define SSL_MAC_MASK 0x00180000L -#define SSL_MD5 0x00080000L -#define SSL_SHA1 0x00100000L +#define SSL_ENC_MASK 0x043F8000L +#define SSL_DES 0x00008000L +#define SSL_3DES 0x00010000L +#define SSL_RC4 0x00020000L +#define SSL_RC2 0x00040000L +#define SSL_IDEA 0x00080000L +#define SSL_eFZA 0x00100000L +#define SSL_eNULL 0x00200000L +#define SSL_AES 0x04000000L + +#define SSL_MAC_MASK 0x00c00000L +#define SSL_MD5 0x00400000L +#define SSL_SHA1 0x00800000L #define SSL_SHA (SSL_SHA1) -#define SSL_SSL_MASK 0x00600000L -#define SSL_SSLV2 0x00200000L -#define SSL_SSLV3 0x00400000L +#define SSL_SSL_MASK 0x03000000L +#define SSL_SSLV2 0x01000000L +#define SSL_SSLV3 0x02000000L #define SSL_TLSV1 SSL_SSLV3 /* for now */ -/* we have used 007fffff - 9 bits left to go */ +/* we have used 07ffffff - 5 bits left to go. */ /* * Export and cipher strength information. For each cipher we have to decide @@ -344,7 +353,8 @@ #define SSL_PKEY_DSA_SIGN 2 #define SSL_PKEY_DH_RSA 3 #define SSL_PKEY_DH_DSA 4 -#define SSL_PKEY_NUM 5 +#define SSL_PKEY_ECC 5 +#define SSL_PKEY_NUM 6 /* SSL_kRSA <- RSA_ENC | (RSA_TMP & RSA_SIGN) | * <- (EXPORT & (RSA_ENC | RSA_TMP) & RSA_SIGN) @@ -360,6 +370,15 @@ #define CERT_PRIVATE_KEY 2 */ +#ifndef OPENSSL_NO_EC +/* From ECC-TLS draft, used in encoding the curve type in + * ECParameters + */ +#define EXPLICIT_PRIME_CURVE_TYPE 1 +#define EXPLICIT_CHAR2_CURVE_TYPE 2 +#define NAMED_CURVE_TYPE 3 +#endif /* OPENSSL_NO_EC */ + typedef struct cert_pkey_st { X509 *x509; @@ -386,6 +405,11 @@ typedef struct cert_st DH *dh_tmp; DH *(*dh_tmp_cb)(SSL *ssl,int is_export,int keysize); #endif +#ifndef OPENSSL_NO_ECDH + EC_KEY *ecdh_tmp; + /* Callback for generating ephemeral ECDH keys */ + EC_KEY *(*ecdh_tmp_cb)(SSL *ssl,int is_export,int keysize); +#endif CERT_PKEY pkeys[SSL_PKEY_NUM]; @@ -411,6 +435,9 @@ typedef struct sess_cert_st #ifndef OPENSSL_NO_DH DH *peer_dh_tmp; /* not used for SSL 2 */ #endif +#ifndef OPENSSL_NO_ECDH + EC_KEY *peer_ecdh_tmp; +#endif int references; /* actually always 1 at the moment */ } SESS_CERT; diff --git a/ssl/ssltest.c b/ssl/ssltest.c index 1afdfa7750..30473b5ff2 100644 --- a/ssl/ssltest.c +++ b/ssl/ssltest.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. + */ #define _XOPEN_SOURCE 600 /* Or gethostname won't be declared properly on Linux and GNU platforms. */ @@ -201,6 +206,9 @@ static void sv_usage(void) fprintf(stderr," -dhe1024dsa - use 1024 bit key (with 160-bit subprime) for DHE\n"); fprintf(stderr," -no_dhe - disable DHE\n"); #endif +#ifndef OPENSSL_NO_ECDH + fprintf(stderr," -no_ecdhe - disable ECDHE\n"); +#endif #ifndef OPENSSL_NO_SSL2 fprintf(stderr," -ssl2 - use SSLv2\n"); #endif @@ -221,7 +229,12 @@ static void sv_usage(void) fprintf(stderr," -f - Test even cases that can't work\n"); fprintf(stderr," -time - measure processor time used by client and server\n"); fprintf(stderr," -zlib - use zlib compression\n"); - fprintf(stderr," -time - use rle compression\n"); + fprintf(stderr," -rle - use rle compression\n"); +#ifndef OPENSSL_NO_ECDH + fprintf(stderr," -named_curve arg - Elliptic curve name to use for ephemeral ECDH keys.\n" \ + " Use \"openssl ecparam -list_curves\" for all names\n" \ + " (default is sect163r2).\n"); +#endif } static void print_details(SSL *c_ssl, const char *prefix) @@ -345,6 +358,7 @@ int main(int argc, char *argv[]) char *server_key=NULL; char *client_cert=TEST_CLIENT_CERT; char *client_key=NULL; + char *named_curve = NULL; SSL_CTX *s_ctx=NULL; SSL_CTX *c_ctx=NULL; SSL_METHOD *meth=NULL; @@ -355,7 +369,11 @@ int main(int argc, char *argv[]) DH *dh; int dhe1024 = 0, dhe1024dsa = 0; #endif +#ifndef OPENSSL_NO_ECDH + EC_KEY *ecdh = NULL; +#endif int no_dhe = 0; + int no_ecdhe = 0; int print_time = 0; clock_t s_time = 0, c_time = 0; int comp = 0; @@ -408,6 +426,8 @@ int main(int argc, char *argv[]) #endif else if (strcmp(*argv,"-no_dhe") == 0) no_dhe=1; + else if (strcmp(*argv,"-no_ecdhe") == 0) + no_ecdhe=1; else if (strcmp(*argv,"-ssl2") == 0) ssl2=1; else if (strcmp(*argv,"-tls1") == 0) @@ -494,6 +514,13 @@ int main(int argc, char *argv[]) { comp = COMP_RLE; } +#ifndef OPENSSL_NO_ECDH + else if (strcmp(*argv,"-named_curve") == 0) + { + if (--argc < 1) goto bad; + named_curve = *(++argv); + } +#endif else if (strcmp(*argv,"-app_verify") == 0) { app_verify = 1; @@ -609,6 +636,44 @@ bad: (void)no_dhe; #endif +#ifndef OPENSSL_NO_ECDH + if (!no_ecdhe) + { + ecdh = EC_KEY_new(); + if (ecdh != NULL) + { + if (named_curve) + { + int nid = OBJ_sn2nid(named_curve); + + if (nid == 0) + { + BIO_printf(bio_err, "unknown curve name (%s)\n", named_curve); + EC_KEY_free(ecdh); + goto end; + } + + ecdh->group = EC_GROUP_new_by_nid(nid); + if (ecdh->group == NULL) + { + BIO_printf(bio_err, "unable to create curve (%s)\n", named_curve); + EC_KEY_free(ecdh); + goto end; + } + } + + if (ecdh->group == NULL) + ecdh->group=EC_GROUP_new_by_nid(NID_sect163r2); + + SSL_CTX_set_tmp_ecdh(s_ctx, ecdh); + SSL_CTX_set_options(s_ctx, SSL_OP_SINGLE_ECDH_USE); + EC_KEY_free(ecdh); + } + } +#else + (void)no_ecdhe; +#endif + #ifndef OPENSSL_NO_RSA SSL_CTX_set_tmp_rsa_callback(s_ctx,tmp_rsa_cb); #endif diff --git a/ssl/tls1.h b/ssl/tls1.h index 38838ea9a5..4d7c9a17b2 100644 --- a/ssl/tls1.h +++ b/ssl/tls1.h @@ -55,6 +55,32 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ +/* ==================================================================== + * 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. + * + */ #ifndef HEADER_TLS1_H #define HEADER_TLS1_H @@ -112,6 +138,48 @@ extern "C" { #define TLS1_CK_DHE_RSA_WITH_AES_256_SHA 0x03000039 #define TLS1_CK_ADH_WITH_AES_256_SHA 0x0300003A +/* ECC ciphersuites from draft-ietf-tls-ecc-01.txt (Mar 15, 2001). + * XXX NOTE: There is a bug in the draft, cipher numbers 4B, and 4C + * are defined twice so we define ECDH_ECDSA_EXPORT cipher + * suites to use 5B and 5C instead (this may change with future + * updates to the IETF draft). + */ +#define TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA 0x03000047 +#define TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA 0x03000048 +#define TLS1_CK_ECDH_ECDSA_WITH_DES_CBC_SHA 0x03000049 +#define TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA 0x0300004A +#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0x0300004B +#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0x0300004C +#define TLS1_CK_ECDH_ECDSA_EXPORT_WITH_RC4_40_SHA 0x0300005B +#define TLS1_CK_ECDH_ECDSA_EXPORT_WITH_RC4_56_SHA 0x0300005C + +#define TLS1_CK_ECDH_RSA_WITH_NULL_SHA 0x0300004D +#define TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA 0x0300004E +#define TLS1_CK_ECDH_RSA_WITH_DES_CBC_SHA 0x0300004F +#define TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA 0x03000050 +#define TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA 0x03000051 +#define TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA 0x03000052 +#define TLS1_CK_ECDH_RSA_EXPORT_WITH_RC4_40_SHA 0x03000053 +#define TLS1_CK_ECDH_RSA_EXPORT_WITH_RC4_56_SHA 0x03000054 + +#define TLS1_CK_ECDH_anon_WITH_NULL_SHA 0x03000055 +#define TLS1_CK_ECDH_anon_WITH_RC4_128_SHA 0x03000056 +#define TLS1_CK_ECDH_anon_WITH_DES_CBC_SHA 0x03000057 +#define TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA 0x03000058 +#define TLS1_CK_ECDH_anon_EXPORT_WITH_DES_40_CBC_SHA 0x03000059 +#define TLS1_CK_ECDH_anon_EXPORT_WITH_RC4_40_SHA 0x0300005A + +/* 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 this file and a new structure in s3_lib.c. We illustrate + * the process for the made-up ciphers ECDHE-ECDSA-AES128-SHA and + * ECDHE-RSA-AES128-SHA. + */ +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0x03000077 +#define TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA 0x03000078 + + /* XXX * Inconsistency alert: * The OpenSSL names of ciphers with ephemeral DH here include the string @@ -142,12 +210,47 @@ extern "C" { #define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA "DHE-RSA-AES256-SHA" #define TLS1_TXT_ADH_WITH_AES_256_SHA "ADH-AES256-SHA" +/* ECC ciphersuites from draft-ietf-tls-ecc-01.txt (Mar 15, 2001) */ +#define TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA "ECDH-ECDSA-NULL-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA "ECDH-ECDSA-RC4-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_DES_CBC_SHA "ECDH-ECDSA-DES-CBC-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA "ECDH-ECDSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA "ECDH-ECDSA-AES128-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA "ECDH-ECDSA-AES256-SHA" +#define TLS1_TXT_ECDH_ECDSA_EXPORT_WITH_RC4_40_SHA "EXP-ECDH-ECDSA-RC4-40-SHA" +#define TLS1_TXT_ECDH_ECDSA_EXPORT_WITH_RC4_56_SHA "EXP-ECDH-ECDSA-RC4-56-SHA" + +#define TLS1_TXT_ECDH_RSA_WITH_NULL_SHA "ECDH-RSA-NULL-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA "ECDH-RSA-RC4-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_DES_CBC_SHA "ECDH-RSA-DES-CBC-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA "ECDH-RSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA "ECDH-RSA-AES128-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA "ECDH-RSA-AES256-SHA" +#define TLS1_TXT_ECDH_RSA_EXPORT_WITH_RC4_40_SHA "EXP-ECDH-RSA-RC4-40-SHA" +#define TLS1_TXT_ECDH_RSA_EXPORT_WITH_RC4_56_SHA "EXP-ECDH-RSA-RC4-56-SHA" + +#define TLS1_TXT_ECDH_anon_WITH_NULL_SHA "AECDH-NULL-SHA" +#define TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA "AECDH-RC4-SHA" +#define TLS1_TXT_ECDH_anon_WITH_DES_CBC_SHA "AECDH-DES-CBC-SHA" +#define TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA "AECDH-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_anon_EXPORT_WITH_DES_40_CBC_SHA "EXP-AECDH-DES-40-CBC-SHA" +#define TLS1_TXT_ECDH_anon_EXPORT_WITH_RC4_40_SHA "EXP-AECDH-RC4-40-SHA" + +/* XXX: Made-up ECC cipher suites offering forward secrecy. This is for + * illustration only. + */ +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA "ECDHE-ECDSA-AES128-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA "ECDHE-RSA-AES128-SHA" + #define TLS_CT_RSA_SIGN 1 #define TLS_CT_DSS_SIGN 2 #define TLS_CT_RSA_FIXED_DH 3 #define TLS_CT_DSS_FIXED_DH 4 -#define TLS_CT_NUMBER 4 +#define TLS_CT_ECDSA_SIGN 5 +#define TLS_CT_RSA_FIXED_ECDH 6 +#define TLS_CT_ECDSA_FIXED_ECDH 7 +#define TLS_CT_NUMBER 7 #define TLS1_FINISH_MAC_LENGTH 12 @@ -193,3 +296,5 @@ extern "C" { #endif #endif + + |