pem.c (3168B)
1 /* Copyright (c) 2001, Matej Pfajfar. 2 * Copyright (c) 2001-2004, Roger Dingledine. 3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 4 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 5 /* See LICENSE for licensing information */ 6 7 /** 8 * \file pem.c 9 * 10 * \brief Implement a trivial version of PEM encoding, for use with NSS. 11 * 12 * We deliberately do not support any encryption here. 13 **/ 14 15 #include "orconfig.h" 16 17 #include "lib/encoding/pem.h" 18 19 #include "lib/ctime/di_ops.h" 20 #include "lib/encoding/binascii.h" 21 #include "lib/log/util_bug.h" 22 #include "lib/malloc/malloc.h" 23 #include "lib/string/printf.h" 24 #include "lib/string/util_string.h" 25 26 #include <string.h> 27 28 /** 29 * Return the length of a <b>src_len</b>-byte object when tagged with 30 * <b>objtype</b> and PEM-encoded. Includes terminating NUL. 31 */ 32 size_t 33 pem_encoded_size(size_t src_len, const char *objtype) 34 { 35 return 36 strlen("-----BEGIN -----\n") + 37 strlen("-----END -----\n") + 38 strlen(objtype) * 2 + 39 base64_encode_size(src_len, BASE64_ENCODE_MULTILINE) 40 + 1; 41 } 42 43 /** 44 * PEM-encode the <b>srclen</b>-byte object at <b>src</b> into the 45 * <b>destlen</b>-byte buffer at <b>dest</b>, tagging it with <b>objtype</b>. 46 * Return 0 on success and -1 on failure. 47 */ 48 int 49 pem_encode(char *dest, size_t destlen, const uint8_t *src, size_t srclen, 50 const char *objtype) 51 { 52 if (tor_snprintf(dest, destlen, "-----BEGIN %s-----\n", objtype) < 0) 53 return -1; 54 55 size_t offset = strlen(dest); 56 57 int n = base64_encode(dest + offset, destlen - offset, 58 (const char *)src, srclen, BASE64_ENCODE_MULTILINE); 59 if (n < 0) 60 return -1; 61 offset += n; 62 if (BUG(offset > destlen)) 63 return -1; 64 65 if (tor_snprintf(dest + offset, destlen - offset, 66 "-----END %s-----\n", objtype) < 0) 67 return -1; 68 69 tor_assert(strlen(dest) + 1 <= pem_encoded_size(srclen, objtype)); 70 return 0; 71 } 72 73 /** 74 * Given a PEM-encoded block of size <b>srclen</b> in <b>src</b>, if it has 75 * object type <b>objtype</b>, decode it into the <b>destlen</b>-byte buffer 76 * at <b>dest</b>. Return the number of characters decoded on success, or -1 77 * on failure. 78 */ 79 int 80 pem_decode(uint8_t *dest, size_t destlen, const char *src, size_t srclen, 81 const char *objtype) 82 { 83 const char *eos = src + srclen; 84 85 src = eat_whitespace_eos(src, eos); 86 87 char *tag = NULL; 88 tor_asprintf(&tag, "-----BEGIN %s-----", objtype); 89 if ((size_t)(eos-src) < strlen(tag) || fast_memneq(src, tag, strlen(tag))) { 90 tor_free(tag); 91 return -1; 92 } 93 src += strlen(tag); 94 tor_free(tag); 95 /* At this point we insist on spaces (including CR), then an LF. */ 96 src = eat_whitespace_eos_no_nl(src, eos); 97 if (src == eos || *src != '\n') { 98 /* Extra junk at end of line: this isn't valid. */ 99 return -1; 100 } 101 102 // NOTE lack of trailing \n. We do not enforce its presence. 103 tor_asprintf(&tag, "\n-----END %s-----", objtype); 104 const char *end_of_base64 = tor_memstr(src, eos-src, tag); 105 tor_free(tag); 106 if (end_of_base64 == NULL) 107 return -1; 108 109 /* Should we actually allow extra stuff at the end? */ 110 111 return base64_decode((char*)dest, destlen, src, end_of_base64-src); 112 }