409 lines
14 KiB
C
409 lines
14 KiB
C
/* 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(void *vctx,
|
|
void *cipherText, unsigned int *cipherTextLen,
|
|
unsigned int maxOutLen, void *plainText,
|
|
unsigned int plainTextLen,
|
|
void *vparams,
|
|
unsigned int paramsLen, void *aad,
|
|
unsigned int aadLen)
|
|
{
|
|
ChaCha20Poly1305Context *ctx = vctx;
|
|
CK_SALSA20_CHACHA20_POLY1305_MSG_PARAMS *params = vparams;
|
|
return ChaCha20Poly1305_Encrypt(ctx, cipherText, cipherTextLen, maxOutLen,
|
|
plainText, plainTextLen, params->pNonce, params->ulNonceLen,
|
|
aad, aadLen, params->pTag);
|
|
}
|
|
|
|
static SECStatus
|
|
sftk_ChaCha20_Poly1305_Message_Decrypt(void *vctx,
|
|
void *plainText, unsigned int *plainTextLen,
|
|
unsigned int maxOutLen, void *cipherText,
|
|
unsigned int cipherTextLen,
|
|
void *vparams,
|
|
unsigned int paramsLen, void *aad,
|
|
unsigned int aadLen)
|
|
{
|
|
ChaCha20Poly1305Context *ctx = vctx;
|
|
CK_SALSA20_CHACHA20_POLY1305_MSG_PARAMS *params = vparams;
|
|
return ChaCha20Poly1305_Decrypt(ctx, plainText, plainTextLen, maxOutLen,
|
|
cipherText, cipherTextLen, params->pNonce, params->ulNonceLen,
|
|
aad, aadLen, params->pTag);
|
|
}
|
|
|
|
void
|
|
sftk_ChaCha20Poly1305_DestroyContext(void *vctx, PRBool freeit)
|
|
{
|
|
ChaCha20Poly1305Context *ctx = vctx;
|
|
ChaCha20Poly1305_DestroyContext(ctx, freeit);
|
|
}
|
|
|
|
static SECStatus
|
|
sftk_AES_AEAD(void *vctx,
|
|
void *plainText, unsigned int *plainTextLen,
|
|
unsigned int maxOutLen, void *cipherText,
|
|
unsigned int cipherTextLen,
|
|
void *params,
|
|
unsigned int paramsLen, void *aad,
|
|
unsigned int aadLen)
|
|
{
|
|
AESContext *ctx = vctx;
|
|
return AES_AEAD(ctx, plainText, plainTextLen, maxOutLen, cipherText, cipherTextLen, params, paramsLen, aad, aadLen);
|
|
}
|
|
|
|
void
|
|
sftk_AES_DestroyContext(void *ctx, PRBool freeit)
|
|
{
|
|
AESContext *actx = ctx;
|
|
AES_DestroyContext(actx, freeit);
|
|
}
|
|
|
|
/*
|
|
* 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 = sftk_AES_AEAD;
|
|
context->destroy = sftk_AES_DestroyContext;
|
|
break;
|
|
case CKM_CHACHA20_POLY1305:
|
|
context->cipherInfo = ChaCha20Poly1305_CreateContext(
|
|
(unsigned char *)att->attrib.pValue, att->attrib.ulValueLen,
|
|
16);
|
|
context->aeadUpdate = (encrypt ? sftk_ChaCha20_Poly1305_Message_Encrypt : sftk_ChaCha20_Poly1305_Message_Decrypt);
|
|
context->destroy = sftk_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;
|
|
}
|