diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libtls/tls_crypto.c | 138 | ||||
-rw-r--r-- | src/libtls/tls_crypto.h | 30 | ||||
-rw-r--r-- | src/libtls/tls_server.c | 72 |
3 files changed, 143 insertions, 97 deletions
diff --git a/src/libtls/tls_crypto.c b/src/libtls/tls_crypto.c index 1f6179565..af0d6302f 100644 --- a/src/libtls/tls_crypto.c +++ b/src/libtls/tls_crypto.c @@ -624,6 +624,55 @@ METHOD(tls_crypto_t, select_cipher_suite, tls_cipher_suite_t, return 0; } +METHOD(tls_crypto_t, get_signature_algorithms, void, + private_tls_crypto_t *this, tls_writer_t *writer) +{ + tls_writer_t *supported; + enumerator_t *enumerator; + hash_algorithm_t alg; + tls_hash_algorithm_t hash; + + supported = tls_writer_create(32); + enumerator = lib->crypto->create_hasher_enumerator(lib->crypto); + while (enumerator->enumerate(enumerator, &alg)) + { + switch (alg) + { + case HASH_MD5: + hash = TLS_HASH_MD5; + break; + case HASH_SHA1: + hash = TLS_HASH_SHA1; + break; + case HASH_SHA224: + hash = TLS_HASH_SHA224; + break; + case HASH_SHA256: + hash = TLS_HASH_SHA256; + break; + case HASH_SHA384: + hash = TLS_HASH_SHA384; + break; + case HASH_SHA512: + hash = TLS_HASH_SHA512; + break; + default: + continue; + } + supported->write_uint8(supported, hash); + supported->write_uint8(supported, TLS_SIG_RSA); + if (alg != HASH_MD5 && alg != HASH_SHA224) + { + supported->write_uint8(supported, hash); + supported->write_uint8(supported, TLS_SIG_ECDSA); + } + } + enumerator->destroy(enumerator); + + writer->write_data16(writer, supported->get_buf(supported)); + supported->destroy(supported); +} + METHOD(tls_crypto_t, set_protection, void, private_tls_crypto_t *this, tls_protection_t *protection) { @@ -642,9 +691,9 @@ METHOD(tls_crypto_t, append_handshake, void, } /** - * Create a hash of the stored handshake data + * Create a hash using the suites HASH algorithm */ -static bool hash_handshake(private_tls_crypto_t *this, chunk_t *hash) +static bool hash_data(private_tls_crypto_t *this, chunk_t data, chunk_t *hash) { if (this->tls->get_version(this->tls) >= TLS_1_2) { @@ -662,7 +711,7 @@ static bool hash_handshake(private_tls_crypto_t *this, chunk_t *hash) DBG1(DBG_TLS, "%N not supported", hash_algorithm_names, alg->hash); return FALSE; } - hasher->allocate_hash(hasher, this->handshake, hash); + hasher->allocate_hash(hasher, data, hash); hasher->destroy(hasher); } else @@ -676,7 +725,7 @@ static bool hash_handshake(private_tls_crypto_t *this, chunk_t *hash) DBG1(DBG_TLS, "%N not supported", hash_algorithm_names, HASH_MD5); return FALSE; } - md5->get_hash(md5, this->handshake, buf); + md5->get_hash(md5, data, buf); md5->destroy(md5); sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); if (!sha1) @@ -684,7 +733,7 @@ static bool hash_handshake(private_tls_crypto_t *this, chunk_t *hash) DBG1(DBG_TLS, "%N not supported", hash_algorithm_names, HASH_SHA1); return FALSE; } - sha1->get_hash(sha1, this->handshake, buf + HASH_SIZE_MD5); + sha1->get_hash(sha1, data, buf + HASH_SIZE_MD5); sha1->destroy(sha1); *hash = chunk_clone(chunk_from_thing(buf)); @@ -745,9 +794,9 @@ static signature_scheme_t hashsig_to_scheme(key_type_t type, } } -METHOD(tls_crypto_t, sign_handshake, bool, +METHOD(tls_crypto_t, sign, bool, private_tls_crypto_t *this, private_key_t *key, tls_writer_t *writer, - chunk_t hashsig) + chunk_t data, chunk_t hashsig) { if (this->tls->get_version(this->tls) >= TLS_1_2) { @@ -757,6 +806,11 @@ METHOD(tls_crypto_t, sign_handshake, bool, chunk_t sig; bool done = FALSE; + if (!hashsig.len) + { /* fallback if none given */ + hashsig = chunk_from_chars( + TLS_HASH_SHA1, TLS_SIG_RSA, TLS_HASH_SHA1, TLS_SIG_ECDSA); + } reader = tls_reader_create(hashsig); while (reader->remaining(reader) >= 2) { @@ -765,7 +819,7 @@ METHOD(tls_crypto_t, sign_handshake, bool, { scheme = hashsig_to_scheme(key->get_type(key), hash, alg); if (scheme != SIGN_UNKNOWN && - key->sign(key, scheme, this->handshake, &sig)) + key->sign(key, scheme, data, &sig)) { done = TRUE; break; @@ -778,7 +832,7 @@ METHOD(tls_crypto_t, sign_handshake, bool, DBG1(DBG_TLS, "none of the proposed hash/sig algorithms supported"); return FALSE; } - DBG2(DBG_TLS, "signed handshake data with %N/%N", + DBG2(DBG_TLS, "created signature with %N/%N", tls_hash_algorithm_names, hash, tls_signature_algorithm_names, alg); writer->write_uint8(writer, hash); writer->write_uint8(writer, alg); @@ -788,29 +842,29 @@ METHOD(tls_crypto_t, sign_handshake, bool, else { chunk_t sig, hash; + bool done; switch (key->get_type(key)) { case KEY_RSA: - if (!hash_handshake(this, &hash)) + if (!hash_data(this, data, &hash)) { return FALSE; } - if (!key->sign(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, &sig)) + done = key->sign(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, &sig); + free(hash.ptr); + if (!done) { - free(hash.ptr); return FALSE; } - DBG2(DBG_TLS, "signed handshake data with SHA1+MD5/RSA"); - free(hash.ptr); + DBG2(DBG_TLS, "created signature with MD5+SHA1/RSA"); break; case KEY_ECDSA: - if (!key->sign(key, SIGN_ECDSA_WITH_SHA1_DER, - this->handshake, &sig)) + if (!key->sign(key, SIGN_ECDSA_WITH_SHA1_DER, data, &sig)) { return FALSE; } - DBG2(DBG_TLS, "signed handshake data with SHA1/ECDSA"); + DBG2(DBG_TLS, "created signature with SHA1/ECDSA"); break; default: return FALSE; @@ -821,8 +875,9 @@ METHOD(tls_crypto_t, sign_handshake, bool, return TRUE; } -METHOD(tls_crypto_t, verify_handshake, bool, - private_tls_crypto_t *this, public_key_t *key, tls_reader_t *reader) +METHOD(tls_crypto_t, verify, bool, + private_tls_crypto_t *this, public_key_t *key, tls_reader_t *reader, + chunk_t data) { if (this->tls->get_version(this->tls) >= TLS_1_2) { @@ -834,56 +889,55 @@ METHOD(tls_crypto_t, verify_handshake, bool, !reader->read_uint8(reader, &alg) || !reader->read_data16(reader, &sig)) { - DBG1(DBG_TLS, "received invalid Certificate Verify"); + DBG1(DBG_TLS, "received invalid signature"); return FALSE; } scheme = hashsig_to_scheme(key->get_type(key), hash, alg); if (scheme == SIGN_UNKNOWN) { - DBG1(DBG_TLS, "Certificate Verify algorithms %N/%N not supported", + DBG1(DBG_TLS, "signature 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)) + if (!key->verify(key, scheme, data, sig)) { return FALSE; } - DBG2(DBG_TLS, "verified handshake data with %N/%N", + DBG2(DBG_TLS, "verified signature with %N/%N", tls_hash_algorithm_names, hash, tls_signature_algorithm_names, alg); } else { chunk_t sig, hash; + bool done; if (!reader->read_data16(reader, &sig)) { - DBG1(DBG_TLS, "received invalid Certificate Verify"); + DBG1(DBG_TLS, "received invalid signature"); return FALSE; } switch (key->get_type(key)) { case KEY_RSA: - if (!hash_handshake(this, &hash)) + if (!hash_data(this, data, &hash)) { return FALSE; } - if (!key->verify(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, sig)) + done = key->verify(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, sig); + free(hash.ptr); + if (!done) { - free(hash.ptr); return FALSE; } - DBG2(DBG_TLS, "verified handshake data with SHA1+MD5/RSA"); - free(hash.ptr); + DBG2(DBG_TLS, "verified signature data with MD5+SHA1/RSA"); break; case KEY_ECDSA: - if (!key->verify(key, SIGN_ECDSA_WITH_SHA1_DER, - this->handshake, sig)) + if (!key->verify(key, SIGN_ECDSA_WITH_SHA1_DER, data, sig)) { - free(hash.ptr); return FALSE; } - DBG2(DBG_TLS, "verified handshake data with SHA1/ECDSA"); + DBG2(DBG_TLS, "verified signature with SHA1/ECDSA"); break; default: return FALSE; @@ -892,6 +946,19 @@ METHOD(tls_crypto_t, verify_handshake, bool, return TRUE; } +METHOD(tls_crypto_t, sign_handshake, bool, + private_tls_crypto_t *this, private_key_t *key, tls_writer_t *writer, + chunk_t hashsig) +{ + return sign(this, key, writer, this->handshake, hashsig); +} + +METHOD(tls_crypto_t, verify_handshake, bool, + private_tls_crypto_t *this, public_key_t *key, tls_reader_t *reader) +{ + return verify(this, key, reader, this->handshake); +} + METHOD(tls_crypto_t, calculate_finished, bool, private_tls_crypto_t *this, char *label, char out[12]) { @@ -901,7 +968,7 @@ METHOD(tls_crypto_t, calculate_finished, bool, { return FALSE; } - if (!hash_handshake(this, &seed)) + if (!hash_data(this, this->handshake, &seed)) { return FALSE; } @@ -1062,8 +1129,11 @@ tls_crypto_t *tls_crypto_create(tls_t *tls) .public = { .get_cipher_suites = _get_cipher_suites, .select_cipher_suite = _select_cipher_suite, + .get_signature_algorithms = _get_signature_algorithms, .set_protection = _set_protection, .append_handshake = _append_handshake, + .sign = _sign, + .verify = _verify, .sign_handshake = _sign_handshake, .verify_handshake = _verify_handshake, .calculate_finished = _calculate_finished, diff --git a/src/libtls/tls_crypto.h b/src/libtls/tls_crypto.h index be4005dad..833928a8a 100644 --- a/src/libtls/tls_crypto.h +++ b/src/libtls/tls_crypto.h @@ -329,6 +329,13 @@ struct tls_crypto_t { tls_cipher_suite_t *suites, int count); /** + * Write the list of supported hash/sig algorithms to writer. + * + * @param writer writer to write supported hash/sig algorithms + */ + void (*get_signature_algorithms)(tls_crypto_t *this, tls_writer_t *writer); + + /** * Set the protection layer of the TLS stack to control it. * * @param protection protection layer to work on @@ -345,6 +352,29 @@ struct tls_crypto_t { tls_handshake_type_t type, chunk_t data); /** + * Sign a blob of data, append signature to writer. + * + * @param key private key to use for signature + * @param writer TLS writer to write signature to + * @param data data to sign + * @param hashsig list of TLS1.2 hash/sig algorithms to select from + * @return TRUE if signature create successfully + */ + bool (*sign)(tls_crypto_t *this, private_key_t *key, + tls_writer_t *writer, chunk_t data, chunk_t hashsig); + + /** + * Verify a blob of data, read signature from a reader. + * + * @param key public key to verify signature with + * @param reader TLS reader to read signature from + * @param data data to verify signature + * @return TRUE if signature valid + */ + bool (*verify)(tls_crypto_t *this, public_key_t *key, + tls_reader_t *reader, chunk_t data); + + /** * Create a signature of the handshake data using a given private key. * * @param key private key to use for signature diff --git a/src/libtls/tls_server.c b/src/libtls/tls_server.c index 493b07e69..9b38c7f7d 100644 --- a/src/libtls/tls_server.c +++ b/src/libtls/tls_server.c @@ -532,12 +532,16 @@ static status_t send_certificate(private_tls_server_t *this, } /** - * Create a list of supported certificate types and hash/sig algorithms + * Send Certificate Request */ -static void get_supported_algorithms(private_tls_server_t *this, - tls_writer_t *writer) +static status_t send_certificate_request(private_tls_server_t *this, + tls_handshake_type_t *type, tls_writer_t *writer) { - tls_writer_t *supported; + tls_writer_t *authorities, *supported; + enumerator_t *enumerator; + certificate_t *cert; + x509_t *x509; + identification_t *id; supported = tls_writer_create(4); /* we propose both RSA and ECDSA */ @@ -545,68 +549,10 @@ static void get_supported_algorithms(private_tls_server_t *this, supported->write_uint8(supported, TLS_ECDSA_SIGN); writer->write_data8(writer, supported->get_buf(supported)); supported->destroy(supported); - if (this->tls->get_version(this->tls) >= TLS_1_2) { - enumerator_t *enumerator; - hash_algorithm_t alg; - tls_hash_algorithm_t hash; - - supported = tls_writer_create(32); - enumerator = lib->crypto->create_hasher_enumerator(lib->crypto); - while (enumerator->enumerate(enumerator, &alg)) - { - switch (alg) - { - case HASH_MD5: - hash = TLS_HASH_MD5; - break; - case HASH_SHA1: - hash = TLS_HASH_SHA1; - break; - case HASH_SHA224: - hash = TLS_HASH_SHA224; - break; - case HASH_SHA256: - hash = TLS_HASH_SHA256; - break; - case HASH_SHA384: - hash = TLS_HASH_SHA384; - break; - case HASH_SHA512: - hash = TLS_HASH_SHA512; - break; - default: - continue; - } - supported->write_uint8(supported, hash); - supported->write_uint8(supported, TLS_SIG_RSA); - if (alg != HASH_MD5 && alg != HASH_SHA224) - { - supported->write_uint8(supported, hash); - supported->write_uint8(supported, TLS_SIG_ECDSA); - } - } - enumerator->destroy(enumerator); - - writer->write_data16(writer, supported->get_buf(supported)); - supported->destroy(supported); + this->crypto->get_signature_algorithms(this->crypto, writer); } -} - -/** - * Send Certificate Request - */ -static status_t send_certificate_request(private_tls_server_t *this, - tls_handshake_type_t *type, tls_writer_t *writer) -{ - tls_writer_t *authorities; - enumerator_t *enumerator; - certificate_t *cert; - x509_t *x509; - identification_t *id; - - get_supported_algorithms(this, writer); authorities = tls_writer_create(64); enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, |