/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file signing.c * \brief Code to sign directory objects. **/ #include "core/or/or.h" #include "feature/dirparse/signing.h" /** Helper: used to generate signatures for routers, directories and * network-status objects. Given a digest_len-byte digest in * digest and a secret private_key, generate an PKCS1-padded * signature, BASE64-encode it, surround it with -----BEGIN/END----- pairs, * and return the new signature on success or NULL on failure. */ char * router_get_dirobj_signature(const char *digest, size_t digest_len, const crypto_pk_t *private_key) { char *signature; size_t i, keysize; int siglen; char *buf = NULL; size_t buf_len; /* overestimate of BEGIN/END lines total len. */ #define BEGIN_END_OVERHEAD_LEN 64 keysize = crypto_pk_keysize(private_key); signature = tor_malloc(keysize); siglen = crypto_pk_private_sign(private_key, signature, keysize, digest, digest_len); if (siglen < 0) { log_warn(LD_BUG,"Couldn't sign digest."); goto err; } /* The *2 here is a ridiculous overestimate of base-64 overhead. */ buf_len = (siglen * 2) + BEGIN_END_OVERHEAD_LEN; buf = tor_malloc(buf_len); if (strlcpy(buf, "-----BEGIN SIGNATURE-----\n", buf_len) >= buf_len) goto truncated; i = strlen(buf); if (base64_encode(buf+i, buf_len-i, signature, siglen, BASE64_ENCODE_MULTILINE) < 0) { log_warn(LD_BUG,"couldn't base64-encode signature"); goto err; } if (strlcat(buf, "-----END SIGNATURE-----\n", buf_len) >= buf_len) goto truncated; tor_free(signature); return buf; truncated: log_warn(LD_BUG,"tried to exceed string length."); err: tor_free(signature); tor_free(buf); return NULL; } /** Helper: used to generate signatures for routers, directories and * network-status objects. Given a digest in digest and a secret * private_key, generate a PKCS1-padded signature, BASE64-encode it, * surround it with -----BEGIN/END----- pairs, and write it to the * buf_len-byte buffer at buf. Return 0 on success, -1 on * failure. */ int router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest, size_t digest_len, crypto_pk_t *private_key) { size_t sig_len, s_len; char *sig = router_get_dirobj_signature(digest, digest_len, private_key); if (!sig) { log_warn(LD_BUG, "No signature generated"); return -1; } sig_len = strlen(sig); s_len = strlen(buf); if (sig_len + s_len + 1 > buf_len) { log_warn(LD_BUG, "Not enough room for signature"); tor_free(sig); return -1; } memcpy(buf+s_len, sig, sig_len+1); tor_free(sig); return 0; }