Closed
Bug 287654
Opened 20 years ago
Closed 20 years ago
NSC_Encrypt with RSA mechanism crashes if len is greater than modulus len
Categories
(NSS :: Libraries, defect, P1)
Tracking
(Not tracked)
RESOLVED
FIXED
3.10
People
(Reporter: julien.pierre, Assigned: julien.pierre)
Details
Attachments
(2 files, 2 obsolete files)
|
667 bytes,
patch
|
nelson
:
superreview+
|
Details | Diff | Splinter Review |
|
2.00 KB,
patch
|
nelson
:
review+
|
Details | Diff | Splinter Review |
I tried to encrypt 140 bytes of data with PK11_PubEncryptRaw . The public key
was 1024 bits. The input and output buffers were both more than large enough
(1024 bytes). This resulted in a crash in the softoken, in rsawrapr.c, in
rsa_FormatBlock .
I used the access checking feature of dbx to identify the problem. See log
below. The issue is that the lower lovel code apparently uses an intermediate
buffer for the encryption, which is only 128 bytes. Then it does a memcpy of the
size of the entire input buffer, which is bigger .
RTC: Enabling Error Checking...
RTC: Running program...
Write to unallocated (wua) on thread 1:
Attempting to write 1 byte at address 0x4aa81c
which is 12 bytes past end of heap block of size 128 bytes at 0x4aa790
This block was allocated from:
[1] PR_Malloc() at line 436 in "prmem.c"
[2] PORT_Alloc() at line 113 in "secport.c"
[3] SECITEM_ArenaDupItem() at line 210 in "secitem.c"
[4] SECITEM_DupItem() at line 186 in "secitem.c"
[5] pk11_addTokenKeyByHandle() at line 2052 in "pkcs11u.c"
[6] pk11_mkHandle() at line 2930 in "pkcs11u.c"
[7] pk11_key_collect() at line 4093 in "pkcs11.c"
[8] nsslowkey_TraverseKeys() at line 439 in "keydb.c"
t@1 (l@1) stopped in rsa_FormatBlock at line 421 in file "rsawrapr.c"
421
PORT_Memcpy(result->data+(modulusLen-data->len),data->data,data->len);
(dbx) p data->len
data->len = 140U
(dbx) where
current thread: t@1
=>[1] rsa_FormatBlock(result = 0xffbfe0f8, modulusLen = 128U, blockType =
RSA_BlockRaw, data = 0xffbfe0ec), line 421 in "rsawrapr.c"
[2] RSA_EncryptRaw(key = 0x4b2728, output = 0xffbfe3a8 "\xff\xbf\xe4",
output_len = 0xffbfe198, max_output_len = 128U, input = 0xffbfe7a8
"^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A"
..., input_len = 140U), line 827 in "rsawrapr.c"
[3] NSC_Encrypt(hSession = 4U, pData = 0xffbfe7a8
"^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A"
..., ulDataLen = 140U, pEncryptedData = 0xffbfe3a8 "\xff\xbf\xe4",
pulEncryptedDataLen = 0xffbfe218), line 889 in "pkcs11c.c"
[4] pk11_PubEncryptRaw(key = 0x4b1ef8, enc = 0xffbfe3a8 "\xff\xbf\xe4", data =
0xffbfe7a8
"^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A"
..., dataLen = 140U, mech = 0xffbfe290, wincx = (nil)), line 824 in "pk11obj.c"
[5] PK11_PubEncryptRaw(key = 0x4b1ef8, enc = 0xffbfe3a8 "\xff\xbf\xe4", data =
0xffbfe7a8
"^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A"
..., dataLen = 140U, wincx = (nil)), line 840 in "pk11obj.c"
[6] PK11_PublicKeyOp(key = 0x4b1ef8, output = 0xffbfe3a8 "\xff\xbf\xe4", input
= 0xffbfe7a8
"^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A"
...), line 240 in "rsaperf.c"
[7] main(argc = 8, argv = 0xffbfec64), line 427 in "rsaperf.c"
(dbx)| Assignee | ||
Comment 1•20 years ago
|
||
| Assignee | ||
Comment 2•20 years ago
|
||
Comment on attachment 178545 [details] [diff] [review] don't try to copy data outside output buffer boundaries This patch fixes the crash (buffer overflow). However, I'm not sure if it is correct thing to do. In this case, the caller of PK11_PubEncryptRaw isn't notified that not all the data was encrypted. That function only returns a SECStatus, and I feel it should return SECFailure in this case. How that should actually accomplished in the various layers in between, I'm not certain. Bob ?
Attachment #178545 -
Flags: review?(rrelyea)
| Assignee | ||
Updated•20 years ago
|
Priority: -- → P1
Target Milestone: --- → 3.10
Comment 3•20 years ago
|
||
PK11_PubEncryptRaw should fail if we try to encrypt more then modulus bytes. The failure should come from NSC_Encrypt, which should get it from blapi. This behavior for NSC_Encrypt is defined by PKCS #11. Encrypt PKCS should also fail if the block is greater than the modulus - the minimum header (there's an assert in the RSA code for this). It's OK to put the check in RSA OP since NSC_Decrypt, NSC_Sign, NSC_Verify, and NSC_VerifyRecover should all fail the same way for RSA operations. bob
| Assignee | ||
Comment 4•20 years ago
|
||
Comment on attachment 178545 [details] [diff] [review] don't try to copy data outside output buffer boundaries Marking patch obsolete
Attachment #178545 -
Attachment is obsolete: true
Attachment #178545 -
Flags: review?(rrelyea)
| Assignee | ||
Comment 5•20 years ago
|
||
Attachment #178872 -
Flags: review?(rrelyea)
| Assignee | ||
Comment 6•20 years ago
|
||
Comment on attachment 178872 [details] [diff] [review] check modulus length for RSA raw encrypt case Bob, Nelson, please review this very short patch. Thanks !
Attachment #178872 -
Flags: superreview?(nelson)
Comment 7•20 years ago
|
||
Comment on attachment 178872 [details] [diff] [review] check modulus length for RSA raw encrypt case >+ if (data->len > modulusLen ) { >+ return SECFailure; >+ } This test suffices to prevent a crash, but still allows SOME invalid data to be processed. Specifically, the input data must be numerically less than the modulus. This is always true when the input data is shorter than the modulus. When the input data and modulus are of equal length, memcmp can be used to compare them, and determine if the input is less than the modulus. I guess we have to decide whether the purpose of the test is only to avoid crashes, or is to ensure correctness of the operation. If it is only to avoid crashes, then this patch is OK.
Comment 8•20 years ago
|
||
Comment on attachment 178872 [details] [diff] [review] check modulus length for RSA raw encrypt case I was going to say we should set an error code before returning SECFailure, then I found that none of the functions in this file sets error code...
Comment 9•20 years ago
|
||
Comment on attachment 178872 [details] [diff] [review] check modulus length for RSA raw encrypt case Re: Nelson's question in comment 7, I think we should ensure correctness of the operation.
| Assignee | ||
Comment 10•20 years ago
|
||
I agree that we should ensure the correctness of the operation. I believe there is a subsequent check in freebl for the test that Nelson talked about in comment 7 . I tripped over this in my testing of rsaperf also when I fed an uninitialized buffer of the correct size, and the operation failed . I can't remember if it was for encrypt or decrypt. Looking at the code in freebl/rsa.c, I see the following code in rsa_PrivateKeyOp : /* check input out of range (needs to be in range [0..n-1]) */ modLen = rsa_modulusLen(&key->modulus); offset = (key->modulus.data[0] == 0) ? 1 : 0; /* may be leading 0 */ if (memcmp(input, key->modulus.data + offset, modLen) >= 0) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } However, I see no equivalent check in rsa_publicKeyOp, which is the encrypt case. So, perhaps we have to do the check at the higher PKCS#11 level. But I think that's inconsistent. Thoughts ?
| Assignee | ||
Comment 11•20 years ago
|
||
Attachment #179314 -
Flags: review?(nelson)
| Assignee | ||
Updated•20 years ago
|
Summary: NSC_Encrypt with RSA mechanism crashes if output len is greater than modulus len → NSC_Encrypt with RSA mechanism crashes if len is greater than modulus len
Comment 12•20 years ago
|
||
Comment on attachment 178872 [details] [diff] [review] check modulus length for RSA raw encrypt case Marking r+=nelson I believe this patch is correct and necessary but not sufficient, as noted above.
Attachment #178872 -
Flags: superreview?(nelson) → superreview+
Comment 13•20 years ago
|
||
Comment on attachment 179314 [details] [diff] [review] also check input value against modulus Several problems with this patch. In the private key code, the value comparison was done before the numbers were converted from canonical byte strings to mp_ints. In this case, the numbers have already been converted to mp_ints so the code cannot simply return here or it will leak the mp_ints. It needs to "go to cleanup". Also, since they are already mp_ints, it is easier and better (and probably faster) to use the mpi comparison function to compare their numeric values. Also, if the input value is numerically too big, SEC_ERROR_INPUT_LEN is probably the right error code. That goes for the previous patch that checked buffer length, too. Suggested (but untested) alternative patch: > /* 2. Represent message as integer in range [0..n-1] */ > CHECK_MPI_OK( mp_read_unsigned_octets(&m, input, modLen) ); >+ /* 2 bis. check input out of range (needs to be in range [0..n-1]) */ >+ if (mp_cmp(&m, &n) >= 0) >+ PORT_SetError(SEC_ERROR_INPUT_LEN); >+ rv = SECFailure; >+ goto cleanup; >+ }
Attachment #179314 -
Flags: review?(nelson) → review-
Comment 14•20 years ago
|
||
That "alternative patch" is missing a {. | Assignee | ||
Comment 15•20 years ago
|
||
Nelson, Thanks for catching the leak. I looked at the code for mp_cmp, and I don't think way it will execute faster than memcmp in most cases. I would be OK with either check.
| Assignee | ||
Comment 16•20 years ago
|
||
I think the attached patch will be most efficient. It checks the input value before converting the message to mp_ints .
Attachment #179314 -
Attachment is obsolete: true
Attachment #179555 -
Flags: review?(nelson)
| Assignee | ||
Comment 17•20 years ago
|
||
Comment on attachment 178872 [details] [diff] [review] check modulus length for RSA raw encrypt case I checked in this patch for the softoken. Checking in rsawrapr.c; /cvsroot/mozilla/security/nss/lib/softoken/rsawrapr.c,v <-- rsawrapr.c new revision: 1.8; previous revision: 1.7 done
Attachment #178872 -
Flags: review?(rrelyea)
Comment 18•20 years ago
|
||
Comment on attachment 179555 [details] [diff] [review] correct patch I agree this patch is correct. I believe it is less efficient because memcmp will load and compare each byte of each string, byte-by-byte, whereas mp_cmp will load and compare the values word-by-word. But this patch is correct, so I leave it to you to decide whether to go with memcmp or mp_cmp.
Attachment #179555 -
Flags: review?(nelson) → review+
| Assignee | ||
Comment 19•20 years ago
|
||
Nelson, I checked in the patch attached to the tip. I believe the mp_cmp will be significantly more complex code due to the use of mp_int structures and pointer indirection, whereas memcmp could be done with just a couple instruction s(using eg. "rep cmpsb" on x86). I actually just benchmarked the two methods briefly. I can't tell them apart, even after running for 30 seconds. The results are within 0.5 % of each other, one way or the other. I'm not going to spend more time on it because we aren't concerned about RSA encrypt performance, which is on the client side. Checking in rsa.c; /cvsroot/mozilla/security/nss/lib/freebl/rsa.c,v <-- rsa.c new revision: 1.35; previous revision: 1.34
Status: NEW → RESOLVED
Closed: 20 years ago
Resolution: --- → FIXED
You need to log in
before you can comment on or make changes to this bug.
Description
•