Keep track of the peer public key as a struct l_key (loaded in the kernel), and use that key in encrypt and verify crypto operations. --- ell/tls-private.h | 3 +- ell/tls.c | 127 ++++++++++++++++-------------------------------------- 2 files changed, 39 insertions(+), 91 deletions(-) diff --git a/ell/tls-private.h b/ell/tls-private.h index 1a47970..516d3db 100644 --- a/ell/tls-private.h +++ b/ell/tls-private.h @@ -164,8 +164,7 @@ struct l_tls { bool cert_requested, cert_sent; bool peer_authenticated; struct tls_cert *peer_cert; - uint8_t *peer_pubkey; - size_t peer_pubkey_length; + struct l_key *peer_pubkey; enum handshake_hash_type signature_hash; /* SecurityParameters current and pending */ diff --git a/ell/tls.c b/ell/tls.c index 18e5fae..da3832c 100644 --- a/ell/tls.c +++ b/ell/tls.c @@ -36,6 +36,7 @@ #include "pem.h" #include "tls-private.h" #include "cipher-private.h" +#include "key.h" void tls10_prf(const uint8_t *secret, size_t secret_len, const char *label, @@ -142,6 +143,7 @@ static void tls_reset_handshake(struct l_tls *tls) if (tls->peer_cert) { l_free(tls->peer_cert); + l_key_free(tls->peer_pubkey); tls->peer_cert = NULL; tls->peer_pubkey = NULL; @@ -860,9 +862,9 @@ static bool tls_send_rsa_client_key_xchg(struct l_tls *tls) uint8_t buf[1024 + 32]; uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; uint8_t pre_master_secret[48]; - struct l_asymmetric_cipher *rsa_server_pubkey; - int key_size; + size_t key_size; ssize_t bytes_encrypted; + bool is_public; if (!tls->peer_pubkey) { tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0); @@ -874,37 +876,30 @@ static bool tls_send_rsa_client_key_xchg(struct l_tls *tls) pre_master_secret[1] = (uint8_t) (TLS_VERSION >> 0); l_getrandom(pre_master_secret + 2, 46); - /* Fill in the RSA Client Key Exchange body */ - - rsa_server_pubkey = l_asymmetric_cipher_new(L_CIPHER_RSA_PKCS1_V1_5, - tls->peer_pubkey, - tls->peer_pubkey_length, - true); - if (!rsa_server_pubkey) { + if (!l_key_get_info(tls->peer_pubkey, L_CIPHER_RSA_PKCS1_V1_5, + L_CHECKSUM_NONE, &key_size, + &is_public)) { tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0); return false; } - key_size = l_asymmetric_cipher_get_key_size(rsa_server_pubkey); + key_size /= 8; if (key_size + 32 > (int) sizeof(buf)) { - l_asymmetric_cipher_free(rsa_server_pubkey); - tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0); return false; } l_put_be16(key_size, ptr); - bytes_encrypted = l_asymmetric_cipher_encrypt(rsa_server_pubkey, - pre_master_secret, - ptr + 2, 48, key_size); + bytes_encrypted = l_key_encrypt(tls->peer_pubkey, + L_CIPHER_RSA_PKCS1_V1_5, + L_CHECKSUM_NONE, pre_master_secret, + ptr + 2, 48, key_size); ptr += key_size + 2; - l_asymmetric_cipher_free(rsa_server_pubkey); - - if (bytes_encrypted != key_size) { + if (bytes_encrypted != (ssize_t) key_size) { tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0); return false; @@ -1006,16 +1001,15 @@ static ssize_t tls_rsa_sign(struct l_tls *tls, uint8_t *out, size_t len, static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len, tls_get_hash_t get_hash) { - struct l_asymmetric_cipher *rsa_client_pubkey; size_t key_size; - ssize_t verify_bytes; uint8_t hash[HANDSHAKE_HASH_MAX_SIZE]; size_t hash_len; enum l_checksum_type hash_type; uint8_t expected[HANDSHAKE_HASH_MAX_SIZE * 2 + 32]; size_t expected_len; - uint8_t *digest_info; unsigned int offset; + bool is_public; + bool success; /* 2 bytes for SignatureAndHashAlgorithm if version >= 1.2 */ offset = 2; @@ -1029,23 +1023,21 @@ static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len, return false; } - rsa_client_pubkey = l_asymmetric_cipher_new(L_CIPHER_RSA_PKCS1_V1_5, - tls->peer_pubkey, - tls->peer_pubkey_length, - true); - if (!rsa_client_pubkey) { + if (!l_key_get_info(tls->peer_pubkey, L_CIPHER_RSA_PKCS1_V1_5, + L_CHECKSUM_NONE, &key_size, + &is_public)) { tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0); return false; } - key_size = l_asymmetric_cipher_get_key_size(rsa_client_pubkey); + key_size /= 8; /* Only the default hash type supported */ if (len != offset + 2 + key_size) { tls_disconnect(tls, TLS_ALERT_DECODE_ERROR, 0); - goto err_free_rsa; + return false; } if (tls->negotiated_version >= TLS_V12) { @@ -1053,13 +1045,13 @@ static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len, if (in[1] != 1 /* RSA_sign */) { tls_disconnect(tls, TLS_ALERT_DECRYPT_ERROR, 0); - goto err_free_rsa; + return false; } if (!get_hash(tls, in[0], hash, &hash_len, &hash_type)) { tls_disconnect(tls, TLS_ALERT_DECRYPT_ERROR, 0); - goto err_free_rsa; + return false; } /* @@ -1091,27 +1083,14 @@ static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len, */ } - digest_info = alloca(expected_len); - - verify_bytes = l_asymmetric_cipher_verify(rsa_client_pubkey, in + 4, - digest_info, key_size, - expected_len); + success = l_key_verify(tls->peer_pubkey, L_CIPHER_RSA_PKCS1_V1_5, + L_CHECKSUM_NONE, expected, in + 4, + expected_len, key_size); - l_asymmetric_cipher_free(rsa_client_pubkey); - - if (verify_bytes != (ssize_t)expected_len || - memcmp(digest_info, expected, expected_len)) { + if (!success) tls_disconnect(tls, TLS_ALERT_DECRYPT_ERROR, 0); - return false; - } - - return true; - -err_free_rsa: - l_asymmetric_cipher_free(rsa_client_pubkey); - - return false; + return success; } static void tls_get_handshake_hash(struct l_tls *tls, @@ -1496,10 +1475,9 @@ decode_error: static void tls_handle_certificate(struct l_tls *tls, const uint8_t *buf, size_t len) { - int total, cert_len, pubkey_len; + int total, cert_len; struct tls_cert *certchain = NULL, **tail = &certchain; struct tls_cert *ca_cert = NULL; - uint8_t *pubkey; /* Length checks */ @@ -1582,26 +1560,19 @@ static void tls_handle_certificate(struct l_tls *tls, goto done; } - /* - * Save the public key from the certificate for use in premaster - * secret encryption. - */ - pubkey = tls_cert_find_pubkey(certchain, &pubkey_len); - if (!pubkey) { - tls_disconnect(tls, TLS_ALERT_UNSUPPORTED_CERT, 0); + /* Save the end-entity cert and free the rest of the chain */ + tls->peer_cert = certchain; + tls_cert_free_certchain(certchain->issuer); + certchain->issuer = NULL; + certchain = NULL; - goto done; - } + tls->peer_pubkey = l_key_new(L_KEY_RSA, tls->peer_cert->asn1, + tls->peer_cert->size); - if (pubkey) { - /* Save the end-entity cert and free the rest of the chain */ - tls->peer_cert = certchain; - tls_cert_free_certchain(certchain->issuer); - certchain->issuer = NULL; - certchain = NULL; + if (!tls->peer_pubkey) { + tls_disconnect(tls, TLS_ALERT_UNSUPPORTED_CERT, 0); - tls->peer_pubkey = pubkey; - tls->peer_pubkey_length = pubkey_len; + goto done; } if (tls->server) @@ -2505,28 +2476,6 @@ void tls_cert_free_certchain(struct tls_cert *cert) } } -uint8_t *tls_cert_find_pubkey(struct tls_cert *cert, int *pubkey_len) -{ - uint8_t *key; - size_t len; - - key = der_find_elem_by_path(cert->asn1, cert->size, ASN1_ID_BIT_STRING, - &len, - X509_CERTIFICATE_POS, - X509_TBSCERTIFICATE_POS, - X509_TBSCERT_SUBJECT_KEY_POS, - X509_SUBJECT_KEY_VALUE_POS, -1); - if (!key || len < 10) - return NULL; - - /* Skip the BIT STRING metadata byte */ - key += 1; - len -= 1; - - *pubkey_len = len; - return key; -} - enum tls_cert_key_type tls_cert_get_pubkey_type(struct tls_cert *cert) { uint8_t *key_type; -- 2.9.2