diff options
Diffstat (limited to '')
-rw-r--r-- | security/nss/lib/softoken/sftkmessage.c | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/security/nss/lib/softoken/sftkmessage.c b/security/nss/lib/softoken/sftkmessage.c new file mode 100644 index 0000000000..3e45445e8e --- /dev/null +++ b/security/nss/lib/softoken/sftkmessage.c @@ -0,0 +1,377 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * This file implements PKCS 11 on top of our existing security modules + * + * Implement the PKCS #11 v3.0 Message interfaces + */ +#include "seccomon.h" +#include "pkcs11.h" +#include "pkcs11i.h" +#include "blapi.h" +#include "prenv.h" +#include "softoken.h" + +static SECStatus +sftk_ChaCha20_Poly1305_Message_Encrypt(ChaCha20Poly1305Context *ctx, + unsigned char *cipherText, unsigned int *cipherTextLen, + unsigned int maxOutLen, const unsigned char *plainText, + unsigned int plainTextLen, + CK_SALSA20_CHACHA20_POLY1305_MSG_PARAMS *params, + unsigned int paramsLen, const unsigned char *aad, + unsigned int aadLen) +{ + return ChaCha20Poly1305_Encrypt(ctx, cipherText, cipherTextLen, maxOutLen, + plainText, plainTextLen, params->pNonce, params->ulNonceLen, + aad, aadLen, params->pTag); +} +static SECStatus +sftk_ChaCha20_Poly1305_Message_Decrypt(ChaCha20Poly1305Context *ctx, + unsigned char *plainText, unsigned int *plainTextLen, + unsigned int maxOutLen, const unsigned char *cipherText, + unsigned int cipherTextLen, + CK_SALSA20_CHACHA20_POLY1305_MSG_PARAMS *params, + unsigned int paramsLen, const unsigned char *aad, + unsigned int aadLen) +{ + return ChaCha20Poly1305_Decrypt(ctx, plainText, plainTextLen, maxOutLen, + cipherText, cipherTextLen, params->pNonce, params->ulNonceLen, + aad, aadLen, params->pTag); +} + +/* + * Handle AEAD Encryption operation + * + * The setup is similiar to sftk_CryptInit except we set the aeadUpdate + * function instead of the normal update function. This function handles + * both the Encrypt case and the Decrypt case. + */ +static CK_RV +sftk_MessageCryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey, SFTKContextType contextType, + CK_ATTRIBUTE_TYPE operation, PRBool encrypt) +{ + SFTKSession *session; + SFTKObject *key; + SFTKSessionContext *context; + SFTKAttribute *att; + CK_KEY_TYPE key_type; + CK_RV crv = CKR_OK; + + if (!pMechanism) { + return CKR_MECHANISM_PARAM_INVALID; + } + + crv = sftk_MechAllowsOperation(pMechanism->mechanism, + CKA_NSS_MESSAGE | operation); + if (crv != CKR_OK) + return crv; + + session = sftk_SessionFromHandle(hSession); + if (session == NULL) + return CKR_SESSION_HANDLE_INVALID; + + crv = sftk_InitGeneric(session, pMechanism, &context, contextType, &key, + hKey, &key_type, CKO_SECRET_KEY, operation); + if (crv != CKR_OK) { + sftk_FreeSession(session); + return crv; + } + + att = sftk_FindAttribute(key, CKA_VALUE); + if (att == NULL) { + sftk_FreeSession(session); + sftk_FreeContext(context); + return CKR_KEY_HANDLE_INVALID; + } + + context->doPad = PR_FALSE; + context->multi = PR_TRUE; /* All message are 'multi' operations */ + + switch (pMechanism->mechanism) { + case CKM_AES_GCM: + context->cipherInfo = AES_CreateContext( + (unsigned char *)att->attrib.pValue, + NULL, NSS_AES_GCM, encrypt, att->attrib.ulValueLen, + AES_BLOCK_SIZE); + context->aeadUpdate = (SFTKAEADCipher)AES_AEAD; + context->destroy = (SFTKDestroy)AES_DestroyContext; + break; + case CKM_CHACHA20_POLY1305: + context->cipherInfo = ChaCha20Poly1305_CreateContext( + (unsigned char *)att->attrib.pValue, att->attrib.ulValueLen, + 16); + context->aeadUpdate = (SFTKAEADCipher)(encrypt ? sftk_ChaCha20_Poly1305_Message_Encrypt : sftk_ChaCha20_Poly1305_Message_Decrypt); + context->destroy = (SFTKDestroy)ChaCha20Poly1305_DestroyContext; + break; + default: + crv = CKR_MECHANISM_INVALID; + break; + } + if (context->cipherInfo == NULL) { + crv = sftk_MapCryptError(PORT_GetError()); + if (crv == CKR_OK) { + crv = CKR_GENERAL_ERROR; + } + } + if (crv != CKR_OK) { + sftk_FreeContext(context); + sftk_FreeSession(session); + return crv; + } + sftk_SetContextByType(session, contextType, context); + sftk_FreeSession(session); + return CKR_OK; +} + +/* + * Generic handler for the actual encryption/decryption. Each call handles + * The authentication data for the entire block. Multiple calls using + * BeginMessage and NextMessage are not supported and CKF_MESSSAGE_MULTI is + * not set on the supported algorithms + */ +static CK_RV +sftk_CryptMessage(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pAssociatedData, + CK_ULONG ulAssociatedDataLen, CK_BYTE_PTR pIntext, + CK_ULONG ulIntextLen, CK_BYTE_PTR pOuttext, + CK_ULONG_PTR pulOuttextLen, SFTKContextType contextType) +{ + SFTKSessionContext *context; + unsigned int outlen; + unsigned int maxout = *pulOuttextLen; + CK_RV crv; + SECStatus rv; + + CHECK_FORK(); + + /* make sure we're legal */ + crv = sftk_GetContext(hSession, &context, contextType, PR_TRUE, NULL); + if (crv != CKR_OK) + return crv; + + if (!pOuttext) { + *pulOuttextLen = ulIntextLen; + return CKR_OK; + } + rv = (*context->aeadUpdate)(context->cipherInfo, pOuttext, &outlen, + maxout, pIntext, ulIntextLen, + pParameter, ulParameterLen, + pAssociatedData, ulAssociatedDataLen); + + if (rv != SECSuccess) { + if (contextType == SFTK_MESSAGE_ENCRYPT) { + return sftk_MapCryptError(PORT_GetError()); + } else { + return sftk_MapDecryptError(PORT_GetError()); + } + } + *pulOuttextLen = (CK_ULONG)(outlen); + return CKR_OK; +} + +/* + * Common message cleanup rountine + */ +static CK_RV +sftk_MessageCryptFinal(CK_SESSION_HANDLE hSession, + SFTKContextType contextType) +{ + SFTKSession *session; + SFTKSessionContext *context; + CK_RV crv; + + CHECK_FORK(); + + /* make sure we're legal */ + crv = sftk_GetContext(hSession, &context, contextType, PR_TRUE, &session); + if (crv != CKR_OK) + return crv; + sftk_TerminateOp(session, contextType, context); + sftk_FreeSession(session); + return CKR_OK; +} + +/* MessageEncrypt and EncryptMessage functions just use the helper functions + * above */ +CK_RV +NSC_MessageEncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey) +{ + return sftk_MessageCryptInit(hSession, pMechanism, hKey, + SFTK_MESSAGE_ENCRYPT, CKA_ENCRYPT, PR_TRUE); +} + +CK_RV +NSC_EncryptMessage(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pAssociatedData, + CK_ULONG ulAssociatedDataLen, CK_BYTE_PTR pPlaintext, + CK_ULONG ulPlaintextLen, CK_BYTE_PTR pCiphertext, + CK_ULONG_PTR pulCiphertextLen) +{ + return sftk_CryptMessage(hSession, pParameter, ulParameterLen, + pAssociatedData, ulAssociatedDataLen, pPlaintext, + ulPlaintextLen, pCiphertext, pulCiphertextLen, + SFTK_MESSAGE_ENCRYPT); +} + +/* + * We only support the single shot function. The Begin/Next version can be + * dealt with if we need to support S/MIME or something. It would probably + * just buffer rather then returning intermediate results. + */ +CK_RV +NSC_EncryptMessageBegin(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pAssociatedData, + CK_ULONG ulAssociatedDataLen) +{ + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +NSC_EncryptMessageNext(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pPlaintextPart, + CK_ULONG ulPlaintextPartLen, CK_BYTE_PTR pCiphertextPart, + CK_ULONG_PTR pulCiphertextPartLen, CK_FLAGS flags) +{ + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +NSC_MessageEncryptFinal(CK_SESSION_HANDLE hSession) +{ + return sftk_MessageCryptFinal(hSession, SFTK_MESSAGE_ENCRYPT); +} + +/* MessageDecrypt and DecryptMessage functions just use the helper functions + * above */ +CK_RV +NSC_MessageDecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey) +{ + return sftk_MessageCryptInit(hSession, pMechanism, hKey, + SFTK_MESSAGE_DECRYPT, CKA_DECRYPT, PR_FALSE); +} + +CK_RV +NSC_DecryptMessage(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pAssociatedData, + CK_ULONG ulAssociatedDataLen, CK_BYTE_PTR pCiphertext, + CK_ULONG ulCiphertextLen, CK_BYTE_PTR pPlaintext, + CK_ULONG_PTR pulPlaintextLen) +{ + return sftk_CryptMessage(hSession, pParameter, ulParameterLen, + pAssociatedData, ulAssociatedDataLen, pCiphertext, + ulCiphertextLen, pPlaintext, pulPlaintextLen, + SFTK_MESSAGE_DECRYPT); +} + +/* + * We only support the single shot function. The Begin/Next version can be + * dealt with if we need to support S/MIME or something. It would probably + * just buffer rather then returning intermediate results. This is expecially + * true for decrypt, which isn't supposed to return any data unless it's been + * authenticated (which can't happen until the last block is processed). + */ +CK_RV +NSC_DecryptMessageBegin(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pAssociatedData, + CK_ULONG ulAssociatedDataLen) +{ + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +NSC_DecryptMessageNext(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pCiphertextPart, + CK_ULONG ulCiphertextPartLen, CK_BYTE_PTR pPlaintextPart, + CK_ULONG_PTR pulPlaintextPartLen, CK_FLAGS flags) +{ + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +NSC_MessageDecryptFinal(CK_SESSION_HANDLE hSession) +{ + return sftk_MessageCryptFinal(hSession, SFTK_MESSAGE_DECRYPT); +} + +/* + * There are no mechanisms defined to use the MessageSign and MessageVerify + * interfaces yet, so we don't need to implement anything. + */ +CK_RV +NSC_MessageSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey) +{ + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +NSC_SignMessage(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pData, CK_ULONG ulDataLen, + CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) +{ + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +NSC_SignMessageBegin(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen) +{ + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +NSC_SignMessageNext(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen) +{ + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +NSC_MessageSignFinal(CK_SESSION_HANDLE hSession) +{ + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +NSC_MessageVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey) +{ + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +NSC_VerifyMessage(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen) +{ + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +NSC_VerifyMessageBegin(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen) +{ + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +NSC_VerifyMessageNext(CK_SESSION_HANDLE hSession, CK_VOID_PTR pParameter, + CK_ULONG ulParameterLen, CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen) +{ + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +NSC_MessageVerifyFinal(CK_SESSION_HANDLE hSession) +{ + return CKR_FUNCTION_NOT_SUPPORTED; +} |