On Tue, 9 Aug 2016, Denis Kenzior wrote:
Hi Mat,
On 08/08/2016 12:25 PM, Mat Martineau wrote:
> 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)) {
We don't seem to ever check the is_public variable anywhere. Should the
is_public be validated somewhere in handle_certificate?
No, just needed a valid bool* to pass in to l_key_get_info.
Also, maybe we should store public_key_size and not incur the syscall
overhead of l_key_get_info more than once?
Sure, that's what the private keys do.
> 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)
Do me a favor and remove the declaration of this function from tls-private.h
Ok.
> -{
> - 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;
>
--
Mat Martineau
Intel OTC