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 crypto_format.c
9 : *
10 : * \brief Formatting and parsing code for crypto-related data structures.
11 : */
12 :
13 : #include "orconfig.h"
14 : #ifdef HAVE_SYS_STAT_H
15 : #include <sys/stat.h>
16 : #endif
17 : #include "lib/container/smartlist.h"
18 : #include "lib/crypt_ops/crypto_curve25519.h"
19 : #include "lib/crypt_ops/crypto_digest.h"
20 : #include "lib/crypt_ops/crypto_ed25519.h"
21 : #include "lib/crypt_ops/crypto_format.h"
22 : #include "lib/crypt_ops/crypto_util.h"
23 : #include "lib/string/compat_string.h"
24 : #include "lib/string/util_string.h"
25 : #include "lib/string/printf.h"
26 : #include "lib/encoding/binascii.h"
27 : #include "lib/log/log.h"
28 : #include "lib/log/util_bug.h"
29 : #include "lib/fs/files.h"
30 :
31 : #include <string.h>
32 : #include <errno.h>
33 :
34 : /** Write the <b>datalen</b> bytes from <b>data</b> to the file named
35 : * <b>fname</b> in the tagged-data format. This format contains a
36 : * 32-byte header, followed by the data itself. The header is the
37 : * NUL-padded string "== <b>typestring</b>: <b>tag</b> ==". The length
38 : * of <b>typestring</b> and <b>tag</b> must therefore be no more than
39 : * 24.
40 : **/
41 : int
42 77 : crypto_write_tagged_contents_to_file(const char *fname,
43 : const char *typestring,
44 : const char *tag,
45 : const uint8_t *data,
46 : size_t datalen)
47 : {
48 77 : char header[32];
49 77 : smartlist_t *chunks = smartlist_new();
50 77 : sized_chunk_t ch0, ch1;
51 77 : int r = -1;
52 :
53 77 : memset(header, 0, sizeof(header));
54 77 : if (tor_snprintf(header, sizeof(header),
55 : "== %s: %s ==", typestring, tag) < 0)
56 0 : goto end;
57 77 : ch0.bytes = header;
58 77 : ch0.len = 32;
59 77 : ch1.bytes = (const char*) data;
60 77 : ch1.len = datalen;
61 77 : smartlist_add(chunks, &ch0);
62 77 : smartlist_add(chunks, &ch1);
63 :
64 77 : r = write_chunks_to_file(fname, chunks, 1, 0);
65 :
66 77 : end:
67 77 : smartlist_free(chunks);
68 77 : return r;
69 : }
70 :
71 : /** Read a tagged-data file from <b>fname</b> into the
72 : * <b>data_out_len</b>-byte buffer in <b>data_out</b>. Check that the
73 : * typestring matches <b>typestring</b>; store the tag into a newly allocated
74 : * string in <b>tag_out</b>. Return -1 on failure, and the number of bytes of
75 : * data on success. Preserves the errno from reading the file. */
76 : ssize_t
77 246 : crypto_read_tagged_contents_from_file(const char *fname,
78 : const char *typestring,
79 : char **tag_out,
80 : uint8_t *data_out,
81 : ssize_t data_out_len)
82 : {
83 246 : char prefix[33];
84 246 : char *content = NULL;
85 246 : struct stat st;
86 246 : ssize_t r = -1;
87 246 : size_t st_size = 0;
88 246 : int saved_errno = 0;
89 :
90 246 : *tag_out = NULL;
91 246 : st.st_size = 0;
92 246 : content = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
93 246 : if (! content) {
94 113 : saved_errno = errno;
95 113 : goto end;
96 : }
97 133 : if (st.st_size < 32 || st.st_size > 32 + data_out_len) {
98 1 : saved_errno = EINVAL;
99 1 : goto end;
100 : }
101 132 : st_size = (size_t)st.st_size;
102 :
103 132 : memcpy(prefix, content, 32);
104 132 : prefix[32] = 0;
105 : /* Check type, extract tag. */
106 264 : if (strcmpstart(prefix, "== ") || strcmpend(prefix, " ==") ||
107 132 : ! fast_mem_is_zero(prefix+strlen(prefix), 32-strlen(prefix))) {
108 0 : saved_errno = EINVAL;
109 0 : goto end;
110 : }
111 :
112 132 : if (strcmpstart(prefix+3, typestring) ||
113 262 : 3+strlen(typestring) >= 32 ||
114 131 : strcmpstart(prefix+3+strlen(typestring), ": ")) {
115 1 : saved_errno = EINVAL;
116 1 : goto end;
117 : }
118 :
119 131 : *tag_out = tor_strndup(prefix+5+strlen(typestring),
120 : strlen(prefix)-8-strlen(typestring));
121 :
122 131 : memcpy(data_out, content+32, st_size-32);
123 131 : r = st_size - 32;
124 :
125 246 : end:
126 246 : if (content)
127 133 : memwipe(content, 0, st_size);
128 246 : tor_free(content);
129 246 : if (saved_errno)
130 113 : errno = saved_errno;
131 246 : return r;
132 : }
133 :
134 : /** Encode <b>pkey</b> as a base64-encoded string in the buffer <b>output</b>.
135 : * If <b>pad</b> is false do not include trailing "=" characters, otherwise
136 : * include them. <b>output</b> must have at least
137 : * CURVE25519_BASE64_PADDED_LEN+1 bytes available, even if <b>pad</b> is false.
138 : * Can not fail.
139 : *
140 : * Careful! CURVE25519_BASE64_PADDED_LEN is one byte longer than
141 : * ED25519_BASE64_LEN.
142 : */
143 : void
144 297 : curve25519_public_to_base64(char *output,
145 : const curve25519_public_key_t *pkey, bool pad)
146 : {
147 297 : int n, expected_len;
148 297 : if (pad) {
149 271 : n = base64_encode(output, CURVE25519_BASE64_PADDED_LEN+1,
150 271 : (const char*)pkey->public_key,
151 : CURVE25519_PUBKEY_LEN, 0);
152 271 : expected_len = CURVE25519_BASE64_PADDED_LEN;
153 : } else {
154 26 : n = base64_encode_nopad(output, CURVE25519_BASE64_PADDED_LEN+1,
155 26 : (const uint8_t*)pkey->public_key,
156 : CURVE25519_PUBKEY_LEN);
157 26 : expected_len = CURVE25519_BASE64_LEN;
158 : }
159 :
160 : /* These asserts should always succeed, unless there is a bug in
161 : * base64_encode(). */
162 297 : tor_assert(n == expected_len);
163 297 : tor_assert(output[expected_len] == '\0');
164 297 : }
165 :
166 : /** Try to decode a base64-encoded curve25519 public key from <b>input</b>
167 : * into the object at <b>pkey</b>. Return 0 on success, -1 on failure.
168 : * Accepts keys with or without a trailing "=". */
169 : int
170 521 : curve25519_public_from_base64(curve25519_public_key_t *pkey,
171 : const char *input)
172 : {
173 521 : size_t len = strlen(input);
174 521 : if (len == CURVE25519_BASE64_LEN) {
175 : /* not padded */
176 62 : return digest256_from_base64((char*)pkey->public_key, input);
177 459 : } else if (len == CURVE25519_BASE64_PADDED_LEN) {
178 454 : char buf[CURVE25519_BASE64_PADDED_LEN+1];
179 454 : if (base64_decode(buf, sizeof(buf), input, len) != CURVE25519_PUBKEY_LEN)
180 : return -1;
181 454 : memcpy(pkey->public_key, buf, CURVE25519_PUBKEY_LEN);
182 454 : return 0;
183 : } else {
184 : return -1;
185 : }
186 : }
187 :
188 : /** For logging convenience: Convert <b>pkey</b> to a statically allocated
189 : * base64 string and return it. Not threadsafe. Format not meant to be
190 : * computer-readable; it may change in the future. Subsequent calls invalidate
191 : * previous returns. */
192 : const char *
193 159 : ed25519_fmt(const ed25519_public_key_t *pkey)
194 : {
195 159 : static char formatted[ED25519_BASE64_LEN+1];
196 159 : if (pkey) {
197 152 : if (ed25519_public_key_is_zero(pkey)) {
198 13 : strlcpy(formatted, "<unset>", sizeof(formatted));
199 : } else {
200 139 : ed25519_public_to_base64(formatted, pkey);
201 : }
202 : } else {
203 7 : strlcpy(formatted, "<null>", sizeof(formatted));
204 : }
205 159 : return formatted;
206 : }
207 :
208 : /** Try to decode the string <b>input</b> into an ed25519 public key. On
209 : * success, store the value in <b>pkey</b> and return 0. Otherwise return
210 : * -1. */
211 : int
212 132 : ed25519_public_from_base64(ed25519_public_key_t *pkey,
213 : const char *input)
214 : {
215 132 : return digest256_from_base64((char*)pkey->pubkey, input);
216 : }
217 :
218 : /** Encode the public key <b>pkey</b> into the buffer at <b>output</b>,
219 : * which must have space for ED25519_BASE64_LEN bytes of encoded key,
220 : * plus one byte for a terminating NUL.
221 : * Can not fail.
222 : *
223 : * Careful! ED25519_BASE64_LEN is one byte shorter than
224 : * CURVE25519_BASE64_PADDED_LEN.
225 : */
226 : void
227 395 : ed25519_public_to_base64(char *output,
228 : const ed25519_public_key_t *pkey)
229 : {
230 395 : digest256_to_base64(output, (const char *)pkey->pubkey);
231 395 : }
232 :
233 : /** Encode the signature <b>sig</b> into the buffer at <b>output</b>,
234 : * which must have space for ED25519_SIG_BASE64_LEN bytes of encoded signature,
235 : * plus one byte for a terminating NUL.
236 : * Can not fail.
237 : */
238 : void
239 87 : ed25519_signature_to_base64(char *output,
240 : const ed25519_signature_t *sig)
241 : {
242 87 : char buf[256];
243 87 : int n = base64_encode_nopad(buf, sizeof(buf), sig->sig, ED25519_SIG_LEN);
244 : /* These asserts should always succeed, unless there is a bug in
245 : * base64_encode_nopad(). */
246 87 : tor_assert(n == ED25519_SIG_BASE64_LEN);
247 87 : tor_assert(buf[ED25519_SIG_BASE64_LEN] == '\0');
248 87 : memcpy(output, buf, ED25519_SIG_BASE64_LEN+1);
249 87 : }
250 :
251 : /** Try to decode the string <b>input</b> into an ed25519 signature. On
252 : * success, store the value in <b>sig</b> and return 0. Otherwise return
253 : * -1. */
254 : int
255 227 : ed25519_signature_from_base64(ed25519_signature_t *sig,
256 : const char *input)
257 : {
258 227 : if (strlen(input) != ED25519_SIG_BASE64_LEN)
259 : return -1;
260 220 : char decoded[128];
261 220 : int n = base64_decode(decoded, sizeof(decoded), input,
262 : ED25519_SIG_BASE64_LEN);
263 220 : if (n < 0 || n != ED25519_SIG_LEN)
264 : return -1;
265 219 : memcpy(sig->sig, decoded, ED25519_SIG_LEN);
266 :
267 219 : return 0;
268 : }
269 :
270 : /** Base64 encode DIGEST_LEN bytes from <b>digest</b>, remove the trailing =
271 : * characters, and store the nul-terminated result in the first
272 : * BASE64_DIGEST_LEN+1 bytes of <b>d64</b>.
273 : * Can not fail. */
274 : void
275 597 : digest_to_base64(char *d64, const char *digest)
276 : {
277 597 : char buf[256];
278 597 : int n = base64_encode_nopad(buf, sizeof(buf),
279 : (const uint8_t *)digest, DIGEST_LEN);
280 : /* These asserts should always succeed, unless there is a bug in
281 : * base64_encode_nopad(). */
282 597 : tor_assert(n == BASE64_DIGEST_LEN);
283 597 : tor_assert(buf[BASE64_DIGEST_LEN] == '\0');
284 597 : memcpy(d64, buf, BASE64_DIGEST_LEN+1);
285 597 : }
286 :
287 : /** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
288 : * trailing newline or = characters), decode it and store the result in the
289 : * first DIGEST_LEN bytes at <b>digest</b>. */
290 : int
291 1455 : digest_from_base64(char *digest, const char *d64)
292 : {
293 1455 : if (base64_decode(digest, DIGEST_LEN, d64, strlen(d64)) == DIGEST_LEN)
294 : return 0;
295 : else
296 1 : return -1;
297 : }
298 :
299 : /** Base64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the
300 : * trailing = characters, and store the nul-terminated result in the first
301 : * BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>.
302 : * Can not fail. */
303 : void
304 500 : digest256_to_base64(char *d64, const char *digest)
305 : {
306 500 : char buf[256];
307 500 : int n = base64_encode_nopad(buf, sizeof(buf),
308 : (const uint8_t *)digest, DIGEST256_LEN);
309 : /* These asserts should always succeed, unless there is a bug in
310 : * base64_encode_nopad(). */
311 500 : tor_assert(n == BASE64_DIGEST256_LEN);
312 500 : tor_assert(buf[BASE64_DIGEST256_LEN] == '\0');
313 500 : memcpy(d64, buf, BASE64_DIGEST256_LEN+1);
314 500 : }
315 :
316 : /** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
317 : * trailing newline or = characters), decode it and store the result in the
318 : * first DIGEST256_LEN bytes at <b>digest</b>. */
319 : int
320 607 : digest256_from_base64(char *digest, const char *d64)
321 : {
322 607 : if (base64_decode(digest, DIGEST256_LEN, d64, strlen(d64)) == DIGEST256_LEN)
323 : return 0;
324 : else
325 7 : return -1;
326 : }
|