pem.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  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-2018, The Tor Project, Inc. */
  5. /* See LICENSE for licensing information */
  6. /**
  7. * \file pem.c
  8. *
  9. * \brief Implement a trivial version of PEM encoding, for use with NSS.
  10. *
  11. * We deliberately do not support any encryption here.
  12. **/
  13. #include "orconfig.h"
  14. #include "lib/encoding/pem.h"
  15. #include "lib/ctime/di_ops.h"
  16. #include "lib/encoding/binascii.h"
  17. #include "lib/log/util_bug.h"
  18. #include "lib/malloc/malloc.h"
  19. #include "lib/string/printf.h"
  20. #include "lib/string/util_string.h"
  21. #include <string.h>
  22. /**
  23. * Return the length of a <b>src_len</b>-byte object when tagged with
  24. * <b>objtype</b> and PEM-encoded. Includes terminating NUL.
  25. */
  26. size_t
  27. pem_encoded_size(size_t src_len, const char *objtype)
  28. {
  29. return
  30. strlen("-----BEGIN -----\n") +
  31. strlen("-----END -----\n") +
  32. strlen(objtype) * 2 +
  33. base64_encode_size(src_len, BASE64_ENCODE_MULTILINE)
  34. + 1;
  35. }
  36. /**
  37. * PEM-encode the <b>srclen</b>-byte object at <b>src</b> into the
  38. * <b>destlen<\b>-byte buffer at <b>dest</b>, tagging it with <b>objtype</b>.
  39. * Return 0 on success and -1 on failure.
  40. */
  41. int
  42. pem_encode(char *dest, size_t destlen, const uint8_t *src, size_t srclen,
  43. const char *objtype)
  44. {
  45. if (tor_snprintf(dest, destlen, "-----BEGIN %s-----\n", objtype) < 0)
  46. return -1;
  47. size_t offset = strlen(dest);
  48. int n = base64_encode(dest + offset, destlen - offset,
  49. (const char *)src, srclen, BASE64_ENCODE_MULTILINE);
  50. if (n < 0)
  51. return -1;
  52. offset += n;
  53. if (BUG(offset > destlen))
  54. return -1;
  55. if (tor_snprintf(dest + offset, destlen - offset,
  56. "-----END %s-----\n", objtype) < 0)
  57. return -1;
  58. tor_assert(strlen(dest) + 1 <= pem_encoded_size(srclen, objtype));
  59. return 0;
  60. }
  61. /**
  62. * Given a PEM-encoded block of size <b>srclen</b> in <b>src</b>, if it has
  63. * object type <b>objtype</b>, decode it into the <b>destlen</b>-byte buffer
  64. * at <b>dest</b>. Return the number of characters decoded on success, or -1
  65. * on failure.
  66. */
  67. int
  68. pem_decode(uint8_t *dest, size_t destlen, const char *src, size_t srclen,
  69. const char *objtype)
  70. {
  71. const char *eos = src + srclen;
  72. src = eat_whitespace_eos(src, eos);
  73. char *tag = NULL;
  74. tor_asprintf(&tag, "-----BEGIN %s-----\n", objtype);
  75. if ((size_t)(eos-src) < strlen(tag) || fast_memneq(src, tag, strlen(tag))) {
  76. tor_free(tag);
  77. return -1;
  78. }
  79. src += strlen(tag);
  80. tor_free(tag);
  81. // NOTE lack of trailing \n. We do not enforce its presence.
  82. tor_asprintf(&tag, "\n-----END %s-----", objtype);
  83. const char *end_of_base64 = tor_memstr(src, eos-src, tag);
  84. tor_free(tag);
  85. if (end_of_base64 == NULL)
  86. return -1;
  87. /* Should we actually allow extra stuff at the end? */
  88. return base64_decode((char*)dest, destlen, src, end_of_base64-src);
  89. }