Continuing TLS v1.2 support: add support for server parsing of

signature algorithms extension and correct signature format for
server key exchange.

All ciphersuites should now work on the server but no client support and
no client certificate support yet.
This commit is contained in:
Dr. Stephen Henson 2011-05-06 13:00:07 +00:00
parent c184711124
commit 6b7be581e5
9 changed files with 286 additions and 38 deletions

View File

@ -4,6 +4,12 @@
Changes between 1.0.1 and 1.1.0 [xx XXX xxxx]
*) Add server support for TLS v1.2 signature algorithms extension. Switch
to new signature format when needed using client digest preference.
All server ciphersuites should now work correctly in TLS v1.2. No client
support yet and no support for client certificates.
[Steve Henson]
*) Initial TLS v1.2 support. Add new SHA256 digest to ssl code, switch
to SHA256 for PRF when using TLS v1.2 and later. Add new SHA256 based
ciphersuites. At present only RSA key exchange ciphersuites work with

View File

@ -1526,6 +1526,9 @@ bad:
SSL_CTX_set_quiet_shutdown(ctx,1);
if (bugs) SSL_CTX_set_options(ctx,SSL_OP_ALL);
if (hack) SSL_CTX_set_options(ctx,SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG);
/* HACK while TLS v1.2 is disabled by default */
if (!(off & SSL_OP_NO_TLSv1_2))
SSL_CTX_clear_options(ctx, SSL_OP_NO_TLSv1_2);
SSL_CTX_set_options(ctx,off);
/* DTLS: partial reads end up discarding unread UDP bytes :-(
* Setting read ahead solves this problem.

View File

@ -1139,7 +1139,7 @@ int dtls1_send_server_key_exchange(SSL *s)
if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
&& !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
{
if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher))
if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher, NULL))
== NULL)
{
al=SSL_AD_DECODE_ERROR;

View File

@ -1530,6 +1530,7 @@ int ssl3_send_server_key_exchange(SSL *s)
BN_CTX *bn_ctx = NULL;
#endif
EVP_PKEY *pkey;
const EVP_MD *md = NULL;
unsigned char *p,*d;
int al,i;
unsigned long type;
@ -1810,7 +1811,7 @@ int ssl3_send_server_key_exchange(SSL *s)
if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
&& !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
{
if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher))
if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher,&md))
== NULL)
{
al=SSL_AD_DECODE_ERROR;
@ -1888,7 +1889,8 @@ int ssl3_send_server_key_exchange(SSL *s)
/* n is the length of the params, they start at &(d[4])
* and p points to the space at the end. */
#ifndef OPENSSL_NO_RSA
if (pkey->type == EVP_PKEY_RSA)
if (pkey->type == EVP_PKEY_RSA
&& s->version < TLS1_2_VERSION)
{
q=md_buf;
j=0;
@ -1915,44 +1917,37 @@ int ssl3_send_server_key_exchange(SSL *s)
}
else
#endif
#if !defined(OPENSSL_NO_DSA)
if (pkey->type == EVP_PKEY_DSA)
if (md)
{
/* lets do DSS */
EVP_SignInit_ex(&md_ctx,EVP_dss1(), NULL);
/* For TLS1.2 and later send signature
* algorithm */
if (s->version >= TLS1_2_VERSION)
{
if (!tls12_get_sigandhash(p, pkey, md))
{
/* Should never happen */
al=SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
goto f_err;
}
p+=2;
}
EVP_SignInit_ex(&md_ctx, md, 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_DSA);
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_EVP);
goto err;
}
s2n(i,p);
n+=i+2;
if (s->version >= TLS1_2_VERSION)
n+= 2;
}
else
#endif
#if !defined(OPENSSL_NO_ECDSA)
if (pkey->type == EVP_PKEY_EC)
{
/* 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;

View File

@ -160,6 +160,21 @@ int SSL_get_ex_data_X509_STORE_CTX_idx(void)
return ssl_x509_store_ctx_idx;
}
static void ssl_cert_set_default_md(CERT *cert)
{
/* Set digest values to defaults */
#ifndef OPENSSL_NO_DSA
cert->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_dss1();
#endif
#ifndef OPENSSL_NO_RSA
cert->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
cert->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
#endif
#ifndef OPENSSL_NO_ECDSA
cert->pkeys[SSL_PKEY_ECC].digest = EVP_ecdsa();
#endif
}
CERT *ssl_cert_new(void)
{
CERT *ret;
@ -174,7 +189,7 @@ CERT *ssl_cert_new(void)
ret->key= &(ret->pkeys[SSL_PKEY_RSA_ENC]);
ret->references=1;
ssl_cert_set_default_md(ret);
return(ret);
}
@ -307,6 +322,10 @@ CERT *ssl_cert_dup(CERT *cert)
* chain is held inside SSL_CTX */
ret->references=1;
/* Set digests to defaults. NB: we don't copy existing values as they
* will be set during handshake.
*/
ssl_cert_set_default_md(ret);
return(ret);

