diff options
author | Martin Willi <martin@revosec.ch> | 2010-09-02 10:29:32 +0200 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2010-09-02 13:07:25 +0200 |
commit | dbb7c0306cbb5e6276745f0cdfd9a46edd086fb1 (patch) | |
tree | 092c02d5557b8066c95f92c1695f769f0591cc9a /src/libtls/tls_crypto.c | |
parent | 99dcaea9bd31f5d8894b7607f0239ea8fa61d7ec (diff) | |
download | strongswan-dbb7c0306cbb5e6276745f0cdfd9a46edd086fb1.tar.bz2 strongswan-dbb7c0306cbb5e6276745f0cdfd9a46edd086fb1.tar.xz |
Support different hash/sig algorithms in handshake signing, including ECDSA
Diffstat (limited to 'src/libtls/tls_crypto.c')
-rw-r--r-- | src/libtls/tls_crypto.c | 172 |
1 files changed, 146 insertions, 26 deletions
diff --git a/src/libtls/tls_crypto.c b/src/libtls/tls_crypto.c index 7e5ca197d..1f6179565 100644 --- a/src/libtls/tls_crypto.c +++ b/src/libtls/tls_crypto.c @@ -692,36 +692,130 @@ static bool hash_handshake(private_tls_crypto_t *this, chunk_t *hash) return TRUE; } -METHOD(tls_crypto_t, sign_handshake, bool, - private_tls_crypto_t *this, private_key_t *key, tls_writer_t *writer) +/** + * Get the signature scheme from a TLS 1.2 hash/sig algorithm pair + */ +static signature_scheme_t hashsig_to_scheme(key_type_t type, + tls_hash_algorithm_t hash, tls_signature_algorithm_t sig) { - chunk_t sig, hash; + switch (sig) + { + case TLS_SIG_RSA: + if (type != KEY_RSA) + { + return SIGN_UNKNOWN; + } + switch (hash) + { + case TLS_HASH_MD5: + return SIGN_RSA_EMSA_PKCS1_MD5; + case TLS_HASH_SHA1: + return SIGN_RSA_EMSA_PKCS1_SHA1; + case TLS_HASH_SHA224: + return SIGN_RSA_EMSA_PKCS1_SHA224; + case TLS_HASH_SHA256: + return SIGN_RSA_EMSA_PKCS1_SHA256; + case TLS_HASH_SHA384: + return SIGN_RSA_EMSA_PKCS1_SHA384; + case TLS_HASH_SHA512: + return SIGN_RSA_EMSA_PKCS1_SHA512; + default: + return SIGN_UNKNOWN; + } + case TLS_SIG_ECDSA: + if (type != KEY_ECDSA) + { + return SIGN_UNKNOWN; + } + switch (hash) + { + case TLS_HASH_SHA224: + return SIGN_ECDSA_WITH_SHA1_DER; + case TLS_HASH_SHA256: + return SIGN_ECDSA_WITH_SHA256_DER; + case TLS_HASH_SHA384: + return SIGN_ECDSA_WITH_SHA384_DER; + case TLS_HASH_SHA512: + return SIGN_ECDSA_WITH_SHA512_DER; + default: + return SIGN_UNKNOWN; + } + default: + return SIGN_UNKNOWN; + } +} +METHOD(tls_crypto_t, sign_handshake, bool, + private_tls_crypto_t *this, private_key_t *key, tls_writer_t *writer, + chunk_t hashsig) +{ if (this->tls->get_version(this->tls) >= TLS_1_2) { - /* TODO: use supported algorithms instead of fixed SHA1/RSA */ - if (!key->sign(key, SIGN_RSA_EMSA_PKCS1_SHA1, this->handshake, &sig)) + signature_scheme_t scheme; + tls_reader_t *reader; + u_int8_t hash, alg; + chunk_t sig; + bool done = FALSE; + + reader = tls_reader_create(hashsig); + while (reader->remaining(reader) >= 2) { + if (reader->read_uint8(reader, &hash) && + reader->read_uint8(reader, &alg)) + { + scheme = hashsig_to_scheme(key->get_type(key), hash, alg); + if (scheme != SIGN_UNKNOWN && + key->sign(key, scheme, this->handshake, &sig)) + { + done = TRUE; + break; + } + } + } + reader->destroy(reader); + if (!done) + { + DBG1(DBG_TLS, "none of the proposed hash/sig algorithms supported"); return FALSE; } - writer->write_uint8(writer, 2); - writer->write_uint8(writer, 1); + DBG2(DBG_TLS, "signed handshake data with %N/%N", + tls_hash_algorithm_names, hash, tls_signature_algorithm_names, alg); + writer->write_uint8(writer, hash); + writer->write_uint8(writer, alg); writer->write_data16(writer, sig); free(sig.ptr); } else { - if (!hash_handshake(this, &hash)) - { - return FALSE; - } - if (!key->sign(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, &sig)) + chunk_t sig, hash; + + switch (key->get_type(key)) { - free(hash.ptr); - return FALSE; + case KEY_RSA: + if (!hash_handshake(this, &hash)) + { + return FALSE; + } + if (!key->sign(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, &sig)) + { + free(hash.ptr); + return FALSE; + } + DBG2(DBG_TLS, "signed handshake data with SHA1+MD5/RSA"); + free(hash.ptr); + break; + case KEY_ECDSA: + if (!key->sign(key, SIGN_ECDSA_WITH_SHA1_DER, + this->handshake, &sig)) + { + return FALSE; + } + DBG2(DBG_TLS, "signed handshake data with SHA1/ECDSA"); + break; + default: + return FALSE; } writer->write_data16(writer, sig); - free(hash.ptr); free(sig.ptr); } return TRUE; @@ -732,6 +826,7 @@ METHOD(tls_crypto_t, verify_handshake, bool, { if (this->tls->get_version(this->tls) >= TLS_1_2) { + signature_scheme_t scheme = SIGN_UNKNOWN; u_int8_t hash, alg; chunk_t sig; @@ -742,12 +837,20 @@ METHOD(tls_crypto_t, verify_handshake, bool, DBG1(DBG_TLS, "received invalid Certificate Verify"); return FALSE; } - /* TODO: map received hash/sig alg to signature scheme */ - if (hash != 2 || alg != 1 || - !key->verify(key, SIGN_RSA_EMSA_PKCS1_SHA1, this->handshake, sig)) + scheme = hashsig_to_scheme(key->get_type(key), hash, alg); + if (scheme == SIGN_UNKNOWN) { + DBG1(DBG_TLS, "Certificate Verify algorithms %N/%N not supported", + tls_hash_algorithm_names, hash, + tls_signature_algorithm_names, alg); return FALSE; } + if (!key->verify(key, scheme, this->handshake, sig)) + { + return FALSE; + } + DBG2(DBG_TLS, "verified handshake data with %N/%N", + tls_hash_algorithm_names, hash, tls_signature_algorithm_names, alg); } else { @@ -758,16 +861,33 @@ METHOD(tls_crypto_t, verify_handshake, bool, DBG1(DBG_TLS, "received invalid Certificate Verify"); return FALSE; } - if (!hash_handshake(this, &hash)) - { - return FALSE; - } - if (!key->verify(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, sig)) + switch (key->get_type(key)) { - free(hash.ptr); - return FALSE; + case KEY_RSA: + if (!hash_handshake(this, &hash)) + { + return FALSE; + } + if (!key->verify(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, sig)) + { + free(hash.ptr); + return FALSE; + } + DBG2(DBG_TLS, "verified handshake data with SHA1+MD5/RSA"); + free(hash.ptr); + break; + case KEY_ECDSA: + if (!key->verify(key, SIGN_ECDSA_WITH_SHA1_DER, + this->handshake, sig)) + { + free(hash.ptr); + return FALSE; + } + DBG2(DBG_TLS, "verified handshake data with SHA1/ECDSA"); + break; + default: + return FALSE; } - free(hash.ptr); } return TRUE; } |