| /* 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; |
| } |