ell-key-crypto kernel branch updated
by Mat Martineau
Hello -
I've updated the ell-key-crypto kernel branch at
https://git.kernel.org/cgit/linux/kernel/git/martineau/linux.git/
This branch is based on v4.7rc2 and consists of:
* linux-fs/keys-next (for keyctl crypto ops)
* AF_ALG akcipher v8 patch set
* My keyctl restricted keyring patch set (v3)
For more background, see
https://lists.01.org/pipermail/ell/2016-May/000668.html
CONFIG_PKCS8_PRIVATE_KEY_PARSER is also required, so update the
configuration instructions to:
$ cp /boot/config-<recent kernel-version> .config
$ make olddefconfig
$ scripts/config --enable CONFIG_KEY_DH_OPERATIONS
$ scripts/config --enable CONFIG_CRYPTO_USER_API_AKCIPHER
$ scripts/config --enable CONFIG_PKCS8_PRIVATE_KEY_PARSER
$ make olddefconfig
--
Mat Martineau
Intel OTC
6 years
[PATCH v2] key: Add placeholder arg to Diffie-Hellman syscall
by Mat Martineau
The final version of the KEYCTL_DH_COMPUTE syscall that went in to
kernel 4.7 added a reserved arg. In the future, this arg will be used
to optionally specify a key derivation function. For now, it's needed
so the system call doesn't return -1 (errno == EINVAL) every time.
---
ell/key.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/ell/key.c b/ell/key.c
index adeac04..e6ae92a 100644
--- a/ell/key.c
+++ b/ell/key.c
@@ -99,7 +99,8 @@ static long kernel_dh_compute(int32_t private, int32_t prime, int32_t base,
.prime = prime,
.base = base };
- return syscall(__NR_keyctl, KEYCTL_DH_COMPUTE, ¶ms, payload, len);
+ return syscall(__NR_keyctl, KEYCTL_DH_COMPUTE, ¶ms, payload, len,
+ NULL);
}
static bool setup_internal_keyring(void)
--
2.9.0
6 years
[PATCH] key: Add placeholder arg to Diffie-Hellman syscall
by Mat Martineau
The final version of the syscall that went in to kernel 4.7 added a
reserved arg to the KEYCTL_DH_COMPUTE syscall. In the future, this arg
will be used to optionally specify a key derivation function. For now,
it's needed so the system call doesn't return -1 (errno == EINVAL)
every time.
---
ell/key.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/ell/key.c b/ell/key.c
index adeac04..e6ae92a 100644
--- a/ell/key.c
+++ b/ell/key.c
@@ -99,7 +99,8 @@ static long kernel_dh_compute(int32_t private, int32_t prime, int32_t base,
.prime = prime,
.base = base };
- return syscall(__NR_keyctl, KEYCTL_DH_COMPUTE, ¶ms, payload, len);
+ return syscall(__NR_keyctl, KEYCTL_DH_COMPUTE, ¶ms, payload, len,
+ NULL);
}
static bool setup_internal_keyring(void)
--
2.9.0
6 years
[PATCH v2] genl: Add unicast listener
by Tim Kourt
---
ell/genl.c | 113 ++++++++++++++++++++++++++++++++++++++-----------------------
ell/genl.h | 10 ++++--
2 files changed, 78 insertions(+), 45 deletions(-)
diff --git a/ell/genl.c b/ell/genl.c
index 15f4782..767bd2f 100644
--- a/ell/genl.c
+++ b/ell/genl.c
@@ -25,7 +25,6 @@
#endif
#include <errno.h>
-#include <unistd.h>
#include <sys/socket.h>
#include <linux/genetlink.h>
@@ -172,7 +171,9 @@ static void mcast_free(void *data, void *user_data)
if (genl && mcast->users > 0) {
int group = mcast->id;
- setsockopt(genl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
+ if (group)
+ setsockopt(genl->fd, SOL_NETLINK,
+ NETLINK_DROP_MEMBERSHIP,
&group, sizeof(group));
}
@@ -227,7 +228,7 @@ static void family_add_mcast(struct l_genl_family *family, const char *name,
strncpy(mcast->name, name, GENL_NAMSIZ);
mcast->id = id;
- mcast->users = 0;
+ mcast->users = id ? 0 : 1; /* id = 0 --> unicast */
l_queue_push_tail(family->mcast_list, mcast);
}
@@ -356,44 +357,6 @@ static bool match_request_seq(const void *a, const void *b)
return request->seq == seq;
}
-static void process_request(struct l_genl *genl, const struct nlmsghdr *nlmsg)
-{
- struct l_genl_msg *msg;
- struct genl_request *request;
-
- if (nlmsg->nlmsg_type == NLMSG_NOOP ||
- nlmsg->nlmsg_type == NLMSG_OVERRUN)
- return;
-
- request = l_queue_remove_if(genl->pending_list, match_request_seq,
- L_UINT_TO_PTR(nlmsg->nlmsg_seq));
- if (!request)
- return;
-
- msg = _genl_msg_create(nlmsg);
- if (!msg) {
- destroy_request(request);
- wakeup_writer(genl);
- return;
- }
-
- if (request->callback && nlmsg->nlmsg_type != NLMSG_DONE)
- request->callback(msg, request->user_data);
-
- if (nlmsg->nlmsg_flags & NLM_F_MULTI) {
- if (nlmsg->nlmsg_type == NLMSG_DONE) {
- destroy_request(request);
- wakeup_writer(genl);
- } else
- l_queue_push_head(genl->pending_list, request);
- } else {
- destroy_request(request);
- wakeup_writer(genl);
- }
-
- l_genl_msg_unref(msg);
-}
-
struct notify_type_group {
struct l_genl_msg *msg;
uint16_t type;
@@ -432,6 +395,46 @@ static void process_notify(struct l_genl *genl, uint32_t group,
l_genl_msg_unref(match.msg);
}
+static void process_request(struct l_genl *genl, const struct nlmsghdr *nlmsg)
+{
+ struct l_genl_msg *msg;
+ struct genl_request *request;
+
+ if (nlmsg->nlmsg_type == NLMSG_NOOP ||
+ nlmsg->nlmsg_type == NLMSG_OVERRUN)
+ return;
+
+ request = l_queue_remove_if(genl->pending_list, match_request_seq,
+ L_UINT_TO_PTR(nlmsg->nlmsg_seq));
+ if (!request) {
+ process_notify(genl, 0, nlmsg);
+ return;
+ }
+
+ msg = _genl_msg_create(nlmsg);
+ if (!msg) {
+ destroy_request(request);
+ wakeup_writer(genl);
+ return;
+ }
+
+ if (request->callback && nlmsg->nlmsg_type != NLMSG_DONE)
+ request->callback(msg, request->user_data);
+
+ if (nlmsg->nlmsg_flags & NLM_F_MULTI) {
+ if (nlmsg->nlmsg_type == NLMSG_DONE) {
+ destroy_request(request);
+ wakeup_writer(genl);
+ } else
+ l_queue_push_head(genl->pending_list, request);
+ } else {
+ destroy_request(request);
+ wakeup_writer(genl);
+ }
+
+ l_genl_msg_unref(msg);
+}
+
static void read_watch_destroy(void *user_data)
{
}
@@ -528,7 +531,7 @@ LIB_EXPORT struct l_genl *l_genl_new(int fd)
return l_genl_ref(genl);
}
-LIB_EXPORT struct l_genl *l_genl_new_default(void)
+LIB_EXPORT struct l_genl *l_genl_new_default_for_pid(pid_t pid)
{
struct l_genl *genl;
struct sockaddr_nl addr;
@@ -542,7 +545,7 @@ LIB_EXPORT struct l_genl *l_genl_new_default(void)
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
- addr.nl_pid = 0;
+ addr.nl_pid = pid;
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(fd);
@@ -569,6 +572,11 @@ LIB_EXPORT struct l_genl *l_genl_new_default(void)
return genl;
}
+LIB_EXPORT struct l_genl *l_genl_new_default(void)
+{
+ return l_genl_new_default_for_pid(0);
+}
+
LIB_EXPORT struct l_genl *l_genl_ref(struct l_genl *genl)
{
if (unlikely(!genl))
@@ -1232,6 +1240,9 @@ static void add_membership(struct l_genl *genl, struct genl_mcast *mcast)
{
int group = mcast->id;
+ if (!group)
+ return;
+
if (mcast->users > 0)
return;
@@ -1301,6 +1312,22 @@ LIB_EXPORT unsigned int l_genl_family_register(struct l_genl_family *family,
return notify->id;
}
+
+LIB_EXPORT unsigned int
+l_genl_family_register_ucast_listener(struct l_genl_family *family,
+ l_genl_msg_func_t ucast_listener,
+ void *user_data,
+ l_genl_destroy_func_t destroy)
+{
+ const char *unicast_group = "unicast";
+
+ if (!l_genl_family_has_group(family, unicast_group))
+ family_add_mcast(family, unicast_group, 0);
+
+ return l_genl_family_register(family, unicast_group, ucast_listener,
+ user_data, destroy);
+}
+
static bool match_notify_id(const void *a, const void *b)
{
const struct genl_notify *notify = a;
diff --git a/ell/genl.h b/ell/genl.h
index 8f5fd52..650f383 100644
--- a/ell/genl.h
+++ b/ell/genl.h
@@ -25,6 +25,7 @@
#include <stdbool.h>
#include <stdint.h>
+#include <unistd.h>
#ifdef __cplusplus
extern "C" {
@@ -37,6 +38,7 @@ struct l_genl;
struct l_genl *l_genl_new(int fd);
struct l_genl *l_genl_new_default(void);
+struct l_genl *l_genl_new_default_for_pid(pid_t pid);
struct l_genl *l_genl_ref(struct l_genl *genl);
void l_genl_unref(struct l_genl *genl);
@@ -82,6 +84,8 @@ bool l_genl_attr_recurse(struct l_genl_attr *attr, struct l_genl_attr *nested);
struct l_genl_family;
+typedef void (*l_genl_msg_func_t)(struct l_genl_msg *msg, void *user_data);
+
struct l_genl_family *l_genl_family_new(struct l_genl *genl, const char *name);
struct l_genl_family *l_genl_family_ref(struct l_genl_family *family);
@@ -94,8 +98,6 @@ bool l_genl_family_set_watches(struct l_genl_family *family,
l_genl_watch_func_t vanished,
void *user_data, l_genl_destroy_func_t destroy);
-typedef void (*l_genl_msg_func_t)(struct l_genl_msg *msg, void *user_data);
-
uint32_t l_genl_family_get_version(struct l_genl_family *family);
bool l_genl_family_can_send(struct l_genl_family *family, uint8_t cmd);
@@ -112,6 +114,10 @@ bool l_genl_family_has_group(struct l_genl_family *family, const char *group);
unsigned int l_genl_family_register(struct l_genl_family *family,
const char *group, l_genl_msg_func_t callback,
void *user_data, l_genl_destroy_func_t destroy);
+unsigned int l_genl_family_register_ucast_listener(struct l_genl_family *family,
+ l_genl_msg_func_t ucast_listener,
+ void *user_data,
+ l_genl_destroy_func_t destroy);
bool l_genl_family_unregister(struct l_genl_family *family, unsigned int id);
#ifdef __cplusplus
--
2.5.5
6 years
[PATCH] genl: Add unicast listener
by Tim Kourt
---
ell/genl.c | 113 ++++++++++++++++++++++++++++++++++++++-----------------------
ell/genl.h | 10 ++++--
2 files changed, 78 insertions(+), 45 deletions(-)
diff --git a/ell/genl.c b/ell/genl.c
index 15f4782..f0d65bd 100644
--- a/ell/genl.c
+++ b/ell/genl.c
@@ -25,7 +25,6 @@
#endif
#include <errno.h>
-#include <unistd.h>
#include <sys/socket.h>
#include <linux/genetlink.h>
@@ -172,7 +171,9 @@ static void mcast_free(void *data, void *user_data)
if (genl && mcast->users > 0) {
int group = mcast->id;
- setsockopt(genl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
+ if (group)
+ setsockopt(genl->fd, SOL_NETLINK,
+ NETLINK_DROP_MEMBERSHIP,
&group, sizeof(group));
}
@@ -227,7 +228,7 @@ static void family_add_mcast(struct l_genl_family *family, const char *name,
strncpy(mcast->name, name, GENL_NAMSIZ);
mcast->id = id;
- mcast->users = 0;
+ mcast->users = id ? 0 : 1; /* id = 0 --> unicast */
l_queue_push_tail(family->mcast_list, mcast);
}
@@ -356,44 +357,6 @@ static bool match_request_seq(const void *a, const void *b)
return request->seq == seq;
}
-static void process_request(struct l_genl *genl, const struct nlmsghdr *nlmsg)
-{
- struct l_genl_msg *msg;
- struct genl_request *request;
-
- if (nlmsg->nlmsg_type == NLMSG_NOOP ||
- nlmsg->nlmsg_type == NLMSG_OVERRUN)
- return;
-
- request = l_queue_remove_if(genl->pending_list, match_request_seq,
- L_UINT_TO_PTR(nlmsg->nlmsg_seq));
- if (!request)
- return;
-
- msg = _genl_msg_create(nlmsg);
- if (!msg) {
- destroy_request(request);
- wakeup_writer(genl);
- return;
- }
-
- if (request->callback && nlmsg->nlmsg_type != NLMSG_DONE)
- request->callback(msg, request->user_data);
-
- if (nlmsg->nlmsg_flags & NLM_F_MULTI) {
- if (nlmsg->nlmsg_type == NLMSG_DONE) {
- destroy_request(request);
- wakeup_writer(genl);
- } else
- l_queue_push_head(genl->pending_list, request);
- } else {
- destroy_request(request);
- wakeup_writer(genl);
- }
-
- l_genl_msg_unref(msg);
-}
-
struct notify_type_group {
struct l_genl_msg *msg;
uint16_t type;
@@ -432,6 +395,46 @@ static void process_notify(struct l_genl *genl, uint32_t group,
l_genl_msg_unref(match.msg);
}
+static void process_request(struct l_genl *genl, const struct nlmsghdr *nlmsg)
+{
+ struct l_genl_msg *msg;
+ struct genl_request *request;
+
+ if (nlmsg->nlmsg_type == NLMSG_NOOP ||
+ nlmsg->nlmsg_type == NLMSG_OVERRUN)
+ return;
+
+ request = l_queue_remove_if(genl->pending_list, match_request_seq,
+ L_UINT_TO_PTR(nlmsg->nlmsg_seq));
+ if (!request) {
+ process_notify(genl, 0, nlmsg);
+ return;
+ }
+
+ msg = _genl_msg_create(nlmsg);
+ if (!msg) {
+ destroy_request(request);
+ wakeup_writer(genl);
+ return;
+ }
+
+ if (request->callback && nlmsg->nlmsg_type != NLMSG_DONE)
+ request->callback(msg, request->user_data);
+
+ if (nlmsg->nlmsg_flags & NLM_F_MULTI) {
+ if (nlmsg->nlmsg_type == NLMSG_DONE) {
+ destroy_request(request);
+ wakeup_writer(genl);
+ } else
+ l_queue_push_head(genl->pending_list, request);
+ } else {
+ destroy_request(request);
+ wakeup_writer(genl);
+ }
+
+ l_genl_msg_unref(msg);
+}
+
static void read_watch_destroy(void *user_data)
{
}
@@ -528,7 +531,7 @@ LIB_EXPORT struct l_genl *l_genl_new(int fd)
return l_genl_ref(genl);
}
-LIB_EXPORT struct l_genl *l_genl_new_default(void)
+LIB_EXPORT struct l_genl *l_genl_new_default_for_pid(pid_t pid)
{
struct l_genl *genl;
struct sockaddr_nl addr;
@@ -542,7 +545,7 @@ LIB_EXPORT struct l_genl *l_genl_new_default(void)
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
- addr.nl_pid = 0;
+ addr.nl_pid = pid;
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(fd);
@@ -569,6 +572,11 @@ LIB_EXPORT struct l_genl *l_genl_new_default(void)
return genl;
}
+LIB_EXPORT struct l_genl *l_genl_new_default(void)
+{
+ return l_genl_new_default_for_pid(0);
+}
+
LIB_EXPORT struct l_genl *l_genl_ref(struct l_genl *genl)
{
if (unlikely(!genl))
@@ -1232,6 +1240,9 @@ static void add_membership(struct l_genl *genl, struct genl_mcast *mcast)
{
int group = mcast->id;
+ if (!group)
+ return;
+
if (mcast->users > 0)
return;
@@ -1301,6 +1312,22 @@ LIB_EXPORT unsigned int l_genl_family_register(struct l_genl_family *family,
return notify->id;
}
+
+LIB_EXPORT unsigned int
+l_genl_family_register_ucast_listener(struct l_genl_family *family,
+ l_genl_msg_func_t ucast_listener,
+ void *user_data,
+ l_genl_destroy_func_t destroy)
+{
+ const char *unicast_group = "unicast";
+
+ if (!l_genl_family_has_group(family, unicast_group))
+ family_add_mcast(family, unicast_group, 0);
+
+ return l_genl_family_register(family, unicast_group, ucast_listener,
+ NULL, NULL);
+}
+
static bool match_notify_id(const void *a, const void *b)
{
const struct genl_notify *notify = a;
diff --git a/ell/genl.h b/ell/genl.h
index 8f5fd52..650f383 100644
--- a/ell/genl.h
+++ b/ell/genl.h
@@ -25,6 +25,7 @@
#include <stdbool.h>
#include <stdint.h>
+#include <unistd.h>
#ifdef __cplusplus
extern "C" {
@@ -37,6 +38,7 @@ struct l_genl;
struct l_genl *l_genl_new(int fd);
struct l_genl *l_genl_new_default(void);
+struct l_genl *l_genl_new_default_for_pid(pid_t pid);
struct l_genl *l_genl_ref(struct l_genl *genl);
void l_genl_unref(struct l_genl *genl);
@@ -82,6 +84,8 @@ bool l_genl_attr_recurse(struct l_genl_attr *attr, struct l_genl_attr *nested);
struct l_genl_family;
+typedef void (*l_genl_msg_func_t)(struct l_genl_msg *msg, void *user_data);
+
struct l_genl_family *l_genl_family_new(struct l_genl *genl, const char *name);
struct l_genl_family *l_genl_family_ref(struct l_genl_family *family);
@@ -94,8 +98,6 @@ bool l_genl_family_set_watches(struct l_genl_family *family,
l_genl_watch_func_t vanished,
void *user_data, l_genl_destroy_func_t destroy);
-typedef void (*l_genl_msg_func_t)(struct l_genl_msg *msg, void *user_data);
-
uint32_t l_genl_family_get_version(struct l_genl_family *family);
bool l_genl_family_can_send(struct l_genl_family *family, uint8_t cmd);
@@ -112,6 +114,10 @@ bool l_genl_family_has_group(struct l_genl_family *family, const char *group);
unsigned int l_genl_family_register(struct l_genl_family *family,
const char *group, l_genl_msg_func_t callback,
void *user_data, l_genl_destroy_func_t destroy);
+unsigned int l_genl_family_register_ucast_listener(struct l_genl_family *family,
+ l_genl_msg_func_t ucast_listener,
+ void *user_data,
+ l_genl_destroy_func_t destroy);
bool l_genl_family_unregister(struct l_genl_family *family, unsigned int id);
#ifdef __cplusplus
--
2.5.5
6 years
[PATCH v7 1/5] tls: Check buffer bounds in tls_rsa_sign
by Mat Martineau
---
ell/tls-private.h | 2 +-
ell/tls.c | 54 ++++++++++++++++++++++++++++++++++++++----------------
2 files changed, 39 insertions(+), 17 deletions(-)
diff --git a/ell/tls-private.h b/ell/tls-private.h
index 184f2ae..1a47970 100644
--- a/ell/tls-private.h
+++ b/ell/tls-private.h
@@ -65,7 +65,7 @@ struct tls_key_exchange_algorithm {
void (*handle_client_key_exchange)(struct l_tls *tls,
const uint8_t *buf, size_t len);
- bool (*sign)(struct l_tls *tls, uint8_t **out,
+ ssize_t (*sign)(struct l_tls *tls, uint8_t *out, size_t len,
tls_get_hash_t get_hash);
bool (*verify)(struct l_tls *tls, const uint8_t *in, size_t len,
tls_get_hash_t get_hash);
diff --git a/ell/tls.c b/ell/tls.c
index 0baddf7..3bd7d7d 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -25,6 +25,7 @@
#define _GNU_SOURCE
#include <time.h>
#include <stdlib.h>
+#include <errno.h>
#include "util.h"
#include "private.h"
@@ -274,7 +275,7 @@ static bool tls_send_rsa_client_key_xchg(struct l_tls *tls);
static void tls_handle_rsa_client_key_xchg(struct l_tls *tls,
const uint8_t *buf, size_t len);
-static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
+static ssize_t tls_rsa_sign(struct l_tls *tls, uint8_t *out, size_t len,
tls_get_hash_t get_hash);
static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len,
tls_get_hash_t get_hash);
@@ -917,23 +918,25 @@ static bool tls_send_rsa_client_key_xchg(struct l_tls *tls)
return true;
}
-static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
+static ssize_t tls_rsa_sign(struct l_tls *tls, uint8_t *out, size_t len,
tls_get_hash_t get_hash)
{
struct l_asymmetric_cipher *rsa_privkey;
uint8_t *privkey;
size_t key_size;
- bool result;
+ ssize_t result;
const struct tls_hash_algorithm *hash_type;
uint8_t hash[HANDSHAKE_HASH_MAX_SIZE];
uint8_t sign_input[HANDSHAKE_HASH_MAX_SIZE * 2 + 32];
size_t sign_input_len;
+ bool prepend_hash_type = false;
+ size_t expected_bytes;
if (!tls->priv_key_path) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
TLS_ALERT_BAD_CERT);
- return false;
+ return -ENOKEY;
}
privkey = l_pem_load_private_key(tls->priv_key_path,
@@ -943,7 +946,7 @@ static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
TLS_ALERT_BAD_CERT);
- return false;
+ return -ENOKEY;
}
rsa_privkey = l_asymmetric_cipher_new(L_CIPHER_RSA_PKCS1_V1_5,
@@ -953,10 +956,11 @@ static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
if (!rsa_privkey) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
- return false;
+ return -ENOKEY;
}
key_size = l_asymmetric_cipher_get_key_size(rsa_privkey);
+ expected_bytes = key_size + 2;
if (tls->negotiated_version >= TLS_V12) {
hash_type = &tls_handshake_hash_data[tls->signature_hash];
@@ -966,21 +970,34 @@ static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
sign_input, &sign_input_len,
hash, hash_type->length);
- *(*out)++ = hash_type->tls_id;
- *(*out)++ = 1; /* RSA_sign */
+ prepend_hash_type = true;
+ expected_bytes += 2;
} else {
get_hash(tls, 1, sign_input + 0, NULL, NULL); /* MD5 */
get_hash(tls, 2, sign_input + 16, NULL, NULL); /* SHA1 */
sign_input_len = 36;
}
- l_put_be16(key_size, *out);
- result = l_asymmetric_cipher_sign(rsa_privkey, sign_input, *out + 2,
- sign_input_len, key_size);
- *out += key_size + 2;
+ result = -EMSGSIZE;
+
+ if (len >= expected_bytes) {
+ if (prepend_hash_type) {
+ *out++ = hash_type->tls_id;
+ *out++ = 1; /* RSA_sign */
+ }
+
+ l_put_be16(key_size, out);
+ if (l_asymmetric_cipher_sign(rsa_privkey, sign_input,
+ out + 2, sign_input_len,
+ key_size))
+ result = expected_bytes;
+ }
l_asymmetric_cipher_free(rsa_privkey);
+ if (result < 0)
+ tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
+
return result;
}
@@ -1137,13 +1154,17 @@ static bool tls_get_handshake_hash_by_id(struct l_tls *tls, uint8_t hash_id,
static bool tls_send_certificate_verify(struct l_tls *tls)
{
uint8_t buf[2048];
- uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
int i;
+ ssize_t sign_len;
/* Fill in the Certificate Verify body */
- if (!tls->pending.cipher_suite->key_xchg->sign(tls, &ptr,
- tls_get_handshake_hash_by_id))
+ sign_len = tls->pending.cipher_suite->key_xchg->sign(tls,
+ buf + TLS_HANDSHAKE_HEADER_SIZE,
+ 2048 - TLS_HANDSHAKE_HEADER_SIZE,
+ tls_get_handshake_hash_by_id);
+
+ if (sign_len < 0)
return false;
/* Stop maintaining handshake message hashes other than SHA256. */
@@ -1152,7 +1173,8 @@ static bool tls_send_certificate_verify(struct l_tls *tls)
if (i != HANDSHAKE_HASH_SHA256)
tls_drop_handshake_hash(tls, i);
- tls_tx_handshake(tls, TLS_CERTIFICATE_VERIFY, buf, ptr - buf);
+ tls_tx_handshake(tls, TLS_CERTIFICATE_VERIFY, buf,
+ sign_len + TLS_HANDSHAKE_HEADER_SIZE);
return true;
}
--
2.9.0
6 years
[PATCH v6 1/5] tls: Check buffer bounds in tls_rsa_sign
by Mat Martineau
---
ell/tls-private.h | 2 +-
ell/tls.c | 55 +++++++++++++++++++++++++++++++++++++++----------------
2 files changed, 40 insertions(+), 17 deletions(-)
diff --git a/ell/tls-private.h b/ell/tls-private.h
index 184f2ae..1a47970 100644
--- a/ell/tls-private.h
+++ b/ell/tls-private.h
@@ -65,7 +65,7 @@ struct tls_key_exchange_algorithm {
void (*handle_client_key_exchange)(struct l_tls *tls,
const uint8_t *buf, size_t len);
- bool (*sign)(struct l_tls *tls, uint8_t **out,
+ ssize_t (*sign)(struct l_tls *tls, uint8_t *out, size_t len,
tls_get_hash_t get_hash);
bool (*verify)(struct l_tls *tls, const uint8_t *in, size_t len,
tls_get_hash_t get_hash);
diff --git a/ell/tls.c b/ell/tls.c
index 0baddf7..e03b464 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -25,6 +25,7 @@
#define _GNU_SOURCE
#include <time.h>
#include <stdlib.h>
+#include <errno.h>
#include "util.h"
#include "private.h"
@@ -274,7 +275,7 @@ static bool tls_send_rsa_client_key_xchg(struct l_tls *tls);
static void tls_handle_rsa_client_key_xchg(struct l_tls *tls,
const uint8_t *buf, size_t len);
-static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
+static ssize_t tls_rsa_sign(struct l_tls *tls, uint8_t *out, size_t len,
tls_get_hash_t get_hash);
static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len,
tls_get_hash_t get_hash);
@@ -917,23 +918,25 @@ static bool tls_send_rsa_client_key_xchg(struct l_tls *tls)
return true;
}
-static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
+static ssize_t tls_rsa_sign(struct l_tls *tls, uint8_t *out, size_t len,
tls_get_hash_t get_hash)
{
struct l_asymmetric_cipher *rsa_privkey;
uint8_t *privkey;
size_t key_size;
- bool result;
+ ssize_t result;
const struct tls_hash_algorithm *hash_type;
uint8_t hash[HANDSHAKE_HASH_MAX_SIZE];
uint8_t sign_input[HANDSHAKE_HASH_MAX_SIZE * 2 + 32];
size_t sign_input_len;
+ bool prepend_hash_type = false;
+ size_t expected_bytes;
if (!tls->priv_key_path) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
TLS_ALERT_BAD_CERT);
- return false;
+ return -ENOKEY;
}
privkey = l_pem_load_private_key(tls->priv_key_path,
@@ -943,7 +946,7 @@ static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
TLS_ALERT_BAD_CERT);
- return false;
+ return -ENOKEY;
}
rsa_privkey = l_asymmetric_cipher_new(L_CIPHER_RSA_PKCS1_V1_5,
@@ -953,10 +956,11 @@ static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
if (!rsa_privkey) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
- return false;
+ return -ENOKEY;
}
key_size = l_asymmetric_cipher_get_key_size(rsa_privkey);
+ expected_bytes = key_size + 2;
if (tls->negotiated_version >= TLS_V12) {
hash_type = &tls_handshake_hash_data[tls->signature_hash];
@@ -966,18 +970,32 @@ static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
sign_input, &sign_input_len,
hash, hash_type->length);
- *(*out)++ = hash_type->tls_id;
- *(*out)++ = 1; /* RSA_sign */
+ prepend_hash_type = true;
+ expected_bytes += 2;
} else {
get_hash(tls, 1, sign_input + 0, NULL, NULL); /* MD5 */
get_hash(tls, 2, sign_input + 16, NULL, NULL); /* SHA1 */
sign_input_len = 36;
}
- l_put_be16(key_size, *out);
- result = l_asymmetric_cipher_sign(rsa_privkey, sign_input, *out + 2,
- sign_input_len, key_size);
- *out += key_size + 2;
+ if (len >= expected_bytes) {
+ if (prepend_hash_type) {
+ *out++ = hash_type->tls_id;
+ *out++ = 1; /* RSA_sign */
+ }
+
+ l_put_be16(key_size, out);
+ if (l_asymmetric_cipher_sign(rsa_privkey, sign_input,
+ out + 2, sign_input_len,
+ key_size)) {
+ result = expected_bytes;
+ } else {
+ result = -EMSGSIZE;
+ }
+ } else {
+ tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
+ result = -EMSGSIZE;
+ }
l_asymmetric_cipher_free(rsa_privkey);
@@ -1137,13 +1155,17 @@ static bool tls_get_handshake_hash_by_id(struct l_tls *tls, uint8_t hash_id,
static bool tls_send_certificate_verify(struct l_tls *tls)
{
uint8_t buf[2048];
- uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
int i;
+ ssize_t sign_len;
/* Fill in the Certificate Verify body */
- if (!tls->pending.cipher_suite->key_xchg->sign(tls, &ptr,
- tls_get_handshake_hash_by_id))
+ sign_len = tls->pending.cipher_suite->key_xchg->sign(tls,
+ buf + TLS_HANDSHAKE_HEADER_SIZE,
+ 2048 - TLS_HANDSHAKE_HEADER_SIZE,
+ tls_get_handshake_hash_by_id);
+
+ if (sign_len < 0)
return false;
/* Stop maintaining handshake message hashes other than SHA256. */
@@ -1152,7 +1174,8 @@ static bool tls_send_certificate_verify(struct l_tls *tls)
if (i != HANDSHAKE_HASH_SHA256)
tls_drop_handshake_hash(tls, i);
- tls_tx_handshake(tls, TLS_CERTIFICATE_VERIFY, buf, ptr - buf);
+ tls_tx_handshake(tls, TLS_CERTIFICATE_VERIFY, buf,
+ sign_len + TLS_HANDSHAKE_HEADER_SIZE);
return true;
}
--
2.9.0
6 years
[PATCH v5 1/5] tls: Check buffer bounds in tls_rsa_sign
by Mat Martineau
---
ell/tls-private.h | 2 +-
ell/tls.c | 29 ++++++++++++++++++++++-------
2 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/ell/tls-private.h b/ell/tls-private.h
index 184f2ae..9ea1554 100644
--- a/ell/tls-private.h
+++ b/ell/tls-private.h
@@ -65,7 +65,7 @@ struct tls_key_exchange_algorithm {
void (*handle_client_key_exchange)(struct l_tls *tls,
const uint8_t *buf, size_t len);
- bool (*sign)(struct l_tls *tls, uint8_t **out,
+ bool (*sign)(struct l_tls *tls, uint8_t **out, size_t len,
tls_get_hash_t get_hash);
bool (*verify)(struct l_tls *tls, const uint8_t *in, size_t len,
tls_get_hash_t get_hash);
diff --git a/ell/tls.c b/ell/tls.c
index 0baddf7..90404e4 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -274,7 +274,7 @@ static bool tls_send_rsa_client_key_xchg(struct l_tls *tls);
static void tls_handle_rsa_client_key_xchg(struct l_tls *tls,
const uint8_t *buf, size_t len);
-static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
+static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out, size_t len,
tls_get_hash_t get_hash);
static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len,
tls_get_hash_t get_hash);
@@ -917,7 +917,7 @@ static bool tls_send_rsa_client_key_xchg(struct l_tls *tls)
return true;
}
-static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
+static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out, size_t len,
tls_get_hash_t get_hash)
{
struct l_asymmetric_cipher *rsa_privkey;
@@ -929,6 +929,12 @@ static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
uint8_t sign_input[HANDSHAKE_HASH_MAX_SIZE * 2 + 32];
size_t sign_input_len;
+ if (len < 2) {
+ tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
+
+ return false;
+ }
+
if (!tls->priv_key_path) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
TLS_ALERT_BAD_CERT);
@@ -968,16 +974,24 @@ static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
*(*out)++ = hash_type->tls_id;
*(*out)++ = 1; /* RSA_sign */
+ len -= 2;
} else {
get_hash(tls, 1, sign_input + 0, NULL, NULL); /* MD5 */
get_hash(tls, 2, sign_input + 16, NULL, NULL); /* SHA1 */
sign_input_len = 36;
}
- l_put_be16(key_size, *out);
- result = l_asymmetric_cipher_sign(rsa_privkey, sign_input, *out + 2,
- sign_input_len, key_size);
- *out += key_size + 2;
+ if (len >= key_size + 2) {
+ l_put_be16(key_size, *out);
+ result = l_asymmetric_cipher_sign(rsa_privkey, sign_input,
+ *out + 2,
+ sign_input_len,
+ key_size);
+ *out += key_size + 2;
+ } else {
+ tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
+ result = false;
+ }
l_asymmetric_cipher_free(rsa_privkey);
@@ -1143,7 +1157,8 @@ static bool tls_send_certificate_verify(struct l_tls *tls)
/* Fill in the Certificate Verify body */
if (!tls->pending.cipher_suite->key_xchg->sign(tls, &ptr,
- tls_get_handshake_hash_by_id))
+ 2048 - TLS_HANDSHAKE_HEADER_SIZE,
+ tls_get_handshake_hash_by_id))
return false;
/* Stop maintaining handshake message hashes other than SHA256. */
--
2.9.0
6 years
[PATCH v4 1/6] cipher: Update for current kernel akcipher interface
by Mat Martineau
There are some significant differences in the current iteration of
kernel AF_ALG akcipher support:
* Kernel handles padding
* Kernel accepts DER-encoded certs as-is (no need to extract values)
* Must explicitly set private or public key
---
ell/cipher-private.h | 3 -
ell/cipher.c | 305 +++++++++++++--------------------------------------
ell/cipher.h | 3 +-
ell/tls.c | 54 ++++-----
4 files changed, 101 insertions(+), 264 deletions(-)
diff --git a/ell/cipher-private.h b/ell/cipher-private.h
index 7d115f6..77ddd06 100644
--- a/ell/cipher-private.h
+++ b/ell/cipher-private.h
@@ -20,9 +20,6 @@
*
*/
-uint8_t *extract_rsakey(uint8_t *pkcs1_key, size_t pkcs1_key_len,
- size_t *out_len);
-
#define ASN1_ID(class, pc, tag) (((class) << 6) | ((pc) << 5) | (tag))
#define ASN1_CLASS_UNIVERSAL 0
diff --git a/ell/cipher.c b/ell/cipher.c
index 671071b..04ef838 100644
--- a/ell/cipher.c
+++ b/ell/cipher.c
@@ -78,6 +78,17 @@ struct af_alg_iv {
#define SOL_ALG 279
#endif
+#ifndef ALG_OP_SIGN
+#define ALG_OP_SIGN 2
+#endif
+#ifndef ALG_OP_VERIFY
+#define ALG_OP_VERIFY 3
+#endif
+
+#ifndef ALG_SET_PUBKEY
+#define ALG_SET_PUBKEY 6
+#endif
+
#define is_valid_type(type) ((type) <= L_CIPHER_DES3_EDE_CBC)
struct l_cipher {
@@ -87,10 +98,11 @@ struct l_cipher {
};
static int create_alg(const char *alg_type, const char *alg_name,
- const void *key, size_t key_length)
+ const void *key, size_t key_length, bool public)
{
struct sockaddr_alg salg;
int sk;
+ int keyopt;
int ret;
sk = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
@@ -107,7 +119,8 @@ static int create_alg(const char *alg_type, const char *alg_name,
return -1;
}
- if (setsockopt(sk, SOL_ALG, ALG_SET_KEY, key, key_length) < 0) {
+ keyopt = public ? ALG_SET_PUBKEY : ALG_SET_KEY;
+ if (setsockopt(sk, SOL_ALG, keyopt, key, key_length) < 0) {
close(sk);
return -1;
}
@@ -149,11 +162,13 @@ LIB_EXPORT struct l_cipher *l_cipher_new(enum l_cipher_type type,
break;
}
- cipher->encrypt_sk = create_alg("skcipher", alg_name, key, key_length);
+ cipher->encrypt_sk = create_alg("skcipher", alg_name, key, key_length,
+ false);
if (cipher->encrypt_sk < 0)
goto error_free;
- cipher->decrypt_sk = create_alg("skcipher", alg_name, key, key_length);
+ cipher->decrypt_sk = create_alg("skcipher", alg_name, key, key_length,
+ false);
if (cipher->decrypt_sk < 0)
goto error_close;
@@ -178,7 +193,8 @@ LIB_EXPORT void l_cipher_free(struct l_cipher *cipher)
}
static bool operate_cipher(int sk, __u32 operation,
- const void *in, void *out, size_t len)
+ const void *in, void *out, size_t len_in,
+ size_t len_out)
{
char c_msg_buf[CMSG_SPACE(sizeof(operation))];
struct msghdr msg;
@@ -198,7 +214,7 @@ static bool operate_cipher(int sk, __u32 operation,
memcpy(CMSG_DATA(c_msg), &operation, sizeof(operation));
iov.iov_base = (void *) in;
- iov.iov_len = len;
+ iov.iov_len = len_in;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
@@ -206,7 +222,7 @@ static bool operate_cipher(int sk, __u32 operation,
if (sendmsg(sk, &msg, 0) < 0)
return false;
- if (read(sk, out, len) < 0)
+ if (read(sk, out, len_out) < 0)
return false;
return true;
@@ -221,7 +237,8 @@ LIB_EXPORT bool l_cipher_encrypt(struct l_cipher *cipher,
if (unlikely(!in) || unlikely(!out))
return false;
- return operate_cipher(cipher->encrypt_sk, ALG_OP_ENCRYPT, in, out, len);
+ return operate_cipher(cipher->encrypt_sk, ALG_OP_ENCRYPT, in, out, len,
+ len);
}
LIB_EXPORT bool l_cipher_decrypt(struct l_cipher *cipher,
@@ -233,7 +250,8 @@ LIB_EXPORT bool l_cipher_decrypt(struct l_cipher *cipher,
if (unlikely(!in) || unlikely(!out))
return false;
- return operate_cipher(cipher->decrypt_sk, ALG_OP_DECRYPT, in, out, len);
+ return operate_cipher(cipher->decrypt_sk, ALG_OP_DECRYPT, in, out, len,
+ len);
}
LIB_EXPORT bool l_cipher_set_iv(struct l_cipher *cipher, const uint8_t *iv,
@@ -334,7 +352,9 @@ static bool parse_rsa_key(struct l_asymmetric_cipher *cipher, const void *key,
* and cache the size of the modulus n for later use.
* (RFC3279)
*/
+ size_t seq_length;
size_t n_length;
+ uint8_t *seq;
uint8_t *der;
uint8_t tag;
@@ -342,12 +362,19 @@ static bool parse_rsa_key(struct l_asymmetric_cipher *cipher, const void *key,
return false;
/* Unpack the outer SEQUENCE */
- der = der_find_elem((uint8_t *) key, key_length, 0, &tag, &n_length);
- if (!der || tag != ASN1_ID_SEQUENCE)
+ seq = der_find_elem((uint8_t *) key, key_length, 0, &tag, &seq_length);
+ if (!seq || tag != ASN1_ID_SEQUENCE)
return false;
- /* Take first INTEGER as the modulus */
- der = der_find_elem(der, n_length, 0, &tag, &n_length);
+ /* First INTEGER may be a 1-byte version (for private key) or
+ * the modulus (public key)
+ */
+ der = der_find_elem(seq, seq_length, 0, &tag, &n_length);
+ if (der && tag == ASN1_ID_INTEGER && n_length == 1) {
+ /* Found version number, implies this is a private key. */
+ der = der_find_elem(seq, seq_length, 1, &tag, &n_length);
+ }
+
if (!der || tag != ASN1_ID_INTEGER || n_length < 4)
return false;
@@ -362,94 +389,10 @@ static bool parse_rsa_key(struct l_asymmetric_cipher *cipher, const void *key,
return true;
}
-static void write_asn1_definite_length(uint8_t **buf, size_t len)
-{
- int n;
-
- if (len < 0x80) {
- *(*buf)++ = len;
-
- return;
- }
-
- for (n = 1; len >> (n * 8); n++);
- *(*buf)++ = 0x80 | n;
-
- while (n--)
- *(*buf)++ = len >> (n * 8);
-}
-
-/*
- * Extract a ASN1 RsaKey-formatted public+private key structure in the
- * form used in the kernel. It is simpler than the PKCS#1 form as it only
- * contains the N, E and D integers and also correctly parses as a PKCS#1
- * RSAPublicKey.
- */
-uint8_t *extract_rsakey(uint8_t *pkcs1_key, size_t pkcs1_key_len,
- size_t *out_len)
-{
- uint8_t *key, *ptr, *ver, *n, *e, *d;
- uint8_t tag;
- size_t ver_len, n_len, e_len, d_len;
- int pos;
-
- /* Unpack the outer SEQUENCE */
- pkcs1_key = der_find_elem(pkcs1_key, pkcs1_key_len, 0, &tag,
- &pkcs1_key_len);
- if (!pkcs1_key || tag != ASN1_ID_SEQUENCE)
- return NULL;
-
- /* Check if the version element if present */
- ver = der_find_elem(pkcs1_key, pkcs1_key_len, 0, &tag, &ver_len);
- if (!ver || tag != ASN1_ID_INTEGER)
- return NULL;
-
- pos = (ver_len == 1 && ver[0] == 0x00) ? 1 : 0;
-
- n = der_find_elem(pkcs1_key, pkcs1_key_len, pos + 0, &tag, &n_len);
- if (!n || tag != ASN1_ID_INTEGER)
- return NULL;
-
- e = der_find_elem(pkcs1_key, pkcs1_key_len, pos + 1, &tag, &e_len);
- if (!e || tag != ASN1_ID_INTEGER)
- return NULL;
-
- d = der_find_elem(pkcs1_key, pkcs1_key_len, pos + 2, &tag, &d_len);
- if (!d || tag != ASN1_ID_INTEGER)
- return NULL;
-
- /* New SEQUENCE length including tags and lengths */
- *out_len = 1 + (n_len >= 0x80 ? n_len >= 0x100 ? 3 : 2 : 1) + n_len +
- 1 + (e_len >= 0x80 ? e_len >= 0x100 ? 3 : 2 : 1) + e_len +
- 1 + (d_len >= 0x80 ? d_len >= 0x100 ? 3 : 2 : 1) + d_len;
- ptr = key = l_malloc(*out_len +
- 1 + (*out_len >= 0x80 ? *out_len >= 0x100 ? 3 : 2 : 1));
-
- *ptr++ = ASN1_ID_SEQUENCE;
- write_asn1_definite_length(&ptr, *out_len);
-
- *ptr++ = ASN1_ID_INTEGER;
- write_asn1_definite_length(&ptr, n_len);
- memcpy(ptr, n, n_len);
- ptr += n_len;
-
- *ptr++ = ASN1_ID_INTEGER;
- write_asn1_definite_length(&ptr, e_len);
- memcpy(ptr, e, e_len);
- ptr += e_len;
-
- *ptr++ = ASN1_ID_INTEGER;
- write_asn1_definite_length(&ptr, d_len);
- memcpy(ptr, d, d_len);
- ptr += d_len;
-
- *out_len = ptr - key;
- return key;
-}
-
LIB_EXPORT struct l_asymmetric_cipher *l_asymmetric_cipher_new(
enum l_asymmetric_cipher_type type,
- const void *key, size_t key_length)
+ const void *key, size_t key_length,
+ bool public_key)
{
struct l_asymmetric_cipher *cipher;
const char *alg_name;
@@ -468,19 +411,22 @@ LIB_EXPORT struct l_asymmetric_cipher *l_asymmetric_cipher_new(
if (!parse_rsa_key(cipher, key, key_length))
goto error_free;
- alg_name = "rsa";
+ alg_name = "pkcs1pad(rsa)";
break;
}
cipher->cipher.encrypt_sk = create_alg("akcipher", alg_name,
- key, key_length);
+ key, key_length, public_key);
if (cipher->cipher.encrypt_sk < 0)
goto error_free;
- cipher->cipher.decrypt_sk = create_alg("akcipher", alg_name,
- key, key_length);
- if (cipher->cipher.decrypt_sk < 0)
- goto error_close;
+ if (public_key) {
+ cipher->cipher.decrypt_sk = create_alg("akcipher", alg_name,
+ key, key_length,
+ public_key);
+ if (cipher->cipher.decrypt_sk < 0)
+ goto error_close;
+ }
return cipher;
@@ -508,151 +454,58 @@ LIB_EXPORT int l_asymmetric_cipher_get_key_size(
return cipher->key_size;
}
-static void getrandom_nonzero(uint8_t *buf, int len)
-{
- while (len--) {
- l_getrandom(buf, 1);
- while (buf[0] == 0)
- l_getrandom(buf, 1);
-
- buf++;
- }
-}
-
LIB_EXPORT bool l_asymmetric_cipher_encrypt(struct l_asymmetric_cipher *cipher,
const void *in, void *out,
size_t len_in, size_t len_out)
{
- if (cipher->cipher.type == L_CIPHER_RSA_PKCS1_V1_5) {
- /* PKCS#1 v1.5 RSA padding according to RFC3447 */
- uint8_t buf[cipher->key_size];
- int ps_len = cipher->key_size - len_in - 3;
-
- if (len_in > (size_t) cipher->key_size - 11)
- return false;
- if (len_out != (size_t) cipher->key_size)
- return false;
-
- buf[0] = 0x00;
- buf[1] = 0x02;
- getrandom_nonzero(buf + 2, ps_len);
- buf[ps_len + 2] = 0x00;
- memcpy(buf + ps_len + 3, in, len_in);
-
- if (!l_cipher_encrypt(&cipher->cipher, buf, out,
- cipher->key_size))
- return false;
- }
+ if (unlikely(!cipher))
+ return false;
- return true;
+ if (unlikely(!in) || unlikely(!out))
+ return false;
+
+ return operate_cipher(cipher->cipher.encrypt_sk, ALG_OP_ENCRYPT,
+ in, out, len_in, len_out);
}
LIB_EXPORT bool l_asymmetric_cipher_decrypt(struct l_asymmetric_cipher *cipher,
const void *in, void *out,
size_t len_in, size_t len_out)
{
- if (cipher->cipher.type == L_CIPHER_RSA_PKCS1_V1_5) {
- /* PKCS#1 v1.5 RSA padding according to RFC3447 */
- uint8_t buf[cipher->key_size];
- int pos;
-
- if (len_in != (size_t) cipher->key_size)
- return false;
-
- if (!l_cipher_decrypt(&cipher->cipher, in, buf,
- cipher->key_size))
- return false;
-
- if (buf[0] != 0x00)
- return false;
- if (buf[1] != 0x02)
- return false;
-
- for (pos = 2; pos < cipher->key_size; pos++)
- if (buf[pos] == 0)
- break;
- if (pos < 10 || pos == cipher->key_size)
- return false;
-
- pos++;
- if (len_out != (size_t) cipher->key_size - pos)
- return false;
-
- memcpy(out, buf + pos, cipher->key_size - pos);
- }
+ if (unlikely(!cipher))
+ return false;
- return true;
+ if (unlikely(!in) || unlikely(!out))
+ return false;
+
+ return operate_cipher(cipher->cipher.decrypt_sk, ALG_OP_DECRYPT,
+ in, out, len_in, len_out);
}
LIB_EXPORT bool l_asymmetric_cipher_sign(struct l_asymmetric_cipher *cipher,
const void *in, void *out,
size_t len_in, size_t len_out)
{
- if (cipher->cipher.type == L_CIPHER_RSA_PKCS1_V1_5) {
- /* PKCS#1 v1.5 RSA padding according to RFC3447 */
- uint8_t buf[cipher->key_size];
- int ps_len = cipher->key_size - len_in - 3;
-
- if (len_in > (size_t) cipher->key_size - 11)
- return false;
- if (len_out != (size_t) cipher->key_size)
- return false;
-
- buf[0] = 0x00;
- buf[1] = 0x01;
- memset(buf + 2, 0xff, ps_len);
- buf[ps_len + 2] = 0x00;
- memcpy(buf + ps_len + 3, in, len_in);
-
- /*
- * The RSA signing operation uses the same primitive as
- * decryption so just call decrypt for now.
- */
- if (!l_cipher_decrypt(&cipher->cipher, buf, out,
- cipher->key_size))
- return false;
- }
+ if (unlikely(!cipher))
+ return false;
- return true;
+ if (unlikely(!in) || unlikely(!out))
+ return false;
+
+ return operate_cipher(cipher->cipher.decrypt_sk, ALG_OP_SIGN,
+ in, out, len_in, len_out);
}
LIB_EXPORT bool l_asymmetric_cipher_verify(struct l_asymmetric_cipher *cipher,
const void *in, void *out,
size_t len_in, size_t len_out)
{
- if (cipher->cipher.type == L_CIPHER_RSA_PKCS1_V1_5) {
- /* PKCS#1 v1.5 RSA padding according to RFC3447 */
- uint8_t buf[cipher->key_size];
- int pos;
-
- if (len_in != (size_t) cipher->key_size)
- return false;
-
- /*
- * The RSA verify operation uses the same primitive as
- * encryption so just call encrypt.
- */
- if (!l_cipher_encrypt(&cipher->cipher, in, buf,
- cipher->key_size))
- return false;
-
- if (buf[0] != 0x00)
- return false;
- if (buf[1] != 0x01)
- return false;
-
- for (pos = 2; pos < cipher->key_size; pos++)
- if (buf[pos] != 0xff)
- break;
- if (pos < 10 || pos == cipher->key_size || buf[pos] != 0)
- return false;
-
- pos++;
- if (len_out != (size_t) cipher->key_size - pos)
- return false;
-
- memcpy(out, buf + pos, cipher->key_size - pos);
- }
+ if (unlikely(!cipher))
+ return false;
- return true;
+ if (unlikely(!in) || unlikely(!out))
+ return false;
+
+ return operate_cipher(cipher->cipher.encrypt_sk, ALG_OP_VERIFY,
+ in, out, len_in, len_out);
}
diff --git a/ell/cipher.h b/ell/cipher.h
index 329f667..b958804 100644
--- a/ell/cipher.h
+++ b/ell/cipher.h
@@ -58,7 +58,8 @@ enum l_asymmetric_cipher_type {
struct l_asymmetric_cipher *l_asymmetric_cipher_new(
enum l_asymmetric_cipher_type type,
- const void *key, size_t key_length);
+ const void *key, size_t key_length,
+ bool public_key);
void l_asymmetric_cipher_free(struct l_asymmetric_cipher *cipher);
diff --git a/ell/tls.c b/ell/tls.c
index a20236f..0baddf7 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -876,8 +876,9 @@ static bool tls_send_rsa_client_key_xchg(struct l_tls *tls)
/* 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);
+ tls->peer_pubkey,
+ tls->peer_pubkey_length,
+ true);
if (!rsa_server_pubkey) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
@@ -920,8 +921,8 @@ static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
tls_get_hash_t get_hash)
{
struct l_asymmetric_cipher *rsa_privkey;
- uint8_t *privkey, *privkey_short;
- size_t key_size, short_size;
+ uint8_t *privkey;
+ size_t key_size;
bool result;
const struct tls_hash_algorithm *hash_type;
uint8_t hash[HANDSHAKE_HASH_MAX_SIZE];
@@ -945,19 +946,9 @@ static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
return false;
}
- privkey_short = extract_rsakey(privkey, key_size, &short_size);
- tls_free_key(privkey, key_size);
-
- if (!privkey_short) {
- tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
- TLS_ALERT_BAD_CERT);
-
- return false;
- }
-
rsa_privkey = l_asymmetric_cipher_new(L_CIPHER_RSA_PKCS1_V1_5,
- privkey_short, short_size);
- tls_free_key(privkey_short, short_size);
+ privkey, key_size, false);
+ tls_free_key(privkey, key_size);
if (!rsa_privkey) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
@@ -1020,8 +1011,9 @@ static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len,
}
rsa_client_pubkey = l_asymmetric_cipher_new(L_CIPHER_RSA_PKCS1_V1_5,
- tls->peer_pubkey,
- tls->peer_pubkey_length);
+ tls->peer_pubkey,
+ tls->peer_pubkey_length,
+ true);
if (!rsa_client_pubkey) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
@@ -1080,11 +1072,14 @@ static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len,
*/
}
- digest_info = alloca(expected_len);
+ if (expected_len > key_size)
+ goto err_free_rsa;
+
+ digest_info = alloca(key_size);
result = l_asymmetric_cipher_verify(rsa_client_pubkey, in + 4,
digest_info,
- key_size, expected_len);
+ key_size, key_size);
l_asymmetric_cipher_free(rsa_client_pubkey);
@@ -1743,8 +1738,8 @@ static void tls_handle_rsa_client_key_xchg(struct l_tls *tls,
{
uint8_t pre_master_secret[48], random_secret[46];
struct l_asymmetric_cipher *rsa_server_privkey;
- uint8_t *privkey, *privkey_short;
- size_t key_size, short_size;
+ uint8_t *privkey;
+ size_t key_size;
bool result;
if (!tls->priv_key_path) {
@@ -1764,19 +1759,10 @@ static void tls_handle_rsa_client_key_xchg(struct l_tls *tls,
return;
}
- privkey_short = extract_rsakey(privkey, key_size, &short_size);
- tls_free_key(privkey, key_size);
-
- if (!privkey_short) {
- tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
- TLS_ALERT_BAD_CERT);
-
- return;
- }
-
rsa_server_privkey = l_asymmetric_cipher_new(L_CIPHER_RSA_PKCS1_V1_5,
- privkey_short, short_size);
- tls_free_key(privkey_short, short_size);
+ privkey, key_size,
+ false);
+ tls_free_key(privkey, key_size);
if (!rsa_server_privkey) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
--
2.9.0
6 years
[PATCH v3 1/5] cipher: Update for current kernel akcipher interface
by Mat Martineau
There are some significant differences in the current iteration of
kernel AF_ALG akcipher support:
* Kernel handles padding
* Kernel accepts DER-encoded certs as-is (no need to extract values)
* Must explicitly set private or public key
---
ell/cipher-private.h | 3 -
ell/cipher.c | 311 ++++++++++++++-------------------------------------
ell/tls.c | 43 +++----
3 files changed, 97 insertions(+), 260 deletions(-)
diff --git a/ell/cipher-private.h b/ell/cipher-private.h
index 7d115f6..77ddd06 100644
--- a/ell/cipher-private.h
+++ b/ell/cipher-private.h
@@ -20,9 +20,6 @@
*
*/
-uint8_t *extract_rsakey(uint8_t *pkcs1_key, size_t pkcs1_key_len,
- size_t *out_len);
-
#define ASN1_ID(class, pc, tag) (((class) << 6) | ((pc) << 5) | (tag))
#define ASN1_CLASS_UNIVERSAL 0
diff --git a/ell/cipher.c b/ell/cipher.c
index 671071b..f23bdda 100644
--- a/ell/cipher.c
+++ b/ell/cipher.c
@@ -78,6 +78,17 @@ struct af_alg_iv {
#define SOL_ALG 279
#endif
+#ifndef ALG_OP_SIGN
+#define ALG_OP_SIGN 2
+#endif
+#ifndef ALG_OP_VERIFY
+#define ALG_OP_VERIFY 3
+#endif
+
+#ifndef ALG_SET_PUBKEY
+#define ALG_SET_PUBKEY 6
+#endif
+
#define is_valid_type(type) ((type) <= L_CIPHER_DES3_EDE_CBC)
struct l_cipher {
@@ -87,10 +98,11 @@ struct l_cipher {
};
static int create_alg(const char *alg_type, const char *alg_name,
- const void *key, size_t key_length)
+ const void *key, size_t key_length, bool public)
{
struct sockaddr_alg salg;
int sk;
+ int keyopt;
int ret;
sk = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
@@ -107,7 +119,8 @@ static int create_alg(const char *alg_type, const char *alg_name,
return -1;
}
- if (setsockopt(sk, SOL_ALG, ALG_SET_KEY, key, key_length) < 0) {
+ keyopt = public ? ALG_SET_PUBKEY : ALG_SET_KEY;
+ if (setsockopt(sk, SOL_ALG, keyopt, key, key_length) < 0) {
close(sk);
return -1;
}
@@ -149,11 +162,13 @@ LIB_EXPORT struct l_cipher *l_cipher_new(enum l_cipher_type type,
break;
}
- cipher->encrypt_sk = create_alg("skcipher", alg_name, key, key_length);
+ cipher->encrypt_sk = create_alg("skcipher", alg_name, key, key_length,
+ false);
if (cipher->encrypt_sk < 0)
goto error_free;
- cipher->decrypt_sk = create_alg("skcipher", alg_name, key, key_length);
+ cipher->decrypt_sk = create_alg("skcipher", alg_name, key, key_length,
+ false);
if (cipher->decrypt_sk < 0)
goto error_close;
@@ -178,7 +193,8 @@ LIB_EXPORT void l_cipher_free(struct l_cipher *cipher)
}
static bool operate_cipher(int sk, __u32 operation,
- const void *in, void *out, size_t len)
+ const void *in, void *out, size_t len_in,
+ size_t len_out)
{
char c_msg_buf[CMSG_SPACE(sizeof(operation))];
struct msghdr msg;
@@ -198,7 +214,7 @@ static bool operate_cipher(int sk, __u32 operation,
memcpy(CMSG_DATA(c_msg), &operation, sizeof(operation));
iov.iov_base = (void *) in;
- iov.iov_len = len;
+ iov.iov_len = len_in;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
@@ -206,7 +222,7 @@ static bool operate_cipher(int sk, __u32 operation,
if (sendmsg(sk, &msg, 0) < 0)
return false;
- if (read(sk, out, len) < 0)
+ if (read(sk, out, len_out) < 0)
return false;
return true;
@@ -221,7 +237,8 @@ LIB_EXPORT bool l_cipher_encrypt(struct l_cipher *cipher,
if (unlikely(!in) || unlikely(!out))
return false;
- return operate_cipher(cipher->encrypt_sk, ALG_OP_ENCRYPT, in, out, len);
+ return operate_cipher(cipher->encrypt_sk, ALG_OP_ENCRYPT, in, out, len,
+ len);
}
LIB_EXPORT bool l_cipher_decrypt(struct l_cipher *cipher,
@@ -233,7 +250,8 @@ LIB_EXPORT bool l_cipher_decrypt(struct l_cipher *cipher,
if (unlikely(!in) || unlikely(!out))
return false;
- return operate_cipher(cipher->decrypt_sk, ALG_OP_DECRYPT, in, out, len);
+ return operate_cipher(cipher->decrypt_sk, ALG_OP_DECRYPT, in, out, len,
+ len);
}
LIB_EXPORT bool l_cipher_set_iv(struct l_cipher *cipher, const uint8_t *iv,
@@ -275,6 +293,7 @@ LIB_EXPORT bool l_cipher_set_iv(struct l_cipher *cipher, const uint8_t *iv,
struct l_asymmetric_cipher {
struct l_cipher cipher;
int key_size;
+ bool public_key;
};
static inline int parse_asn1_definite_length(const uint8_t **buf,
@@ -334,20 +353,31 @@ static bool parse_rsa_key(struct l_asymmetric_cipher *cipher, const void *key,
* and cache the size of the modulus n for later use.
* (RFC3279)
*/
+ size_t seq_length;
size_t n_length;
+ uint8_t *seq;
uint8_t *der;
uint8_t tag;
+ bool pubkey = true;
if (key_length < 8)
return false;
/* Unpack the outer SEQUENCE */
- der = der_find_elem((uint8_t *) key, key_length, 0, &tag, &n_length);
- if (!der || tag != ASN1_ID_SEQUENCE)
+ seq = der_find_elem((uint8_t *) key, key_length, 0, &tag, &seq_length);
+ if (!seq || tag != ASN1_ID_SEQUENCE)
return false;
- /* Take first INTEGER as the modulus */
- der = der_find_elem(der, n_length, 0, &tag, &n_length);
+ /* First INTEGER may be a 1-byte version (for private key) or
+ * the modulus (public key)
+ */
+ der = der_find_elem(seq, seq_length, 0, &tag, &n_length);
+ if (der && tag == ASN1_ID_INTEGER && n_length == 1) {
+ /* Found version number, implies this is a private key. */
+ der = der_find_elem(seq, seq_length, 1, &tag, &n_length);
+ pubkey = false;
+ }
+
if (!der || tag != ASN1_ID_INTEGER || n_length < 4)
return false;
@@ -358,95 +388,11 @@ static bool parse_rsa_key(struct l_asymmetric_cipher *cipher, const void *key,
}
cipher->key_size = n_length;
+ cipher->public_key = pubkey;
return true;
}
-static void write_asn1_definite_length(uint8_t **buf, size_t len)
-{
- int n;
-
- if (len < 0x80) {
- *(*buf)++ = len;
-
- return;
- }
-
- for (n = 1; len >> (n * 8); n++);
- *(*buf)++ = 0x80 | n;
-
- while (n--)
- *(*buf)++ = len >> (n * 8);
-}
-
-/*
- * Extract a ASN1 RsaKey-formatted public+private key structure in the
- * form used in the kernel. It is simpler than the PKCS#1 form as it only
- * contains the N, E and D integers and also correctly parses as a PKCS#1
- * RSAPublicKey.
- */
-uint8_t *extract_rsakey(uint8_t *pkcs1_key, size_t pkcs1_key_len,
- size_t *out_len)
-{
- uint8_t *key, *ptr, *ver, *n, *e, *d;
- uint8_t tag;
- size_t ver_len, n_len, e_len, d_len;
- int pos;
-
- /* Unpack the outer SEQUENCE */
- pkcs1_key = der_find_elem(pkcs1_key, pkcs1_key_len, 0, &tag,
- &pkcs1_key_len);
- if (!pkcs1_key || tag != ASN1_ID_SEQUENCE)
- return NULL;
-
- /* Check if the version element if present */
- ver = der_find_elem(pkcs1_key, pkcs1_key_len, 0, &tag, &ver_len);
- if (!ver || tag != ASN1_ID_INTEGER)
- return NULL;
-
- pos = (ver_len == 1 && ver[0] == 0x00) ? 1 : 0;
-
- n = der_find_elem(pkcs1_key, pkcs1_key_len, pos + 0, &tag, &n_len);
- if (!n || tag != ASN1_ID_INTEGER)
- return NULL;
-
- e = der_find_elem(pkcs1_key, pkcs1_key_len, pos + 1, &tag, &e_len);
- if (!e || tag != ASN1_ID_INTEGER)
- return NULL;
-
- d = der_find_elem(pkcs1_key, pkcs1_key_len, pos + 2, &tag, &d_len);
- if (!d || tag != ASN1_ID_INTEGER)
- return NULL;
-
- /* New SEQUENCE length including tags and lengths */
- *out_len = 1 + (n_len >= 0x80 ? n_len >= 0x100 ? 3 : 2 : 1) + n_len +
- 1 + (e_len >= 0x80 ? e_len >= 0x100 ? 3 : 2 : 1) + e_len +
- 1 + (d_len >= 0x80 ? d_len >= 0x100 ? 3 : 2 : 1) + d_len;
- ptr = key = l_malloc(*out_len +
- 1 + (*out_len >= 0x80 ? *out_len >= 0x100 ? 3 : 2 : 1));
-
- *ptr++ = ASN1_ID_SEQUENCE;
- write_asn1_definite_length(&ptr, *out_len);
-
- *ptr++ = ASN1_ID_INTEGER;
- write_asn1_definite_length(&ptr, n_len);
- memcpy(ptr, n, n_len);
- ptr += n_len;
-
- *ptr++ = ASN1_ID_INTEGER;
- write_asn1_definite_length(&ptr, e_len);
- memcpy(ptr, e, e_len);
- ptr += e_len;
-
- *ptr++ = ASN1_ID_INTEGER;
- write_asn1_definite_length(&ptr, d_len);
- memcpy(ptr, d, d_len);
- ptr += d_len;
-
- *out_len = ptr - key;
- return key;
-}
-
LIB_EXPORT struct l_asymmetric_cipher *l_asymmetric_cipher_new(
enum l_asymmetric_cipher_type type,
const void *key, size_t key_length)
@@ -468,19 +414,23 @@ LIB_EXPORT struct l_asymmetric_cipher *l_asymmetric_cipher_new(
if (!parse_rsa_key(cipher, key, key_length))
goto error_free;
- alg_name = "rsa";
+ alg_name = "pkcs1pad(rsa)";
break;
}
cipher->cipher.encrypt_sk = create_alg("akcipher", alg_name,
- key, key_length);
+ key, key_length,
+ cipher->public_key);
if (cipher->cipher.encrypt_sk < 0)
goto error_free;
- cipher->cipher.decrypt_sk = create_alg("akcipher", alg_name,
- key, key_length);
- if (cipher->cipher.decrypt_sk < 0)
- goto error_close;
+ if (!cipher->public_key) {
+ cipher->cipher.decrypt_sk = create_alg("akcipher", alg_name,
+ key, key_length,
+ cipher->public_key);
+ if (cipher->cipher.decrypt_sk < 0)
+ goto error_close;
+ }
return cipher;
@@ -508,151 +458,58 @@ LIB_EXPORT int l_asymmetric_cipher_get_key_size(
return cipher->key_size;
}
-static void getrandom_nonzero(uint8_t *buf, int len)
-{
- while (len--) {
- l_getrandom(buf, 1);
- while (buf[0] == 0)
- l_getrandom(buf, 1);
-
- buf++;
- }
-}
-
-LIB_EXPORT bool l_asymmetric_cipher_encrypt(struct l_asymmetric_cipher *cipher,
+LIB_EXPORT bool l_asymmetric_cipher_encrypt(struct l_asymmetric_cipher *acipher,
const void *in, void *out,
size_t len_in, size_t len_out)
{
- if (cipher->cipher.type == L_CIPHER_RSA_PKCS1_V1_5) {
- /* PKCS#1 v1.5 RSA padding according to RFC3447 */
- uint8_t buf[cipher->key_size];
- int ps_len = cipher->key_size - len_in - 3;
-
- if (len_in > (size_t) cipher->key_size - 11)
- return false;
- if (len_out != (size_t) cipher->key_size)
- return false;
-
- buf[0] = 0x00;
- buf[1] = 0x02;
- getrandom_nonzero(buf + 2, ps_len);
- buf[ps_len + 2] = 0x00;
- memcpy(buf + ps_len + 3, in, len_in);
-
- if (!l_cipher_encrypt(&cipher->cipher, buf, out,
- cipher->key_size))
- return false;
- }
+ if (unlikely(!acipher))
+ return false;
- return true;
+ if (unlikely(!in) || unlikely(!out))
+ return false;
+
+ return operate_cipher(acipher->cipher.encrypt_sk, ALG_OP_ENCRYPT,
+ in, out, len_in, len_out);
}
-LIB_EXPORT bool l_asymmetric_cipher_decrypt(struct l_asymmetric_cipher *cipher,
+LIB_EXPORT bool l_asymmetric_cipher_decrypt(struct l_asymmetric_cipher *acipher,
const void *in, void *out,
size_t len_in, size_t len_out)
{
- if (cipher->cipher.type == L_CIPHER_RSA_PKCS1_V1_5) {
- /* PKCS#1 v1.5 RSA padding according to RFC3447 */
- uint8_t buf[cipher->key_size];
- int pos;
-
- if (len_in != (size_t) cipher->key_size)
- return false;
-
- if (!l_cipher_decrypt(&cipher->cipher, in, buf,
- cipher->key_size))
- return false;
-
- if (buf[0] != 0x00)
- return false;
- if (buf[1] != 0x02)
- return false;
-
- for (pos = 2; pos < cipher->key_size; pos++)
- if (buf[pos] == 0)
- break;
- if (pos < 10 || pos == cipher->key_size)
- return false;
-
- pos++;
- if (len_out != (size_t) cipher->key_size - pos)
- return false;
-
- memcpy(out, buf + pos, cipher->key_size - pos);
- }
+ if (unlikely(!acipher))
+ return false;
- return true;
+ if (unlikely(!in) || unlikely(!out))
+ return false;
+
+ return operate_cipher(acipher->cipher.decrypt_sk, ALG_OP_DECRYPT,
+ in, out, len_in, len_out);
}
LIB_EXPORT bool l_asymmetric_cipher_sign(struct l_asymmetric_cipher *cipher,
const void *in, void *out,
size_t len_in, size_t len_out)
{
- if (cipher->cipher.type == L_CIPHER_RSA_PKCS1_V1_5) {
- /* PKCS#1 v1.5 RSA padding according to RFC3447 */
- uint8_t buf[cipher->key_size];
- int ps_len = cipher->key_size - len_in - 3;
-
- if (len_in > (size_t) cipher->key_size - 11)
- return false;
- if (len_out != (size_t) cipher->key_size)
- return false;
-
- buf[0] = 0x00;
- buf[1] = 0x01;
- memset(buf + 2, 0xff, ps_len);
- buf[ps_len + 2] = 0x00;
- memcpy(buf + ps_len + 3, in, len_in);
-
- /*
- * The RSA signing operation uses the same primitive as
- * decryption so just call decrypt for now.
- */
- if (!l_cipher_decrypt(&cipher->cipher, buf, out,
- cipher->key_size))
- return false;
- }
+ if (unlikely(!acipher))
+ return false;
- return true;
+ if (unlikely(!in) || unlikely(!out))
+ return false;
+
+ return operate_cipher(acipher->cipher.decrypt_sk, ALG_OP_SIGN,
+ in, out, len_in, len_out);
}
LIB_EXPORT bool l_asymmetric_cipher_verify(struct l_asymmetric_cipher *cipher,
const void *in, void *out,
size_t len_in, size_t len_out)
{
- if (cipher->cipher.type == L_CIPHER_RSA_PKCS1_V1_5) {
- /* PKCS#1 v1.5 RSA padding according to RFC3447 */
- uint8_t buf[cipher->key_size];
- int pos;
-
- if (len_in != (size_t) cipher->key_size)
- return false;
-
- /*
- * The RSA verify operation uses the same primitive as
- * encryption so just call encrypt.
- */
- if (!l_cipher_encrypt(&cipher->cipher, in, buf,
- cipher->key_size))
- return false;
-
- if (buf[0] != 0x00)
- return false;
- if (buf[1] != 0x01)
- return false;
-
- for (pos = 2; pos < cipher->key_size; pos++)
- if (buf[pos] != 0xff)
- break;
- if (pos < 10 || pos == cipher->key_size || buf[pos] != 0)
- return false;
-
- pos++;
- if (len_out != (size_t) cipher->key_size - pos)
- return false;
-
- memcpy(out, buf + pos, cipher->key_size - pos);
- }
+ if (unlikely(!acipher))
+ return false;
- return true;
+ if (unlikely(!in) || unlikely(!out))
+ return false;
+
+ return operate_cipher(acipher->cipher.encrypt_sk, ALG_OP_VERIFY,
+ in, out, len_in, len_out);
}
diff --git a/ell/tls.c b/ell/tls.c
index a20236f..a55f24c 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -920,8 +920,8 @@ static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
tls_get_hash_t get_hash)
{
struct l_asymmetric_cipher *rsa_privkey;
- uint8_t *privkey, *privkey_short;
- size_t key_size, short_size;
+ uint8_t *privkey;
+ size_t key_size;
bool result;
const struct tls_hash_algorithm *hash_type;
uint8_t hash[HANDSHAKE_HASH_MAX_SIZE];
@@ -945,19 +945,9 @@ static bool tls_rsa_sign(struct l_tls *tls, uint8_t **out,
return false;
}
- privkey_short = extract_rsakey(privkey, key_size, &short_size);
- tls_free_key(privkey, key_size);
-
- if (!privkey_short) {
- tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
- TLS_ALERT_BAD_CERT);
-
- return false;
- }
-
rsa_privkey = l_asymmetric_cipher_new(L_CIPHER_RSA_PKCS1_V1_5,
- privkey_short, short_size);
- tls_free_key(privkey_short, short_size);
+ privkey, key_size);
+ tls_free_key(privkey, key_size);
if (!rsa_privkey) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
@@ -1080,11 +1070,14 @@ static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len,
*/
}
- digest_info = alloca(expected_len);
+ if (expected_len > key_size)
+ goto err_free_rsa;
+
+ digest_info = alloca(key_size);
result = l_asymmetric_cipher_verify(rsa_client_pubkey, in + 4,
digest_info,
- key_size, expected_len);
+ key_size, key_size);
l_asymmetric_cipher_free(rsa_client_pubkey);
@@ -1743,8 +1736,8 @@ static void tls_handle_rsa_client_key_xchg(struct l_tls *tls,
{
uint8_t pre_master_secret[48], random_secret[46];
struct l_asymmetric_cipher *rsa_server_privkey;
- uint8_t *privkey, *privkey_short;
- size_t key_size, short_size;
+ uint8_t *privkey;
+ size_t key_size;
bool result;
if (!tls->priv_key_path) {
@@ -1764,19 +1757,9 @@ static void tls_handle_rsa_client_key_xchg(struct l_tls *tls,
return;
}
- privkey_short = extract_rsakey(privkey, key_size, &short_size);
- tls_free_key(privkey, key_size);
-
- if (!privkey_short) {
- tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
- TLS_ALERT_BAD_CERT);
-
- return;
- }
-
rsa_server_privkey = l_asymmetric_cipher_new(L_CIPHER_RSA_PKCS1_V1_5,
- privkey_short, short_size);
- tls_free_key(privkey_short, short_size);
+ privkey, key_size);
+ tls_free_key(privkey, key_size);
if (!rsa_server_privkey) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
--
2.8.4
6 years