Fix a heap overflow found by debuger, and make it harder to make that mistake again

Our public key functions assumed that they were always writing into a
large enough buffer.  In one case, they weren't.

(Incorporates fixes from sebastian)
This commit is contained in:
Nick Mathewson 2011-01-13 14:36:41 -05:00
parent a16902b9d4
commit 115782bdbe
12 changed files with 105 additions and 42 deletions

9
changes/tolen_asserts Normal file
View File

@ -0,0 +1,9 @@
o Major bugfixes (security)
- Fix a heap overflow bug where an adversary could cause heap
corruption. Since the contents of the corruption would need to be
the output of an RSA decryption, we do not think this is easy to
turn in to a remote code execution attack, but everybody should
upgrade anyway. Found by debuger. Bugfix on 0.1.2.10-rc.
o Defensive programming
- Introduce output size checks on all of our decryption functions.

View File

@ -717,9 +717,12 @@ crypto_pk_copy_full(crypto_pk_env_t *env)
* in <b>env</b>, using the padding method <b>padding</b>. On success, * 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 * write the result to <b>to</b>, and return the number of bytes
* written. On failure, return -1. * 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 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) const char *from, size_t fromlen, int padding)
{ {
int r; int r;
@ -727,6 +730,7 @@ crypto_pk_public_encrypt(crypto_pk_env_t *env, char *to,
tor_assert(from); tor_assert(from);
tor_assert(to); tor_assert(to);
tor_assert(fromlen<INT_MAX); tor_assert(fromlen<INT_MAX);
tor_assert(tolen >= crypto_pk_keysize(env));
r = RSA_public_encrypt((int)fromlen, r = RSA_public_encrypt((int)fromlen,
(unsigned char*)from, (unsigned char*)to, (unsigned char*)from, (unsigned char*)to,
@ -742,9 +746,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, * 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 * write the result to <b>to</b>, and return the number of bytes
* written. On failure, return -1. * 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 int
crypto_pk_private_decrypt(crypto_pk_env_t *env, char *to, crypto_pk_private_decrypt(crypto_pk_env_t *env, char *to,
size_t tolen,
const char *from, size_t fromlen, const char *from, size_t fromlen,
int padding, int warnOnFailure) int padding, int warnOnFailure)
{ {
@ -754,6 +762,7 @@ crypto_pk_private_decrypt(crypto_pk_env_t *env, char *to,
tor_assert(to); tor_assert(to);
tor_assert(env->key); tor_assert(env->key);
tor_assert(fromlen<INT_MAX); tor_assert(fromlen<INT_MAX);
tor_assert(tolen >= crypto_pk_keysize(env));
if (!env->key->p) if (!env->key->p)
/* Not a private key */ /* Not a private key */
return -1; return -1;
@ -774,9 +783,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 * 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. * signed data to <b>to</b>, and return the number of bytes written.
* On failure, return -1. * 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 int
crypto_pk_public_checksig(crypto_pk_env_t *env, char *to, crypto_pk_public_checksig(crypto_pk_env_t *env, char *to,
size_t tolen,
const char *from, size_t fromlen) const char *from, size_t fromlen)
{ {
int r; int r;
@ -784,6 +797,7 @@ crypto_pk_public_checksig(crypto_pk_env_t *env, char *to,
tor_assert(from); tor_assert(from);
tor_assert(to); tor_assert(to);
tor_assert(fromlen < INT_MAX); tor_assert(fromlen < INT_MAX);
tor_assert(tolen >= crypto_pk_keysize(env));
r = RSA_public_decrypt((int)fromlen, r = RSA_public_decrypt((int)fromlen,
(unsigned char*)from, (unsigned char*)to, (unsigned char*)from, (unsigned char*)to,
env->key, RSA_PKCS1_PADDING); env->key, RSA_PKCS1_PADDING);
@ -806,6 +820,7 @@ crypto_pk_public_checksig_digest(crypto_pk_env_t *env, const char *data,
{ {
char digest[DIGEST_LEN]; char digest[DIGEST_LEN];
char *buf; char *buf;
size_t buflen;
int r; int r;
tor_assert(env); tor_assert(env);
@ -818,8 +833,9 @@ crypto_pk_public_checksig_digest(crypto_pk_env_t *env, const char *data,
log_warn(LD_BUG, "couldn't compute digest"); log_warn(LD_BUG, "couldn't compute digest");
return -1; return -1;
} }
buf = tor_malloc(crypto_pk_keysize(env)+1); buflen = crypto_pk_keysize(env)+1;
r = crypto_pk_public_checksig(env,buf,sig,siglen); buf = tor_malloc(buflen);
r = crypto_pk_public_checksig(env,buf,buflen,sig,siglen);
if (r != DIGEST_LEN) { if (r != DIGEST_LEN) {
log_warn(LD_CRYPTO, "Invalid signature"); log_warn(LD_CRYPTO, "Invalid signature");
tor_free(buf); tor_free(buf);
@ -839,9 +855,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>env</b>, using PKCS1 padding. On success, write the signature to
* <b>to</b>, and return the number of bytes written. On failure, return * <b>to</b>, and return the number of bytes written. On failure, return
* -1. * -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 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) const char *from, size_t fromlen)
{ {
int r; int r;
@ -849,6 +868,7 @@ crypto_pk_private_sign(crypto_pk_env_t *env, char *to,
tor_assert(from); tor_assert(from);
tor_assert(to); tor_assert(to);
tor_assert(fromlen < INT_MAX); tor_assert(fromlen < INT_MAX);
tor_assert(tolen >= crypto_pk_keysize(env));
if (!env->key->p) if (!env->key->p)
/* Not a private key */ /* Not a private key */
return -1; return -1;
@ -867,16 +887,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 * <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 * store it in <b>to</b>. Return the number of bytes written on
* success, and -1 on failure. * 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 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) const char *from, size_t fromlen)
{ {
int r; int r;
char digest[DIGEST_LEN]; char digest[DIGEST_LEN];
if (crypto_digest(digest,from,fromlen)<0) if (crypto_digest(digest,from,fromlen)<0)
return -1; 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)); memset(digest, 0, sizeof(digest));
return r; return r;
} }
@ -900,7 +923,7 @@ crypto_pk_private_sign_digest(crypto_pk_env_t *env, char *to,
*/ */
int int
crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env, crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env,
char *to, char *to, size_t tolen,
const char *from, const char *from,
size_t fromlen, size_t fromlen,
int padding, int force) int padding, int force)
@ -923,8 +946,13 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env,
if (!force && fromlen+overhead <= pkeylen) { if (!force && fromlen+overhead <= pkeylen) {
/* It all fits in a single encrypt. */ /* 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(); cipher = crypto_new_cipher_env();
if (!cipher) return -1; if (!cipher) return -1;
if (crypto_cipher_generate_key(cipher)<0) if (crypto_cipher_generate_key(cipher)<0)
@ -946,7 +974,7 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env,
/* Length of symmetrically encrypted data. */ /* Length of symmetrically encrypted data. */
symlen = fromlen-(pkeylen-overhead-CIPHER_KEY_LEN); 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) { if (outlen!=(int)pkeylen) {
goto err; goto err;
} }
@ -972,6 +1000,7 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env,
int int
crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env, crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env,
char *to, char *to,
size_t tolen,
const char *from, const char *from,
size_t fromlen, size_t fromlen,
int padding, int warnOnFailure) int padding, int warnOnFailure)
@ -985,11 +1014,12 @@ crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env,
pkeylen = crypto_pk_keysize(env); pkeylen = crypto_pk_keysize(env);
if (fromlen <= pkeylen) { 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); warnOnFailure);
} }
buf = tor_malloc(pkeylen+1); 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); warnOnFailure);
if (outlen<0) { if (outlen<0) {
log_fn(warnOnFailure?LOG_WARN:LOG_DEBUG, LD_CRYPTO, log_fn(warnOnFailure?LOG_WARN:LOG_DEBUG, LD_CRYPTO,
@ -1007,6 +1037,7 @@ crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env,
} }
memcpy(to,buf+CIPHER_KEY_LEN,outlen-CIPHER_KEY_LEN); memcpy(to,buf+CIPHER_KEY_LEN,outlen-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); r = crypto_cipher_decrypt(cipher, to+outlen, from+pkeylen, fromlen-pkeylen);
if (r<0) if (r<0)
goto err; goto err;

View File

@ -93,23 +93,25 @@ crypto_pk_env_t *crypto_pk_dup_key(crypto_pk_env_t *orig);
crypto_pk_env_t *crypto_pk_copy_full(crypto_pk_env_t *orig); crypto_pk_env_t *crypto_pk_copy_full(crypto_pk_env_t *orig);
int crypto_pk_key_is_private(const crypto_pk_env_t *key); int crypto_pk_key_is_private(const crypto_pk_env_t *key);
int crypto_pk_public_encrypt(crypto_pk_env_t *env, char *to, int crypto_pk_public_encrypt(crypto_pk_env_t *env, char *to, size_t tolen,
const char *from, size_t fromlen, int padding); const char *from, size_t fromlen, int padding);
int crypto_pk_private_decrypt(crypto_pk_env_t *env, char *to, int crypto_pk_private_decrypt(crypto_pk_env_t *env, char *to, size_t tolen,
const char *from, size_t fromlen, const char *from, size_t fromlen,
int padding, int warnOnFailure); int padding, int warnOnFailure);
int crypto_pk_public_checksig(crypto_pk_env_t *env, char *to, int crypto_pk_public_checksig(crypto_pk_env_t *env, char *to, size_t tolen,
const char *from, size_t fromlen); const char *from, size_t fromlen);
int crypto_pk_public_checksig_digest(crypto_pk_env_t *env, const char *data, int crypto_pk_public_checksig_digest(crypto_pk_env_t *env, const char *data,
size_t datalen, const char *sig, size_t siglen); size_t datalen, const char *sig, size_t siglen);
int crypto_pk_private_sign(crypto_pk_env_t *env, char *to, int crypto_pk_private_sign(crypto_pk_env_t *env, char *to, size_t tolen,
const char *from, size_t fromlen); const char *from, size_t fromlen);
int crypto_pk_private_sign_digest(crypto_pk_env_t *env, char *to, int crypto_pk_private_sign_digest(crypto_pk_env_t *env, char *to, size_t tolen,
const char *from, size_t fromlen); const char *from, size_t fromlen);
int crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env, char *to, int crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env, char *to,
size_t tolen,
const char *from, size_t fromlen, const char *from, size_t fromlen,
int padding, int force); int padding, int force);
int crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env, char *to, int crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env, char *to,
size_t tolen,
const char *from, size_t fromlen, const char *from, size_t fromlen,
int padding, int warnOnFailure); int padding, int warnOnFailure);

View File

@ -5321,7 +5321,8 @@ or_state_save(time_t now)
tor_free(state); tor_free(state);
fname = get_datadir_fname("state"); fname = get_datadir_fname("state");
if (write_str_to_file(fname, contents, 0)<0) { if (write_str_to_file(fname, contents, 0)<0) {
log_warn(LD_FS, "Unable to write state to file \"%s\"", fname); log_warn(LD_FS, "Unable to write state to file \"%s\"; "
"will try again later", fname);
tor_free(fname); tor_free(fname);
tor_free(contents); tor_free(contents);
return -1; return -1;

View File

@ -362,6 +362,7 @@ networkstatus_check_voter_signature(networkstatus_t *consensus,
signed_digest = tor_malloc(signed_digest_len); signed_digest = tor_malloc(signed_digest_len);
if (crypto_pk_public_checksig(cert->signing_key, if (crypto_pk_public_checksig(cert->signing_key,
signed_digest, signed_digest,
signed_digest_len,
voter->signature, voter->signature,
voter->signature_len) != DIGEST_LEN || voter->signature_len) != DIGEST_LEN ||
memcmp(signed_digest, consensus->networkstatus_digest, DIGEST_LEN)) { memcmp(signed_digest, consensus->networkstatus_digest, DIGEST_LEN)) {

View File

@ -188,6 +188,7 @@ onion_skin_create(crypto_pk_env_t *dest_router_key,
/* set meeting point, meeting cookie, etc here. Leave zero for now. */ /* set meeting point, meeting cookie, etc here. Leave zero for now. */
if (crypto_pk_public_hybrid_encrypt(dest_router_key, onion_skin_out, if (crypto_pk_public_hybrid_encrypt(dest_router_key, onion_skin_out,
ONIONSKIN_CHALLENGE_LEN,
challenge, DH_KEY_LEN, challenge, DH_KEY_LEN,
PK_PKCS1_OAEP_PADDING, 1)<0) PK_PKCS1_OAEP_PADDING, 1)<0)
goto err; goto err;
@ -230,6 +231,7 @@ onion_skin_server_handshake(const char *onion_skin, /*ONIONSKIN_CHALLENGE_LEN*/
break; break;
note_crypto_pk_op(DEC_ONIONSKIN); note_crypto_pk_op(DEC_ONIONSKIN);
len = crypto_pk_private_hybrid_decrypt(k, challenge, len = crypto_pk_private_hybrid_decrypt(k, challenge,
ONIONSKIN_CHALLENGE_LEN,
onion_skin, ONIONSKIN_CHALLENGE_LEN, onion_skin, ONIONSKIN_CHALLENGE_LEN,
PK_PKCS1_OAEP_PADDING,0); PK_PKCS1_OAEP_PADDING,0);
if (len>0) if (len>0)

View File

@ -193,6 +193,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
/*XXX maybe give crypto_pk_public_hybrid_encrypt a max_len arg, /*XXX maybe give crypto_pk_public_hybrid_encrypt a max_len arg,
* to avoid buffer overflows? */ * to avoid buffer overflows? */
r = crypto_pk_public_hybrid_encrypt(intro_key, payload+DIGEST_LEN, r = crypto_pk_public_hybrid_encrypt(intro_key, payload+DIGEST_LEN,
sizeof(payload)-DIGEST_LEN,
tmp, tmp,
(int)(dh_offset+DH_KEY_LEN), (int)(dh_offset+DH_KEY_LEN),
PK_PKCS1_OAEP_PADDING, 0); PK_PKCS1_OAEP_PADDING, 0);

View File

@ -700,7 +700,9 @@ rend_encode_service_descriptor(rend_service_descriptor_t *desc,
cp += ipoint_len+1; cp += ipoint_len+1;
} }
note_crypto_pk_op(REND_SERVER); note_crypto_pk_op(REND_SERVER);
r = crypto_pk_private_sign_digest(key, cp, *str_out, cp-*str_out); r = crypto_pk_private_sign_digest(key,
cp, buflen - (cp - *str_out),
*str_out, cp-*str_out);
if (r<0) { if (r<0) {
tor_free(*str_out); tor_free(*str_out);
return -1; return -1;

View File

@ -979,7 +979,8 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
/* Next N bytes is encrypted with service key */ /* Next N bytes is encrypted with service key */
note_crypto_pk_op(REND_SERVER); note_crypto_pk_op(REND_SERVER);
r = crypto_pk_private_hybrid_decrypt( r = crypto_pk_private_hybrid_decrypt(
intro_key,buf,(char*)(request+DIGEST_LEN),request_len-DIGEST_LEN, intro_key,buf,sizeof(buf),
(char*)(request+DIGEST_LEN),request_len-DIGEST_LEN,
PK_PKCS1_OAEP_PADDING,1); PK_PKCS1_OAEP_PADDING,1);
if (r<0) { if (r<0) {
log_warn(LD_PROTOCOL, "Couldn't decrypt INTRODUCE2 cell."); log_warn(LD_PROTOCOL, "Couldn't decrypt INTRODUCE2 cell.");
@ -1424,7 +1425,8 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
goto err; goto err;
len += 20; len += 20;
note_crypto_pk_op(REND_SERVER); note_crypto_pk_op(REND_SERVER);
r = crypto_pk_private_sign_digest(intro_key, buf+len, buf, len); r = crypto_pk_private_sign_digest(intro_key, buf+len, sizeof(buf)-len,
buf, len);
if (r<0) { if (r<0) {
log_warn(LD_BUG, "Internal error: couldn't sign introduction request."); log_warn(LD_BUG, "Internal error: couldn't sign introduction request.");
reason = END_CIRC_REASON_INTERNAL; reason = END_CIRC_REASON_INTERNAL;

View File

@ -4676,7 +4676,8 @@ routerinfo_incompatible_with_extrainfo(routerinfo_t *ri, extrainfo_t *ei,
if (ei->pending_sig) { if (ei->pending_sig) {
char signed_digest[128]; char signed_digest[128];
if (crypto_pk_public_checksig(ri->identity_pkey, signed_digest, if (crypto_pk_public_checksig(ri->identity_pkey,
signed_digest, sizeof(signed_digest),
ei->pending_sig, ei->pending_sig_len) != DIGEST_LEN || ei->pending_sig, ei->pending_sig_len) != DIGEST_LEN ||
memcmp(signed_digest, ei->cache_info.signed_descriptor_digest, memcmp(signed_digest, ei->cache_info.signed_descriptor_digest,
DIGEST_LEN)) { DIGEST_LEN)) {

View File

@ -571,10 +571,12 @@ router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
crypto_pk_env_t *private_key) crypto_pk_env_t *private_key)
{ {
char *signature; char *signature;
size_t i; size_t i, keysize;
signature = tor_malloc(crypto_pk_keysize(private_key)); keysize = crypto_pk_keysize(private_key);
if (crypto_pk_private_sign(private_key, signature, digest, DIGEST_LEN) < 0) { signature = tor_malloc(keysize);
if (crypto_pk_private_sign(private_key, signature, keysize,
digest, DIGEST_LEN) < 0) {
log_warn(LD_BUG,"Couldn't sign digest."); log_warn(LD_BUG,"Couldn't sign digest.");
goto err; goto err;
@ -924,6 +926,7 @@ check_signature_token(const char *digest,
const char *doctype) const char *doctype)
{ {
char *signed_digest; char *signed_digest;
size_t keysize;
const int check_authority = (flags & CST_CHECK_AUTHORITY); const int check_authority = (flags & CST_CHECK_AUTHORITY);
const int check_objtype = ! (flags & CST_NO_CHECK_OBJTYPE); const int check_objtype = ! (flags & CST_NO_CHECK_OBJTYPE);
@ -945,9 +948,10 @@ check_signature_token(const char *digest,
} }
} }
signed_digest = tor_malloc(tok->object_size); keysize = crypto_pk_keysize(pkey);
if (crypto_pk_public_checksig(pkey, signed_digest, tok->object_body, signed_digest = tor_malloc(keysize);
tok->object_size) if (crypto_pk_public_checksig(pkey, signed_digest, keysize,
tok->object_body, tok->object_size)
!= DIGEST_LEN) { != DIGEST_LEN) {
log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype); log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype);
tor_free(signed_digest); tor_free(signed_digest);

View File

@ -701,25 +701,27 @@ test_crypto_pk(void)
test_eq(128, crypto_pk_keysize(pk1)); test_eq(128, crypto_pk_keysize(pk1));
test_eq(128, crypto_pk_keysize(pk2)); test_eq(128, crypto_pk_keysize(pk2));
test_eq(128, crypto_pk_public_encrypt(pk2, data1, "Hello whirled.", 15, test_eq(128, crypto_pk_public_encrypt(pk2, data1, sizeof(data1),
"Hello whirled.", 15,
PK_PKCS1_OAEP_PADDING)); PK_PKCS1_OAEP_PADDING));
test_eq(128, crypto_pk_public_encrypt(pk1, data2, "Hello whirled.", 15, test_eq(128, crypto_pk_public_encrypt(pk1, data2, sizeof(data2),
"Hello whirled.", 15,
PK_PKCS1_OAEP_PADDING)); PK_PKCS1_OAEP_PADDING));
/* oaep padding should make encryption not match */ /* oaep padding should make encryption not match */
test_memneq(data1, data2, 128); test_memneq(data1, data2, 128);
test_eq(15, crypto_pk_private_decrypt(pk1, data3, data1, 128, test_eq(15, crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data1, 128,
PK_PKCS1_OAEP_PADDING,1)); PK_PKCS1_OAEP_PADDING,1));
test_streq(data3, "Hello whirled."); test_streq(data3, "Hello whirled.");
memset(data3, 0, 1024); memset(data3, 0, 1024);
test_eq(15, crypto_pk_private_decrypt(pk1, data3, data2, 128, test_eq(15, crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data2, 128,
PK_PKCS1_OAEP_PADDING,1)); PK_PKCS1_OAEP_PADDING,1));
test_streq(data3, "Hello whirled."); test_streq(data3, "Hello whirled.");
/* Can't decrypt with public key. */ /* Can't decrypt with public key. */
test_eq(-1, crypto_pk_private_decrypt(pk2, data3, data2, 128, test_eq(-1, crypto_pk_private_decrypt(pk2, data3, sizeof(data3), data2, 128,
PK_PKCS1_OAEP_PADDING,1)); PK_PKCS1_OAEP_PADDING,1));
/* Try again with bad padding */ /* Try again with bad padding */
memcpy(data2+1, "XYZZY", 5); /* This has fails ~ once-in-2^40 */ memcpy(data2+1, "XYZZY", 5); /* This has fails ~ once-in-2^40 */
test_eq(-1, crypto_pk_private_decrypt(pk1, data3, data2, 128, test_eq(-1, crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data2, 128,
PK_PKCS1_OAEP_PADDING,1)); PK_PKCS1_OAEP_PADDING,1));
/* File operations: save and load private key */ /* File operations: save and load private key */
@ -734,19 +736,22 @@ test_crypto_pk(void)
get_fname("xyzzy")) < 0); get_fname("xyzzy")) < 0);
test_assert(! crypto_pk_read_private_key_from_filename(pk2, test_assert(! crypto_pk_read_private_key_from_filename(pk2,
get_fname("pkey1"))); get_fname("pkey1")));
test_eq(15, crypto_pk_private_decrypt(pk2, data3, data1, 128, test_eq(15, crypto_pk_private_decrypt(pk2, data3, sizeof(data3), data1, 128,
PK_PKCS1_OAEP_PADDING,1)); PK_PKCS1_OAEP_PADDING,1));
/* Now try signing. */ /* Now try signing. */
strlcpy(data1, "Ossifrage", 1024); strlcpy(data1, "Ossifrage", 1024);
test_eq(128, crypto_pk_private_sign(pk1, data2, data1, 10)); test_eq(128, crypto_pk_private_sign(pk1, data2, sizeof(data2), data1, 10));
test_eq(10, crypto_pk_public_checksig(pk1, data3, data2, 128)); test_eq(10, crypto_pk_public_checksig(pk1, data3, sizeof(data3), data2, 128));
test_streq(data3, "Ossifrage"); test_streq(data3, "Ossifrage");
/* Try signing digests. */ /* Try signing digests. */
test_eq(128, crypto_pk_private_sign_digest(pk1, data2, data1, 10)); test_eq(128, crypto_pk_private_sign_digest(pk1, data2, sizeof(data2),
test_eq(20, crypto_pk_public_checksig(pk1, data3, data2, 128)); data1, 10));
test_eq(0, crypto_pk_public_checksig_digest(pk1, data1, 10, data2, 128)); test_eq(20, crypto_pk_public_checksig(pk1, data3, sizeof(data1), data2, 128));
test_eq(-1, crypto_pk_public_checksig_digest(pk1, data1, 11, data2, 128)); test_eq(0, crypto_pk_public_checksig_digest(pk1, data1,
10, data2, 128));
test_eq(-1, crypto_pk_public_checksig_digest(pk1, data1,
11, data2, 128));
/*XXXX test failed signing*/ /*XXXX test failed signing*/
/* Try encoding */ /* Try encoding */
@ -767,9 +772,11 @@ test_crypto_pk(void)
continue; continue;
p = (i==0)?PK_NO_PADDING: p = (i==0)?PK_NO_PADDING:
(i==1)?PK_PKCS1_PADDING:PK_PKCS1_OAEP_PADDING; (i==1)?PK_PKCS1_PADDING:PK_PKCS1_OAEP_PADDING;
len = crypto_pk_public_hybrid_encrypt(pk1,data2,data1,j,p,0); len = crypto_pk_public_hybrid_encrypt(pk1,data2,sizeof(data2),
data1,j,p,0);
test_assert(len>=0); test_assert(len>=0);
len = crypto_pk_private_hybrid_decrypt(pk1,data3,data2,len,p,1); len = crypto_pk_private_hybrid_decrypt(pk1,data3,sizeof(data3),
data2,len,p,1);
test_eq(len,j); test_eq(len,j);
test_memeq(data1,data3,j); test_memeq(data1,data3,j);
} }