Line data Source code
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 275 : pem_encoded_size(size_t src_len, const char *objtype)
34 : {
35 275 : return
36 : strlen("-----BEGIN -----\n") +
37 275 : strlen("-----END -----\n") +
38 550 : strlen(objtype) * 2 +
39 275 : base64_encode_size(src_len, BASE64_ENCODE_MULTILINE)
40 275 : + 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 139 : pem_encode(char *dest, size_t destlen, const uint8_t *src, size_t srclen,
50 : const char *objtype)
51 : {
52 139 : if (tor_snprintf(dest, destlen, "-----BEGIN %s-----\n", objtype) < 0)
53 : return -1;
54 :
55 139 : size_t offset = strlen(dest);
56 :
57 139 : int n = base64_encode(dest + offset, destlen - offset,
58 : (const char *)src, srclen, BASE64_ENCODE_MULTILINE);
59 139 : if (n < 0)
60 : return -1;
61 139 : offset += n;
62 139 : if (BUG(offset > destlen))
63 0 : return -1;
64 :
65 139 : if (tor_snprintf(dest + offset, destlen - offset,
66 : "-----END %s-----\n", objtype) < 0)
67 : return -1;
68 :
69 138 : 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 41294 : pem_decode(uint8_t *dest, size_t destlen, const char *src, size_t srclen,
81 : const char *objtype)
82 : {
83 41294 : const char *eos = src + srclen;
84 :
85 41294 : src = eat_whitespace_eos(src, eos);
86 :
87 41294 : char *tag = NULL;
88 41294 : tor_asprintf(&tag, "-----BEGIN %s-----", objtype);
89 41294 : if ((size_t)(eos-src) < strlen(tag) || fast_memneq(src, tag, strlen(tag))) {
90 30 : tor_free(tag);
91 30 : return -1;
92 : }
93 41264 : src += strlen(tag);
94 41264 : tor_free(tag);
95 : /* At this point we insist on spaces (including CR), then an LF. */
96 41264 : src = eat_whitespace_eos_no_nl(src, eos);
97 41264 : 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 41263 : tor_asprintf(&tag, "\n-----END %s-----", objtype);
104 41263 : const char *end_of_base64 = tor_memstr(src, eos-src, tag);
105 41263 : tor_free(tag);
106 41263 : if (end_of_base64 == NULL)
107 : return -1;
108 :
109 : /* Should we actually allow extra stuff at the end? */
110 :
111 41062 : return base64_decode((char*)dest, destlen, src, end_of_base64-src);
112 : }
|