From 41ebe0592b78b5f5176296c10d854efeca36cc4b Mon Sep 17 00:00:00 2001 From: "ian.mcgreer%sun.com" Date: Wed, 19 Jun 2002 14:59:24 +0000 Subject: [PATCH] bug 150704, PK11_Finalize can crash because softoken does not implement C_XXXFinal correctly --- security/nss/lib/pk11wrap/pk11skey.c | 27 +++++++-- security/nss/lib/softoken/pkcs11c.c | 90 ++++++++++++++++++++++++---- 2 files changed, 100 insertions(+), 17 deletions(-) diff --git a/security/nss/lib/pk11wrap/pk11skey.c b/security/nss/lib/pk11wrap/pk11skey.c index e11a8e9470b..236fa1e576c 100644 --- a/security/nss/lib/pk11wrap/pk11skey.c +++ b/security/nss/lib/pk11wrap/pk11skey.c @@ -4020,31 +4020,34 @@ pk11_Finalize(PK11Context *context) { CK_ULONG count = 0; CK_RV crv; + unsigned char stackBuf[256]; + unsigned char *buffer = NULL; if (!context->ownSession) { return SECSuccess; } +finalize: switch (context->operation) { case CKA_ENCRYPT: crv=PK11_GETTAB(context->slot)->C_EncryptFinal(context->session, - NULL,&count); + buffer, &count); break; case CKA_DECRYPT: crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session, - NULL,&count); + buffer, &count); break; case CKA_SIGN: crv=PK11_GETTAB(context->slot)->C_SignFinal(context->session, - NULL,&count); + buffer, &count); break; case CKA_VERIFY: crv=PK11_GETTAB(context->slot)->C_VerifyFinal(context->session, - NULL,count); + buffer, count); break; case CKA_DIGEST: crv=PK11_GETTAB(context->slot)->C_DigestFinal(context->session, - NULL,&count); + buffer, &count); break; default: crv = CKR_OPERATION_NOT_INITIALIZED; @@ -4052,9 +4055,23 @@ pk11_Finalize(PK11Context *context) } if (crv != CKR_OK) { + if (crv == CKR_OPERATION_NOT_INITIALIZED) { + /* if there's no operation, it is finalized */ + return SECSuccess; + } PORT_SetError( PK11_MapError(crv) ); return SECFailure; } + + /* try to finalize the session with a buffer */ + if (buffer == NULL && count > 0) { + if (count < sizeof stackBuf) { + buffer = stackBuf; + goto finalize; + } else { + return SECFailure; + } + } return SECSuccess; } diff --git a/security/nss/lib/softoken/pkcs11c.c b/security/nss/lib/softoken/pkcs11c.c index f5107e43375..ad598cb951b 100644 --- a/security/nss/lib/softoken/pkcs11c.c +++ b/security/nss/lib/softoken/pkcs11c.c @@ -443,6 +443,7 @@ pk11_InitGeneric(PK11Session *session,PK11SessionContext **contextPtr, context->doPad = PR_FALSE; context->padDataLength = 0; context->key = key; + context->blockSize = 0; *contextPtr = context; return CKR_OK; @@ -795,12 +796,21 @@ CK_RV NSC_EncryptFinal(CK_SESSION_HANDLE hSession, unsigned int maxout = *pulLastEncryptedPartLen; CK_RV crv; SECStatus rv = SECSuccess; + PRBool contextFinished = PR_TRUE; /* make sure we're legal */ crv = pk11_GetContext(hSession,&context,PK11_ENCRYPT,PR_TRUE,&session); if (crv != CKR_OK) return crv; *pulLastEncryptedPartLen = 0; + if (!pLastEncryptedPart) { + /* caller is checking the amount of remaining data */ + if (context->blockSize > 0) { + *pulLastEncryptedPartLen = context->blockSize; + contextFinished = PR_FALSE; /* still have padding to go */ + } + goto finish; + } /* do padding */ if (context->doPad) { @@ -815,9 +825,11 @@ CK_RV NSC_EncryptFinal(CK_SESSION_HANDLE hSession, if (rv == SECSuccess) *pulLastEncryptedPartLen = (CK_ULONG) outlen; } - /* do it */ - pk11_SetContextByType(session, PK11_ENCRYPT, NULL); - pk11_FreeContext(context); +finish: + if (contextFinished) { + pk11_SetContextByType(session, PK11_ENCRYPT, NULL); + pk11_FreeContext(context); + } pk11_FreeSession(session); return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; } @@ -839,6 +851,11 @@ CK_RV NSC_Encrypt (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, crv = pk11_GetContext(hSession,&context,PK11_ENCRYPT,PR_FALSE,&session); if (crv != CKR_OK) return crv; + if (!pEncryptedData) { + *pulEncryptedDataLen = ulDataLen + 2 * context->blockSize; + goto finish; + } + if (context->doPad) { CK_ULONG finalLen; /* padding is fairly complicated, have the update and final @@ -860,8 +877,9 @@ CK_RV NSC_Encrypt (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, rv = (*context->update)(context->cipherInfo, pEncryptedData, &outlen, maxoutlen, pData, ulDataLen); *pulEncryptedDataLen = (CK_ULONG) outlen; - pk11_FreeContext(context); pk11_SetContextByType(session, PK11_ENCRYPT, NULL); + pk11_FreeContext(context); +finish: pk11_FreeSession(session); return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; @@ -930,12 +948,22 @@ CK_RV NSC_DecryptFinal(CK_SESSION_HANDLE hSession, unsigned int maxout = *pulLastPartLen; CK_RV crv; SECStatus rv = SECSuccess; + PRBool contextFinished = PR_TRUE; /* make sure we're legal */ crv = pk11_GetContext(hSession,&context,PK11_DECRYPT,PR_TRUE,&session); if (crv != CKR_OK) return crv; *pulLastPartLen = 0; + if (!pLastPart) { + /* caller is checking the amount of remaining data */ + if (context->padDataLength > 0) { + *pulLastPartLen = 2 * context->blockSize; + contextFinished = PR_FALSE; /* still have padding to go */ + } + goto finish; + } + if (context->doPad) { /* decrypt our saved buffer */ if (context->padDataLength != 0) { @@ -955,9 +983,11 @@ CK_RV NSC_DecryptFinal(CK_SESSION_HANDLE hSession, } } - /* do it */ - pk11_SetContextByType(session, PK11_DECRYPT, NULL); - pk11_FreeContext(context); +finish: + if (contextFinished) { + pk11_SetContextByType(session, PK11_DECRYPT, NULL); + pk11_FreeContext(context); + } pk11_FreeSession(session); return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; } @@ -979,6 +1009,11 @@ CK_RV NSC_Decrypt(CK_SESSION_HANDLE hSession, crv = pk11_GetContext(hSession,&context,PK11_DECRYPT,PR_FALSE,&session); if (crv != CKR_OK) return crv; + if (!pData) { + *pulDataLen = ulEncryptedDataLen + context->blockSize; + goto finish; + } + if (context->doPad) { CK_ULONG finalLen; /* padding is fairly complicated, have the update and final @@ -998,8 +1033,9 @@ CK_RV NSC_Decrypt(CK_SESSION_HANDLE hSession, rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen, pEncryptedData, ulEncryptedDataLen); *pulDataLen = (CK_ULONG) outlen; - pk11_FreeContext(context); pk11_SetContextByType(session, PK11_DECRYPT, NULL); + pk11_FreeContext(context); +finish: pk11_FreeSession(session); return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; } @@ -1042,6 +1078,7 @@ CK_RV NSC_DigestInit(CK_SESSION_HANDLE hSession, context->hashUpdate = (PK11Hash) MD2_Update; context->end = (PK11End) MD2_End; context->destroy = (PK11Destroy) MD2_DestroyContext; + context->maxLen = MD2_LENGTH; MD2_Begin(md2_context); break; case CKM_MD5: @@ -1056,6 +1093,7 @@ CK_RV NSC_DigestInit(CK_SESSION_HANDLE hSession, context->hashUpdate = (PK11Hash) MD5_Update; context->end = (PK11End) MD5_End; context->destroy = (PK11Destroy) MD5_DestroyContext; + context->maxLen = MD5_LENGTH; MD5_Begin(md5_context); break; case CKM_SHA_1: @@ -1071,6 +1109,7 @@ CK_RV NSC_DigestInit(CK_SESSION_HANDLE hSession, context->end = (PK11End) SHA1_End; context->destroy = (PK11Destroy) SHA1_DestroyContext; SHA1_Begin(sha1_context); + context->maxLen = SHA1_LENGTH; break; default: crv = CKR_MECHANISM_INVALID; @@ -1103,6 +1142,11 @@ CK_RV NSC_Digest(CK_SESSION_HANDLE hSession, crv = pk11_GetContext(hSession,&context,PK11_HASH,PR_FALSE,&session); if (crv != CKR_OK) return crv; + if (pDigest == NULL) { + *pulDigestLen = context->maxLen; + goto finish; + } + /* do it: */ (*context->hashUpdate)(context->cipherInfo, pData, ulDataLen); /* NOTE: this assumes buf size is bigenough for the algorithm */ @@ -1111,6 +1155,7 @@ CK_RV NSC_Digest(CK_SESSION_HANDLE hSession, pk11_SetContextByType(session, PK11_HASH, NULL); pk11_FreeContext(context); +finish: pk11_FreeSession(session); return CKR_OK; } @@ -1149,12 +1194,12 @@ CK_RV NSC_DigestFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pDigest, if (pDigest != NULL) { (*context->end)(context->cipherInfo, pDigest, &digestLen, maxout); *pulDigestLen = digestLen; + pk11_SetContextByType(session, PK11_HASH, NULL); + pk11_FreeContext(context); } else { - *pulDigestLen = 0; + *pulDigestLen = context->maxLen; } - pk11_SetContextByType(session, PK11_HASH, NULL); - pk11_FreeContext(context); pk11_FreeSession(session); return CKR_OK; } @@ -1264,6 +1309,7 @@ pk11_doHMACInit(PK11SessionContext *context,HASH_HashType hash, context->destroy = (PK11Destroy) pk11_Space; context->update = (PK11Cipher) pk11_HMACCopy; context->verify = (PK11Verify) pk11_HMACCmp; + context->maxLen = hashObj->length; HMAC_Begin(HMACcontext); return CKR_OK; } @@ -1384,6 +1430,7 @@ pk11_doSSLMACInit(PK11SessionContext *context,SECOidTag oid, context->destroy = (PK11Destroy) pk11_Space; context->update = (PK11Cipher) pk11_SSLMACSign; context->verify = (PK11Verify) pk11_SSLMACVerify; + context->maxLen = mac_size; return CKR_OK; } @@ -1855,6 +1902,7 @@ finish_rsa: context->cipherInfo = privKey; context->destroy = (PK11Destroy)pk11_Null; } + context->maxLen = nsslowkey_PrivateModulusLen(privKey); break; case CKM_DSA_SHA1: @@ -1876,6 +1924,7 @@ finish_rsa: context->update = (PK11Cipher) nsc_DSA_Sign_Stub; context->destroy = (privKey == key->objectInfo) ? (PK11Destroy) pk11_Null:(PK11Destroy)pk11_FreePrivKey; + context->maxLen = DSA_SIGNATURE_LEN; break; case CKM_MD2_HMAC_GENERAL: @@ -2023,7 +2072,10 @@ CK_RV NSC_SignFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pSignature, crv = pk11_GetContext(hSession,&context,PK11_SIGN,PR_TRUE,&session); if (crv != CKR_OK) return crv; - if (context->hashInfo) { + if (!pSignature) { + *pulSignatureLen = context->maxLen; + goto finish; + } else if (context->hashInfo) { (*context->end)(context->hashInfo, tmpbuf, &digestLen, sizeof(tmpbuf)); rv = (*context->update)(context->cipherInfo, pSignature, &outlen, maxoutlen, tmpbuf, digestLen); @@ -2047,6 +2099,8 @@ CK_RV NSC_SignFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pSignature, pk11_FreeContext(context); pk11_SetContextByType(session, PK11_SIGN, NULL); + +finish: pk11_FreeSession(session); return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; @@ -2070,6 +2124,11 @@ CK_RV NSC_Sign(CK_SESSION_HANDLE hSession, crv = pk11_GetContext(hSession,&context,PK11_SIGN,PR_FALSE,&session); if (crv != CKR_OK) return crv; + if (!pSignature) { + *pulSignatureLen = context->maxLen; + goto finish; + } + /* multi part Signing are completely implemented by SignUpdate and * sign Final */ if (context->multi) { @@ -2085,6 +2144,8 @@ CK_RV NSC_Sign(CK_SESSION_HANDLE hSession, *pulSignatureLen = (CK_ULONG) outlen; pk11_FreeContext(context); pk11_SetContextByType(session, PK11_SIGN, NULL); + +finish: pk11_FreeSession(session); return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; @@ -5095,6 +5156,7 @@ CK_RV NSC_GetOperationState(CK_SESSION_HANDLE hSession, PK11SessionContext *context; PK11Session *session; CK_RV crv; + CK_ULONG pOSLen = *pulOperationStateLen; /* make sure we're legal */ crv = pk11_GetContext(hSession, &context, PK11_HASH, PR_TRUE, &session); @@ -5105,6 +5167,10 @@ CK_RV NSC_GetOperationState(CK_SESSION_HANDLE hSession, if (pOperationState == NULL) { pk11_FreeSession(session); return CKR_OK; + } else { + if (pOSLen < *pulOperationStateLen) { + return CKR_BUFFER_TOO_SMALL; + } } PORT_Memcpy(pOperationState,&context->type,sizeof(PK11ContextType)); pOperationState += sizeof(PK11ContextType);