[PATCH 1/2] cipher: Add AEAD API with AES-CCM
by Mat Martineau
Add new function calls to handle encryption and decryption for
authenticated encryption with associated data (AEAD).
The only AEAD cipher supported so far is AES-CCM.
Requires kernel v4.10 or later for l_aead_cipher_encrypt() and
l_aead_cipher_decrypt() to return the correct length. Earlier kernels have a
bug in AF_ALG aead sockets.
---
ell/cipher.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
ell/cipher.h | 24 ++++++
2 files changed, 244 insertions(+), 18 deletions(-)
diff --git a/ell/cipher.c b/ell/cipher.c
index ac5248a..ddcd310 100644
--- a/ell/cipher.c
+++ b/ell/cipher.c
@@ -28,6 +28,7 @@
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
+#include <alloca.h>
#include "util.h"
#include "cipher.h"
@@ -85,8 +86,14 @@ struct l_cipher {
int decrypt_sk;
};
+struct l_aead_cipher {
+ int type;
+ int encrypt_sk;
+ int decrypt_sk;
+};
+
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, size_t tag_length)
{
struct sockaddr_alg salg;
int sk;
@@ -111,6 +118,12 @@ static int create_alg(const char *alg_type, const char *alg_name,
return -1;
}
+ if (tag_length && setsockopt(sk, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL,
+ tag_length)) {
+ close(sk);
+ return -1;
+ }
+
ret = accept4(sk, NULL, 0, SOCK_CLOEXEC);
close(sk);
@@ -151,11 +164,55 @@ 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,
+ 0);
+ if (cipher->encrypt_sk < 0)
+ goto error_free;
+
+ cipher->decrypt_sk = create_alg("skcipher", alg_name, key, key_length,
+ 0);
+ if (cipher->decrypt_sk < 0)
+ goto error_close;
+
+ return cipher;
+
+error_close:
+ close(cipher->encrypt_sk);
+error_free:
+ l_free(cipher);
+ return NULL;
+}
+
+LIB_EXPORT struct l_aead_cipher *l_aead_cipher_new(enum l_aead_cipher_type type,
+ const void *key,
+ size_t key_length,
+ size_t tag_length)
+{
+ struct l_aead_cipher *cipher;
+ const char *alg_name;
+
+ if (unlikely(!key))
+ return NULL;
+
+ if (type != L_AEAD_CIPHER_AES_CCM)
+ return NULL;
+
+ cipher = l_new(struct l_aead_cipher, 1);
+ cipher->type = type;
+
+ switch (type) {
+ case L_AEAD_CIPHER_AES_CCM:
+ alg_name = "ccm(aes)";
+ break;
+ }
+
+ cipher->encrypt_sk = create_alg("aead", alg_name, key, key_length,
+ tag_length);
if (cipher->encrypt_sk < 0)
goto error_free;
- cipher->decrypt_sk = create_alg("skcipher", alg_name, key, key_length);
+ cipher->decrypt_sk = create_alg("aead", alg_name, key, key_length,
+ tag_length);
if (cipher->decrypt_sk < 0)
goto error_close;
@@ -179,21 +236,61 @@ LIB_EXPORT void l_cipher_free(struct l_cipher *cipher)
l_free(cipher);
}
+LIB_EXPORT void l_aead_cipher_free(struct l_aead_cipher *cipher)
+{
+ if (unlikely(!cipher))
+ return;
+
+ close(cipher->encrypt_sk);
+ close(cipher->decrypt_sk);
+
+ 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, void *out, size_t len_in,
- size_t len_out)
+ 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)
{
- char c_msg_buf[CMSG_SPACE(sizeof(operation))];
+ char *c_msg_buf;
+ size_t c_msg_size;
struct msghdr msg;
struct cmsghdr *c_msg;
- struct iovec iov;
+ struct iovec iov[2];
ssize_t result;
- memset(&c_msg_buf, 0, sizeof(c_msg_buf));
+ c_msg_size = CMSG_SPACE(sizeof(operation));
+ c_msg_size += ad_len ? CMSG_SPACE(sizeof(uint32_t)) : 0;
+ c_msg_size += (nonce && iv_len) ?
+ CMSG_SPACE(sizeof(struct af_alg_iv) + iv_len) : 0;
+
+ c_msg_buf = alloca(c_msg_size);
+
+ memset(c_msg_buf, 0, c_msg_size);
memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = iov;
+
msg.msg_control = c_msg_buf;
- msg.msg_controllen = sizeof(c_msg_buf);
+ msg.msg_controllen = c_msg_size;
c_msg = CMSG_FIRSTHDR(&msg);
c_msg->cmsg_level = SOL_ALG;
@@ -201,17 +298,75 @@ static ssize_t operate_cipher(int sk, __u32 operation,
c_msg->cmsg_len = CMSG_LEN(sizeof(operation));
memcpy(CMSG_DATA(c_msg), &operation, sizeof(operation));
- iov.iov_base = (void *) in;
- iov.iov_len = len_in;
+ if (ad_len) {
+ uint32_t *ad_data;
+
+ c_msg = CMSG_NXTHDR(&msg, c_msg);
+ c_msg->cmsg_level = SOL_ALG;
+ c_msg->cmsg_type = ALG_SET_AEAD_ASSOCLEN;
+ c_msg->cmsg_len = CMSG_LEN(sizeof(*ad_data));
+ ad_data = (void *) CMSG_DATA(c_msg);
+ *ad_data = ad_len;
+
+ iov[0].iov_base = (void *) ad;
+ iov[0].iov_len = ad_len;
+ iov[1].iov_base = (void *) in;
+ iov[1].iov_len = in_len;
+ msg.msg_iovlen = 2;
+ } else {
+ iov[0].iov_base = (void *) in;
+ iov[0].iov_len = in_len;
+ msg.msg_iovlen = 1;
+ }
+
+ if (nonce && iv_len) {
+ struct af_alg_iv *algiv;
+
+ c_msg = CMSG_NXTHDR(&msg, c_msg);
+ c_msg->cmsg_level = SOL_ALG;
+ c_msg->cmsg_type = ALG_SET_IV;
+ c_msg->cmsg_len = CMSG_LEN(sizeof(*algiv) + iv_len);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
+ 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;
+ }
result = sendmsg(sk, &msg, 0);
if (result < 0)
return -errno;
- result = read(sk, out, len_out);
+ if (ad) {
+ /*
+ * When AEAD additional data is passed to sendmsg() for
+ * use in computing the tag, those bytes also appear at
+ * the beginning of the encrypt or decrypt results. Rather
+ * than force the caller to pad their result buffer with
+ * the correct number of bytes for the additional data,
+ * the necessary space is allocated here and then the
+ * duplicate AAD is discarded.
+ */
+ iov[0].iov_base = l_malloc(ad_len);
+ iov[0].iov_len = ad_len;
+ iov[1].iov_base = (void *) out;
+ iov[1].iov_len = out_len;
+ msg.msg_iovlen = 2;
+
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+
+ result = recvmsg(sk, &msg, 0);
+
+ if (result > (ssize_t) ad_len)
+ result -= ad_len;
+
+ l_free(iov[0].iov_base);
+ } else {
+ result = read(sk, out, out_len);
+ }
+
if (result < 0)
return -errno;
@@ -227,8 +382,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,
- len) >= 0;
+ return operate_cipher(cipher->encrypt_sk, ALG_OP_ENCRYPT, in, len,
+ NULL, 0, NULL, 0, out, len, 0) >= 0;
}
LIB_EXPORT bool l_cipher_decrypt(struct l_cipher *cipher,
@@ -240,8 +395,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,
- len) >= 0;
+ return operate_cipher(cipher->decrypt_sk, ALG_OP_DECRYPT, in, len,
+ NULL, 0, NULL, 0, out, len, 0) >= 0;
}
LIB_EXPORT bool l_cipher_set_iv(struct l_cipher *cipher, const uint8_t *iv,
@@ -279,3 +434,50 @@ LIB_EXPORT bool l_cipher_set_iv(struct l_cipher *cipher, const uint8_t *iv,
return true;
}
+
+static size_t l_aead_cipher_get_ivlen(struct l_aead_cipher *cipher)
+{
+ size_t ret;
+
+ switch (cipher->type) {
+ case L_AEAD_CIPHER_AES_CCM:
+ ret = 16;
+ break;
+ }
+
+ return ret;
+}
+
+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)
+{
+ if (unlikely(!cipher))
+ return false;
+
+ if (unlikely(!in) || unlikely(!out))
+ return false;
+
+ 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)) >= 0;
+}
+
+LIB_EXPORT bool l_aead_cipher_decrypt(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)
+{
+ if (unlikely(!cipher))
+ return false;
+
+ if (unlikely(!in) || unlikely(!out))
+ return false;
+
+ 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)) >= 0;
+}
diff --git a/ell/cipher.h b/ell/cipher.h
index f9ff42f..29c9542 100644
--- a/ell/cipher.h
+++ b/ell/cipher.h
@@ -51,6 +51,30 @@ bool l_cipher_decrypt(struct l_cipher *cipher,
bool l_cipher_set_iv(struct l_cipher *cipher, const uint8_t *iv,
size_t iv_length);
+struct l_aead_cipher;
+
+enum l_aead_cipher_type {
+ L_AEAD_CIPHER_AES_CCM = 0,
+};
+
+struct l_aead_cipher *l_aead_cipher_new(enum l_aead_cipher_type type,
+ const void *key, size_t key_length,
+ size_t tag_length);
+
+void l_aead_cipher_free(struct l_aead_cipher *cipher);
+
+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);
+
+bool l_aead_cipher_decrypt(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);
+
#ifdef __cplusplus
}
#endif
--
2.11.0
4 years, 2 months
[PATCH 1/3] cipher: Remove more public key vestiges from cipher internals
by Mat Martineau
---
ell/cipher.c | 23 ++++-------------------
1 file changed, 4 insertions(+), 19 deletions(-)
diff --git a/ell/cipher.c b/ell/cipher.c
index 139331e..ac5248a 100644
--- a/ell/cipher.c
+++ b/ell/cipher.c
@@ -77,17 +77,6 @@ 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 {
@@ -97,11 +86,10 @@ struct l_cipher {
};
static int create_alg(const char *alg_type, const char *alg_name,
- const void *key, size_t key_length, bool public)
+ const void *key, size_t key_length)
{
struct sockaddr_alg salg;
int sk;
- int keyopt;
int ret;
sk = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
@@ -118,8 +106,7 @@ static int create_alg(const char *alg_type, const char *alg_name,
return -1;
}
- keyopt = public ? ALG_SET_PUBKEY : ALG_SET_KEY;
- if (setsockopt(sk, SOL_ALG, keyopt, key, key_length) < 0) {
+ if (setsockopt(sk, SOL_ALG, ALG_SET_KEY, key, key_length) < 0) {
close(sk);
return -1;
}
@@ -164,13 +151,11 @@ 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,
- false);
+ cipher->encrypt_sk = create_alg("skcipher", alg_name, key, key_length);
if (cipher->encrypt_sk < 0)
goto error_free;
- cipher->decrypt_sk = create_alg("skcipher", alg_name, key, key_length,
- false);
+ cipher->decrypt_sk = create_alg("skcipher", alg_name, key, key_length);
if (cipher->decrypt_sk < 0)
goto error_close;
--
2.11.0
4 years, 2 months
[PATCH] genl: Add a genl_family getter for genl
by Andrew Zaborowski
Add l_genl_family_get_genl function (redundant but accurate name)
---
ell/genl.c | 8 ++++++++
ell/genl.h | 1 +
2 files changed, 9 insertions(+)
diff --git a/ell/genl.c b/ell/genl.c
index c522ae7..cff3a9a 100644
--- a/ell/genl.c
+++ b/ell/genl.c
@@ -1173,6 +1173,14 @@ LIB_EXPORT uint32_t l_genl_family_get_version(struct l_genl_family *family)
return family->version;
}
+LIB_EXPORT struct l_genl *l_genl_family_get_genl(struct l_genl_family *family)
+{
+ if (unlikely(!family))
+ return 0;
+
+ return family->genl;
+}
+
static bool match_op_id(const void *a, const void *b)
{
const struct genl_op *op = a;
diff --git a/ell/genl.h b/ell/genl.h
index fe188d9..8597c8f 100644
--- a/ell/genl.h
+++ b/ell/genl.h
@@ -104,6 +104,7 @@ bool l_genl_set_unicast_handler(struct l_genl *genl,
l_genl_destroy_func_t destroy);
uint32_t l_genl_family_get_version(struct l_genl_family *family);
+struct l_genl *l_genl_family_get_genl(struct l_genl_family *family);
bool l_genl_family_can_send(struct l_genl_family *family, uint8_t cmd);
bool l_genl_family_can_dump(struct l_genl_family *family, uint8_t cmd);
--
2.9.3
4 years, 2 months
Build ell with clang
by ell@ongy.net
Hello,
the following patchseries allows ell to be build with clang.
For clang -Wcast-align has to be removed. I asked about this on
#llvm(a)irc.oftc.net and was told, this is the best option.
They also told me that gcc only actually produces a warning, if the
compilation target does not support unaligned access at all, so for x86
the option does nothing.
It may well be, that gcc will error out as well, if such an architecture
were to be targeted.
It may be better to remove -Wcast-align completely instead of making it
gcc specific, as this patch does.
Regards,
Markus
4 years, 2 months
[PATCH v2 1/2] string: Add l_utf8_get_codepoint to string
by Markus Ongyerth
From: Markus Ongyerth <ell(a)ongy.net>
Add a function to get an unicode codepoint from a utf-8 string.
This can be used to convert strings to other representations.
Also rewrite the l_utf8_validdate to use the new function.
---
ell/string.c | 85 +++++++++++++++++++++++++++++++++++++++---------------------
ell/string.h | 2 ++
2 files changed, 57 insertions(+), 30 deletions(-)
diff --git a/ell/string.c b/ell/string.c
index 6c443d0..ce165aa 100644
--- a/ell/string.c
+++ b/ell/string.c
@@ -345,6 +345,57 @@ static inline bool __attribute__ ((always_inline))
}
/**
+ * l_utf8_get_codepoint
+ * @str: a pointer to codepoint data
+ * @len: maximum bytes to read
+ * @cp: destination for codepoint
+ *
+ * Returns: number of bytes read, or -1 for invalid coddepoint
+ **/
+LIB_EXPORT int l_utf8_get_codepoint(const char *str, size_t len, wchar_t *cp)
+{
+ static const int mins[3] = { 1 << 7, 1 << 11, 1 << 16 };
+ unsigned int expect_bytes;
+ wchar_t val;
+ size_t i;
+
+ if (str[0] > 0) {
+ *cp = str[0];
+ return 1;
+ }
+
+ expect_bytes = __builtin_clz(~(str[0] << 24));
+
+ if (expect_bytes < 2 || expect_bytes > 4)
+ goto error;
+
+ if (expect_bytes > len)
+ goto error;
+
+ val = str[0] & (0xff >> (expect_bytes + 1));
+
+ for (i = 1; i < expect_bytes; i++) {
+ if ((str[i] & 0xc0) == 0)
+ goto error;
+
+ val <<= 6;
+ val |= str[i] & 0x3f;
+ }
+
+ if (val < mins[expect_bytes - 2])
+ goto error;
+
+ if (valid_unicode(val) == false)
+ goto error;
+
+ *cp = val;
+ return expect_bytes;
+
+error:
+ return -1;
+}
+
+/**
* l_utf8_validate:
* @str: a pointer to character data
* @len: max bytes to validate
@@ -359,43 +410,17 @@ static inline bool __attribute__ ((always_inline))
**/
LIB_EXPORT bool l_utf8_validate(const char *str, size_t len, const char **end)
{
- static const int mins[3] = { 1 << 7, 1 << 11, 1 << 16 };
size_t pos = 0;
- unsigned int expect_bytes;
+ int ret;
wchar_t val;
- size_t i;
while (pos < len && str[pos]) {
- if (str[pos] > 0) {
- pos += 1;
- continue;
- }
-
- expect_bytes = __builtin_clz(~(str[pos] << 24));
-
- if (expect_bytes < 2 || expect_bytes > 4)
- goto error;
-
- if (pos + expect_bytes > len)
- goto error;
-
- val = str[pos] & (0xff >> (expect_bytes + 1));
-
- for (i = pos + 1; i < pos + expect_bytes; i++) {
- if ((str[i] & 0xc0) == 0)
- goto error;
-
- val <<= 6;
- val |= str[i] & 0x3f;
- }
-
- if (val < mins[expect_bytes - 2])
- goto error;
+ ret = l_utf8_get_codepoint(str + pos, len - pos, &val);
- if (valid_unicode(val) == false)
+ if (ret < 0)
goto error;
- pos += expect_bytes;
+ pos += ret;
}
error:
diff --git a/ell/string.h b/ell/string.h
index 6549a05..09e6f2d 100644
--- a/ell/string.h
+++ b/ell/string.h
@@ -25,6 +25,7 @@
#include <stdbool.h>
#include <stdarg.h>
+#include <wchar.h>
#ifdef __cplusplus
extern "C" {
@@ -117,6 +118,7 @@ struct l_string *l_string_truncate(struct l_string *string, size_t new_size);
unsigned int l_string_length(struct l_string *string);
bool l_utf8_validate(const char *src, size_t len, const char **end);
+int l_utf8_get_codepoint(const char *str, size_t len, wchar_t *cp);
size_t l_utf8_strlen(const char *src);
#ifdef __cplusplus
--
2.10.2
4 years, 2 months
[PATCH 1/2] Add l_utf8_get_codepoint to string
by Markus Ongyerth
Add a function to get an unicode codepoint from a utf-8 string.
This can be used to convert strings to other representations.
Also rewrite the l_utf8_validdate to use the new function.
---
ell/string.c | 86 +++++++++++++++++++++++++++++++++++++++---------------------
ell/string.h | 2 ++
2 files changed, 58 insertions(+), 30 deletions(-)
diff --git a/ell/string.c b/ell/string.c
index 6c443d0..0ae099c 100644
--- a/ell/string.c
+++ b/ell/string.c
@@ -345,6 +345,58 @@ static inline bool __attribute__ ((always_inline))
}
/**
+ * l_utf8_get_codepoint
+ * @str: a pointer to codepoint data
+ * @len: maximum bytes to read
+ * @cp: destination for codepoint
+ *
+ * Returns: number of bytes read, or -1 for invalid coddepoint
+ **/
+LIB_EXPORT int l_utf8_get_codepoint(const char *str, size_t len, wchar_t *cp)
+{
+ static const int mins[3] = { 1 << 7, 1 << 11, 1 << 16 };
+ unsigned int expect_bytes;
+ wchar_t val;
+ size_t i;
+
+ if (str[0] > 0) {
+ *cp = str[0];
+ return 1;
+ }
+
+ expect_bytes = __builtin_clz(~(str[0] << 24));
+
+ if (expect_bytes < 2 || expect_bytes > 4)
+ goto error;
+
+ if (expect_bytes > len)
+ goto error;
+
+ val = str[0] & (0xff >> (expect_bytes + 1));
+
+ for (i = 1; i < expect_bytes; i++) {
+ if ((str[i] & 0xc0) == 0)
+ goto error;
+
+ val <<= 6;
+ val |= str[i] & 0x3f;
+ }
+
+ if (val < mins[expect_bytes - 2])
+ goto error;
+
+ if (valid_unicode(val) == false)
+ goto error;
+
+ *cp = val;
+ return expect_bytes;
+
+error:
+ *cp = 0;
+ return -1;
+}
+
+/**
* l_utf8_validate:
* @str: a pointer to character data
* @len: max bytes to validate
@@ -359,43 +411,17 @@ static inline bool __attribute__ ((always_inline))
**/
LIB_EXPORT bool l_utf8_validate(const char *str, size_t len, const char **end)
{
- static const int mins[3] = { 1 << 7, 1 << 11, 1 << 16 };
size_t pos = 0;
- unsigned int expect_bytes;
+ int ret;
wchar_t val;
- size_t i;
while (pos < len && str[pos]) {
- if (str[pos] > 0) {
- pos += 1;
- continue;
- }
-
- expect_bytes = __builtin_clz(~(str[pos] << 24));
-
- if (expect_bytes < 2 || expect_bytes > 4)
- goto error;
-
- if (pos + expect_bytes > len)
- goto error;
-
- val = str[pos] & (0xff >> (expect_bytes + 1));
-
- for (i = pos + 1; i < pos + expect_bytes; i++) {
- if ((str[i] & 0xc0) == 0)
- goto error;
-
- val <<= 6;
- val |= str[i] & 0x3f;
- }
-
- if (val < mins[expect_bytes - 2])
- goto error;
+ ret = l_utf8_get_codepoint(str + pos, len - pos, &val);
- if (valid_unicode(val) == false)
+ if (ret < 0)
goto error;
- pos += expect_bytes;
+ pos += ret;
}
error:
diff --git a/ell/string.h b/ell/string.h
index 6549a05..09e6f2d 100644
--- a/ell/string.h
+++ b/ell/string.h
@@ -25,6 +25,7 @@
#include <stdbool.h>
#include <stdarg.h>
+#include <wchar.h>
#ifdef __cplusplus
extern "C" {
@@ -117,6 +118,7 @@ struct l_string *l_string_truncate(struct l_string *string, size_t new_size);
unsigned int l_string_length(struct l_string *string);
bool l_utf8_validate(const char *src, size_t len, const char **end);
+int l_utf8_get_codepoint(const char *str, size_t len, wchar_t *cp);
size_t l_utf8_strlen(const char *src);
#ifdef __cplusplus
--
2.10.2
4 years, 2 months
[PATCH] Add a timing safe bcmp function
by Markus Ongyerth
From: Markus Ongyerth <ell(a)ongy.net>
For comparing cryptographically relevant memory area, a constant time
comparison function is required to prevent timing side channel attacks.
The timingsafe_bcmp function taken from openbsd is such a function.
The l_util_timingsafe_bcmp function exports it for ell.
---
Makefile.am | 4 +++-
ell/timingsafe-bcmp-private.h | 24 ++++++++++++++++++++++++
ell/timingsafe-bcmp.c | 34 ++++++++++++++++++++++++++++++++++
ell/util.c | 12 ++++++++++++
ell/util.h | 2 ++
5 files changed, 75 insertions(+), 1 deletion(-)
create mode 100644 ell/timingsafe-bcmp-private.h
create mode 100644 ell/timingsafe-bcmp.c
diff --git a/Makefile.am b/Makefile.am
index d6863ba..c1892ac 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -91,7 +91,9 @@ ell_libell_la_SOURCES = $(linux_headers) \
ell/tls.c \
ell/tls-record.c \
ell/uuid.c \
- ell/key.c
+ ell/key.c \
+ ell/timingsafe-bcmp.c \
+ ell/timingsafe-bcmp-private.h
ell_libell_la_LDFLAGS = -no-undefined \
-version-info $(ELL_CURRENT):$(ELL_REVISION):$(ELL_AGE)
diff --git a/ell/timingsafe-bcmp-private.h b/ell/timingsafe-bcmp-private.h
new file mode 100644
index 0000000..20ccace
--- /dev/null
+++ b/ell/timingsafe-bcmp-private.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * Embedded Linux library
+ *
+ * Copyright (C) 2016 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
+ *
+ */
+
+#include <stdlib.h>
+int timingsafe_bcmp(const void *b1, const void *b2, size_t n);
diff --git a/ell/timingsafe-bcmp.c b/ell/timingsafe-bcmp.c
new file mode 100644
index 0000000..5f686f1
--- /dev/null
+++ b/ell/timingsafe-bcmp.c
@@ -0,0 +1,34 @@
+/* $OpenBSD: timingsafe_bcmp.c,v 1.3 2015/08/31 02:53:57 guenther Exp $ */
+/*
+ * Copyright (c) 2010 Damien Miller. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file is taken from [1] and only modified to fit into the ell
+ * [1] http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/lib/libc/string/t...
+ */
+
+#include "timingsafe-bcmp-private.h"
+
+int
+timingsafe_bcmp(const void *b1, const void *b2, size_t n)
+{
+ const unsigned char *p1 = b1, *p2 = b2;
+ int ret = 0;
+
+ for (; n > 0; n--)
+ ret |= *p1++ ^ *p2++;
+ return (ret != 0);
+}
diff --git a/ell/util.c b/ell/util.c
index 98916e5..838c1fd 100644
--- a/ell/util.c
+++ b/ell/util.c
@@ -33,6 +33,7 @@
#include "util.h"
#include "private.h"
+#include "timingsafe-bcmp-private.h"
/**
* SECTION:util
@@ -681,3 +682,14 @@ LIB_EXPORT const char *l_util_get_debugfs_path(void)
return path;
}
+
+/**
+ * l_util_timingsafe_bcmp:
+ *
+ * A utility function to compare memory areas in time proportional to size.
+ * This should be used to prevent timing attacks when comparing e.g. hashes
+ **/
+LIB_EXPORT int l_util_timingsafe_bcmp(void *m1, void *m2, size_t n)
+{
+ return timingsafe_bcmp(m1, m2, n);
+}
diff --git a/ell/util.h b/ell/util.h
index a77c0b8..748ac57 100644
--- a/ell/util.h
+++ b/ell/util.h
@@ -237,6 +237,8 @@ void l_util_debug(l_util_hexdump_func_t function, void *user_data,
const char *l_util_get_debugfs_path(void);
+int l_util_timingsafe_bcmp(void *m1, void *m2, size_t n);
+
#ifdef __cplusplus
}
#endif
--
2.10.2
4 years, 2 months
[PATCH 1/2] Add DES and MD4 support
by Markus Ongyerth
From: Markus Ongyerth <ell(a)ongy.net>
Add support for DES in cipher and MD4 in checksum to allow implementing
the mschapv2 protocol.
---
ell/checksum.c | 8 ++++++++
ell/checksum.h | 1 +
ell/cipher.c | 3 +++
ell/cipher.h | 1 +
ell/key.c | 3 +++
5 files changed, 16 insertions(+)
diff --git a/ell/checksum.c b/ell/checksum.c
index 5a5228d..39e351e 100644
--- a/ell/checksum.c
+++ b/ell/checksum.c
@@ -128,6 +128,9 @@ LIB_EXPORT struct l_checksum *l_checksum_new(enum l_checksum_type type)
switch (type) {
case L_CHECKSUM_NONE:
return NULL;
+ case L_CHECKSUM_MD4:
+ name = "md4";
+ break;
case L_CHECKSUM_MD5:
name = "md5";
break;
@@ -207,6 +210,9 @@ struct l_checksum *l_checksum_new_hmac(enum l_checksum_type type,
switch (type) {
case L_CHECKSUM_NONE:
return NULL;
+ case L_CHECKSUM_MD4:
+ name = "hmac(md4)";
+ break;
case L_CHECKSUM_MD5:
name = "hmac(md5)";
break;
@@ -406,12 +412,14 @@ LIB_EXPORT char *l_checksum_get_string(struct l_checksum *checksum)
const char *name;
size_t digest_len;
} digest_lut[] = {
+ { .name = "md4", .digest_len = 16 },
{ .name = "md5", .digest_len = 16 },
{ .name = "sha1", .digest_len = 20 },
{ .name = "sha256", .digest_len = 32 },
{ .name = "sha384", .digest_len = 48 },
{ .name = "sha512", .digest_len = 64 },
{ .name = "cmac(aes)", .digest_len = 16 },
+ { .name = "hmac(md4)", .digest_len = 16 },
{ .name = "hmac(md5)", .digest_len = 16 },
{ .name = "hmac(sha1)", .digest_len = 20 },
{ .name = "hmac(sha256)", .digest_len = 32 },
diff --git a/ell/checksum.h b/ell/checksum.h
index be118ff..9895b1c 100644
--- a/ell/checksum.h
+++ b/ell/checksum.h
@@ -35,6 +35,7 @@ struct l_checksum;
enum l_checksum_type {
L_CHECKSUM_NONE,
+ L_CHECKSUM_MD4,
L_CHECKSUM_MD5,
L_CHECKSUM_SHA1,
L_CHECKSUM_SHA256,
diff --git a/ell/cipher.c b/ell/cipher.c
index 8312451..139331e 100644
--- a/ell/cipher.c
+++ b/ell/cipher.c
@@ -156,6 +156,9 @@ LIB_EXPORT struct l_cipher *l_cipher_new(enum l_cipher_type type,
case L_CIPHER_ARC4:
alg_name = "ecb(arc4)";
break;
+ case L_CIPHER_DES:
+ alg_name = "ecb(des)";
+ break;
case L_CIPHER_DES3_EDE_CBC:
alg_name = "cbc(des3_ede)";
break;
diff --git a/ell/cipher.h b/ell/cipher.h
index f5c6646..f9ff42f 100644
--- a/ell/cipher.h
+++ b/ell/cipher.h
@@ -33,6 +33,7 @@ enum l_cipher_type {
L_CIPHER_AES = 0,
L_CIPHER_AES_CBC,
L_CIPHER_ARC4,
+ L_CIPHER_DES,
L_CIPHER_DES3_EDE_CBC,
};
diff --git a/ell/key.c b/ell/key.c
index 11700e8..db9abb1 100644
--- a/ell/key.c
+++ b/ell/key.c
@@ -357,6 +357,9 @@ static const char *lookup_checksum(enum l_checksum_type checksum)
switch (checksum) {
case L_CHECKSUM_NONE:
break;
+ case L_CHECKSUM_MD4:
+ ret = "md4";
+ break;
case L_CHECKSUM_MD5:
ret = "md5";
break;
--
2.10.2
4 years, 2 months