diff options
Diffstat (limited to 'src/common/crypto.c')
-rw-r--r-- | src/common/crypto.c | 53 |
1 files changed, 42 insertions, 11 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c index da4e03edd8..208e1c5fe1 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -719,9 +719,12 @@ crypto_pk_copy_full(crypto_pk_env_t *env) * in <b>env</b>, using the padding method <b>padding</b>. On success, * write the result to <b>to</b>, and return the number of bytes * written. On failure, return -1. + * + * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be + * at least the length of the modulus of <b>env</b>. */ int -crypto_pk_public_encrypt(crypto_pk_env_t *env, char *to, +crypto_pk_public_encrypt(crypto_pk_env_t *env, char *to, size_t tolen, const char *from, size_t fromlen, int padding) { int r; @@ -729,6 +732,7 @@ crypto_pk_public_encrypt(crypto_pk_env_t *env, char *to, tor_assert(from); tor_assert(to); tor_assert(fromlen<INT_MAX); + tor_assert(tolen >= crypto_pk_keysize(env)); r = RSA_public_encrypt((int)fromlen, (unsigned char*)from, (unsigned char*)to, @@ -744,9 +748,13 @@ crypto_pk_public_encrypt(crypto_pk_env_t *env, char *to, * in <b>env</b>, using the padding method <b>padding</b>. On success, * write the result to <b>to</b>, and return the number of bytes * written. On failure, return -1. + * + * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be + * at least the length of the modulus of <b>env</b>. */ int crypto_pk_private_decrypt(crypto_pk_env_t *env, char *to, + size_t tolen, const char *from, size_t fromlen, int padding, int warnOnFailure) { @@ -756,6 +764,7 @@ crypto_pk_private_decrypt(crypto_pk_env_t *env, char *to, tor_assert(to); tor_assert(env->key); tor_assert(fromlen<INT_MAX); + tor_assert(tolen >= crypto_pk_keysize(env)); if (!env->key->p) /* Not a private key */ return -1; @@ -776,9 +785,13 @@ crypto_pk_private_decrypt(crypto_pk_env_t *env, char *to, * public key in <b>env</b>, using PKCS1 padding. On success, write the * signed data to <b>to</b>, and return the number of bytes written. * On failure, return -1. + * + * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be + * at least the length of the modulus of <b>env</b>. */ int crypto_pk_public_checksig(crypto_pk_env_t *env, char *to, + size_t tolen, const char *from, size_t fromlen) { int r; @@ -786,6 +799,7 @@ crypto_pk_public_checksig(crypto_pk_env_t *env, char *to, tor_assert(from); tor_assert(to); tor_assert(fromlen < INT_MAX); + tor_assert(tolen >= crypto_pk_keysize(env)); r = RSA_public_decrypt((int)fromlen, (unsigned char*)from, (unsigned char*)to, env->key, RSA_PKCS1_PADDING); @@ -808,6 +822,7 @@ crypto_pk_public_checksig_digest(crypto_pk_env_t *env, const char *data, { char digest[DIGEST_LEN]; char *buf; + size_t buflen; int r; tor_assert(env); @@ -820,8 +835,9 @@ crypto_pk_public_checksig_digest(crypto_pk_env_t *env, const char *data, log_warn(LD_BUG, "couldn't compute digest"); return -1; } - buf = tor_malloc(crypto_pk_keysize(env)+1); - r = crypto_pk_public_checksig(env,buf,sig,siglen); + buflen = crypto_pk_keysize(env)+1; + buf = tor_malloc(buflen); + r = crypto_pk_public_checksig(env,buf,buflen,sig,siglen); if (r != DIGEST_LEN) { log_warn(LD_CRYPTO, "Invalid signature"); tor_free(buf); @@ -841,9 +857,12 @@ crypto_pk_public_checksig_digest(crypto_pk_env_t *env, const char *data, * <b>env</b>, using PKCS1 padding. On success, write the signature to * <b>to</b>, and return the number of bytes written. On failure, return * -1. + * + * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be + * at least the length of the modulus of <b>env</b>. */ int -crypto_pk_private_sign(crypto_pk_env_t *env, char *to, +crypto_pk_private_sign(crypto_pk_env_t *env, char *to, size_t tolen, const char *from, size_t fromlen) { int r; @@ -851,6 +870,7 @@ crypto_pk_private_sign(crypto_pk_env_t *env, char *to, tor_assert(from); tor_assert(to); tor_assert(fromlen < INT_MAX); + tor_assert(tolen >= crypto_pk_keysize(env)); if (!env->key->p) /* Not a private key */ return -1; @@ -869,16 +889,19 @@ crypto_pk_private_sign(crypto_pk_env_t *env, char *to, * <b>from</b>; sign the data with the private key in <b>env</b>, and * store it in <b>to</b>. Return the number of bytes written on * success, and -1 on failure. + * + * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be + * at least the length of the modulus of <b>env</b>. */ int -crypto_pk_private_sign_digest(crypto_pk_env_t *env, char *to, +crypto_pk_private_sign_digest(crypto_pk_env_t *env, char *to, size_t tolen, const char *from, size_t fromlen) { int r; char digest[DIGEST_LEN]; if (crypto_digest(digest,from,fromlen)<0) return -1; - r = crypto_pk_private_sign(env,to,digest,DIGEST_LEN); + r = crypto_pk_private_sign(env,to,tolen,digest,DIGEST_LEN); memset(digest, 0, sizeof(digest)); return r; } @@ -902,7 +925,7 @@ crypto_pk_private_sign_digest(crypto_pk_env_t *env, char *to, */ int crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env, - char *to, + char *to, size_t tolen, const char *from, size_t fromlen, int padding, int force) @@ -925,8 +948,13 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env, if (!force && fromlen+overhead <= pkeylen) { /* It all fits in a single encrypt. */ - return crypto_pk_public_encrypt(env,to,from,fromlen,padding); + return crypto_pk_public_encrypt(env,to, + tolen, + from,fromlen,padding); } + tor_assert(tolen >= fromlen + overhead + CIPHER_KEY_LEN); + tor_assert(tolen >= pkeylen); + cipher = crypto_new_cipher_env(); if (!cipher) return -1; if (crypto_cipher_generate_key(cipher)<0) @@ -948,7 +976,7 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env, /* Length of symmetrically encrypted data. */ symlen = fromlen-(pkeylen-overhead-CIPHER_KEY_LEN); - outlen = crypto_pk_public_encrypt(env,to,buf,pkeylen-overhead,padding); + outlen = crypto_pk_public_encrypt(env,to,tolen,buf,pkeylen-overhead,padding); if (outlen!=(int)pkeylen) { goto err; } @@ -974,6 +1002,7 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env, int crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env, char *to, + size_t tolen, const char *from, size_t fromlen, int padding, int warnOnFailure) @@ -987,11 +1016,12 @@ crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env, pkeylen = crypto_pk_keysize(env); if (fromlen <= pkeylen) { - return crypto_pk_private_decrypt(env,to,from,fromlen,padding, + return crypto_pk_private_decrypt(env,to,tolen,from,fromlen,padding, warnOnFailure); } + buf = tor_malloc(pkeylen+1); - outlen = crypto_pk_private_decrypt(env,buf,from,pkeylen,padding, + outlen = crypto_pk_private_decrypt(env,buf,pkeylen+1,from,pkeylen,padding, warnOnFailure); if (outlen<0) { log_fn(warnOnFailure?LOG_WARN:LOG_DEBUG, LD_CRYPTO, @@ -1009,6 +1039,7 @@ crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env, } memcpy(to,buf+CIPHER_KEY_LEN,outlen-CIPHER_KEY_LEN); outlen -= CIPHER_KEY_LEN; + tor_assert(tolen - outlen >= fromlen - pkeylen); r = crypto_cipher_decrypt(cipher, to+outlen, from+pkeylen, fromlen-pkeylen); if (r<0) goto err; |