sigcommon.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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 sigcommon.c
  8. * \brief Shared hashing, signing, and signature-checking code for directory
  9. * objects.
  10. **/
  11. #define SIGCOMMON_PRIVATE
  12. #include "core/or/or.h"
  13. #include "feature/dirparse/parsecommon.h"
  14. #include "feature/dirparse/sigcommon.h"
  15. /** Helper function for <b>router_get_hash_impl</b>: given <b>s</b>,
  16. * <b>s_len</b>, <b>start_str</b>, <b>end_str</b>, and <b>end_c</b> with the
  17. * same semantics as in that function, set *<b>start_out</b> (inclusive) and
  18. * *<b>end_out</b> (exclusive) to the boundaries of the string to be hashed.
  19. *
  20. * Return 0 on success and -1 on failure.
  21. */
  22. int
  23. router_get_hash_impl_helper(const char *s, size_t s_len,
  24. const char *start_str,
  25. const char *end_str, char end_c,
  26. int log_severity,
  27. const char **start_out, const char **end_out)
  28. {
  29. const char *start, *end;
  30. start = tor_memstr(s, s_len, start_str);
  31. if (!start) {
  32. log_fn(log_severity,LD_DIR,
  33. "couldn't find start of hashed material \"%s\"",start_str);
  34. return -1;
  35. }
  36. if (start != s && *(start-1) != '\n') {
  37. log_fn(log_severity,LD_DIR,
  38. "first occurrence of \"%s\" is not at the start of a line",
  39. start_str);
  40. return -1;
  41. }
  42. end = tor_memstr(start+strlen(start_str),
  43. s_len - (start-s) - strlen(start_str), end_str);
  44. if (!end) {
  45. log_fn(log_severity,LD_DIR,
  46. "couldn't find end of hashed material \"%s\"",end_str);
  47. return -1;
  48. }
  49. end = memchr(end+strlen(end_str), end_c, s_len - (end-s) - strlen(end_str));
  50. if (!end) {
  51. log_fn(log_severity,LD_DIR,
  52. "couldn't find EOL");
  53. return -1;
  54. }
  55. ++end;
  56. *start_out = start;
  57. *end_out = end;
  58. return 0;
  59. }
  60. /** Compute the digest of the substring of <b>s</b> taken from the first
  61. * occurrence of <b>start_str</b> through the first instance of c after the
  62. * first subsequent occurrence of <b>end_str</b>; store the 20-byte or 32-byte
  63. * result in <b>digest</b>; return 0 on success.
  64. *
  65. * If no such substring exists, return -1.
  66. */
  67. int
  68. router_get_hash_impl(const char *s, size_t s_len, char *digest,
  69. const char *start_str,
  70. const char *end_str, char end_c,
  71. digest_algorithm_t alg)
  72. {
  73. const char *start=NULL, *end=NULL;
  74. if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,LOG_WARN,
  75. &start,&end)<0)
  76. return -1;
  77. return router_compute_hash_final(digest, start, end-start, alg);
  78. }
  79. /** Compute the digest of the <b>len</b>-byte directory object at
  80. * <b>start</b>, using <b>alg</b>. Store the result in <b>digest</b>, which
  81. * must be long enough to hold it. */
  82. MOCK_IMPL(STATIC int,
  83. router_compute_hash_final,(char *digest,
  84. const char *start, size_t len,
  85. digest_algorithm_t alg))
  86. {
  87. if (alg == DIGEST_SHA1) {
  88. if (crypto_digest(digest, start, len) < 0) {
  89. log_warn(LD_BUG,"couldn't compute digest");
  90. return -1;
  91. }
  92. } else {
  93. if (crypto_digest256(digest, start, len, alg) < 0) {
  94. log_warn(LD_BUG,"couldn't compute digest");
  95. return -1;
  96. }
  97. }
  98. return 0;
  99. }
  100. /** As router_get_hash_impl, but compute all hashes. */
  101. int
  102. router_get_hashes_impl(const char *s, size_t s_len, common_digests_t *digests,
  103. const char *start_str,
  104. const char *end_str, char end_c)
  105. {
  106. const char *start=NULL, *end=NULL;
  107. if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,LOG_WARN,
  108. &start,&end)<0)
  109. return -1;
  110. if (crypto_common_digests(digests, start, end-start)) {
  111. log_warn(LD_BUG,"couldn't compute digests");
  112. return -1;
  113. }
  114. return 0;
  115. }
  116. MOCK_IMPL(STATIC int,
  117. signed_digest_equals, (const uint8_t *d1, const uint8_t *d2, size_t len))
  118. {
  119. return tor_memeq(d1, d2, len);
  120. }
  121. /** Check whether the object body of the token in <b>tok</b> has a good
  122. * signature for <b>digest</b> using key <b>pkey</b>.
  123. * If <b>CST_NO_CHECK_OBJTYPE</b> is set, do not check
  124. * the object type of the signature object. Use <b>doctype</b> as the type of
  125. * the document when generating log messages. Return 0 on success, negative
  126. * on failure.
  127. */
  128. int
  129. check_signature_token(const char *digest,
  130. ssize_t digest_len,
  131. directory_token_t *tok,
  132. crypto_pk_t *pkey,
  133. int flags,
  134. const char *doctype)
  135. {
  136. char *signed_digest;
  137. size_t keysize;
  138. const int check_objtype = ! (flags & CST_NO_CHECK_OBJTYPE);
  139. tor_assert(pkey);
  140. tor_assert(tok);
  141. tor_assert(digest);
  142. tor_assert(doctype);
  143. if (check_objtype) {
  144. if (strcmp(tok->object_type, "SIGNATURE")) {
  145. log_warn(LD_DIR, "Bad object type on %s signature", doctype);
  146. return -1;
  147. }
  148. }
  149. keysize = crypto_pk_keysize(pkey);
  150. signed_digest = tor_malloc(keysize);
  151. if (crypto_pk_public_checksig(pkey, signed_digest, keysize,
  152. tok->object_body, tok->object_size)
  153. < digest_len) {
  154. log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype);
  155. tor_free(signed_digest);
  156. return -1;
  157. }
  158. // log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
  159. // hex_str(signed_digest,4));
  160. if (! signed_digest_equals((const uint8_t *)digest,
  161. (const uint8_t *)signed_digest, digest_len)) {
  162. log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
  163. tor_free(signed_digest);
  164. return -1;
  165. }
  166. tor_free(signed_digest);
  167. return 0;
  168. }