diff options
Diffstat (limited to 'src/common/crypto.c')
-rw-r--r-- | src/common/crypto.c | 89 |
1 files changed, 66 insertions, 23 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c index a69e6c5cb8..30990ecc8f 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -425,7 +425,7 @@ crypto_cipher_free(crypto_cipher_t *env) tor_assert(env->cipher); aes_cipher_free(env->cipher); - memset(env, 0, sizeof(crypto_cipher_t)); + memwipe(env, 0, sizeof(crypto_cipher_t)); tor_free(env); } @@ -529,7 +529,7 @@ crypto_pk_read_private_key_from_filename(crypto_pk_t *env, /* Try to parse it. */ r = crypto_pk_read_private_key_from_string(env, contents, -1); - memset(contents, 0, strlen(contents)); + memwipe(contents, 0, strlen(contents)); tor_free(contents); if (r) return -1; /* read_private_key_from_string already warned, so we don't.*/ @@ -671,7 +671,7 @@ crypto_pk_write_private_key_to_filename(crypto_pk_t *env, s[len]='\0'; r = write_str_to_file(fname, s, 0); BIO_free(bio); - memset(s, 0, strlen(s)); + memwipe(s, 0, strlen(s)); tor_free(s); return r; } @@ -981,7 +981,7 @@ crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen, if (crypto_digest(digest,from,fromlen)<0) return -1; r = crypto_pk_private_sign(env,to,tolen,digest,DIGEST_LEN); - memset(digest, 0, sizeof(digest)); + memwipe(digest, 0, sizeof(digest)); return r; } @@ -1045,14 +1045,14 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_t *env, from+pkeylen-overhead-CIPHER_KEY_LEN, symlen); if (r<0) goto err; - memset(buf, 0, pkeylen); + memwipe(buf, 0, pkeylen); tor_free(buf); crypto_cipher_free(cipher); tor_assert(outlen+symlen < INT_MAX); return (int)(outlen + symlen); err: - memset(buf, 0, pkeylen); + memwipe(buf, 0, pkeylen); tor_free(buf); crypto_cipher_free(cipher); return -1; @@ -1103,13 +1103,13 @@ crypto_pk_private_hybrid_decrypt(crypto_pk_t *env, r = crypto_cipher_decrypt(cipher, to+outlen, from+pkeylen, fromlen-pkeylen); if (r<0) goto err; - memset(buf,0,pkeylen); + memwipe(buf,0,pkeylen); tor_free(buf); crypto_cipher_free(cipher); tor_assert(outlen + fromlen < INT_MAX); return (int)(outlen + (fromlen-pkeylen)); err: - memset(buf,0,pkeylen); + memwipe(buf,0,pkeylen); tor_free(buf); crypto_cipher_free(cipher); return -1; @@ -1509,7 +1509,7 @@ crypto_digest_free(crypto_digest_t *digest) { if (!digest) return; - memset(digest, 0, sizeof(crypto_digest_t)); + memwipe(digest, 0, sizeof(crypto_digest_t)); tor_free(digest); } @@ -1571,7 +1571,7 @@ crypto_digest_get_digest(crypto_digest_t *digest, break; } memcpy(out, r, out_len); - memset(r, 0, sizeof(r)); + memwipe(r, 0, sizeof(r)); } /** Allocate and return a new digest object with the same state as @@ -1673,10 +1673,10 @@ crypto_hmac_sha256(char *hmac_out, SHA256_Final((uint8_t*)hmac_out, &st); /* Now clear everything. */ - memset(k, 0, sizeof(k)); - memset(pad, 0, sizeof(pad)); - memset(d, 0, sizeof(d)); - memset(&st, 0, sizeof(st)); + memwipe(k, 0, sizeof(k)); + memwipe(pad, 0, sizeof(pad)); + memwipe(d, 0, sizeof(d)); + memwipe(&st, 0, sizeof(st)); #undef BLOCKSIZE #undef DIGESTSIZE #endif @@ -2208,7 +2208,7 @@ crypto_dh_compute_secret(int severity, crypto_dh_t *dh, if (pubkey_bn) BN_free(pubkey_bn); if (secret_tmp) { - memset(secret_tmp, 0, secret_tmp_len); + memwipe(secret_tmp, 0, secret_tmp_len); tor_free(secret_tmp); } if (result < 0) @@ -2243,15 +2243,15 @@ crypto_expand_key_material(const char *key_in, size_t key_in_len, goto err; memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out))); } - memset(tmp, 0, key_in_len+1); + memwipe(tmp, 0, key_in_len+1); tor_free(tmp); - memset(digest, 0, sizeof(digest)); + memwipe(digest, 0, sizeof(digest)); return 0; err: - memset(tmp, 0, key_in_len+1); + memwipe(tmp, 0, key_in_len+1); tor_free(tmp); - memset(digest, 0, sizeof(digest)); + memwipe(digest, 0, sizeof(digest)); return -1; } @@ -2343,7 +2343,7 @@ crypto_seed_rng(int startup) return rand_poll_status ? 0 : -1; } RAND_seed(buf, sizeof(buf)); - memset(buf, 0, sizeof(buf)); + memwipe(buf, 0, sizeof(buf)); seed_weak_rng(); return 0; #else @@ -2360,7 +2360,7 @@ crypto_seed_rng(int startup) return -1; } RAND_seed(buf, (int)sizeof(buf)); - memset(buf, 0, sizeof(buf)); + memwipe(buf, 0, sizeof(buf)); seed_weak_rng(); return 0; } @@ -2843,7 +2843,7 @@ base32_decode(char *dest, size_t destlen, const char *src, size_t srclen) } } - memset(tmp, 0, srclen); + memwipe(tmp, 0, srclen); tor_free(tmp); tmp = NULL; return 0; @@ -2888,11 +2888,54 @@ secret_to_key(char *key_out, size_t key_out_len, const char *secret, } } crypto_digest_get_digest(d, key_out, key_out_len); - memset(tmp, 0, tmplen); + memwipe(tmp, 0, tmplen); tor_free(tmp); crypto_digest_free(d); } +/** + * Destroy the <b>sz</b> bytes of data stored at <b>mem</b>, setting them to + * the value <b>byte</b>. + * + * This function is preferable to memset, since many compilers will happily + * optimize out memset() when they can convince themselves that the data being + * cleared will never be read. + * + * Right now, our convention is to use this function when we are wiping data + * that's about to become inaccessible, such as stack buffers that are about + * to go out of scope or structures that are about to get freed. (In + * practice, it appears that the compilers we're currently using will optimize + * out the memset()s for stack-allocated buffers, but not those for + * about-to-be-freed structures. That could change, though, so we're being + * wary.) If there are live reads for the data, then you can just use + * memset(). + */ +void +memwipe(void *mem, uint8_t byte, size_t sz) +{ + /* Because whole-program-optimization exists, we may not be able to just + * have this function call "memset". A smart compiler could inline it, then + * eliminate dead memsets, and declare itself to be clever. */ + + /* This is a slow and ugly function from OpenSSL that fills 'mem' with junk + * based on the pointer value, then uses that junk to update a global + * variable. It's an elaborate ruse to trick the compiler into not + * optimizing out the "wipe this memory" code. Read it if you like zany + * programming tricks! In later versions of Tor, we should look for better + * not-optimized-out memory wiping stuff. */ + OPENSSL_cleanse(mem, sz); + /* Just in case some caller of memwipe() is relying on getting a buffer + * filled with a particular value, fill the buffer. + * + * If this function gets inlined, this memset might get eliminated, but + * that's okay: We only care about this particular memset in the case where + * the caller should have been using memset(), and the memset() wouldn't get + * eliminated. In other words, this is here so that we won't break anything + * if somebody accidentally calls memwipe() instead of memset(). + **/ + memset(mem, byte, sz); +} + #ifdef TOR_IS_MULTITHREADED /** Helper: OpenSSL uses this callback to manipulate mutexes. */ static void |