Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow loading PEM credentials from memory #284

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ SET(MINICRYPTO_LIBRARY_FILES
deps/cifra/src/sha512.c)
SET(CORE_FILES
lib/picotls.c
lib/cred_buffer.c
lib/pembase64.c)
SET(CORE_TEST_FILES
t/picotls.c)
Expand Down Expand Up @@ -83,7 +84,9 @@ ADD_EXECUTABLE(test-minicrypto.t
${CORE_TEST_FILES}
t/minicrypto.c
lib/asn1.c
lib/cred_buffer.c
lib/pembase64.c
lib/minicrypto-pem.c
lib/ffx.c
lib/cifra/x25519.c
lib/cifra/chacha20.c
Expand All @@ -99,7 +102,7 @@ IF (OPENSSL_FOUND AND NOT (OPENSSL_VERSION VERSION_LESS "1.0.1"))
INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
ADD_LIBRARY(picotls-openssl lib/openssl.c)
TARGET_LINK_LIBRARIES(picotls-openssl ${OPENSSL_LIBRARIES} picotls-core ${CMAKE_DL_LIBS})
ADD_EXECUTABLE(cli t/cli.c lib/pembase64.c)
ADD_EXECUTABLE(cli t/cli.c lib/cred_buffer.c lib/pembase64.c)
TARGET_LINK_LIBRARIES(cli picotls-openssl picotls-core)
ADD_EXECUTABLE(picotls-esni src/esni.c)
TARGET_LINK_LIBRARIES(picotls-esni picotls-openssl picotls-core ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS})
Expand All @@ -114,6 +117,7 @@ IF (OPENSSL_FOUND AND NOT (OPENSSL_VERSION VERSION_LESS "1.0.1"))
lib/cifra/random.c
lib/uecc.c
lib/asn1.c
lib/cred_buffer.c
lib/pembase64.c
lib/ffx.c
deps/picotest/picotest.c
Expand Down
30 changes: 30 additions & 0 deletions include/picotls/cred_buffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef PTLS_CRED_BUFFER_H
#define PTLS_CRED_BUFFER_H

#ifdef __cplusplus
extern "C" {
#endif

#include "picotls.h"

typedef struct ptls_cred_buffer_s {
char *base;
size_t len;
size_t off;
int owns_base;
#define PTLS_CRED_BUFFER_RPOS(buf) ((buf)->base + (buf)->off)
#define PTLS_CRED_BUFFER_REND(buf) ((buf)->base + (buf)->len)
#define PTLS_CRED_BUFFER_LEFT(buf) ((buf)->len - (buf)->off)
} ptls_cred_buffer_t;

int ptls_cred_buffer_set_from_file(ptls_cred_buffer_t *buf, const char *fname);
int ptls_cred_buffer_set_from_string(ptls_cred_buffer_t *buf, char *s);
void ptls_cred_buffer_dispose(ptls_cred_buffer_t *buf);
void ptls_cred_buffer_rewind(ptls_cred_buffer_t *buf);
char *ptls_cred_buffer_gets(char *s, int n, ptls_cred_buffer_t *buf);

#ifdef __cplusplus
}
#endif

#endif /* !PTLS_CRED_BUFFER_H */
2 changes: 2 additions & 0 deletions include/picotls/minicrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ extern "C" {
#endif

#include "picotls.h"
#include "picotls/cred_buffer.h"

#define SECP256R1_PRIVATE_KEY_SIZE 32
#define SECP256R1_PUBLIC_KEY_SIZE 65 /* including the header */
Expand Down Expand Up @@ -62,6 +63,7 @@ typedef struct st_ptls_asn1_pkcs8_private_key_t {
} ptls_asn1_pkcs8_private_key_t;

int ptls_minicrypto_load_private_key(ptls_context_t *ctx, char const *pem_fname);
int ptls_minicrypto_load_private_key_from_memory(ptls_context_t *ctx, ptls_cred_buffer_t *mem);

#ifdef __cplusplus
}
Expand Down
6 changes: 6 additions & 0 deletions include/picotls/pembase64.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#ifndef PTLS_PEMBASE64_H
#define PTLS_PEMBASE64_H

