Initial TLS v1.2 client support. Include a default supported signature
algorithms extension (including everything we support). Swicth to new
signature format where needed and relax ECC restrictions.
Not TLS v1.2 client certifcate support yet but client will handle case
where a certificate is requested and we don't have one.
diff --git a/CHANGES b/CHANGES
index a955b3f..1ee3a47 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,12 @@
Changes between 1.0.1 and 1.1.0 [xx XXX xxxx]
+ *) Initial TLS v1.2 client support. Add a default signature algorithms
+ extension including all the algorithms we support. Parse new signature
+ format in client key exchange. Relax some ECC signing restrictions for
+ TLS v1.2 as indicated in RFC5246.
+ [Steve Henson]
+
*) 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
diff --git a/apps/s_client.c b/apps/s_client.c
index faf7f39..2b8b145 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -1103,6 +1103,9 @@
SSL_CTX_set_psk_client_callback(ctx, psk_client_cb);
}
#endif
+ /* 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);
if (bugs)
SSL_CTX_set_options(ctx,SSL_OP_ALL|off);
else
@@ -2011,6 +2014,18 @@
}
#endif
+#ifdef SSL_DEBUG
+ {
+ /* Print out local port of connection: useful for debugging */
+ int sock;
+ struct sockaddr_in ladd;
+ socklen_t ladd_size = sizeof(ladd);
+ sock = SSL_get_fd(s);
+ getsockname(sock, (struct sockaddr *)&ladd, &ladd_size);
+ BIO_printf(bio_c_out, "LOCAL PORT is %u\n", ntohs(ladd.sin_port));
+ }
+#endif
+
SSL_SESSION_print(bio,SSL_get_session(s));
BIO_printf(bio,"---\n");
if (peer != NULL)
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index f96ec4f..0541de9 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -1203,6 +1203,7 @@
int al,i,j,param_len,ok;
long n,alg_k,alg_a;
EVP_PKEY *pkey=NULL;
+ const EVP_MD *md = NULL;
#ifndef OPENSSL_NO_RSA
RSA *rsa=NULL;
#endif
@@ -1653,6 +1654,38 @@
/* if it was signed, check the signature */
if (pkey != NULL)
{
+ if (s->version >= TLS1_2_VERSION)
+ {
+ int sigalg = tls12_get_sigid(pkey);
+ /* Should never happen */
+ if (sigalg == -1)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ /* Check key type is consistent with signature */
+ if (sigalg != (int)p[1])
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_WRONG_SIGNATURE_TYPE);
+ al=SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+ md = tls12_get_hash(p[0]);
+ if (md == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNKNOWN_DIGEST);
+ al=SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+#ifdef SSL_DEBUG
+fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
+#endif
+ p += 2;
+ n -= 2;
+ }
+ else
+ md = EVP_sha1();
+
n2s(p,i);
n-=2;
j=EVP_PKEY_size(pkey);
@@ -1666,7 +1699,7 @@
}
#ifndef OPENSSL_NO_RSA
- if (pkey->type == EVP_PKEY_RSA)
+ if (pkey->type == EVP_PKEY_RSA && s->version < TLS1_2_VERSION)
{
int num;
@@ -1701,11 +1734,8 @@
}
else
#endif
-#ifndef OPENSSL_NO_DSA
- if (pkey->type == EVP_PKEY_DSA)
{
- /* lets do DSS */
- EVP_VerifyInit_ex(&md_ctx,EVP_dss1(), NULL);
+ EVP_VerifyInit_ex(&md_ctx, md, 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);
@@ -1717,30 +1747,6 @@
goto f_err;
}
}
- else
-#endif
-#ifndef OPENSSL_NO_ECDSA
- if (pkey->type == EVP_PKEY_EC)
- {
- /* 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) <= 0)
- {
- /* 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;
- }
}
else
{
@@ -1787,7 +1793,7 @@
{
int ok,ret=0;
unsigned long n,nc,l;
- unsigned int llen,ctype_num,i;
+ unsigned int llen,sigalglen, ctype_num,i;
X509_NAME *xn=NULL;
const unsigned char *p,*q;
unsigned char *d;
@@ -1843,6 +1849,17 @@
for (i=0; i<ctype_num; i++)
s->s3->tmp.ctype[i]= p[i];
p+=ctype_num;
+ /* HACK! For now just skip over signatature algorithms */
+ if (s->version >= TLS1_2_VERSION)
+ {
+ n2s(p, sigalglen);
+ p += sigalglen;
+ sigalglen += 2;
+ }
+ else
+ sigalglen = 0;
+
+
/* get the CA RDNs */
n2s(p,llen);
@@ -1855,7 +1872,7 @@
}
#endif
- if ((llen+ctype_num+2+1) != n)
+ if ((llen+ctype_num+sigalglen+2+1) != n)
{
ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_LENGTH_MISMATCH);
@@ -3059,7 +3076,7 @@
if (idx == SSL_PKEY_ECC)
{
if (ssl_check_srvr_ecc_cert_and_alg(sc->peer_pkeys[idx].x509,
- s->s3->tmp.new_cipher) == 0)
+ s) == 0)
{ /* check failed */
SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_BAD_ECC_CERT);
goto f_err;
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 4eec497..0f203ec 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -1932,6 +1932,10 @@
}
p+=2;
}
+#ifdef SSL_DEBUG
+ fprintf(stderr, "Using hash %s\n",
+ EVP_MD_name(md));
+#endif
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);
diff --git a/ssl/ssl.h b/ssl/ssl.h
index c487407..755dd85 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -2500,6 +2500,7 @@
#define SSL_R_UNKNOWN_CERTIFICATE_TYPE 247
#define SSL_R_UNKNOWN_CIPHER_RETURNED 248
#define SSL_R_UNKNOWN_CIPHER_TYPE 249
+#define SSL_R_UNKNOWN_DIGEST 357
#define SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE 250
#define SSL_R_UNKNOWN_PKEY_TYPE 251
#define SSL_R_UNKNOWN_PROTOCOL 252
@@ -2520,6 +2521,7 @@
#define SSL_R_WRONG_NUMBER_OF_KEY_BITS 263
#define SSL_R_WRONG_SIGNATURE_LENGTH 264
#define SSL_R_WRONG_SIGNATURE_SIZE 265
+#define SSL_R_WRONG_SIGNATURE_TYPE 358
#define SSL_R_WRONG_SSL_VERSION 266
#define SSL_R_WRONG_VERSION_NUMBER 267
#define SSL_R_X509_LIB 268
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index af52856..76c8e1e 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -543,6 +543,7 @@
{ERR_REASON(SSL_R_UNKNOWN_CERTIFICATE_TYPE),"unknown certificate type"},
{ERR_REASON(SSL_R_UNKNOWN_CIPHER_RETURNED),"unknown cipher returned"},
{ERR_REASON(SSL_R_UNKNOWN_CIPHER_TYPE) ,"unknown cipher type"},
+{ERR_REASON(SSL_R_UNKNOWN_DIGEST) ,"unknown digest"},
{ERR_REASON(SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE),"unknown key exchange type"},
{ERR_REASON(SSL_R_UNKNOWN_PKEY_TYPE) ,"unknown pkey type"},
{ERR_REASON(SSL_R_UNKNOWN_PROTOCOL) ,"unknown protocol"},
@@ -563,6 +564,7 @@
{ERR_REASON(SSL_R_WRONG_NUMBER_OF_KEY_BITS),"wrong number of key bits"},
{ERR_REASON(SSL_R_WRONG_SIGNATURE_LENGTH),"wrong signature length"},
{ERR_REASON(SSL_R_WRONG_SIGNATURE_SIZE) ,"wrong signature size"},
+{ERR_REASON(SSL_R_WRONG_SIGNATURE_TYPE) ,"wrong signature type"},
{ERR_REASON(SSL_R_WRONG_SSL_VERSION) ,"wrong ssl version"},
{ERR_REASON(SSL_R_WRONG_VERSION_NUMBER) ,"wrong version number"},
{ERR_REASON(SSL_R_X509_LIB) ,"x509 lib"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 114ad47..3f60ab1 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2185,12 +2185,13 @@
#ifndef OPENSSL_NO_EC
-int ssl_check_srvr_ecc_cert_and_alg(X509 *x, const SSL_CIPHER *cs)
+int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s)
{
unsigned long alg_k, alg_a;
EVP_PKEY *pkey = NULL;
int keysize = 0;
int signature_nid = 0;
+ const SSL_CIPHER *cs = s->s3->tmp.new_cipher;
alg_k = cs->algorithm_mkey;
alg_a = cs->algorithm_auth;
@@ -2217,7 +2218,7 @@
SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT);
return 0;
}
- if (alg_k & SSL_kECDHe)
+ if ((alg_k & SSL_kECDHe) && s->version < TLS1_2_VERSION)
{
/* signature alg must be ECDSA */
if (signature_nid != NID_ecdsa_with_SHA1)
@@ -2226,7 +2227,7 @@
return 0;
}
}
- if (alg_k & SSL_kECDHr)
+ if ((alg_k & SSL_kECDHr) && s->version < TLS1_2_VERSION)
{
/* signature alg must be RSA */
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 3225d65..78958d4 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1050,7 +1050,7 @@
int ssl_ok(SSL *s);
#ifndef OPENSSL_NO_ECDH
-int ssl_check_srvr_ecc_cert_and_alg(X509 *x, const SSL_CIPHER *cs);
+int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s);
#endif
SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n);
@@ -1077,6 +1077,12 @@
#endif
int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
const unsigned char *limit, SSL_SESSION **ret);
+
+int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk,
+ const EVP_MD *md);
+int tls12_get_sigid(const EVP_PKEY *pk);
+const EVP_MD *tls12_get_hash(unsigned char hash_alg);
+
#endif
EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ;
void ssl_clear_hash_ctx(EVP_MD_CTX **hash);
@@ -1090,4 +1096,3 @@
int *al);
long ssl_get_algorithm2(SSL *s);
#endif
-int tls12_get_sigandhash(unsigned char *p, EVP_PKEY *pk, const EVP_MD *md);
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 95a5b35..c60bccd 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -1008,6 +1008,7 @@
const void *co = NULL, *so = NULL;
int col = 0, sol = 0;
+
#ifdef KSSL_DEBUG
printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len);
#endif /* KSSL_DEBUG */
@@ -1032,6 +1033,16 @@
so, sol,
p,len,
s->session->master_key,buff,sizeof buff);
+#ifdef SSL_DEBUG
+ fprintf(stderr, "Premaster Secret:\n");
+ BIO_dump_fp(stderr, (char *)p, len);
+ fprintf(stderr, "Client Random:\n");
+ BIO_dump_fp(stderr, (char *)s->s3->client_random, SSL3_RANDOM_SIZE);
+ fprintf(stderr, "Server Random:\n");
+ BIO_dump_fp(stderr, (char *)s->s3->server_random, SSL3_RANDOM_SIZE);
+ fprintf(stderr, "Master Secret:\n");
+ BIO_dump_fp(stderr, (char *)s->session->master_key, SSL3_MASTER_SECRET_SIZE);
+#endif
#ifdef KSSL_DEBUG
printf ("tls1_generate_master_secret() complete\n");
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 67a3f86..ca4b2db 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -451,6 +451,62 @@
}
skip_ext:
+ if (s->version >= TLS1_2_VERSION)
+ {
+ /* List of supported signature algorithms and hashes.
+ * Should make this customisable at some point, for
+ * now include everything we support.
+ */
+ static unsigned char sigalgs[] = {
+#ifndef OPENSSL_NO_RSA
+# ifndef OPENSSL_NO_SHA512
+ TLSEXT_hash_sha512, TLSEXT_signature_rsa,
+ TLSEXT_hash_sha384, TLSEXT_signature_rsa,
+# endif
+# ifndef OPENSSL_NO_SHA256
+ TLSEXT_hash_sha256, TLSEXT_signature_rsa,
+ TLSEXT_hash_sha224, TLSEXT_signature_rsa,
+# endif
+# ifndef OPENSSL_NO_SHA
+ TLSEXT_hash_sha1, TLSEXT_signature_rsa,
+# endif
+#endif
+#ifndef OPENSSL_NO_ECDSA
+# ifndef OPENSSL_NO_SHA512
+ TLSEXT_hash_sha512, TLSEXT_signature_ecdsa,
+ TLSEXT_hash_sha384, TLSEXT_signature_ecdsa,
+# endif
+# ifndef OPENSSL_NO_SHA256
+ TLSEXT_hash_sha256, TLSEXT_signature_ecdsa,
+ TLSEXT_hash_sha224, TLSEXT_signature_ecdsa,
+# endif
+# ifndef OPENSSL_NO_SHA
+ TLSEXT_hash_sha1, TLSEXT_signature_ecdsa,
+# endif
+#endif
+#ifndef OPENSSL_NO_DSA
+# ifndef OPENSSL_NO_SHA512
+ TLSEXT_hash_sha512, TLSEXT_signature_dsa,
+ TLSEXT_hash_sha384, TLSEXT_signature_dsa,
+# endif
+# ifndef OPENSSL_NO_SHA256
+ TLSEXT_hash_sha256, TLSEXT_signature_dsa,
+ TLSEXT_hash_sha224, TLSEXT_signature_dsa,
+# endif
+# ifndef OPENSSL_NO_SHA
+ TLSEXT_hash_sha1, TLSEXT_signature_dsa
+# endif
+#endif
+ };
+ if ((size_t)(limit - ret) < sizeof(sigalgs) + 6)
+ return NULL;
+ s2n(TLSEXT_TYPE_signature_algorithms,ret);
+ s2n(sizeof(sigalgs) + 2, ret);
+ s2n(sizeof(sigalgs), ret);
+ memcpy(ret, sigalgs, sizeof(sigalgs));
+ ret += sizeof(sigalgs);
+ }
+
#ifdef TLSEXT_TYPE_opaque_prf_input
if (s->s3->client_opaque_prf_input != NULL &&
s->version != DTLS1_VERSION)
@@ -1976,15 +2032,15 @@
return -1;
}
#endif
-int tls12_get_sigandhash(unsigned char *p, EVP_PKEY *pk, const EVP_MD *md)
+
+int tls12_get_sigandhash(unsigned char *p, const 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));
+ sig_id = tls12_get_sigid(pk);
if (sig_id == -1)
return 0;
p[0] = (unsigned char)md_id;
@@ -1992,9 +2048,47 @@
return 1;
}
+int tls12_get_sigid(const EVP_PKEY *pk)
+ {
+ return tls12_find_id(pk->type, tls12_sig,
+ sizeof(tls12_sig)/sizeof(tls12_lookup));
+ }
+
+const EVP_MD *tls12_get_hash(unsigned char hash_alg)
+ {
+ switch(hash_alg)
+ {
+#ifndef OPENSSL_NO_MD5
+ case TLSEXT_hash_md5:
+ return EVP_md5();
+#endif
+#ifndef OPENSSL_NO_SHA
+ case TLSEXT_hash_sha1:
+ return EVP_sha1();
+#endif
+#ifndef OPENSSL_NO_SHA256
+ case TLSEXT_hash_sha224:
+ return EVP_sha224();
+
+ case TLSEXT_hash_sha256:
+ return EVP_sha256();
+#endif
+#ifndef OPENSSL_NO_SHA512
+ case TLSEXT_hash_sha384:
+ return EVP_sha384();
+
+ case TLSEXT_hash_sha512:
+ return EVP_sha512();
+#endif
+ default:
+ return NULL;
+
+ }
+ }
+
/* Set preferred digest for each key type */
-int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
+static int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
{
int i, idx;
const EVP_MD *md;
@@ -2033,48 +2127,17 @@
continue;
}
- if (c->pkeys[idx].digest)
- continue;
-
- switch(hash_alg)
+ if (c->pkeys[idx].digest == NULL)
{
-#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;
-
+ md = tls12_get_hash(hash_alg);
+ if (md)
+ {
+ c->pkeys[idx].digest = md;
+ if (idx == SSL_PKEY_RSA_SIGN)
+ c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
+ }
}
- 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