summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/softoken/sftkmessage.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/softoken/sftkmessage.c')
-rw-r--r--security/nss/lib/softoken/sftkmessage.c377
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;
+}