#include "picotls/cred_buffer.h"

/*
* Base64 functions used in encoding and decoding of PEM files
*/
Expand All @@ -41,4 +43,8 @@ int ptls_base64_decode(const char *base64_text, ptls_base64_decode_state_t *stat

int ptls_load_pem_objects(char const *pem_fname, const char *label, ptls_iovec_t *list, size_t list_max, size_t *nb_objects);

int ptls_load_pem_objects_from_memory(ptls_cred_buffer_t *mem, const char *label, ptls_iovec_t *list, size_t list_max, size_t *nb_objects);

int ptls_load_certificates_from_memory(ptls_context_t *ctx, ptls_cred_buffer_t *mem);

#endif /* PTLS_PEMBASE64_H */
139 changes: 139 additions & 0 deletions lib/cred_buffer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "picotls/cred_buffer.h"

#define MIN(a, b) ((a) < (b) ? (a) : (b))

static int cred_buffer_getc(ptls_cred_buffer_t *buf)
{
return PTLS_CRED_BUFFER_LEFT(buf) > 0 ? buf->base[buf->off++] : -1;
}

static ssize_t fsize(FILE *fp)
{
long sz;

if (fseek(fp, 0, SEEK_END) == -1 || (sz = ftell(fp)) == -1) {
return -1;
}

rewind(fp);

return (ssize_t) sz;
}

/* The caller owns 'mem' and must have called ptls_buffer_init prior to
* invoking this function */
int ptls_cred_buffer_set_from_file(ptls_cred_buffer_t *buf, const char *fname)
{
FILE *fp = NULL;
ssize_t sz;
char *m = NULL;

#ifdef _WINDOWS
errno_t err = fopen_s(&fp, fname, "r");
if (err != 0) {
return -1;
}
#else
fp = fopen(fname, "r");
if (fp == NULL) {
return -1;
}
#endif

if ((sz = fsize(fp)) == -1 ||
(m = malloc(sz)) == NULL ||
fread(m, sz, 1, fp) != 1) {
goto err;
}

(void) fclose(fp);

buf->base = m;
buf->len = sz;
buf->off = 0;
buf->owns_base = 1;

return 0;
err:
if (m)
free(m);
if (fp != NULL)
(void) fclose(fp);

return -1;
}

int ptls_cred_buffer_set_from_string(ptls_cred_buffer_t *buf, char *s)
{
buf->base = s;
buf->len = strlen(s);
buf->off = 0;
buf->owns_base = 0;

return 0;
}

void ptls_cred_buffer_dispose(ptls_cred_buffer_t *buf)
{
if (buf->owns_base) {
if (buf->base) {
free(buf->base);
buf->base = NULL;
}
buf->len = buf->off = 0;
buf->owns_base = 0;
}

return;
}

void ptls_cred_buffer_rewind(ptls_cred_buffer_t *buf)
{
buf->off = 0;
return;
}

/* z -> nlptr */
char *ptls_cred_buffer_gets(char *s, int n, ptls_cred_buffer_t *buf)
{
char *p = s;
char *z;
size_t k;
int c;

if (n-- <= 1) {
if (n) return NULL;
*s = '\0';
return s;
}

while (n) {
if (PTLS_CRED_BUFFER_RPOS(buf) != PTLS_CRED_BUFFER_REND(buf)) {
z = memchr(PTLS_CRED_BUFFER_RPOS(buf), '\n', PTLS_CRED_BUFFER_LEFT(buf));
k = z ? z - PTLS_CRED_BUFFER_RPOS(buf) + 1 : PTLS_CRED_BUFFER_LEFT(buf);
k = MIN(k, n);
memcpy(p, PTLS_CRED_BUFFER_RPOS(buf), k);
buf->off += k;
p += k;
n -= k;
if (z || !n) break;
}

if ((c = cred_buffer_getc(buf)) < 0) {
if (p == s || PTLS_CRED_BUFFER_LEFT(buf) > 0) s = NULL;
break;
}

n--;

if ((*p++ = c) == '\n') break;
}

if (s) *p = '\0';

return s;
}
68 changes: 67 additions & 1 deletion lib/minicrypto-pem.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,47 @@ size_t ptls_minicrypto_asn1_decode_private_key(ptls_asn1_pkcs8_private_key_t *pk
return byte_index;
}

static int ptls_pem_parse_private_key_from_memory(ptls_cred_buffer_t *mem, ptls_asn1_pkcs8_private_key_t *pkey,
ptls_minicrypto_log_ctx_t *log_ctx)
{
size_t nb_keys = 0;
int ret = ptls_load_pem_objects_from_memory(mem, "PRIVATE KEY", &pkey->vec, 1, &nb_keys);

if (ret == 0) {
if (nb_keys != 1) {
ret = PTLS_ERROR_PEM_LABEL_NOT_FOUND;
}
}

if (ret == 0 && nb_keys == 1) {
int decode_error = 0;

if (log_ctx != NULL) {
log_ctx->fn(log_ctx->ctx, "\nFound PRIVATE KEY, length = %d bytes\n", (int)pkey->vec.len);
}

(void)ptls_minicrypto_asn1_decode_private_key(pkey, &decode_error, log_ctx);

if (decode_error != 0) {
ret = decode_error;
}
}

return ret;
}

static int ptls_pem_parse_private_key(char const *pem_fname, ptls_asn1_pkcs8_private_key_t *pkey,
ptls_minicrypto_log_ctx_t *log_ctx)
{
size_t nb_keys = 0;
int ret = ptls_load_pem_objects(pem_fname, "PRIVATE KEY", &pkey->vec, 1, &nb_keys);
int ret;
ptls_cred_buffer_t mem;

if ((ret = ptls_cred_buffer_set_from_file(&mem, pem_fname)) != 0) {
goto end;
}

ret = ptls_load_pem_objects_from_memory(&mem, "PRIVATE KEY", &pkey->vec, 1, &nb_keys);
if (ret == 0) {
if (nb_keys != 1) {
ret = PTLS_ERROR_PEM_LABEL_NOT_FOUND;
Expand All @@ -191,6 +226,9 @@ static int ptls_pem_parse_private_key(char const *pem_fname, ptls_asn1_pkcs8_pri
}
}

/* Fallthrough */
end:
ptls_cred_buffer_dispose(&mem);
return ret;
}

Expand Down Expand Up @@ -321,6 +359,34 @@ static int ptls_set_ecdsa_private_key(ptls_context_t *ctx, ptls_asn1_pkcs8_priva
return decode_error;
}

int ptls_minicrypto_load_private_key_from_memory(ptls_context_t *ctx, ptls_cred_buffer_t *mem)
{
ptls_asn1_pkcs8_private_key_t pkey = {{0}};
int ret = ptls_pem_parse_private_key_from_memory(mem, &pkey, NULL);

if (ret != 0)
goto err;

/* Check that this is the expected key type.
* At this point, the minicrypto library only supports ECDSA keys.
* In theory, we could add support for RSA keys at some point.
*/
if (pkey.algorithm_length != sizeof(ptls_asn1_algorithm_ecdsa) ||
memcmp(pkey.vec.base + pkey.algorithm_index, ptls_asn1_algorithm_ecdsa, sizeof(ptls_asn1_algorithm_ecdsa)) != 0) {
ret = -1;
goto err;
}

ret = ptls_set_ecdsa_private_key(ctx, &pkey, NULL);

err:
if (pkey.vec.base) {
ptls_clear_memory(pkey.vec.base, pkey.vec.len);
free(pkey.vec.base);
}
return ret;
}

int ptls_minicrypto_load_private_key(ptls_context_t *ctx, char const *pem_fname)
{
ptls_asn1_pkcs8_private_key_t pkey = {{0}};
Expand Down
Loading