View File

@ -2322,34 +2322,36 @@ X509 *ssl_get_server_send_cert(SSL *s)
return(c->pkeys[i].x509);
}
EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher)
EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher, const EVP_MD **pmd)
{
unsigned long alg_a;
CERT *c;
int idx = -1;
alg_a = cipher->algorithm_auth;
c=s->cert;
if ((alg_a & SSL_aDSS) &&
(c->pkeys[SSL_PKEY_DSA_SIGN].privatekey != NULL))
return(c->pkeys[SSL_PKEY_DSA_SIGN].privatekey);
idx = SSL_PKEY_DSA_SIGN;
else if (alg_a & SSL_aRSA)
{
if (c->pkeys[SSL_PKEY_RSA_SIGN].privatekey != NULL)
return(c->pkeys[SSL_PKEY_RSA_SIGN].privatekey);
idx = SSL_PKEY_RSA_SIGN;
else if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey != NULL)
return(c->pkeys[SSL_PKEY_RSA_ENC].privatekey);
else
return(NULL);
idx = SSL_PKEY_RSA_ENC;
}
else if ((alg_a & SSL_aECDSA) &&
(c->pkeys[SSL_PKEY_ECC].privatekey != NULL))
return(c->pkeys[SSL_PKEY_ECC].privatekey);
else /* if (alg_a & SSL_aNULL) */
idx = SSL_PKEY_ECC;
if (idx == -1)
{
SSLerr(SSL_F_SSL_GET_SIGN_PKEY,ERR_R_INTERNAL_ERROR);
return(NULL);
}
if (pmd)
*pmd = c->pkeys[idx].digest;
return c->pkeys[idx].privatekey;
}
void ssl_update_cache(SSL *s,int mode)

View File

@ -461,6 +461,8 @@ typedef struct cert_pkey_st
{
X509 *x509;
EVP_PKEY *privatekey;
/* Digest to use when signing */
const EVP_MD *digest;
} CERT_PKEY;
typedef struct cert_st
@ -814,7 +816,7 @@ int ssl_undefined_function(SSL *s);
int ssl_undefined_void_function(void);
int ssl_undefined_const_function(const SSL *s);
X509 *ssl_get_server_send_cert(SSL *);
EVP_PKEY *ssl_get_sign_pkey(SSL *,const SSL_CIPHER *);
EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *c, const EVP_MD **pmd);
int ssl_cert_type(X509 *x,EVP_PKEY *pkey);
void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher);
STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s);
@ -1088,3 +1090,4 @@ int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len,
int *al);
long ssl_get_algorithm2(SSL *s);
#endif
int tls12_get_sigandhash(unsigned char *p, EVP_PKEY *pk, const EVP_MD *md);

View File

