Merge branch 'bug26913_033' into maint-0.3.3
[tor.git] / src / common / crypto_format.c
blob1d090a8770de069c1f4c9ed92e209c980a8b98fb
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-2017, 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 "container.h"
18 #include "crypto.h"
19 #include "crypto_curve25519.h"
20 #include "crypto_ed25519.h"
21 #include "crypto_format.h"
22 #include "util.h"
23 #include "util_format.h"
24 #include "torlog.h"
26 /** Write the <b>datalen</b> bytes from <b>data</b> to the file named
27 * <b>fname</b> in the tagged-data format. This format contains a
28 * 32-byte header, followed by the data itself. The header is the
29 * NUL-padded string "== <b>typestring</b>: <b>tag</b> ==". The length
30 * of <b>typestring</b> and <b>tag</b> must therefore be no more than
31 * 24.
32 **/
33 int
34 crypto_write_tagged_contents_to_file(const char *fname,
35 const char *typestring,
36 const char *tag,
37 const uint8_t *data,
38 size_t datalen)
40 char header[32];
41 smartlist_t *chunks = smartlist_new();
42 sized_chunk_t ch0, ch1;
43 int r = -1;
45 memset(header, 0, sizeof(header));
46 if (tor_snprintf(header, sizeof(header),
47 "== %s: %s ==", typestring, tag) < 0)
48 goto end;
49 ch0.bytes = header;
50 ch0.len = 32;
51 ch1.bytes = (const char*) data;
52 ch1.len = datalen;
53 smartlist_add(chunks, &ch0);
54 smartlist_add(chunks, &ch1);
56 r = write_chunks_to_file(fname, chunks, 1, 0);
58 end:
59 smartlist_free(chunks);
60 return r;
63 /** Read a tagged-data file from <b>fname</b> into the
64 * <b>data_out_len</b>-byte buffer in <b>data_out</b>. Check that the
65 * typestring matches <b>typestring</b>; store the tag into a newly allocated
66 * string in <b>tag_out</b>. Return -1 on failure, and the number of bytes of
67 * data on success. Preserves the errno from reading the file. */
68 ssize_t
69 crypto_read_tagged_contents_from_file(const char *fname,
70 const char *typestring,
71 char **tag_out,
72 uint8_t *data_out,
73 ssize_t data_out_len)
75 char prefix[33];
76 char *content = NULL;
77 struct stat st;
78 ssize_t r = -1;
79 size_t st_size = 0;
80 int saved_errno = 0;
82 *tag_out = NULL;
83 st.st_size = 0;
84 content = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
85 if (! content) {
86 saved_errno = errno;
87 goto end;
89 if (st.st_size < 32 || st.st_size > 32 + data_out_len) {
90 saved_errno = EINVAL;
91 goto end;
93 st_size = (size_t)st.st_size;
95 memcpy(prefix, content, 32);
96 prefix[32] = 0;
97 /* Check type, extract tag. */
98 if (strcmpstart(prefix, "== ") || strcmpend(prefix, " ==") ||
99 ! tor_mem_is_zero(prefix+strlen(prefix), 32-strlen(prefix))) {
100 saved_errno = EINVAL;
101 goto end;
104 if (strcmpstart(prefix+3, typestring) ||
105 3+strlen(typestring) >= 32 ||
106 strcmpstart(prefix+3+strlen(typestring), ": ")) {
107 saved_errno = EINVAL;
108 goto end;
111 *tag_out = tor_strndup(prefix+5+strlen(typestring),
112 strlen(prefix)-8-strlen(typestring));
114 memcpy(data_out, content+32, st_size-32);
115 r = st_size - 32;
117 end:
118 if (content)
119 memwipe(content, 0, st_size);
120 tor_free(content);
121 if (saved_errno)
122 errno = saved_errno;
123 return r;
126 /** Encode <b>pkey</b> as a base64-encoded string, without trailing "="
127 * characters, in the buffer <b>output</b>, which must have at least
128 * CURVE25519_BASE64_PADDED_LEN+1 bytes available. Return 0 on success, -1 on
129 * failure. */
131 curve25519_public_to_base64(char *output,
132 const curve25519_public_key_t *pkey)
134 char buf[128];
135 base64_encode(buf, sizeof(buf),
136 (const char*)pkey->public_key, CURVE25519_PUBKEY_LEN, 0);
137 buf[CURVE25519_BASE64_PADDED_LEN] = '\0';
138 memcpy(output, buf, CURVE25519_BASE64_PADDED_LEN+1);
139 return 0;
142 /** Try to decode a base64-encoded curve25519 public key from <b>input</b>
143 * into the object at <b>pkey</b>. Return 0 on success, -1 on failure.
144 * Accepts keys with or without a trailing "=". */
146 curve25519_public_from_base64(curve25519_public_key_t *pkey,
147 const char *input)
149 size_t len = strlen(input);
150 if (len == CURVE25519_BASE64_PADDED_LEN - 1) {
151 /* not padded */
152 return digest256_from_base64((char*)pkey->public_key, input);
153 } else if (len == CURVE25519_BASE64_PADDED_LEN) {
154 char buf[128];
155 if (base64_decode(buf, sizeof(buf), input, len) != CURVE25519_PUBKEY_LEN)
156 return -1;
157 memcpy(pkey->public_key, buf, CURVE25519_PUBKEY_LEN);
158 return 0;
159 } else {
160 return -1;
164 /** For logging convenience: Convert <b>pkey</b> to a statically allocated
165 * base64 string and return it. Not threadsafe. Format not meant to be
166 * computer-readable; it may change in the future. Subsequent calls invalidate
167 * previous returns. */
168 const char *
169 ed25519_fmt(const ed25519_public_key_t *pkey)
171 static char formatted[ED25519_BASE64_LEN+1];
172 if (pkey) {
173 if (ed25519_public_key_is_zero(pkey)) {
174 strlcpy(formatted, "<unset>", sizeof(formatted));
175 } else {
176 int r = ed25519_public_to_base64(formatted, pkey);
177 tor_assert(!r);
179 } else {
180 strlcpy(formatted, "<null>", sizeof(formatted));
182 return formatted;
185 /** Try to decode the string <b>input</b> into an ed25519 public key. On
186 * success, store the value in <b>pkey</b> and return 0. Otherwise return
187 * -1. */
189 ed25519_public_from_base64(ed25519_public_key_t *pkey,
190 const char *input)
192 return digest256_from_base64((char*)pkey->pubkey, input);
195 /** Encode the public key <b>pkey</b> into the buffer at <b>output</b>,
196 * which must have space for ED25519_BASE64_LEN bytes of encoded key,
197 * plus one byte for a terminating NUL. Return 0 on success, -1 on failure.
200 ed25519_public_to_base64(char *output,
201 const ed25519_public_key_t *pkey)
203 return digest256_to_base64(output, (const char *)pkey->pubkey);
206 /** Encode the signature <b>sig</b> into the buffer at <b>output</b>,
207 * which must have space for ED25519_SIG_BASE64_LEN bytes of encoded signature,
208 * plus one byte for a terminating NUL. Return 0 on success, -1 on failure.
211 ed25519_signature_to_base64(char *output,
212 const ed25519_signature_t *sig)
214 char buf[256];
215 int n = base64_encode_nopad(buf, sizeof(buf), sig->sig, ED25519_SIG_LEN);
216 tor_assert(n == ED25519_SIG_BASE64_LEN);
217 memcpy(output, buf, ED25519_SIG_BASE64_LEN+1);
218 return 0;
221 /** Try to decode the string <b>input</b> into an ed25519 signature. On
222 * success, store the value in <b>sig</b> and return 0. Otherwise return
223 * -1. */
225 ed25519_signature_from_base64(ed25519_signature_t *sig,
226 const char *input)
229 if (strlen(input) != ED25519_SIG_BASE64_LEN)
230 return -1;
231 char buf[ED25519_SIG_BASE64_LEN+3];
232 memcpy(buf, input, ED25519_SIG_BASE64_LEN);
233 buf[ED25519_SIG_BASE64_LEN+0] = '=';
234 buf[ED25519_SIG_BASE64_LEN+1] = '=';
235 buf[ED25519_SIG_BASE64_LEN+2] = 0;
236 char decoded[128];
237 int n = base64_decode(decoded, sizeof(decoded), buf, strlen(buf));
238 if (n < 0 || n != ED25519_SIG_LEN)
239 return -1;
240 memcpy(sig->sig, decoded, ED25519_SIG_LEN);
242 return 0;
245 /** Base64 encode DIGEST_LINE bytes from <b>digest</b>, remove the trailing =
246 * characters, and store the nul-terminated result in the first
247 * BASE64_DIGEST_LEN+1 bytes of <b>d64</b>. */
248 /* XXXX unify with crypto_format.c code */
250 digest_to_base64(char *d64, const char *digest)
252 char buf[256];
253 base64_encode(buf, sizeof(buf), digest, DIGEST_LEN, 0);
254 buf[BASE64_DIGEST_LEN] = '\0';
255 memcpy(d64, buf, BASE64_DIGEST_LEN+1);
256 return 0;
259 /** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
260 * trailing newline or = characters), decode it and store the result in the
261 * first DIGEST_LEN bytes at <b>digest</b>. */
262 /* XXXX unify with crypto_format.c code */
264 digest_from_base64(char *digest, const char *d64)
266 if (base64_decode(digest, DIGEST_LEN, d64, strlen(d64)) == DIGEST_LEN)
267 return 0;
268 else
269 return -1;
272 /** Base64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the
273 * trailing = characters, and store the nul-terminated result in the first
274 * BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>. */
275 /* XXXX unify with crypto_format.c code */
277 digest256_to_base64(char *d64, const char *digest)
279 char buf[256];
280 base64_encode(buf, sizeof(buf), digest, DIGEST256_LEN, 0);
281 buf[BASE64_DIGEST256_LEN] = '\0';
282 memcpy(d64, buf, BASE64_DIGEST256_LEN+1);
283 return 0;
286 /** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
287 * trailing newline or = characters), decode it and store the result in the
288 * first DIGEST256_LEN bytes at <b>digest</b>. */
289 /* XXXX unify with crypto_format.c code */
291 digest256_from_base64(char *digest, const char *d64)
293 if (base64_decode(digest, DIGEST256_LEN, d64, strlen(d64)) == DIGEST256_LEN)
294 return 0;
295 else
296 return -1;