signing.c 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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 signing.c
  8. * \brief Code to sign directory objects.
  9. **/
  10. #include "core/or/or.h"
  11. #include "feature/dirparse/signing.h"
  12. /** Helper: used to generate signatures for routers, directories and
  13. * network-status objects. Given a <b>digest_len</b>-byte digest in
  14. * <b>digest</b> and a secret <b>private_key</b>, generate an PKCS1-padded
  15. * signature, BASE64-encode it, surround it with -----BEGIN/END----- pairs,
  16. * and return the new signature on success or NULL on failure.
  17. */
  18. char *
  19. router_get_dirobj_signature(const char *digest,
  20. size_t digest_len,
  21. const crypto_pk_t *private_key)
  22. {
  23. char *signature;
  24. size_t i, keysize;
  25. int siglen;
  26. char *buf = NULL;
  27. size_t buf_len;
  28. /* overestimate of BEGIN/END lines total len. */
  29. #define BEGIN_END_OVERHEAD_LEN 64
  30. keysize = crypto_pk_keysize(private_key);
  31. signature = tor_malloc(keysize);
  32. siglen = crypto_pk_private_sign(private_key, signature, keysize,
  33. digest, digest_len);
  34. if (siglen < 0) {
  35. log_warn(LD_BUG,"Couldn't sign digest.");
  36. goto err;
  37. }
  38. /* The *2 here is a ridiculous overestimate of base-64 overhead. */
  39. buf_len = (siglen * 2) + BEGIN_END_OVERHEAD_LEN;
  40. buf = tor_malloc(buf_len);
  41. if (strlcpy(buf, "-----BEGIN SIGNATURE-----\n", buf_len) >= buf_len)
  42. goto truncated;
  43. i = strlen(buf);
  44. if (base64_encode(buf+i, buf_len-i, signature, siglen,
  45. BASE64_ENCODE_MULTILINE) < 0) {
  46. log_warn(LD_BUG,"couldn't base64-encode signature");
  47. goto err;
  48. }
  49. if (strlcat(buf, "-----END SIGNATURE-----\n", buf_len) >= buf_len)
  50. goto truncated;
  51. tor_free(signature);
  52. return buf;
  53. truncated:
  54. log_warn(LD_BUG,"tried to exceed string length.");
  55. err:
  56. tor_free(signature);
  57. tor_free(buf);
  58. return NULL;
  59. }
  60. /** Helper: used to generate signatures for routers, directories and
  61. * network-status objects. Given a digest in <b>digest</b> and a secret
  62. * <b>private_key</b>, generate a PKCS1-padded signature, BASE64-encode it,
  63. * surround it with -----BEGIN/END----- pairs, and write it to the
  64. * <b>buf_len</b>-byte buffer at <b>buf</b>. Return 0 on success, -1 on
  65. * failure.
  66. */
  67. int
  68. router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
  69. size_t digest_len, crypto_pk_t *private_key)
  70. {
  71. size_t sig_len, s_len;
  72. char *sig = router_get_dirobj_signature(digest, digest_len, private_key);
  73. if (!sig) {
  74. log_warn(LD_BUG, "No signature generated");
  75. return -1;
  76. }
  77. sig_len = strlen(sig);
  78. s_len = strlen(buf);
  79. if (sig_len + s_len + 1 > buf_len) {
  80. log_warn(LD_BUG, "Not enough room for signature");
  81. tor_free(sig);
  82. return -1;
  83. }
  84. memcpy(buf+s_len, sig, sig_len+1);
  85. tor_free(sig);
  86. return 0;
  87. }