[PATCH 1/8] cipher: Only do the RFC3610 IV formatting for CCM
by Andrew Zaborowski
In preparation to add the AES GCM mode, move the CCM-specific IV
formatting code from operate_cipher to the callers (only aead encrypt
and decrypt), make operate_cipher accept the IV buffer directly. Check
that the nonce is >= 7 bytes.
Zero the "counter" part of the IV to avoid sending uninitialized bytes
to the kernel (the kernel will zero them again though)
---
ell/cipher.c | 96 +++++++++++++++++++++++++++++++++++-----------------
1 file changed, 65 insertions(+), 31 deletions(-)
diff --git a/ell/cipher.c b/ell/cipher.c
index 0128e2e..977ebc8 100644
--- a/ell/cipher.c
+++ b/ell/cipher.c
@@ -268,28 +268,11 @@ LIB_EXPORT void l_aead_cipher_free(struct l_aead_cipher *cipher)
l_free(cipher);
}
-static ssize_t build_iv(const void *nonce, uint8_t nonce_len, uint8_t *iv,
- uint8_t iv_len)
-{
- const size_t iv_overhead = 2;
-
- if (nonce_len + iv_overhead > iv_len)
- return -EINVAL;
-
- iv[0] = iv_len - iv_overhead - nonce_len;
- memcpy(iv + 1, nonce, nonce_len);
-
- /* Assumes that remaining bytes in iv were already zeroed out */
-
- return iv_len;
-}
-
static ssize_t operate_cipher(int sk, __u32 operation,
const void *in, size_t in_len,
const void *ad, size_t ad_len,
- const void *nonce, size_t nonce_len,
- void *out, size_t out_len,
- size_t iv_len)
+ const void *iv, size_t iv_len,
+ void *out, size_t out_len)
{
char *c_msg_buf;
size_t c_msg_size;
@@ -300,7 +283,7 @@ static ssize_t operate_cipher(int sk, __u32 operation,
c_msg_size = CMSG_SPACE(sizeof(operation));
c_msg_size += ad_len ? CMSG_SPACE(sizeof(uint32_t)) : 0;
- c_msg_size += (nonce && iv_len) ?
+ c_msg_size += iv_len ?
CMSG_SPACE(sizeof(struct af_alg_iv) + iv_len) : 0;
c_msg_buf = alloca(c_msg_size);
@@ -340,7 +323,7 @@ static ssize_t operate_cipher(int sk, __u32 operation,
msg.msg_iovlen = 1;
}
- if (nonce && iv_len) {
+ if (iv_len) {
struct af_alg_iv *algiv;
c_msg = CMSG_NXTHDR(&msg, c_msg);
@@ -350,9 +333,7 @@ static ssize_t operate_cipher(int sk, __u32 operation,
algiv = (void *)CMSG_DATA(c_msg);
algiv->ivlen = iv_len;
- result = build_iv(nonce, nonce_len, &algiv->iv[0], iv_len);
- if (result < 0)
- return result;
+ memcpy(algiv->iv, iv, iv_len);
}
result = sendmsg(sk, &msg, 0);
@@ -446,7 +427,7 @@ LIB_EXPORT bool l_cipher_encrypt(struct l_cipher *cipher,
return false;
return operate_cipher(cipher->encrypt_sk, ALG_OP_ENCRYPT, in, len,
- NULL, 0, NULL, 0, out, len, 0) >= 0;
+ NULL, 0, NULL, 0, out, len) >= 0;
}
LIB_EXPORT bool l_cipher_encryptv(struct l_cipher *cipher,
@@ -473,7 +454,7 @@ LIB_EXPORT bool l_cipher_decrypt(struct l_cipher *cipher,
return false;
return operate_cipher(cipher->decrypt_sk, ALG_OP_DECRYPT, in, len,
- NULL, 0, NULL, 0, out, len, 0) >= 0;
+ NULL, 0, NULL, 0, out, len) >= 0;
}
LIB_EXPORT bool l_cipher_decryptv(struct l_cipher *cipher,
@@ -526,11 +507,13 @@ LIB_EXPORT bool l_cipher_set_iv(struct l_cipher *cipher, const uint8_t *iv,
return true;
}
+#define CCM_IV_SIZE 16
+
static size_t l_aead_cipher_get_ivlen(struct l_aead_cipher *cipher)
{
switch (cipher->type) {
case L_AEAD_CIPHER_AES_CCM:
- return 16;
+ return CCM_IV_SIZE;
case L_AEAD_CIPHER_AES_GCM:
return 12;
}
@@ -538,21 +521,55 @@ static size_t l_aead_cipher_get_ivlen(struct l_aead_cipher *cipher)
return 0;
}
+/* RFC3610 Section 2.3 */
+static ssize_t build_ccm_iv(const void *nonce, uint8_t nonce_len,
+ uint8_t (*iv)[CCM_IV_SIZE])
+{
+ const size_t iv_overhead = 2;
+ int lprime = 15 - nonce_len - 1;
+
+ if (unlikely(nonce_len + iv_overhead > CCM_IV_SIZE || lprime > 7))
+ return -EINVAL;
+
+ (*iv)[0] = lprime;
+ memcpy(*iv + 1, nonce, nonce_len);
+ memset(*iv + 1 + nonce_len, 0, lprime + 1);
+
+ return CCM_IV_SIZE;
+}
+
LIB_EXPORT bool l_aead_cipher_encrypt(struct l_aead_cipher *cipher,
const void *in, size_t in_len,
const void *ad, size_t ad_len,
const void *nonce, size_t nonce_len,
void *out, size_t out_len)
{
+ uint8_t ccm_iv[CCM_IV_SIZE];
+ const uint8_t *iv;
+ ssize_t iv_len;
+
if (unlikely(!cipher))
return false;
if (unlikely(!in) || unlikely(!out))
return false;
+ if (cipher->type == L_AEAD_CIPHER_AES_CCM) {
+ iv_len = build_ccm_iv(nonce, nonce_len, &ccm_iv);
+ if (unlikely(iv_len < 0))
+ return false;
+
+ iv = ccm_iv;
+ } else {
+ if (unlikely(nonce_len != l_aead_cipher_get_ivlen(cipher)))
+ return false;
+
+ iv = nonce;
+ iv_len = nonce_len;
+ }
+
return operate_cipher(cipher->encrypt_sk, ALG_OP_ENCRYPT, in, in_len,
- ad, ad_len, nonce, nonce_len, out, out_len,
- l_aead_cipher_get_ivlen(cipher)) ==
+ ad, ad_len, iv, iv_len, out, out_len) ==
(ssize_t)out_len;
}
@@ -562,15 +579,32 @@ LIB_EXPORT bool l_aead_cipher_decrypt(struct l_aead_cipher *cipher,
const void *nonce, size_t nonce_len,
void *out, size_t out_len)
{
+ uint8_t ccm_iv[CCM_IV_SIZE];
+ const uint8_t *iv;
+ ssize_t iv_len;
+
if (unlikely(!cipher))
return false;
if (unlikely(!in) || unlikely(!out))
return false;
+ if (cipher->type == L_AEAD_CIPHER_AES_CCM) {
+ iv_len = build_ccm_iv(nonce, nonce_len, &ccm_iv);
+ if (unlikely(iv_len < 0))
+ return false;
+
+ iv = ccm_iv;
+ } else {
+ if (unlikely(nonce_len != l_aead_cipher_get_ivlen(cipher)))
+ return false;
+
+ iv = nonce;
+ iv_len = nonce_len;
+ }
+
return operate_cipher(cipher->decrypt_sk, ALG_OP_DECRYPT, in, in_len,
- ad, ad_len, nonce, nonce_len, out, out_len,
- l_aead_cipher_get_ivlen(cipher)) ==
+ ad, ad_len, iv, iv_len, out, out_len) ==
(ssize_t)out_len;
}
--
2.19.1
2 years, 3 months
[PATCH] tls: fixed intentation in X509 definitions
by James Prestwood
Someones editor must have been misbehaving
---
ell/tls.c | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/ell/tls.c b/ell/tls.c
index 9dc97ff..2d2dd4b 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -2549,23 +2549,23 @@ const char *tls_handshake_state_to_str(enum tls_handshake_state state)
/* X509 Certificates and Certificate Chains */
#define X509_CERTIFICATE_POS 0
-#define X509_TBSCERTIFICATE_POS 0
-#define X509_TBSCERT_VERSION_POS 0
-#define X509_TBSCERT_SERIAL_POS 1
-#define X509_TBSCERT_SIGNATURE_POS 2
-#define X509_ALGORITHM_ID_ALGORITHM_POS 0
-#define X509_ALGORITHM_ID_PARAMS_POS 1
-#define X509_TBSCERT_ISSUER_DN_POS 3
-#define X509_TBSCERT_VALIDITY_POS 4
-#define X509_TBSCERT_SUBJECT_DN_POS 5
-#define X509_TBSCERT_SUBJECT_KEY_POS 6
-#define X509_SUBJECT_KEY_ALGORITHM_POS 0
-#define X509_SUBJECT_KEY_VALUE_POS 1
-#define X509_TBSCERT_ISSUER_UID_POS 7
-#define X509_TBSCERT_SUBJECT_UID_POS 8
-#define X509_TBSCERT_EXTENSIONS_POS 9
-#define X509_SIGNATURE_ALGORITHM_POS 1
-#define X509_SIGNATURE_VALUE_POS 2
+#define X509_TBSCERTIFICATE_POS 0
+#define X509_TBSCERT_VERSION_POS 0
+#define X509_TBSCERT_SERIAL_POS 1
+#define X509_TBSCERT_SIGNATURE_POS 2
+#define X509_ALGORITHM_ID_ALGORITHM_POS 0
+#define X509_ALGORITHM_ID_PARAMS_POS 1
+#define X509_TBSCERT_ISSUER_DN_POS 3
+#define X509_TBSCERT_VALIDITY_POS 4
+#define X509_TBSCERT_SUBJECT_DN_POS 5
+#define X509_TBSCERT_SUBJECT_KEY_POS 6
+#define X509_SUBJECT_KEY_ALGORITHM_POS 0
+#define X509_SUBJECT_KEY_VALUE_POS 1
+#define X509_TBSCERT_ISSUER_UID_POS 7
+#define X509_TBSCERT_SUBJECT_UID_POS 8
+#define X509_TBSCERT_EXTENSIONS_POS 9
+#define X509_SIGNATURE_ALGORITHM_POS 1
+#define X509_SIGNATURE_VALUE_POS 2
struct tls_cert *tls_cert_load_file(const char *filename)
{
--
2.17.1
2 years, 3 months
[PATCH 01/12] cipher: Only do the RFC3610 IV formatting for CCM
by Andrew Zaborowski
In preparation to add the AES GCM mode, move the CCM-specific IV
formatting code from operate_cipher to the callers (only aead encrypt
and decrypt), make operate_cipher accept the IV buffer directly. Check
that the nonce is >= 7 bytes.
Zero the "counter" part of the IV to avoid sending uninitialized bytes
to the kernel (the kernel will zero them again though)
---
ell/cipher.c | 91 +++++++++++++++++++++++++++++++++++-----------------
1 file changed, 61 insertions(+), 30 deletions(-)
diff --git a/ell/cipher.c b/ell/cipher.c
index 79cecdb..af4bc10 100644
--- a/ell/cipher.c
+++ b/ell/cipher.c
@@ -266,28 +266,11 @@ LIB_EXPORT void l_aead_cipher_free(struct l_aead_cipher *cipher)
l_free(cipher);
}
-static ssize_t build_iv(const void *nonce, uint8_t nonce_len, uint8_t *iv,
- uint8_t iv_len)
-{
- const size_t iv_overhead = 2;
-
- if (nonce_len + iv_overhead > iv_len)
- return -EINVAL;
-
- iv[0] = iv_len - iv_overhead - nonce_len;
- memcpy(iv + 1, nonce, nonce_len);
-
- /* Assumes that remaining bytes in iv were already zeroed out */
-
- return iv_len;
-}
-
static ssize_t operate_cipher(int sk, __u32 operation,
const void *in, size_t in_len,
const void *ad, size_t ad_len,
- const void *nonce, size_t nonce_len,
- void *out, size_t out_len,
- size_t iv_len)
+ const void *iv, size_t iv_len,
+ void *out, size_t out_len)
{
char *c_msg_buf;
size_t c_msg_size;
@@ -298,7 +281,7 @@ static ssize_t operate_cipher(int sk, __u32 operation,
c_msg_size = CMSG_SPACE(sizeof(operation));
c_msg_size += ad_len ? CMSG_SPACE(sizeof(uint32_t)) : 0;
- c_msg_size += (nonce && iv_len) ?
+ c_msg_size += iv_len ?
CMSG_SPACE(sizeof(struct af_alg_iv) + iv_len) : 0;
c_msg_buf = alloca(c_msg_size);
@@ -338,7 +321,7 @@ static ssize_t operate_cipher(int sk, __u32 operation,
msg.msg_iovlen = 1;
}
- if (nonce && iv_len) {
+ if (iv_len) {
struct af_alg_iv *algiv;
c_msg = CMSG_NXTHDR(&msg, c_msg);
@@ -348,9 +331,7 @@ static ssize_t operate_cipher(int sk, __u32 operation,
algiv = (void *)CMSG_DATA(c_msg);
algiv->ivlen = iv_len;
- result = build_iv(nonce, nonce_len, &algiv->iv[0], iv_len);
- if (result < 0)
- return result;
+ memcpy(algiv->iv, iv, iv_len);
}
result = sendmsg(sk, &msg, 0);
@@ -444,7 +425,7 @@ LIB_EXPORT bool l_cipher_encrypt(struct l_cipher *cipher,
return false;
return operate_cipher(cipher->encrypt_sk, ALG_OP_ENCRYPT, in, len,
- NULL, 0, NULL, 0, out, len, 0) >= 0;
+ NULL, 0, NULL, 0, out, len) >= 0;
}
LIB_EXPORT bool l_cipher_encryptv(struct l_cipher *cipher,
@@ -471,7 +452,7 @@ LIB_EXPORT bool l_cipher_decrypt(struct l_cipher *cipher,
return false;
return operate_cipher(cipher->decrypt_sk, ALG_OP_DECRYPT, in, len,
- NULL, 0, NULL, 0, out, len, 0) >= 0;
+ NULL, 0, NULL, 0, out, len) >= 0;
}
LIB_EXPORT bool l_cipher_decryptv(struct l_cipher *cipher,
@@ -534,21 +515,54 @@ static size_t l_aead_cipher_get_ivlen(struct l_aead_cipher *cipher)
return 0;
}
+/* RFC3610 Section 2.3 */
+static ssize_t build_ccm_iv(const void *nonce, uint8_t nonce_len, uint8_t *iv)
+{
+ const size_t iv_overhead = 2;
+ const size_t iv_len = 16;
+
+ if (unlikely(nonce_len + iv_overhead > iv_len || nonce_len < 7))
+ return -EINVAL;
+
+ iv[0] = iv_len - iv_overhead - nonce_len;
+ memcpy(iv + 1, nonce, nonce_len);
+ memset(iv + 1 + nonce_len, 0, iv_len - 1 - nonce_len);
+
+ return iv_len;
+}
+
LIB_EXPORT bool l_aead_cipher_encrypt(struct l_aead_cipher *cipher,
const void *in, size_t in_len,
const void *ad, size_t ad_len,
const void *nonce, size_t nonce_len,
void *out, size_t out_len)
{
+ uint8_t ccm_iv[16];
+ const uint8_t *iv;
+ ssize_t iv_len;
+
if (unlikely(!cipher))
return false;
if (unlikely(!in) || unlikely(!out))
return false;
+ if (cipher->type == L_AEAD_CIPHER_AES_CCM) {
+ iv_len = build_ccm_iv(nonce, nonce_len, ccm_iv);
+ if (unlikely(iv_len < 0))
+ return false;
+
+ iv = ccm_iv;
+ } else {
+ if (unlikely(nonce_len != l_aead_cipher_get_ivlen(cipher)))
+ return false;
+
+ iv = nonce;
+ iv_len = nonce_len;
+ }
+
return operate_cipher(cipher->encrypt_sk, ALG_OP_ENCRYPT, in, in_len,
- ad, ad_len, nonce, nonce_len, out, out_len,
- l_aead_cipher_get_ivlen(cipher)) ==
+ ad, ad_len, iv, iv_len, out, out_len) ==
(ssize_t)out_len;
}
@@ -558,15 +572,32 @@ LIB_EXPORT bool l_aead_cipher_decrypt(struct l_aead_cipher *cipher,
const void *nonce, size_t nonce_len,
void *out, size_t out_len)
{
+ uint8_t ccm_iv[16];
+ const uint8_t *iv;
+ ssize_t iv_len;
+
if (unlikely(!cipher))
return false;
if (unlikely(!in) || unlikely(!out))
return false;
+ if (cipher->type == L_AEAD_CIPHER_AES_CCM) {
+ iv_len = build_ccm_iv(nonce, nonce_len, ccm_iv);
+ if (unlikely(iv_len < 0))
+ return false;
+
+ iv = ccm_iv;
+ } else {
+ if (unlikely(nonce_len != l_aead_cipher_get_ivlen(cipher)))
+ return false;
+
+ iv = nonce;
+ iv_len = nonce_len;
+ }
+
return operate_cipher(cipher->decrypt_sk, ALG_OP_DECRYPT, in, in_len,
- ad, ad_len, nonce, nonce_len, out, out_len,
- l_aead_cipher_get_ivlen(cipher)) ==
+ ad, ad_len, iv, iv_len, out, out_len) ==
(ssize_t)out_len;
}
--
2.19.1
2 years, 3 months
[PATCH] signal: Restrict signal_mask to file scope
by Mat Martineau
---
ell/signal.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ell/signal.c b/ell/signal.c
index 710dc5c..36d6326 100644
--- a/ell/signal.c
+++ b/ell/signal.c
@@ -64,7 +64,7 @@ struct signal_desc {
static struct l_io *signalfd_io = NULL;
static struct l_queue *signal_list = NULL;
-sigset_t signal_mask;
+static sigset_t signal_mask;
static void handle_callback(struct signal_desc *desc)
{
--
2.19.1
2 years, 3 months
[PATCH 1/5] cert: Add cert.c for certificate types and routines
by Andrew Zaborowski
Create a new file for all the generic X.509 certificate utilities so far
living in tls.c and make the l_cert type a public object. There are
only minor changes from the tls.c code to add accessors, otherwise the
intention is not to make the code perfect and only move the existing
code so that for example pem.c can start returning l_cert objects
directly.
---
Makefile.am | 6 +-
ell/cert.c | 306 ++++++++++++++++++++++++++++++++++++++++++++++++++++
ell/cert.h | 57 ++++++++++
ell/ell.h | 1 +
ell/ell.sym | 8 ++
5 files changed, 376 insertions(+), 2 deletions(-)
create mode 100644 ell/cert.c
create mode 100644 ell/cert.h
diff --git a/Makefile.am b/Makefile.am
index 0a8d0f6..a67f0a5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -48,7 +48,8 @@ pkginclude_HEADERS = ell/ell.h \
ell/file.h \
ell/dir.h \
ell/net.h \
- ell/dhcp.h
+ ell/dhcp.h \
+ ell/cert.h
lib_LTLIBRARIES = ell/libell.la
@@ -109,7 +110,8 @@ ell_libell_la_SOURCES = $(linux_headers) \
ell/dhcp-private.h \
ell/dhcp.c \
ell/dhcp-transport.c \
- ell/dhcp-lease.c
+ ell/dhcp-lease.c \
+ ell/cert.c
ell_libell_la_LDFLAGS = -no-undefined \
-Wl,--version-script=$(top_srcdir)/ell/ell.sym \
diff --git a/ell/cert.c b/ell/cert.c
new file mode 100644
index 0000000..82ea005
--- /dev/null
+++ b/ell/cert.c
@@ -0,0 +1,306 @@
+/*
+ * Embedded Linux library
+ *
+ * Copyright (C) 2018 Intel Corporation. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "private.h"
+#include "key.h"
+#include "asn1-private.h"
+#include "cert.h"
+
+#define X509_CERTIFICATE_POS 0
+#define X509_TBSCERTIFICATE_POS 0
+#define X509_TBSCERT_VERSION_POS 0
+#define X509_TBSCERT_SERIAL_POS 1
+#define X509_TBSCERT_SIGNATURE_POS 2
+#define X509_ALGORITHM_ID_ALGORITHM_POS 0
+#define X509_ALGORITHM_ID_PARAMS_POS 1
+#define X509_TBSCERT_ISSUER_DN_POS 3
+#define X509_TBSCERT_VALIDITY_POS 4
+#define X509_TBSCERT_SUBJECT_DN_POS 5
+#define X509_TBSCERT_SUBJECT_KEY_POS 6
+#define X509_SUBJECT_KEY_ALGORITHM_POS 0
+#define X509_SUBJECT_KEY_VALUE_POS 1
+#define X509_TBSCERT_ISSUER_UID_POS 7
+#define X509_TBSCERT_SUBJECT_UID_POS 8
+#define X509_TBSCERT_EXTENSIONS_POS 9
+#define X509_SIGNATURE_ALGORITHM_POS 1
+#define X509_SIGNATURE_VALUE_POS 2
+
+struct l_cert {
+ struct l_cert *issuer;
+ struct l_cert *issued;
+ enum l_cert_key_type pubkey_type;
+ size_t asn1_len;
+ uint8_t asn1[0];
+};
+
+static const struct pkcs1_encryption_oid {
+ enum l_cert_key_type key_type;
+ struct asn1_oid oid;
+} pkcs1_encryption_oids[] = {
+ { /* rsaEncryption */
+ L_CERT_KEY_RSA,
+ { 9, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 } },
+ },
+};
+
+static bool cert_set_pubkey_type(struct l_cert *cert)
+{
+ const uint8_t *key_type;
+ size_t key_type_len;
+ int i;
+
+ key_type = asn1_der_find_elem_by_path(cert->asn1, cert->asn1_len,
+ ASN1_ID_OID, &key_type_len,
+ X509_CERTIFICATE_POS,
+ X509_TBSCERTIFICATE_POS,
+ X509_TBSCERT_SUBJECT_KEY_POS,
+ X509_SUBJECT_KEY_ALGORITHM_POS,
+ X509_ALGORITHM_ID_ALGORITHM_POS,
+ -1);
+ if (!key_type)
+ return false;
+
+ for (i = 0; i < (int) L_ARRAY_SIZE(pkcs1_encryption_oids); i++)
+ if (asn1_oid_eq(&pkcs1_encryption_oids[i].oid,
+ key_type_len, key_type))
+ break;
+
+ if (i == L_ARRAY_SIZE(pkcs1_encryption_oids))
+ cert->pubkey_type = L_CERT_KEY_UNKNOWN;
+ else
+ cert->pubkey_type = pkcs1_encryption_oids[i].key_type;
+
+ return true;
+}
+
+LIB_EXPORT struct l_cert *l_cert_new_from_der(const uint8_t *buf,
+ size_t buf_len)
+{
+ const uint8_t *seq = buf;
+ size_t seq_len = buf_len;
+ size_t content_len;
+ struct l_cert *cert;
+
+ /* Sanity check: outer element is a SEQUENCE */
+ if (seq_len-- < 1 || *seq++ != ASN1_ID_SEQUENCE)
+ return NULL;
+
+ /* Sanity check: the SEQUENCE spans the whole buffer */
+ content_len = asn1_parse_definite_length(&seq, &seq_len);
+ if (content_len < 64 || content_len != seq_len)
+ return NULL;
+
+ /*
+ * We could require the signature algorithm and the key algorithm
+ * to be one of our supported types here but instead we only
+ * require that when the user wants to verify this certificate or
+ * get the public key respectively.
+ */
+
+ cert = l_malloc(sizeof(struct l_cert) + buf_len);
+ cert->issuer = NULL;
+ cert->issued = NULL;
+ cert->asn1_len = buf_len;
+ memcpy(cert->asn1, buf, buf_len);
+
+ /* Sanity check: structure is correct up to the Public Key Algorithm */
+ if (!cert_set_pubkey_type(cert)) {
+ l_free(cert);
+ return NULL;
+ }
+
+ return cert;
+}
+
+LIB_EXPORT void l_cert_free(struct l_cert *cert)
+{
+ while (cert) {
+ struct l_cert *next = cert->issuer;
+
+ l_free(cert);
+ cert = next;
+ }
+}
+
+LIB_EXPORT bool l_cert_link_issuer(struct l_cert *cert, struct l_cert *issuer)
+{
+ if (!cert)
+ return false;
+
+ if (issuer && (issuer->issued || cert->issuer))
+ return false;
+
+ if (cert->issuer)
+ cert->issuer->issued = NULL;
+
+ cert->issuer = issuer;
+ return true;
+}
+
+LIB_EXPORT struct l_cert *l_cert_get_issuer(struct l_cert *cert)
+{
+ return cert->issuer;
+}
+
+LIB_EXPORT const uint8_t *l_cert_get_der_data(struct l_cert *cert,
+ size_t *out_len)
+{
+ *out_len = cert->asn1_len;
+ return cert->asn1;
+}
+
+LIB_EXPORT bool l_cert_find_certchain(struct l_cert *cert,
+ struct l_cert *ca_cert)
+{
+ return true;
+}
+
+static void cert_key_cleanup(struct l_key **p)
+{
+ l_key_free_norevoke(*p);
+}
+
+static bool cert_verify_with_keyring(struct l_cert *cert,
+ struct l_keyring *ring,
+ struct l_cert *root,
+ struct l_keyring *trusted)
+{
+ if (!cert)
+ return true;
+
+ if (cert->pubkey_type != L_CERT_KEY_RSA)
+ return false;
+
+ /*
+ * RFC5246 7.4.2:
+ * "Because certificate validation requires that root keys be
+ * distributed independently, the self-signed certificate that
+ * specifies the root certificate authority MAY be omitted from
+ * the chain, under the assumption that the remote end must
+ * already possess it in order to validate it in any case."
+ */
+ if (!cert->issuer && root && cert->asn1_len == root->asn1_len &&
+ !memcmp(cert->asn1, root->asn1, root->asn1_len))
+ return true;
+
+ if (cert_verify_with_keyring(cert->issuer, ring, root, trusted)) {
+ L_AUTO_CLEANUP_VAR(struct l_key *, key, cert_key_cleanup);
+
+ key = l_key_new(L_KEY_RSA, cert->asn1, cert->asn1_len);
+ if (!key)
+ return false;
+
+ if (!l_keyring_link(ring, key))
+ return false;
+
+ if (trusted || cert->issuer)
+ return true;
+
+ /*
+ * If execution reaches this point, it's known that:
+ * * No trusted root key was supplied, so the chain is only
+ * being checked against its own root
+ * * The keyring 'ring' is not restricted yet
+ * * The chain's root cert was just linked in to the
+ * previously empty keyring 'ring'.
+ *
+ * By restricting 'ring' now, the rest of the certs in
+ * the chain will have their signature validated using 'key'
+ * as the root.
+ */
+ return l_keyring_restrict(ring, L_KEYRING_RESTRICT_ASYM_CHAIN,
+ trusted);
+ }
+
+ return false;
+}
+
+static void cert_keyring_cleanup(struct l_keyring **p)
+{
+ l_keyring_free(*p);
+}
+
+LIB_EXPORT bool l_cert_verify_certchain(struct l_cert *certchain,
+ struct l_cert *ca_cert)
+{
+ L_AUTO_CLEANUP_VAR(struct l_keyring *, ca_ring,
+ cert_keyring_cleanup) = NULL;
+ L_AUTO_CLEANUP_VAR(struct l_keyring *, verify_ring,
+ cert_keyring_cleanup) = NULL;
+
+ if (!certchain || certchain->pubkey_type != L_CERT_KEY_RSA)
+ return false;
+
+ if (ca_cert && ca_cert->pubkey_type != L_CERT_KEY_RSA)
+ return false;
+
+ if (ca_cert) {
+ L_AUTO_CLEANUP_VAR(struct l_key *, ca_key, cert_key_cleanup);
+ ca_key = NULL;
+
+ ca_ring = l_keyring_new();
+ if (!ca_ring)
+ return false;
+
+ ca_key = l_key_new(L_KEY_RSA, ca_cert->asn1, ca_cert->asn1_len);
+ if (!ca_key || !l_keyring_link(ca_ring, ca_key))
+ return false;
+ }
+
+ verify_ring = l_keyring_new();
+ if (!verify_ring)
+ return false;
+
+ /*
+ * If a CA cert was supplied, restrict verify_ring now so
+ * everything else in certchain is validated against the CA.
+ * Otherwise, verify_ring will be restricted after the root of
+ * certchain is added to verify_ring by
+ * cert_verify_with_keyring().
+ */
+ if (ca_ring && !l_keyring_restrict(verify_ring,
+ L_KEYRING_RESTRICT_ASYM_CHAIN,
+ ca_ring)) {
+ return false;
+ }
+
+ return cert_verify_with_keyring(certchain, verify_ring, ca_cert,
+ ca_ring);
+}
+
+LIB_EXPORT enum l_cert_key_type l_cert_get_pubkey_type(struct l_cert *cert)
+{
+ return cert->pubkey_type;
+}
+
+LIB_EXPORT struct l_key *l_cert_get_pubkey(struct l_cert *cert)
+{
+ /* Use kernel's ASN.1 certificate parser to find the key data for us */
+ if (cert->pubkey_type == L_CERT_KEY_RSA)
+ return l_key_new(L_KEY_RSA, cert->asn1, cert->asn1_len);
+
+ return NULL;
+}
diff --git a/ell/cert.h b/ell/cert.h
new file mode 100644
index 0000000..4d809be
--- /dev/null
+++ b/ell/cert.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * Embedded Linux library
+ *
+ * Copyright (C) 2018 Intel Corporation. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __ELL_CERT_H
+#define __ELL_CERT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#include <ell/key.h>
+
+struct l_cert;
+
+enum l_cert_key_type {
+ L_CERT_KEY_RSA,
+ L_CERT_KEY_UNKNOWN,
+};
+
+struct l_cert *l_cert_new_from_der(const uint8_t *buf, size_t buf_len);
+void l_cert_free(struct l_cert *cert);
+
+bool l_cert_link_issuer(struct l_cert *cert, struct l_cert *issuer);
+struct l_cert *l_cert_get_issuer(struct l_cert *cert);
+const uint8_t *l_cert_get_der_data(struct l_cert *cert, size_t *out_len);
+bool l_cert_find_certchain(struct l_cert *cert, struct l_cert *ca_cert);
+bool l_cert_verify_certchain(struct l_cert *certchain, struct l_cert *ca_cert);
+enum l_cert_key_type l_cert_get_pubkey_type(struct l_cert *cert);
+struct l_key *l_cert_get_pubkey(struct l_cert *cert);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ELL_CERT_H */
diff --git a/ell/ell.h b/ell/ell.h
index ba1928d..4b0eac4 100644
--- a/ell/ell.h
+++ b/ell/ell.h
@@ -56,3 +56,4 @@
#include <ell/dbus-service.h>
#include <ell/dbus-client.h>
#include <ell/dhcp.h>
+#include <ell/cert.h>
diff --git a/ell/ell.sym b/ell/ell.sym
index 614bc93..d100005 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -432,6 +432,14 @@ global:
l_uuid_is_valid;
l_uuid_get_version;
l_uuid_to_string;
+ /* cert */
+ l_cert_new_from_der;
+ l_cert_free;
+ l_cert_get_der_data;
+ l_cert_find_certchain;
+ l_cert_verify_certchain;
+ l_cert_get_pubkey_type;
+ l_cert_get_pubkey;
local:
*;
};
--
2.19.1
2 years, 3 months
[PATCH v2] ell/ell.sym: add missing l_genl_family_set_unicast_handler
by Peter Seiderer
Add l_genl_family_set_unicast_handler (and remove legacy
l_genl_set_unicast_handler).
Fixes iwd compile failure:
src/netdev.o: In function `netdev_set_nl80211':
netdev.c:(.text+0x6f04): undefined reference to `l_genl_family_set_unicast_handler'
---
Changes v1 -> v2:
- remove legacy l_genl_set_unicast_handler (suggested by Marcel Holtmann)
- remove Signed-off-by line (suggested by Marcel Holtmann )
---
ell/ell.sym | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ell/ell.sym b/ell/ell.sym
index 614bc93..c21fb21 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -239,7 +239,6 @@ global:
l_genl_unref;
l_genl_set_debug;
l_genl_set_close_on_unref;
- l_genl_set_unicast_handler;
l_genl_msg_new;
l_genl_msg_new_sized;
l_genl_msg_ref;
@@ -257,6 +256,7 @@ global:
l_genl_family_new;
l_genl_family_ref;
l_genl_family_unref;
+ l_genl_family_set_unicast_handler;
l_genl_family_set_watches;
l_genl_family_get_version;
l_genl_family_get_genl;
--
2.19.1
2 years, 3 months
[PATCH v1] ell/ell.sym: add missing l_genl_family_set_unicast_handler
by Peter Seiderer
Fixes iwd compile failure:
src/netdev.o: In function `netdev_set_nl80211':
netdev.c:(.text+0x6f04): undefined reference to `l_genl_family_set_unicast_handler'
Signed-off-by: Peter Seiderer <ps.report(a)gmx.net>
---
ell/ell.sym | 1 +
1 file changed, 1 insertion(+)
diff --git a/ell/ell.sym b/ell/ell.sym
index 614bc93..cdd2c21 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -257,6 +257,7 @@ global:
l_genl_family_new;
l_genl_family_ref;
l_genl_family_unref;
+ l_genl_family_set_unicast_handler;
l_genl_family_set_watches;
l_genl_family_get_version;
l_genl_family_get_genl;
--
2.19.1
2 years, 3 months
[PATCH] key: Have kernel handle padding
by Denis Kenzior
---
ell/key.c | 170 ++++++++++++--------------------------------------------------
1 file changed, 33 insertions(+), 137 deletions(-)
diff --git a/ell/key.c b/ell/key.c
index fe2fbb3..37e1841 100644
--- a/ell/key.c
+++ b/ell/key.c
@@ -238,6 +238,26 @@ static long kernel_key_eds(int op, int32_t serial, const char *encoding,
return result >= 0 ? result : -errno;
}
+static long kernel_key_verify(int32_t serial,
+ const char *encoding, const char *hash,
+ const void *data, size_t data_len,
+ const void *sig, size_t sig_len)
+{
+ struct keyctl_pkey_params params = {
+ .key_id = serial,
+ .in_len = data_len,
+ .in2_len = sig_len,
+ };
+ char *info = format_key_info(encoding, hash);
+ long result;
+
+ result = syscall(__NR_keyctl, KEYCTL_PKEY_VERIFY, ¶ms,
+ info ?: "", data, sig);
+ l_free(info);
+
+ return result >= 0 ? result : -errno;
+}
+
static bool setup_internal_keyring(void)
{
internal_keyring = kernel_add_key("keyring", "ell-internal", NULL, 0,
@@ -352,7 +372,7 @@ static const char *lookup_cipher(enum l_key_cipher_type cipher)
/* Padding is handled in userspace, so the kernel only sees
* raw RSA operations
*/
- ret = "raw";
+ ret = "pkcs1";
break;
case L_KEY_RSA_RAW:
ret = "raw";
@@ -461,75 +481,6 @@ static ssize_t eds_common(struct l_key *key,
len_out);
}
-static void getrandom_nonzero(uint8_t *buf, int len)
-{
- l_getrandom(buf, len);
-
- while (len--) {
- while (buf[0] == 0)
- l_getrandom(buf, 1);
-
- buf++;
- }
-}
-
-/* PKCS#1 v1.5 RSA padding according to RFC3447 */
-static uint8_t *pad(const uint8_t *in, size_t len_in, size_t len_out,
- uint8_t flag, bool randfill)
-{
- size_t fill_len;
- uint8_t *padded;
-
- if (len_in > len_out - 11)
- return NULL;
-
- padded = l_malloc(len_out);
- fill_len = len_out - len_in - 3;
-
- padded[0] = 0x00;
- padded[1] = flag;
-
- if (randfill)
- getrandom_nonzero(padded + 2, fill_len);
- else
- memset(padded + 2, 0xff, fill_len);
-
- padded[fill_len + 2] = 0x00;
- memcpy(padded + fill_len + 3, in, len_in);
-
- return padded;
-}
-
-static ssize_t unpad(uint8_t *in, uint8_t *out, size_t len_in, size_t len_out,
- uint8_t flag, bool randfill)
-{
- size_t pos;
- ssize_t unpad_len;
-
- if (in[0] != 0x00 || in[1] != flag)
- return -EINVAL;
-
- if (randfill)
- for (pos = 2; pos < len_in && in[pos] != 0x00; pos++);
- else
- for (pos = 2; pos < len_in && in[pos] == 0xff; pos++);
-
- if (pos < 10 || pos == len_in)
- return -EINVAL;
-
- pos++;
- unpad_len = len_in - pos;
-
- if (out) {
- if ((size_t)unpad_len > len_out)
- return -EINVAL;
-
- memcpy(out, in + pos, unpad_len);
- }
-
- return unpad_len;
-}
-
LIB_EXPORT ssize_t l_key_encrypt(struct l_key *key,
enum l_key_cipher_type cipher,
enum l_checksum_type checksum,
@@ -543,14 +494,6 @@ LIB_EXPORT ssize_t l_key_encrypt(struct l_key *key,
if (checksum != L_CHECKSUM_NONE)
return -EINVAL;
- if (cipher == L_KEY_RSA_PKCS1_V1_5) {
- padded = pad(in, len_in, len_out, 0x02, true);
- if (!padded)
- return -EOVERFLOW;
-
- cipher = L_KEY_RSA_RAW;
- }
-
ret_len = eds_common(key, cipher, checksum, padded ?: in, out,
padded ? len_out : len_in, len_out,
KEYCTL_PKEY_ENCRYPT);
@@ -566,28 +509,19 @@ LIB_EXPORT ssize_t l_key_decrypt(struct l_key *key,
const void *in, void *out,
size_t len_in, size_t len_out)
{
- uint8_t *padded = NULL;
ssize_t ret_len;
/* Other checksum types are not yet supported */
if (checksum != L_CHECKSUM_NONE)
return -EINVAL;
- if (cipher == L_KEY_RSA_PKCS1_V1_5)
- padded = l_malloc(len_in);
-
- ret_len = eds_common(key, cipher, checksum, in, padded ?: out, len_in,
- padded ? len_in : len_out, KEYCTL_PKEY_DECRYPT);
+ ret_len = eds_common(key, cipher, checksum, in, out, len_in,
+ len_out, KEYCTL_PKEY_DECRYPT);
if (ret_len < 0)
goto done;
- if (padded)
- ret_len = unpad(padded, out, ret_len, len_out, 0x02, true);
-
done:
- l_free(padded);
-
return ret_len;
}
@@ -596,27 +530,16 @@ LIB_EXPORT ssize_t l_key_sign(struct l_key *key,
enum l_checksum_type checksum, const void *in,
void *out, size_t len_in, size_t len_out)
{
- uint8_t *padded = NULL;
ssize_t ret_len;
/* Other checksum types are not yet supported */
if (checksum != L_CHECKSUM_NONE)
return -EINVAL;
- if (cipher == L_KEY_RSA_PKCS1_V1_5) {
- padded = pad(in, len_in, len_out, 0x01, false);
- if (!padded)
- return -EOVERFLOW;
-
- cipher = L_KEY_RSA_RAW;
- }
-
- ret_len = eds_common(key, cipher, checksum, padded ?: in, out,
- padded ? len_out : len_in, len_out,
+ ret_len = eds_common(key, cipher, checksum, in, out,
+ len_in, len_out,
KEYCTL_PKEY_SIGN);
- l_free(padded);
-
return ret_len;
}
@@ -626,48 +549,21 @@ LIB_EXPORT bool l_key_verify(struct l_key *key,
const void *sig, size_t len_data,
size_t len_sig)
{
- enum l_key_cipher_type kernel_cipher;
- ssize_t hash_len;
- uint8_t *compare_hash;
- L_AUTO_FREE_VAR(uint8_t *, sig_hash);
+ long result;
- sig_hash = l_malloc(len_sig);
+ if (unlikely(!key))
+ return false;
/* Other checksum types are not yet supported */
if (checksum != L_CHECKSUM_NONE)
return false;
- /* The keyctl verify implementation compares the verify results
- * before we get a chance to unpad it. Instead, use the *encrypt*
- * operation (which uses the same math as verify) to get the hash
- * returned to us so it can be unpadded before comparing
- */
- if (cipher == L_KEY_RSA_PKCS1_V1_5)
- kernel_cipher = L_KEY_RSA_RAW;
- else
- kernel_cipher = cipher;
-
- hash_len = eds_common(key, kernel_cipher, checksum, sig, sig_hash,
- len_sig, len_sig, KEYCTL_PKEY_ENCRYPT);
-
- if (hash_len < 0)
- return false;
-
- compare_hash = sig_hash;
-
- if (cipher == L_KEY_RSA_PKCS1_V1_5) {
- ssize_t unpad_len;
-
- unpad_len = unpad(sig_hash, NULL, hash_len, 0, 0x01, false);
- if (unpad_len < 0)
- return false;
-
- compare_hash += hash_len - unpad_len;
- hash_len = unpad_len;
- }
+ result = kernel_key_verify(key->serial, lookup_cipher(cipher),
+ lookup_checksum(checksum),
+ data, len_data,
+ sig, len_sig);
- return (len_data == (size_t)hash_len) &&
- (memcmp(data, compare_hash, hash_len) == 0);
+ return result >= 0;
}
LIB_EXPORT struct l_keyring *l_keyring_new(void)
--
2.16.1
2 years, 3 months
[PATCHv2] key: Have kernel handle padding
by Denis Kenzior
Starting with Linux Kernel 4.20 the padding can be handled entirely in
kernel space. In preparation for that Kernel version (which will be
the first upstream kernel with asymmetric key support) remove the
userspace padding code.
---
v2:
- Addressing comments from Mat
- Removed L_CHECKSUM_NONE sanity checks based on input from Andrew
ell/key.c | 196 +++++++++++---------------------------------------------------
1 file changed, 34 insertions(+), 162 deletions(-)
diff --git a/ell/key.c b/ell/key.c
index fe2fbb3..4dcc9cd 100644
--- a/ell/key.c
+++ b/ell/key.c
@@ -35,7 +35,6 @@
#include "util.h"
#include "key.h"
#include "string.h"
-#include "random.h"
#ifndef KEYCTL_DH_COMPUTE
#define KEYCTL_DH_COMPUTE 23
@@ -238,6 +237,26 @@ static long kernel_key_eds(int op, int32_t serial, const char *encoding,
return result >= 0 ? result : -errno;
}
+static long kernel_key_verify(int32_t serial,
+ const char *encoding, const char *hash,
+ const void *data, size_t data_len,
+ const void *sig, size_t sig_len)
+{
+ struct keyctl_pkey_params params = {
+ .key_id = serial,
+ .in_len = data_len,
+ .in2_len = sig_len,
+ };
+ char *info = format_key_info(encoding, hash);
+ long result;
+
+ result = syscall(__NR_keyctl, KEYCTL_PKEY_VERIFY, ¶ms,
+ info ?: "", data, sig);
+ l_free(info);
+
+ return result >= 0 ? result : -errno;
+}
+
static bool setup_internal_keyring(void)
{
internal_keyring = kernel_add_key("keyring", "ell-internal", NULL, 0,
@@ -352,7 +371,7 @@ static const char *lookup_cipher(enum l_key_cipher_type cipher)
/* Padding is handled in userspace, so the kernel only sees
* raw RSA operations
*/
- ret = "raw";
+ ret = "pkcs1";
break;
case L_KEY_RSA_RAW:
ret = "raw";
@@ -402,10 +421,6 @@ LIB_EXPORT bool l_key_get_info(struct l_key *key, enum l_key_cipher_type cipher,
if (unlikely(!key))
return false;
- /* Other checksum types are not yet supported */
- if (checksum != L_CHECKSUM_NONE)
- return false;
-
return !kernel_query_key(key->serial, lookup_cipher(cipher),
lookup_checksum(checksum), bits,
public);
@@ -461,102 +476,18 @@ static ssize_t eds_common(struct l_key *key,
len_out);
}
-static void getrandom_nonzero(uint8_t *buf, int len)
-{
- l_getrandom(buf, len);
-
- while (len--) {
- while (buf[0] == 0)
- l_getrandom(buf, 1);
-
- buf++;
- }
-}
-
-/* PKCS#1 v1.5 RSA padding according to RFC3447 */
-static uint8_t *pad(const uint8_t *in, size_t len_in, size_t len_out,
- uint8_t flag, bool randfill)
-{
- size_t fill_len;
- uint8_t *padded;
-
- if (len_in > len_out - 11)
- return NULL;
-
- padded = l_malloc(len_out);
- fill_len = len_out - len_in - 3;
-
- padded[0] = 0x00;
- padded[1] = flag;
-
- if (randfill)
- getrandom_nonzero(padded + 2, fill_len);
- else
- memset(padded + 2, 0xff, fill_len);
-
- padded[fill_len + 2] = 0x00;
- memcpy(padded + fill_len + 3, in, len_in);
-
- return padded;
-}
-
-static ssize_t unpad(uint8_t *in, uint8_t *out, size_t len_in, size_t len_out,
- uint8_t flag, bool randfill)
-{
- size_t pos;
- ssize_t unpad_len;
-
- if (in[0] != 0x00 || in[1] != flag)
- return -EINVAL;
-
- if (randfill)
- for (pos = 2; pos < len_in && in[pos] != 0x00; pos++);
- else
- for (pos = 2; pos < len_in && in[pos] == 0xff; pos++);
-
- if (pos < 10 || pos == len_in)
- return -EINVAL;
-
- pos++;
- unpad_len = len_in - pos;
-
- if (out) {
- if ((size_t)unpad_len > len_out)
- return -EINVAL;
-
- memcpy(out, in + pos, unpad_len);
- }
-
- return unpad_len;
-}
-
LIB_EXPORT ssize_t l_key_encrypt(struct l_key *key,
enum l_key_cipher_type cipher,
enum l_checksum_type checksum,
const void *in, void *out,
size_t len_in, size_t len_out)
{
- uint8_t *padded = NULL;
ssize_t ret_len;
- /* Other checksum types are not yet supported */
- if (checksum != L_CHECKSUM_NONE)
- return -EINVAL;
-
- if (cipher == L_KEY_RSA_PKCS1_V1_5) {
- padded = pad(in, len_in, len_out, 0x02, true);
- if (!padded)
- return -EOVERFLOW;
-
- cipher = L_KEY_RSA_RAW;
- }
-
- ret_len = eds_common(key, cipher, checksum, padded ?: in, out,
- padded ? len_out : len_in, len_out,
+ ret_len = eds_common(key, cipher, checksum, in, out,
+ len_in, len_out,
KEYCTL_PKEY_ENCRYPT);
- l_free(padded);
-
return ret_len;
}
@@ -566,28 +497,15 @@ LIB_EXPORT ssize_t l_key_decrypt(struct l_key *key,
const void *in, void *out,
size_t len_in, size_t len_out)
{
- uint8_t *padded = NULL;
ssize_t ret_len;
- /* Other checksum types are not yet supported */
- if (checksum != L_CHECKSUM_NONE)
- return -EINVAL;
-
- if (cipher == L_KEY_RSA_PKCS1_V1_5)
- padded = l_malloc(len_in);
-
- ret_len = eds_common(key, cipher, checksum, in, padded ?: out, len_in,
- padded ? len_in : len_out, KEYCTL_PKEY_DECRYPT);
+ ret_len = eds_common(key, cipher, checksum, in, out, len_in,
+ len_out, KEYCTL_PKEY_DECRYPT);
if (ret_len < 0)
goto done;
- if (padded)
- ret_len = unpad(padded, out, ret_len, len_out, 0x02, true);
-
done:
- l_free(padded);
-
return ret_len;
}
@@ -596,27 +514,12 @@ LIB_EXPORT ssize_t l_key_sign(struct l_key *key,
enum l_checksum_type checksum, const void *in,
void *out, size_t len_in, size_t len_out)
{
- uint8_t *padded = NULL;
ssize_t ret_len;
- /* Other checksum types are not yet supported */
- if (checksum != L_CHECKSUM_NONE)
- return -EINVAL;
-
- if (cipher == L_KEY_RSA_PKCS1_V1_5) {
- padded = pad(in, len_in, len_out, 0x01, false);
- if (!padded)
- return -EOVERFLOW;
-
- cipher = L_KEY_RSA_RAW;
- }
-
- ret_len = eds_common(key, cipher, checksum, padded ?: in, out,
- padded ? len_out : len_in, len_out,
+ ret_len = eds_common(key, cipher, checksum, in, out,
+ len_in, len_out,
KEYCTL_PKEY_SIGN);
- l_free(padded);
-
return ret_len;
}
@@ -626,48 +529,17 @@ LIB_EXPORT bool l_key_verify(struct l_key *key,
const void *sig, size_t len_data,
size_t len_sig)
{
- enum l_key_cipher_type kernel_cipher;
- ssize_t hash_len;
- uint8_t *compare_hash;
- L_AUTO_FREE_VAR(uint8_t *, sig_hash);
-
- sig_hash = l_malloc(len_sig);
-
- /* Other checksum types are not yet supported */
- if (checksum != L_CHECKSUM_NONE)
- return false;
-
- /* The keyctl verify implementation compares the verify results
- * before we get a chance to unpad it. Instead, use the *encrypt*
- * operation (which uses the same math as verify) to get the hash
- * returned to us so it can be unpadded before comparing
- */
- if (cipher == L_KEY_RSA_PKCS1_V1_5)
- kernel_cipher = L_KEY_RSA_RAW;
- else
- kernel_cipher = cipher;
-
- hash_len = eds_common(key, kernel_cipher, checksum, sig, sig_hash,
- len_sig, len_sig, KEYCTL_PKEY_ENCRYPT);
+ long result;
- if (hash_len < 0)
+ if (unlikely(!key))
return false;
- compare_hash = sig_hash;
-
- if (cipher == L_KEY_RSA_PKCS1_V1_5) {
- ssize_t unpad_len;
-
- unpad_len = unpad(sig_hash, NULL, hash_len, 0, 0x01, false);
- if (unpad_len < 0)
- return false;
-
- compare_hash += hash_len - unpad_len;
- hash_len = unpad_len;
- }
+ result = kernel_key_verify(key->serial, lookup_cipher(cipher),
+ lookup_checksum(checksum),
+ data, len_data,
+ sig, len_sig);
- return (len_data == (size_t)hash_len) &&
- (memcmp(data, compare_hash, hash_len) == 0);
+ return result >= 0;
}
LIB_EXPORT struct l_keyring *l_keyring_new(void)
--
2.16.1
2 years, 3 months
[PATCH 01/11] settings: Fix a format string
by Andrew Zaborowski
The %d conersion specifier is for integers.
---
ell/settings.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ell/settings.c b/ell/settings.c
index c6cb0ff..e3e8303 100644
--- a/ell/settings.c
+++ b/ell/settings.c
@@ -1068,7 +1068,7 @@ LIB_EXPORT bool l_settings_set_double(struct l_settings *settings,
{
L_AUTO_FREE_VAR(char *, buf);
- buf = l_strdup_printf("%d", in);
+ buf = l_strdup_printf("%f", in);
return l_settings_set_value(settings, group_name, key, buf);
}
--
2.19.1
2 years, 3 months