LCOV - code coverage report
Current view: top level - lib/encoding - pem.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 32 33 97.0 %
Date: 2021-11-24 03:28:48 Functions: 3 3 100.0 %

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

Generated by: LCOV version 1.14