summaryrefslogtreecommitdiffstats
path: root/ssl/t1_lib.c
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2011-05-11 13:37:52 +0000
committerDr. Stephen Henson <steve@openssl.org>2011-05-11 13:37:52 +0000
commit9472baae0d17ddf425f891a3154057356217af08 (patch)
tree8ceed735328184e381c811fe0913264f1327fea1 /ssl/t1_lib.c
parentae17b9ecd5d243c93b071c6be309b4f230a1aa52 (diff)
Backport TLS v1.2 support from HEAD.
This includes TLS v1.2 server and client support but at present client certificate support is not implemented.
Diffstat (limited to 'ssl/t1_lib.c')
-rw-r--r--ssl/t1_lib.c268
1 files changed, 268 insertions, 0 deletions
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index ed6518166c..9bed9a33dc 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -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={
@@ -450,6 +451,62 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
}
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)
@@ -656,6 +713,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;
@@ -919,6 +977,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)
{
@@ -1781,4 +1861,192 @@ 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, 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_get_sigid(pk);
+ if (sig_id == -1)
+ return 0;
+ p[0] = (unsigned char)md_id;
+ p[1] = (unsigned char)sig_id;
+ 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 */
+
+static 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 == NULL)
+ {
+ 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;
+ }
+ }
+
+ }
+
+ /* 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