Skip to content

Commit 0522382

Browse files
committed
Fix RSA_METHOD parameter mismatch and use-after-free in EVP_PKEY_derive_set_peer
Custom RSA_METHOD callbacks (sign_raw, verify_raw, encrypt, decrypt) were receiving max_out (output buffer size) as their first parameter instead of in_len (input data length). This caused callbacks to read past the input buffer by up to (RSA_size - actual_input_length) bytes. Fixed all 4 dispatch sites to pass in_len, matching OpenSSL's flen semantics for RSA_private_encrypt/RSA_public_decrypt/etc. EVP_PKEY_derive_set_peer had a use-after-free when called with the same peer key already set and a refcount of 1: EVP_PKEY_free freed the key before EVP_PKEY_up_ref took a new reference. Reordered to up_ref before free, and added proper cleanup in the ctrl failure path.
1 parent c5e1710 commit 0522382

4 files changed

Lines changed: 12 additions & 9 deletions

File tree

crypto/fipsmodule/evp/evp_ctx.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,17 +366,20 @@ int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer) {
366366
return 0;
367367
}
368368

369+
// Take a reference to the new peer before freeing the old one, in case
370+
// peer == ctx->peerkey and the caller holds the sole reference.
371+
EVP_PKEY_up_ref(peer);
369372
EVP_PKEY_free(ctx->peerkey);
370373
ctx->peerkey = peer;
371374

372375
ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer);
373376

374377
if (ret <= 0) {
378+
EVP_PKEY_free(ctx->peerkey);
375379
ctx->peerkey = NULL;
376380
return 0;
377381
}
378382

379-
EVP_PKEY_up_ref(peer);
380383
return 1;
381384
}
382385

crypto/fipsmodule/rsa/rsa.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -549,12 +549,12 @@ static int rsa_sign_raw_no_self_test(RSA *rsa, size_t *out_len, uint8_t *out,
549549
// and expect an |out_len| parameter. To remain compatible with this new
550550
// paradigm and OpenSSL, we initialize |out_len| based on the return value
551551
// here.
552-
if (max_out > INT_MAX) {
552+
if (in_len > INT_MAX) {
553553
OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
554554
*out_len = 0;
555555
return 0;
556556
}
557-
int ret = rsa->meth->sign_raw((int)max_out, in, out, rsa, padding);
557+
int ret = rsa->meth->sign_raw((int)in_len, in, out, rsa, padding);
558558
if(ret < 0) {
559559
*out_len = 0;
560560
return 0;

crypto/fipsmodule/rsa/rsa_impl.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ int rsa_verify_raw_no_self_test(RSA *rsa, size_t *out_len, uint8_t *out,
360360
size_t max_out, const uint8_t *in,
361361
size_t in_len, int padding) {
362362
if(rsa->meth && rsa->meth->verify_raw) {
363-
if (max_out > INT_MAX) {
363+
if (in_len > INT_MAX) {
364364
OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
365365
*out_len = 0;
366366
return 0;
@@ -372,7 +372,7 @@ int rsa_verify_raw_no_self_test(RSA *rsa, size_t *out_len, uint8_t *out,
372372
// and expect an |out_len| parameter. To remain compatible with this new
373373
// paradigm and OpenSSL, we initialize |out_len| based on the return value
374374
// here.
375-
int ret = rsa->meth->verify_raw((int)max_out, in, out, rsa, padding);
375+
int ret = rsa->meth->verify_raw((int)in_len, in, out, rsa, padding);
376376
if(ret < 0) {
377377
*out_len = 0;
378378
return 0;

crypto/rsa_extra/rsa_crypt.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -338,12 +338,12 @@ int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
338338
// expect an |out_len| parameter. To remain compatible with this new
339339
// paradigm and OpenSSL, we initialize |out_len| based on the return value
340340
// here.
341-
if (max_out > INT_MAX) {
341+
if (in_len > INT_MAX) {
342342
OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
343343
*out_len = 0;
344344
return 0;
345345
}
346-
int ret = rsa->meth->encrypt((int)max_out, in, out, rsa, padding);
346+
int ret = rsa->meth->encrypt((int)in_len, in, out, rsa, padding);
347347
if(ret < 0) {
348348
*out_len = 0;
349349
return 0;
@@ -515,12 +515,12 @@ int RSA_decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
515515
// functions like |RSA_decrypt| diverge from this paradigm and expect
516516
// an |out_len| parameter. To remain compatible with this new paradigm and
517517
// OpenSSL, we initialize |out_len| based on the return value here.
518-
if (max_out > INT_MAX) {
518+
if (in_len > INT_MAX) {
519519
OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
520520
*out_len = 0;
521521
return 0;
522522
}
523-
int ret = rsa->meth->decrypt((int)max_out, in, out, rsa, padding);
523+
int ret = rsa->meth->decrypt((int)in_len, in, out, rsa, padding);
524524
if(ret < 0) {
525525
*out_len = 0;
526526
return 0;

0 commit comments

Comments
 (0)