Merge branch 'maint-0.3.5' into maint-0.4.5
[tor.git] / src / lib / crypt_ops / crypto_format.c
blob4483b7d2f5181c8d24ea413e441371a8edb40e07
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-2020, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
7 /**
8 * \file crypto_format.c
10 * \brief Formatting and parsing code for crypto-related data structures.
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"
31 #include <string.h>
32 #include <errno.h>
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 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)
48 char header[32];
49 smartlist_t *chunks = smartlist_new();
50 sized_chunk_t ch0, ch1;
51 int r = -1;
53 memset(header, 0, sizeof(header));
54 if (tor_snprintf(header, sizeof(header),
55 "== %s: %s ==", typestring, tag) < 0)
56 goto end;
57 ch0.bytes = header;
58 ch0.len = 32;
59 ch1.bytes = (const char*) data;
60 ch1.len = datalen;
61 smartlist_add(chunks, &ch0);
62 smartlist_add(chunks, &ch1);
64 r = write_chunks_to_file(fname, chunks, 1, 0);
66 end:
67 smartlist_free(chunks);
68 return r;
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 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)
83 char prefix[33];
84 char *content = NULL;
85 struct stat st;
86 ssize_t r = -1;
87 size_t st_size = 0;
88 int saved_errno = 0;
90 *tag_out = NULL;
91 st.st_size = 0;
92 content = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
93 if (! content) {
94 saved_errno = errno;
95 goto end;
97 if (st.st_size < 32 || st.st_size > 32 + data_out_len) {
98 saved_errno = EINVAL;
99 goto end;
101 st_size = (size_t)st.st_size;
103 memcpy(prefix, content, 32);
104 prefix[32] = 0;
105 /* Check type, extract tag. */
106 if (strcmpstart(prefix, "== ") || strcmpend(prefix, " ==") ||
107 ! fast_mem_is_zero(prefix+strlen(prefix), 32-strlen(prefix))) {
108 saved_errno = EINVAL;
109 goto end;
112 if (strcmpstart(prefix+3, typestring) ||
113 3+strlen(typestring) >= 32 ||
114 strcmpstart(prefix+3+strlen(typestring), ": ")) {
115 saved_errno = EINVAL;
116 goto end;
119 *tag_out = tor_strndup(prefix+5+strlen(typestring),
120 strlen(prefix)-8-strlen(typestring));
122 memcpy(data_out, content+32, st_size-32);
123 r = st_size - 32;
125 end:
126 if (content)
127 memwipe(content, 0, st_size);
128 tor_free(content);
129 if (saved_errno)
130 errno = saved_errno;
131 return r;
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.
140 * Careful! CURVE25519_BASE64_PADDED_LEN is one byte longer than
141 * ED25519_BASE64_LEN.
143 void
144 curve25519_public_to_base64(char *output,
145 const curve25519_public_key_t *pkey, bool pad)
147 int n, expected_len;
148 if (pad) {
149 n = base64_encode(output, CURVE25519_BASE64_PADDED_LEN+1,
150 (const char*)pkey->public_key,
151 CURVE25519_PUBKEY_LEN, 0);
152 expected_len = CURVE25519_BASE64_PADDED_LEN;
153 } else {
154 n = base64_encode_nopad(output, CURVE25519_BASE64_PADDED_LEN+1,
155 (const uint8_t*)pkey->public_key,
156 CURVE25519_PUBKEY_LEN);
157 expected_len = CURVE25519_BASE64_LEN;
160 /* These asserts should always succeed, unless there is a bug in
161 * base64_encode(). */
162 tor_assert(n == expected_len);
163 tor_assert(output[expected_len] == '\0');
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 "=". */
170 curve25519_public_from_base64(curve25519_public_key_t *pkey,
171 const char *input)
173 size_t len = strlen(input);
174 if (len == CURVE25519_BASE64_LEN) {
175 /* not padded */
176 return digest256_from_base64((char*)pkey->public_key, input);
177 } else if (len == CURVE25519_BASE64_PADDED_LEN) {
178 char buf[CURVE25519_BASE64_PADDED_LEN+1];
179 if (base64_decode(buf, sizeof(buf), input, len) != CURVE25519_PUBKEY_LEN)
180 return -1;
181 memcpy(pkey->public_key, buf, CURVE25519_PUBKEY_LEN);
182 return 0;
183 } else {
184 return -1;
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 ed25519_fmt(const ed25519_public_key_t *pkey)
195 static char formatted[ED25519_BASE64_LEN+1];
196 if (pkey) {
197 if (ed25519_public_key_is_zero(pkey)) {
198 strlcpy(formatted, "<unset>", sizeof(formatted));
199 } else {
200 ed25519_public_to_base64(formatted, pkey);
202 } else {
203 strlcpy(formatted, "<null>", sizeof(formatted));
205 return formatted;
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. */
212 ed25519_public_from_base64(ed25519_public_key_t *pkey,
213 const char *input)
215 return digest256_from_base64((char*)pkey->pubkey, input);
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.
223 * Careful! ED25519_BASE64_LEN is one byte shorter than
224 * CURVE25519_BASE64_PADDED_LEN.
226 void
227 ed25519_public_to_base64(char *output,
228 const ed25519_public_key_t *pkey)
230 digest256_to_base64(output, (const char *)pkey->pubkey);
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.
238 void
239 ed25519_signature_to_base64(char *output,
240 const ed25519_signature_t *sig)
242 char buf[256];
243 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 tor_assert(n == ED25519_SIG_BASE64_LEN);
247 tor_assert(buf[ED25519_SIG_BASE64_LEN] == '\0');
248 memcpy(output, buf, ED25519_SIG_BASE64_LEN+1);
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. */
255 ed25519_signature_from_base64(ed25519_signature_t *sig,
256 const char *input)
258 if (strlen(input) != ED25519_SIG_BASE64_LEN)
259 return -1;
260 char decoded[128];
261 int n = base64_decode(decoded, sizeof(decoded), input,
262 ED25519_SIG_BASE64_LEN);
263 if (n < 0 || n != ED25519_SIG_LEN)
264 return -1;
265 memcpy(sig->sig, decoded, ED25519_SIG_LEN);
267 return 0;
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 digest_to_base64(char *d64, const char *digest)
277 char buf[256];
278 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 tor_assert(n == BASE64_DIGEST_LEN);
283 tor_assert(buf[BASE64_DIGEST_LEN] == '\0');
284 memcpy(d64, buf, BASE64_DIGEST_LEN+1);
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>. */
291 digest_from_base64(char *digest, const char *d64)
293 if (base64_decode(digest, DIGEST_LEN, d64, strlen(d64)) == DIGEST_LEN)
294 return 0;
295 else
296 return -1;
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 digest256_to_base64(char *d64, const char *digest)
306 char buf[256];
307 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 tor_assert(n == BASE64_DIGEST256_LEN);
312 tor_assert(buf[BASE64_DIGEST256_LEN] == '\0');
313 memcpy(d64, buf, BASE64_DIGEST256_LEN+1);
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>. */
320 digest256_from_base64(char *digest, const char *d64)
322 if (base64_decode(digest, DIGEST256_LEN, d64, strlen(d64)) == DIGEST256_LEN)
323 return 0;
324 else
325 return -1;