@ -122,6 +122,7 @@ const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT;
static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen,
const unsigned char *sess_id, int sesslen,
SSL_SESSION **psess);
static int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize);
#endif
SSL3_ENC_METHOD TLSv1_enc_data={
@ -693,6 +694,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
unsigned short len;
unsigned char *data = *p;
int renegotiate_seen = 0;
int sigalg_seen = 0;
s->servername_done = 0;
s->tlsext_status_type = -1;
@ -956,6 +958,28 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
return 0;
renegotiate_seen = 1;
}
else if (type == TLSEXT_TYPE_signature_algorithms)
{
int dsize;
if (sigalg_seen || size < 2)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
sigalg_seen = 1;
n2s(data,dsize);
size -= 2;
if (dsize != size || dsize & 1)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
if (!tls1_process_sigalgs(s, data, dsize))
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
}
else if (type == TLSEXT_TYPE_status_request &&
s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
{
@ -1893,4 +1917,185 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
return 0;
}
/* Tables to translate from NIDs to TLS v1.2 ids */
typedef struct
{
int nid;
int id;
} tls12_lookup;
static tls12_lookup tls12_md[] = {
#ifndef OPENSSL_NO_MD5
{NID_md5, TLSEXT_hash_md5},
#endif
#ifndef OPENSSL_NO_SHA
{NID_sha1, TLSEXT_hash_sha1},
#endif
#ifndef OPENSSL_NO_SHA256
{NID_sha224, TLSEXT_hash_sha224},
{NID_sha256, TLSEXT_hash_sha256},
#endif
#ifndef OPENSSL_NO_SHA512
{NID_sha384, TLSEXT_hash_sha384},
{NID_sha512, TLSEXT_hash_sha512}
#endif
};
static tls12_lookup tls12_sig[] = {
#ifndef OPENSSL_NO_RSA
{EVP_PKEY_RSA, TLSEXT_signature_rsa},
#endif
#ifndef OPENSSL_NO_RSA
{EVP_PKEY_DSA, TLSEXT_signature_dsa},
#endif
#ifndef OPENSSL_NO_ECDSA
{EVP_PKEY_EC, TLSEXT_signature_ecdsa}
#endif
};
static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen)
{
size_t i;
for (i = 0; i < tlen; i++)
{
if (table[i].nid == nid)
return table[i].id;
}
return -1;
}
#if 0
static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen)
{
size_t i;
for (i = 0; i < tlen; i++)
{
if (table[i].id == id)
return table[i].nid;
}
return -1;
}
#endif
int tls12_get_sigandhash(unsigned char *p, EVP_PKEY *pk, const EVP_MD *md)
{
int sig_id, md_id;
md_id = tls12_find_id(EVP_MD_type(md), tls12_md,
sizeof(tls12_md)/sizeof(tls12_lookup));
if (md_id == -1)
return 0;
sig_id = tls12_find_id(pk->type, tls12_sig,
sizeof(tls12_sig)/sizeof(tls12_lookup));
if (sig_id == -1)
return 0;
p[0] = (unsigned char)md_id;
p[1] = (unsigned char)sig_id;
return 1;
}
/* Set preferred digest for each key type */
int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
{
int i, idx;
const EVP_MD *md;
CERT *c = s->cert;
/* Extension ignored for TLS versions below 1.2 */
if (s->version < TLS1_2_VERSION)
return 1;
c->pkeys[SSL_PKEY_DSA_SIGN].digest = NULL;
c->pkeys[SSL_PKEY_RSA_SIGN].digest = NULL;
c->pkeys[SSL_PKEY_RSA_ENC].digest = NULL;
c->pkeys[SSL_PKEY_ECC].digest = NULL;
for (i = 0; i < dsize; i += 2)
{
unsigned char hash_alg = data[i], sig_alg = data[i+1];
switch(sig_alg)
{
#ifndef OPENSSL_NO_RSA
case TLSEXT_signature_rsa:
idx = SSL_PKEY_RSA_SIGN;
break;
#endif
#ifndef OPENSSL_NO_DSA
case TLSEXT_signature_dsa:
idx = SSL_PKEY_DSA_SIGN;
break;
#endif
#ifndef OPENSSL_NO_ECDSA
case TLSEXT_signature_ecdsa:
idx = SSL_PKEY_ECC;
break;
#endif
default:
continue;
}
if (c->pkeys[idx].digest)
continue;
switch(hash_alg)
{
#ifndef OPENSSL_NO_MD5
case TLSEXT_hash_md5:
md = EVP_md5();
break;
#endif
#ifndef OPENSSL_NO_SHA
case TLSEXT_hash_sha1:
md = EVP_sha1();
break;
#endif
#ifndef OPENSSL_NO_SHA256
case TLSEXT_hash_sha224:
md = EVP_sha224();
break;
case TLSEXT_hash_sha256:
md = EVP_sha256();
break;
#endif
#ifndef OPENSSL_NO_SHA512
case TLSEXT_hash_sha384:
md = EVP_sha384();
break;
case TLSEXT_hash_sha512:
md = EVP_sha512();
break;
#endif
default:
continue;
}
c->pkeys[idx].digest = md;
if (idx == SSL_PKEY_RSA_SIGN)
c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
}
/* Set any remaining keys to default values. NOTE: if alg is not
* supported it stays as NULL.
*/
#ifndef OPENSSL_NO_DSA
if (!c->pkeys[SSL_PKEY_DSA_SIGN].digest)
c->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_dss1();
#endif
#ifndef OPENSSL_NO_RSA
if (!c->pkeys[SSL_PKEY_RSA_SIGN].digest)
{
c->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
c->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
}
#endif
#ifndef OPENSSL_NO_ECDSA
if (!c->pkeys[SSL_PKEY_ECC].digest)
c->pkeys[SSL_PKEY_ECC].digest = EVP_ecdsa();
#endif
return 1;
}
#endif

View File

@ -234,6 +234,21 @@ extern "C" {
#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2 2
#define TLSEXT_ECPOINTFORMAT_last 2
/* Signature and hash algorithms from RFC 5246 */
#define TLSEXT_signature_anonymous 0
#define TLSEXT_signature_rsa 1
#define TLSEXT_signature_dsa 2
#define TLSEXT_signature_ecdsa 3
#define TLSEXT_hash_none 0
#define TLSEXT_hash_md5 1
#define TLSEXT_hash_sha1 2
#define TLSEXT_hash_sha224 3
#define TLSEXT_hash_sha256 4
#define TLSEXT_hash_sha384 5
#define TLSEXT_hash_sha512 6
#ifndef OPENSSL_NO_TLSEXT
#define TLSEXT_MAXLEN_host_name 255