diff options
author | Nick Mathewson <nickm@torproject.org> | 2018-07-19 15:47:48 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2018-08-21 12:24:08 -0400 |
commit | 9566ed6fd9e4aab2ce6b84afc2f7112550cf0483 (patch) | |
tree | c9fc667a53d2b6e748062b08f7ca3c9734b78741 /src/lib/encoding/pem.c | |
parent | 0812f1cbc2f528f0acb785e2fea416b9f2113c7c (diff) | |
download | tor-9566ed6fd9e4aab2ce6b84afc2f7112550cf0483.tar.gz tor-9566ed6fd9e4aab2ce6b84afc2f7112550cf0483.zip |
Add rudimentary support for PEM-encoding, since NSS doesn't do that.
Diffstat (limited to 'src/lib/encoding/pem.c')
-rw-r--r-- | src/lib/encoding/pem.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/src/lib/encoding/pem.c b/src/lib/encoding/pem.c new file mode 100644 index 0000000000..0d4a814f6f --- /dev/null +++ b/src/lib/encoding/pem.c @@ -0,0 +1,106 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file pem.c + * + * \brief Implement a trivial version of PEM encoding, for use with NSS. + * + * We deliberately do not support any encryption here. + **/ + +#include "orconfig.h" + +#include "lib/encoding/pem.h" + +#include "lib/ctime/di_ops.h" +#include "lib/encoding/binascii.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/malloc.h" +#include "lib/string/printf.h" +#include "lib/string/util_string.h" + +#include <string.h> + +/** + * Return the length of a <b>src_len</b>-byte object when tagged with + * <b>objtype</b> and PEM-encoded. Includes terminating NUL. + */ +size_t +pem_encoded_size(size_t src_len, const char *objtype) +{ + return + strlen("-----BEGIN -----\n") + + strlen("-----END -----\n") + + strlen(objtype) * 2 + + base64_encode_size(src_len, BASE64_ENCODE_MULTILINE) + + 1; +} + +/** + * PEM-encode the <b>srclen</b>-byte object at <b>src</b> into the + * <b>destlen<\b>-byte buffer at <b>dest</b>, tagging it with <b>objtype</b>. + * Return 0 on success and -1 on failure. + */ +int +pem_encode(char *dest, size_t destlen, const uint8_t *src, size_t srclen, + const char *objtype) +{ + if (tor_snprintf(dest, destlen, "-----BEGIN %s-----\n", objtype) < 0) + return -1; + + size_t offset = strlen(dest); + + int n = base64_encode(dest + offset, destlen - offset, + (const char *)src, srclen, BASE64_ENCODE_MULTILINE); + if (n < 0) + return -1; + offset += n; + if (BUG(offset > destlen)) + return -1; + + if (tor_snprintf(dest + offset, destlen - offset, + "-----END %s-----\n", objtype) < 0) + return -1; + + tor_assert(strlen(dest) + 1 <= pem_encoded_size(srclen, objtype)); + return 0; +} + +/** + * Given a PEM-encoded block of size <b>srclen</b> in <b>src</b>, if it has + * object type <b>objtype</b>, decode it into the <b>destlen</b>-byte buffer + * at <b>dest</b>. Return the number of characters decoded on success, or -1 + * on failure. + */ +int +pem_decode(uint8_t *dest, size_t destlen, const char *src, size_t srclen, + const char *objtype) +{ + const char *eos = src + srclen; + + src = eat_whitespace_eos(src, eos); + + char *tag = NULL; + tor_asprintf(&tag, "-----BEGIN %s-----\n", objtype); + if ((size_t)(eos-src) < strlen(tag) || fast_memneq(src, tag, strlen(tag))) { + tor_free(tag); + return -1; + } + src += strlen(tag); + tor_free(tag); + + // NOTE lack of trailing \n. We do not enforce its presence. + tor_asprintf(&tag, "\n-----END %s-----", objtype); + const char *end_of_base64 = tor_memstr(src, eos-src, tag); + tor_free(tag); + if (end_of_base64 == NULL) + return -1; + + /* Should we actually allow extra stuff at the end? */ + + return base64_decode((char*)dest, destlen, src, end_of_base64-src); +} |