[PATCH v3 1/5] tls: Convert encrypt and verify to l_key crypto
by Mat Martineau
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 | 6 +--
ell/tls.c | 151 ++++++++++++++++--------------------------------------
2 files changed, 45 insertions(+), 112 deletions(-)
diff --git a/ell/tls-private.h b/ell/tls-private.h
index 1a47970..f4335eb 100644
--- a/ell/tls-private.h
+++ b/ell/tls-private.h
@@ -164,8 +164,8 @@ 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;
+ size_t peer_pubkey_size;
enum handshake_hash_type signature_hash;
/* SecurityParameters current and pending */
@@ -243,8 +243,6 @@ bool tls_cert_verify_certchain(struct tls_cert *certchain,
void tls_cert_free_certchain(struct tls_cert *cert);
-uint8_t *tls_cert_find_pubkey(struct tls_cert *cert, int *pubkey_len);
-
enum tls_cert_key_type tls_cert_get_pubkey_type(struct tls_cert *cert);
void tls_prf_get_bytes(struct l_tls *tls,
diff --git a/ell/tls.c b/ell/tls.c
index 18e5fae..fca6902 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,
@@ -140,12 +141,12 @@ static void tls_reset_handshake(struct l_tls *tls)
memset(tls->pending.key_block, 0, sizeof(tls->pending.key_block));
- if (tls->peer_cert) {
- l_free(tls->peer_cert);
+ l_free(tls->peer_cert);
+ l_key_free(tls->peer_pubkey);
- tls->peer_cert = NULL;
- tls->peer_pubkey = NULL;
- }
+ tls->peer_cert = NULL;
+ tls->peer_pubkey = NULL;
+ tls->peer_pubkey_size = 0;
for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
tls_drop_handshake_hash(tls, hash);
@@ -860,8 +861,6 @@ 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;
ssize_t bytes_encrypted;
if (!tls->peer_pubkey) {
@@ -874,37 +873,20 @@ 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) {
- tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
-
- return false;
- }
-
- key_size = l_asymmetric_cipher_get_key_size(rsa_server_pubkey);
-
- if (key_size + 32 > (int) sizeof(buf)) {
- l_asymmetric_cipher_free(rsa_server_pubkey);
-
+ if (tls->peer_pubkey_size + 32 > (int) sizeof(buf)) {
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);
- ptr += key_size + 2;
-
- l_asymmetric_cipher_free(rsa_server_pubkey);
+ l_put_be16(tls->peer_pubkey_size, ptr);
+ bytes_encrypted = l_key_encrypt(tls->peer_pubkey,
+ L_CIPHER_RSA_PKCS1_V1_5,
+ L_CHECKSUM_NONE, pre_master_secret,
+ ptr + 2, 48, tls->peer_pubkey_size);
+ ptr += tls->peer_pubkey_size + 2;
- if (bytes_encrypted != key_size) {
+ if (bytes_encrypted != (ssize_t) tls->peer_pubkey_size) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
return false;
@@ -1006,16 +988,13 @@ 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 success;
/* 2 bytes for SignatureAndHashAlgorithm if version >= 1.2 */
offset = 2;
@@ -1029,23 +1008,11 @@ 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) {
- tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
-
- return false;
- }
-
- key_size = l_asymmetric_cipher_get_key_size(rsa_client_pubkey);
-
/* Only the default hash type supported */
- if (len != offset + 2 + key_size) {
+ if (len != offset + 2 + tls->peer_pubkey_size) {
tls_disconnect(tls, TLS_ALERT_DECODE_ERROR, 0);
- goto err_free_rsa;
+ return false;
}
if (tls->negotiated_version >= TLS_V12) {
@@ -1053,13 +1020,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 +1058,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);
-
- l_asymmetric_cipher_free(rsa_client_pubkey);
+ success = l_key_verify(tls->peer_pubkey, L_CIPHER_RSA_PKCS1_V1_5,
+ L_CHECKSUM_NONE, expected, in + 4,
+ expected_len, tls->peer_pubkey_size);
- 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 +1450,10 @@ 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;
+ bool dummy;
/* Length checks */
@@ -1582,28 +1536,31 @@ 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) {
+ /* 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;
+
+ tls->peer_pubkey = l_key_new(L_KEY_RSA, tls->peer_cert->asn1,
+ tls->peer_cert->size);
+
+ if (!tls->peer_pubkey) {
tls_disconnect(tls, TLS_ALERT_UNSUPPORTED_CERT, 0);
goto done;
}
- 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 (!l_key_get_info(tls->peer_pubkey, L_CIPHER_RSA_PKCS1_V1_5,
+ L_CHECKSUM_NONE, &tls->peer_pubkey_size,
+ &dummy)) {
+ tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
- tls->peer_pubkey = pubkey;
- tls->peer_pubkey_length = pubkey_len;
+ goto done;
}
+ tls->peer_pubkey_size /= 8;
+
if (tls->server)
tls->state = TLS_HANDSHAKE_WAIT_KEY_EXCHANGE;
else
@@ -2505,28 +2462,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
4 years, 5 months
[PATCH v2 1/6] key: Add NULL check to l_key_get_info
by Mat Martineau
---
ell/key.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/ell/key.c b/ell/key.c
index 669d257..01489bb 100644
--- a/ell/key.c
+++ b/ell/key.c
@@ -378,6 +378,9 @@ bool l_key_get_info(struct l_key *key, enum l_asymmetric_cipher_type cipher,
enum l_checksum_type hash, size_t *bits,
bool *public)
{
+ if (unlikely(!key))
+ return false;
+
return !kernel_query_key(key->serial, lookup_cipher(cipher),
lookup_checksum(hash), bits, public);
}
--
2.9.2
4 years, 5 months
[PATCH 1/6] key: Add NULL check to l_key_get_info
by Mat Martineau
---
ell/key.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/ell/key.c b/ell/key.c
index 669d257..01489bb 100644
--- a/ell/key.c
+++ b/ell/key.c
@@ -378,6 +378,9 @@ bool l_key_get_info(struct l_key *key, enum l_asymmetric_cipher_type cipher,
enum l_checksum_type hash, size_t *bits,
bool *public)
{
+ if (unlikely(!key))
+ return false;
+
return !kernel_query_key(key->serial, lookup_cipher(cipher),
lookup_checksum(hash), bits, public);
}
--
2.9.2
4 years, 5 months
[PATCH 1/2] hwdb: Remove unutilized return value
by Mat Martineau
trie_fnmatch always returned 0. Make it return void instead.
---
ell/hwdb.c | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/ell/hwdb.c b/ell/hwdb.c
index caa8eb3..b251f27 100644
--- a/ell/hwdb.c
+++ b/ell/hwdb.c
@@ -198,8 +198,9 @@ LIB_EXPORT void l_hwdb_unref(struct l_hwdb *hwdb)
l_free(hwdb);
}
-static int trie_fnmatch(const void *addr, uint64_t offset, const char *prefix,
- const char *string, struct l_hwdb_entry **entries)
+static void trie_fnmatch(const void *addr, uint64_t offset, const char *prefix,
+ const char *string,
+ struct l_hwdb_entry **entries)
{
const struct trie_node *node = addr + offset;
const void *addr_ptr = addr + offset + sizeof(*node);
@@ -217,25 +218,22 @@ static int trie_fnmatch(const void *addr, uint64_t offset, const char *prefix,
for (i = 0; i < child_count; i++) {
const struct trie_child *child = addr_ptr;
- int err;
scratch_buf[scratch_len] = child->c;
- err = trie_fnmatch(addr, le64_to_cpu(child->child_offset),
- scratch_buf, string, entries);
- if (err)
- return err;
+ trie_fnmatch(addr, le64_to_cpu(child->child_offset),
+ scratch_buf, string, entries);
addr_ptr += sizeof(*child);
}
if (!entry_count)
- return 0;
+ return;
scratch_buf[scratch_len] = '\0';
if (fnmatch(scratch_buf, string, 0))
- return 0;
+ return;
for (i = 0; i < entry_count; i++) {
const struct trie_entry *entry = addr_ptr;
@@ -254,8 +252,6 @@ static int trie_fnmatch(const void *addr, uint64_t offset, const char *prefix,
addr_ptr += sizeof(*entry);
}
-
- return 0;
}
LIB_EXPORT struct l_hwdb_entry *l_hwdb_lookup(struct l_hwdb *hwdb,
--
2.9.2
4 years, 5 months
[PATCH v3 1/4] unit: Rename asymmetric key type to L_KEY_RSA
by Mat Martineau
---
unit/test-key.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/unit/test-key.c b/unit/test-key.c
index d52ae1b..7f5124f 100644
--- a/unit/test-key.c
+++ b/unit/test-key.c
@@ -375,9 +375,9 @@ static void test_trusted_keyring(const void *data)
&certlen);
assert(cert);
- cakey = l_key_new(L_KEY_ASYMMETRIC, cacert, cacertlen);
+ cakey = l_key_new(L_KEY_RSA, cacert, cacertlen);
assert(cakey);
- key = l_key_new(L_KEY_ASYMMETRIC, cert, certlen);
+ key = l_key_new(L_KEY_RSA, cert, certlen);
assert(key);
trust = l_keyring_new(L_KEYRING_SIMPLE, NULL);
--
2.9.2
4 years, 5 months
[PATCH v2 1/7] key: Consistently return errno from syscall wrappers
by Mat Martineau
---
ell/key.c | 44 +++++++++++++++++++++++++++++++++++++-------
1 file changed, 37 insertions(+), 7 deletions(-)
diff --git a/ell/key.c b/ell/key.c
index 6117e31..a8d011a 100644
--- a/ell/key.c
+++ b/ell/key.c
@@ -29,6 +29,7 @@
#include <stdint.h>
#include <sys/syscall.h>
#include <linux/keyctl.h>
+#include <errno.h>
#include "private.h"
#include "util.h"
@@ -64,43 +65,72 @@ static const char * const key_type_names[] = {
static long kernel_add_key(const char *type, const char *description,
const void *payload, size_t len, int32_t keyring)
{
- return syscall(__NR_add_key, type, description, payload, len, keyring);
+ long result;
+
+ result = syscall(__NR_add_key, type, description, payload, len,
+ keyring);
+
+ return result >= 0 ? result : -errno;
}
static long kernel_read_key(int32_t serial, const void *payload, size_t len)
{
- return syscall(__NR_keyctl, KEYCTL_READ, serial, payload, len);
+ long result;
+
+ result = syscall(__NR_keyctl, KEYCTL_READ, serial, payload, len);
+
+ return result >= 0 ? result : -errno;
}
static long kernel_update_key(int32_t serial, const void *payload, size_t len)
{
- return syscall(__NR_keyctl, KEYCTL_UPDATE, serial, payload, len);
+ long result;
+
+ result = syscall(__NR_keyctl, KEYCTL_UPDATE, serial, payload, len);
+
+ return result >= 0 ? result : -errno;
}
static long kernel_revoke_key(int32_t serial)
{
- return syscall(__NR_keyctl, KEYCTL_REVOKE, serial);
+ long result;
+
+ result = syscall(__NR_keyctl, KEYCTL_REVOKE, serial);
+
+ return result >= 0 ? result : -errno;
}
static long kernel_link_key(int32_t key_serial, int32_t ring_serial)
{
- return syscall(__NR_keyctl, KEYCTL_LINK, key_serial, ring_serial);
+ long result;
+
+ result = syscall(__NR_keyctl, KEYCTL_LINK, key_serial, ring_serial);
+
+ return result >= 0 ? result : -errno;
}
static long kernel_unlink_key(int32_t key_serial, int32_t ring_serial)
{
- return syscall(__NR_keyctl, KEYCTL_UNLINK, key_serial, ring_serial);
+ long result;
+
+ result = syscall(__NR_keyctl, KEYCTL_UNLINK, key_serial, ring_serial);
+
+ return result >= 0 ? result : -errno;
}
static long kernel_dh_compute(int32_t private, int32_t prime, int32_t base,
void *payload, size_t len)
{
+ long result;
+
struct keyctl_dh_params params = { .private = private,
.prime = prime,
.base = base };
- return syscall(__NR_keyctl, KEYCTL_DH_COMPUTE, ¶ms, payload, len,
+ result = syscall(__NR_keyctl, KEYCTL_DH_COMPUTE, ¶ms, payload, len,
NULL);
+
+ return result >= 0 ? result : -errno;
}
static bool setup_internal_keyring(void)
--
2.9.2
4 years, 5 months
[PATCH] hwdb: Fall back to other known paths for hwdb.bin
by Mat Martineau
l_hwdb_new_default() assumed one standard path for hwdb.bin, but it can
vary depending on distro and whether the database is immutable or
regenerated by the system.
---
ell/hwdb.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/ell/hwdb.c b/ell/hwdb.c
index 0a26299..caa8eb3 100644
--- a/ell/hwdb.c
+++ b/ell/hwdb.c
@@ -161,7 +161,16 @@ failed:
LIB_EXPORT struct l_hwdb *l_hwdb_new_default(void)
{
- return l_hwdb_new("/etc/udev/hwdb.bin");
+ struct l_hwdb *db = NULL;
+ size_t i;
+ const char * const paths[] = {"/etc/udev/hwdb.bin",
+ "/usr/lib/udev/hwdb.bin",
+ "/lib/udev/hwdb.bin"};
+
+ for (i = 0; !db && i < L_ARRAY_SIZE(paths); i++)
+ db = l_hwdb_new(paths[i]);
+
+ return db;
}
LIB_EXPORT struct l_hwdb *l_hwdb_ref(struct l_hwdb *hwdb)
--
2.9.2
4 years, 5 months