Add l_pem_load_certificate_chain and l_pem_load_certificate_list that
load certificate chains and lists of certificates such as those
generated by openssl and return an l_certchain and an l_queue
respectively.
---
ell/pem.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++--------
ell/pem.h | 5 ++
2 files changed, 123 insertions(+), 19 deletions(-)
diff --git a/ell/pem.c b/ell/pem.c
index e24dd7d..fee24d5 100644
--- a/ell/pem.c
+++ b/ell/pem.c
@@ -39,6 +39,7 @@
#include "asn1-private.h"
#include "pkcs5-private.h"
#include "cipher.h"
+#include "cert-private.h"
#define PEM_START_BOUNDARY "-----BEGIN "
#define PEM_END_BOUNDARY "-----END "
@@ -119,7 +120,8 @@ static bool is_end_boundary(const uint8_t *buf, size_t buf_len,
}
static uint8_t *pem_load_buffer(const uint8_t *buf, size_t buf_len, int index,
- char **type_label, size_t *len)
+ char **type_label, size_t *len,
+ const uint8_t **endp)
{
const uint8_t *base64_data = NULL, *label = NULL, *eol;
uint8_t *data;
@@ -152,6 +154,9 @@ static uint8_t *pem_load_buffer(const uint8_t *buf, size_t buf_len,
int index,
*type_label = l_strndup((const char *) label,
label_len);
+ if (endp)
+ *endp = eol + 1;
+
return data;
}
@@ -171,6 +176,10 @@ static uint8_t *pem_load_buffer(const uint8_t *buf, size_t buf_len,
int index,
}
}
+ /* If we found no label signal EOF rather than parse error */
+ if (!base64_data && endp)
+ *endp = NULL;
+
return NULL;
}
@@ -178,38 +187,58 @@ LIB_EXPORT uint8_t *l_pem_load_buffer(const uint8_t *buf, size_t
buf_len,
int index, char **type_label,
size_t *out_len)
{
- return pem_load_buffer(buf, buf_len, index, type_label, out_len);
+ return pem_load_buffer(buf, buf_len, index, type_label, out_len, NULL);
}
-LIB_EXPORT uint8_t *l_pem_load_file(const char *filename, int index,
- char **type_label, size_t *len)
-{
+struct pem_file_info {
int fd;
struct stat st;
- uint8_t *data, *result;
+ uint8_t *data;
+};
- fd = open(filename, O_RDONLY);
- if (fd < 0)
- return NULL;
+static int pem_file_open(struct pem_file_info *info, const char *filename)
+{
+ info->fd = open(filename, O_RDONLY);
+ if (info->fd < 0)
+ return -errno;
- if (fstat(fd, &st) < 0) {
- close(fd);
+ if (fstat(info->fd, &info->st) < 0) {
+ int r = -errno;
- return NULL;
+ close(info->fd);
+ return r;
}
- data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
- if (data == MAP_FAILED) {
- close(fd);
+ info->data = mmap(NULL, info->st.st_size,
+ PROT_READ, MAP_SHARED, info->fd, 0);
+ if (info->data == MAP_FAILED) {
+ int r = -errno;
- return NULL;
+ close(info->fd);
+ return r;
}
- result = pem_load_buffer(data, st.st_size, index, type_label, len);
+ return 0;
+}
+
+static void pem_file_close(struct pem_file_info *info)
+{
+ munmap(info->data, info->st.st_size);
+ close(info->fd);
+}
+
+LIB_EXPORT uint8_t *l_pem_load_file(const char *filename, int index,
+ char **type_label, size_t *len)
+{
+ struct pem_file_info file;
+ uint8_t *result;
- munmap(data, st.st_size);
- close(fd);
+ if (pem_file_open(&file, filename) < 0)
+ return NULL;
+ result = pem_load_buffer(file.data, file.st.st_size, index,
+ type_label, len, NULL);
+ pem_file_close(&file);
return result;
}
@@ -233,6 +262,76 @@ LIB_EXPORT uint8_t *l_pem_load_certificate(const char *filename,
size_t *len)
return content;
}
+LIB_EXPORT struct l_certchain *l_pem_load_certificate_chain(
+ const char *filename)
+{
+ struct l_queue *list = l_pem_load_certificate_list(filename);
+ struct l_certchain *chain;
+
+ if (!list)
+ return NULL;
+
+ chain = certchain_new_from_leaf(l_queue_pop_head(list));
+
+ while (!l_queue_isempty(list))
+ certchain_link_issuer(chain, l_queue_pop_head(list));
+
+ l_queue_destroy(list, NULL);
+ return chain;
+}
+
+LIB_EXPORT struct l_queue *l_pem_load_certificate_list(const char *filename)
+{
+ struct pem_file_info file;
+ const uint8_t *ptr, *end;
+ struct l_queue *list = NULL;
+
+ if (pem_file_open(&file, filename) < 0)
+ return NULL;
+
+ ptr = file.data;
+ end = file.data + file.st.st_size;
+
+ while (ptr && ptr < end) {
+ uint8_t *der;
+ size_t der_len;
+ char *label;
+ struct l_cert *cert;
+
+ der = pem_load_buffer(ptr, end - ptr, 0, &label, &der_len, &ptr);
+
+ if (!der || strcmp(label, "CERTIFICATE")) {
+ l_free(der);
+ l_free(label);
+
+ if (!ptr) /* EOF */
+ break;
+ else
+ goto error;
+ }
+
+ l_free(label);
+ cert = l_cert_new_from_der(der, der_len);
+ l_free(der);
+
+ if (!cert)
+ goto error;
+
+ if (!list)
+ list = l_queue_new();
+
+ l_queue_push_tail(list, cert);
+ }
+
+ pem_file_close(&file);
+ return list;
+
+error:
+ l_queue_destroy(list, (l_queue_destroy_func_t) l_cert_free);
+ pem_file_close(&file);
+ return NULL;
+}
+
/**
* l_pem_load_private_key
* @filename: path string to the PEM file to load
diff --git a/ell/pem.h b/ell/pem.h
index 93282a3..d381707 100644
--- a/ell/pem.h
+++ b/ell/pem.h
@@ -27,12 +27,17 @@
extern "C" {
#endif
+#include <ell/cert.h>
+#include <ell/queue.h>
+
uint8_t *l_pem_load_buffer(const uint8_t *buf, size_t buf_len,
int index, char **type_label, size_t *out_len);
uint8_t *l_pem_load_file(const char *filename, int index,
char **type_label, size_t *len);
uint8_t *l_pem_load_certificate(const char *filename, size_t *len);
+struct l_certchain *l_pem_load_certificate_chain(const char *filename);
+struct l_queue *l_pem_load_certificate_list(const char *filename);
uint8_t *l_pem_load_private_key(const char *filename, const char *passphrase,
bool *encrypted, size_t *len);
--
2.19.1