From 666718998eaa044f6f25fe99810a78dca8471393 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 18 May 2014 20:49:35 +0200 Subject: [PATCH] Implement a PEM-like format for Ed25519 keys. We don't require compatibility with any other software, but we do want Ed25519 keys to work the same as RSA keys for now. --- src/ed25519/ecdsa.c | 47 ++++++++++++++++++++++++++++++++++++++++-- src/ed25519/ecdsagen.c | 20 ++++++++++++++++-- src/tincctl.c | 2 +- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/ed25519/ecdsa.c b/src/ed25519/ecdsa.c index 4515131a..bfdabc19 100644 --- a/src/ed25519/ecdsa.c +++ b/src/ed25519/ecdsa.c @@ -62,9 +62,52 @@ char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) { // Read PEM ECDSA keys +static bool read_pem(FILE *fp, const char *type, void *buf, size_t size) { + char line[1024]; + bool data = false; + size_t typelen = strlen(type); + + while(fgets(line, sizeof line, fp)) { + if(!data) { + if(strncmp(line, "-----BEGIN ", 11)) + continue; + if(strncmp(line + 11, type, typelen)) + continue; + data = true; + continue; + } + + if(!strncmp(line, "-----END ", 9)) + break; + + size_t linelen = strcspn(line, "\r\n"); + size_t len = b64decode(line, line, linelen); + if(!len) { + logger(DEBUG_ALWAYS, LOG_ERR, "Invalid base64 data in PEM file\n"); + return false; + } + + if(len > size) { + logger(DEBUG_ALWAYS, LOG_ERR, "Too much base64 data in PEM file\n"); + return false; + } + + memcpy(buf, line, len); + buf += len; + size -= len; + } + + if(size) { + logger(DEBUG_ALWAYS, LOG_ERR, "Too little base64 data in PEM file\n"); + return false; + } + + return true; +} + ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) { ecdsa_t *ecdsa = xzalloc(sizeof *ecdsa); - if(fread(ecdsa->public, sizeof ecdsa->public, 1, fp) == 1) + if(read_pem(fp, "ED25519 PUBLIC KEY", ecdsa->public, sizeof ecdsa->public)) return ecdsa; free(ecdsa); return 0; @@ -72,7 +115,7 @@ ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) { ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) { ecdsa_t *ecdsa = xmalloc(sizeof *ecdsa); - if(fread(ecdsa, sizeof *ecdsa, 1, fp) == 1) + if(read_pem(fp, "ED25519 PRIVATE KEY", ecdsa->private, sizeof *ecdsa)) return ecdsa; free(ecdsa); return 0; diff --git a/src/ed25519/ecdsagen.c b/src/ed25519/ecdsagen.c index 41845739..d2a14890 100644 --- a/src/ed25519/ecdsagen.c +++ b/src/ed25519/ecdsagen.c @@ -46,10 +46,26 @@ ecdsa_t *ecdsa_generate(void) { // Write PEM ECDSA keys +static bool write_pem(FILE *fp, const char *type, void *buf, size_t size) { + fprintf(fp, "-----BEGIN %s-----\n", type); + + char base64[65]; + while(size) { + size_t todo = size > 48 ? 48 : size; + b64encode(buf, base64, todo); + fprintf(fp, "%s\n", base64); + buf += todo; + size -= todo; + } + + fprintf(fp, "-----END %s-----\n", type); + return !ferror(fp); +} + bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) { - return fwrite(ecdsa->public, sizeof ecdsa->public, 1, fp) == 1; + return write_pem(fp, "ED25519 PUBLIC KEY", ecdsa->public, sizeof ecdsa->public); } bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) { - return fwrite(ecdsa, sizeof *ecdsa, 1, fp) == 1; + return write_pem(fp, "ED25519 PRIVATE KEY", ecdsa->private, sizeof *ecdsa); } diff --git a/src/tincctl.c b/src/tincctl.c index 5f2b1351..7a3195e5 100644 --- a/src/tincctl.c +++ b/src/tincctl.c @@ -246,7 +246,7 @@ static void disable_old_keys(const char *filename, const char *what) { while(fgets(buf, sizeof buf, r)) { if(!block && !strncmp(buf, "-----BEGIN ", 11)) { - if((strstr(buf, " RSA ") && strstr(what, "RSA"))) { + if((strstr(buf, " ED25519 ") && strstr(what, "Ed25519")) || (strstr(buf, " RSA ") && strstr(what, "RSA"))) { disabled = true; block = true; } -- 2.20.1