tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

crypto_format.c (10518B)


      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 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  char header[32];
     49  smartlist_t *chunks = smartlist_new();
     50  sized_chunk_t ch0, ch1;
     51  int r = -1;
     52 
     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);
     63 
     64  r = write_chunks_to_file(fname, chunks, 1, 0);
     65 
     66 end:
     67  smartlist_free(chunks);
     68  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 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  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;
     89 
     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;
     96  }
     97  if (st.st_size < 32 || st.st_size > 32 + data_out_len) {
     98    saved_errno = EINVAL;
     99    goto end;
    100  }
    101  st_size = (size_t)st.st_size;
    102 
    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;
    110  }
    111 
    112  if (strcmpstart(prefix+3, typestring) ||
    113      3+strlen(typestring) >= 32 ||
    114      strcmpstart(prefix+3+strlen(typestring), ": ")) {
    115    saved_errno = EINVAL;
    116    goto end;
    117  }
    118 
    119  *tag_out = tor_strndup(prefix+5+strlen(typestring),
    120                         strlen(prefix)-8-strlen(typestring));
    121 
    122  memcpy(data_out, content+32, st_size-32);
    123  r = st_size - 32;
    124 
    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;
    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 curve25519_public_to_base64(char *output,
    145                            const curve25519_public_key_t *pkey, bool pad)
    146 {
    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;
    158  }
    159 
    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');
    164 }
    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 curve25519_public_from_base64(curve25519_public_key_t *pkey,
    171                              const char *input)
    172 {
    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;
    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 ed25519_fmt(const ed25519_public_key_t *pkey)
    194 {
    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);
    201    }
    202  } else {
    203    strlcpy(formatted, "<null>", sizeof(formatted));
    204  }
    205  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 ed25519_public_from_base64(ed25519_public_key_t *pkey,
    213                           const char *input)
    214 {
    215  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 ed25519_public_to_base64(char *output,
    228                         const ed25519_public_key_t *pkey)
    229 {
    230  digest256_to_base64(output, (const char *)pkey->pubkey);
    231 }
    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 ed25519_signature_to_base64(char *output,
    240                            const ed25519_signature_t *sig)
    241 {
    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);
    249 }
    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 ed25519_signature_from_base64(ed25519_signature_t *sig,
    256                              const char *input)
    257 {
    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);
    266 
    267  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 digest_to_base64(char *d64, const char *digest)
    276 {
    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);
    285 }
    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 digest_from_base64(char *digest, const char *d64)
    292 {
    293  if (base64_decode(digest, DIGEST_LEN, d64, strlen(d64)) == DIGEST_LEN)
    294    return 0;
    295  else
    296    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 digest256_to_base64(char *d64, const char *digest)
    305 {
    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);
    314 }
    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 digest256_from_base64(char *digest, const char *d64)
    321 {
    322  if (base64_decode(digest, DIGEST256_LEN, d64, strlen(d64)) == DIGEST256_LEN)
    323    return 0;
    324  else
    325    return -1;
    326 }