aboutsummaryrefslogtreecommitdiffstats
path: root/src/libtls/tls_crypto.c
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2010-09-02 10:29:32 +0200
committerMartin Willi <martin@revosec.ch>2010-09-02 13:07:25 +0200
commitdbb7c0306cbb5e6276745f0cdfd9a46edd086fb1 (patch)
tree092c02d5557b8066c95f92c1695f769f0591cc9a /src/libtls/tls_crypto.c
parent99dcaea9bd31f5d8894b7607f0239ea8fa61d7ec (diff)
downloadstrongswan-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.c172
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;
}