From daa2dfa2dbc6e732d989a89ce97253d5a2eb7a63 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sun, 22 Mar 2015 14:39:14 +0100 Subject: [PATCH] pem.c: add _libssh2_pem_parse_memory to parse PEM from memory Requirement to implement 18cfec8336e for Libgcrypt and WinCNG. --- src/libssh2_priv.h | 5 +++ src/pem.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h index 6007e7b..83f154f 100644 --- a/src/libssh2_priv.h +++ b/src/libssh2_priv.h @@ -1026,6 +1026,11 @@ int _libssh2_pem_parse(LIBSSH2_SESSION * session, const char *headerbegin, const char *headerend, FILE * fp, unsigned char **data, unsigned int *datalen); +int _libssh2_pem_parse_memory(LIBSSH2_SESSION * session, + const char *headerbegin, + const char *headerend, + const char *filedata, size_t filedata_len, + unsigned char **data, unsigned int *datalen); int _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen); int _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, unsigned char **i, unsigned int *ilen); diff --git a/src/pem.c b/src/pem.c index c939ea0..3e496fe 100644 --- a/src/pem.c +++ b/src/pem.c @@ -67,6 +67,33 @@ readline(char *line, int line_size, FILE * fp) return 0; } +static int +readline_memory(char *line, size_t line_size, + const char *filedata, size_t filedata_len, + size_t *filedata_offset) +{ + size_t off, len; + + off = *filedata_offset; + + for (len = 0; off + len < filedata_len && len < line_size; len++) { + if (filedata[off + len] == '\n' || + filedata[off + len] == '\r') { + break; + } + } + + if (len) { + memcpy(line, filedata + off, len); + *filedata_offset += len; + } + + line[len] = '\0'; + *filedata_offset++; + + return 0; +} + #define LINE_SIZE 128 int @@ -133,6 +160,72 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, return ret; } +int +_libssh2_pem_parse_memory(LIBSSH2_SESSION * session, + const char *headerbegin, + const char *headerend, + const char *filedata, size_t filedata_len, + unsigned char **data, unsigned int *datalen) +{ + char line[LINE_SIZE]; + char *b64data = NULL; + unsigned int b64datalen = 0; + size_t off = 0; + int ret; + + do { + *line = '\0'; + + if (readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { + return -1; + } + } + while (strcmp(line, headerbegin) != 0); + + *line = '\0'; + + do { + if (*line) { + char *tmp; + size_t linelen; + + linelen = strlen(line); + tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); + if (!tmp) { + ret = -1; + goto out; + } + memcpy(tmp + b64datalen, line, linelen); + b64data = tmp; + b64datalen += linelen; + } + + *line = '\0'; + + if (readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { + ret = -1; + goto out; + } + } while (strcmp(line, headerend) != 0); + + if (!b64data) { + return -1; + } + + if (libssh2_base64_decode(session, (char**) data, datalen, + b64data, b64datalen)) { + ret = -1; + goto out; + } + + ret = 0; + out: + if (b64data) { + LIBSSH2_FREE(session, b64data); + } + return ret; +} + static int read_asn1_length(const unsigned char *data, unsigned int datalen, unsigned int *len)