tor

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

pem.c (3168B)


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