Index: mozilla/security/nss/lib/softoken/pkcs11c.c |
=================================================================== |
--- mozilla/security/nss/lib/softoken/pkcs11c.c (revision 191424) |
+++ mozilla/security/nss/lib/softoken/pkcs11c.c (working copy) |
@@ -1,6931 +0,0 @@ |
-/* 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 |
- * |
- * For more information about PKCS 11 See PKCS 11 Token Inteface Standard. |
- * This implementation has two slots: |
- * slot 1 is our generic crypto support. It does not require login. |
- * It supports Public Key ops, and all they bulk ciphers and hashes. |
- * It can also support Private Key ops for imported Private keys. It does |
- * not have any token storage. |
- * slot 2 is our private key support. It requires a login before use. It |
- * can store Private Keys and Certs as token objects. Currently only private |
- * keys and their associated Certificates are saved on the token. |
- * |
- * In this implementation, session objects are only visible to the session |
- * that created or generated them. |
- */ |
-#include "seccomon.h" |
-#include "secitem.h" |
-#include "secport.h" |
-#include "blapi.h" |
-#include "pkcs11.h" |
-#include "pkcs11i.h" |
-#include "lowkeyi.h" |
-#include "secder.h" |
-#include "secdig.h" |
-#include "lowpbe.h" /* We do PBE below */ |
-#include "pkcs11t.h" |
-#include "secoid.h" |
-#include "alghmac.h" |
-#include "softoken.h" |
-#include "secasn1.h" |
-#include "secerr.h" |
- |
-#include "prprf.h" |
- |
-#define __PASTE(x,y) x##y |
- |
-/* |
- * we renamed all our internal functions, get the correct |
- * definitions for them... |
- */ |
-#undef CK_PKCS11_FUNCTION_INFO |
-#undef CK_NEED_ARG_LIST |
- |
-#define CK_EXTERN extern |
-#define CK_PKCS11_FUNCTION_INFO(func) \ |
- CK_RV __PASTE(NS,func) |
-#define CK_NEED_ARG_LIST 1 |
- |
-#include "pkcs11f.h" |
- |
-typedef struct { |
- uint8 client_version[2]; |
- uint8 random[46]; |
-} SSL3RSAPreMasterSecret; |
- |
-static void sftk_Null(void *data, PRBool freeit) |
-{ |
- return; |
-} |
- |
-#ifdef NSS_ENABLE_ECC |
-#ifdef EC_DEBUG |
-#define SEC_PRINT(str1, str2, num, sitem) \ |
- printf("pkcs11c.c:%s:%s (keytype=%d) [len=%d]\n", \ |
- str1, str2, num, sitem->len); \ |
- for (i = 0; i < sitem->len; i++) { \ |
- printf("%02x:", sitem->data[i]); \ |
- } \ |
- printf("\n") |
-#else |
-#define SEC_PRINT(a, b, c, d) |
-#endif |
-#endif /* NSS_ENABLE_ECC */ |
- |
-/* |
- * free routines.... Free local type allocated data, and convert |
- * other free routines to the destroy signature. |
- */ |
-static void |
-sftk_FreePrivKey(NSSLOWKEYPrivateKey *key, PRBool freeit) |
-{ |
- nsslowkey_DestroyPrivateKey(key); |
-} |
- |
-static void |
-sftk_Space(void *data, PRBool freeit) |
-{ |
- PORT_Free(data); |
-} |
- |
-/* |
- * map all the SEC_ERROR_xxx error codes that may be returned by freebl |
- * functions to CKR_xxx. return CKR_DEVICE_ERROR by default for backward |
- * compatibility. |
- */ |
-static CK_RV |
-sftk_MapCryptError(int error) |
-{ |
- switch (error) { |
- case SEC_ERROR_INVALID_ARGS: |
- case SEC_ERROR_BAD_DATA: /* MP_RANGE gets mapped to this */ |
- return CKR_ARGUMENTS_BAD; |
- case SEC_ERROR_INPUT_LEN: |
- return CKR_DATA_LEN_RANGE; |
- case SEC_ERROR_OUTPUT_LEN: |
- return CKR_BUFFER_TOO_SMALL; |
- case SEC_ERROR_LIBRARY_FAILURE: |
- return CKR_GENERAL_ERROR; |
- case SEC_ERROR_NO_MEMORY: |
- return CKR_HOST_MEMORY; |
- case SEC_ERROR_BAD_SIGNATURE: |
- return CKR_SIGNATURE_INVALID; |
- case SEC_ERROR_INVALID_KEY: |
- return CKR_KEY_SIZE_RANGE; |
- case SEC_ERROR_BAD_KEY: /* an EC public key that fails validation */ |
- return CKR_KEY_SIZE_RANGE; /* the closest error code */ |
- case SEC_ERROR_UNSUPPORTED_EC_POINT_FORM: |
- return CKR_TEMPLATE_INCONSISTENT; |
- /* EC functions set this error if NSS_ENABLE_ECC is not defined */ |
- case SEC_ERROR_UNSUPPORTED_KEYALG: |
- return CKR_MECHANISM_INVALID; |
- case SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE: |
- return CKR_DOMAIN_PARAMS_INVALID; |
- /* key pair generation failed after max number of attempts */ |
- case SEC_ERROR_NEED_RANDOM: |
- return CKR_FUNCTION_FAILED; |
- } |
- return CKR_DEVICE_ERROR; |
-} |
- |
-/* used by Decrypt and UnwrapKey (indirectly) */ |
-static CK_RV |
-sftk_MapDecryptError(int error) |
-{ |
- switch (error) { |
- case SEC_ERROR_BAD_DATA: |
- return CKR_ENCRYPTED_DATA_INVALID; |
- default: |
- return sftk_MapCryptError(error); |
- } |
-} |
- |
-/* |
- * return CKR_SIGNATURE_INVALID instead of CKR_DEVICE_ERROR by default for |
- * backward compatibilty. |
- */ |
-static CK_RV |
-sftk_MapVerifyError(int error) |
-{ |
- CK_RV crv = sftk_MapCryptError(error); |
- if (crv == CKR_DEVICE_ERROR) |
- crv = CKR_SIGNATURE_INVALID; |
- return crv; |
-} |
- |
- |
-/* |
- * turn a CDMF key into a des key. CDMF is an old IBM scheme to export DES by |
- * Deprecating a full des key to 40 bit key strenth. |
- */ |
-static CK_RV |
-sftk_cdmf2des(unsigned char *cdmfkey, unsigned char *deskey) |
-{ |
- unsigned char key1[8] = { 0xc4, 0x08, 0xb0, 0x54, 0x0b, 0xa1, 0xe0, 0xae }; |
- unsigned char key2[8] = { 0xef, 0x2c, 0x04, 0x1c, 0xe6, 0x38, 0x2f, 0xe6 }; |
- unsigned char enc_src[8]; |
- unsigned char enc_dest[8]; |
- unsigned int leng,i; |
- DESContext *descx; |
- SECStatus rv; |
- |
- |
- /* zero the parity bits */ |
- for (i=0; i < 8; i++) { |
- enc_src[i] = cdmfkey[i] & 0xfe; |
- } |
- |
- /* encrypt with key 1 */ |
- descx = DES_CreateContext(key1, NULL, NSS_DES, PR_TRUE); |
- if (descx == NULL) return CKR_HOST_MEMORY; |
- rv = DES_Encrypt(descx, enc_dest, &leng, 8, enc_src, 8); |
- DES_DestroyContext(descx,PR_TRUE); |
- if (rv != SECSuccess) return sftk_MapCryptError(PORT_GetError()); |
- |
- /* xor source with des, zero the parity bits and deprecate the key*/ |
- for (i=0; i < 8; i++) { |
- if (i & 1) { |
- enc_src[i] = (enc_src[i] ^ enc_dest[i]) & 0xfe; |
- } else { |
- enc_src[i] = (enc_src[i] ^ enc_dest[i]) & 0x0e; |
- } |
- } |
- |
- /* encrypt with key 2 */ |
- descx = DES_CreateContext(key2, NULL, NSS_DES, PR_TRUE); |
- if (descx == NULL) return CKR_HOST_MEMORY; |
- rv = DES_Encrypt(descx, deskey, &leng, 8, enc_src, 8); |
- DES_DestroyContext(descx,PR_TRUE); |
- if (rv != SECSuccess) return sftk_MapCryptError(PORT_GetError()); |
- |
- /* set the corret parity on our new des key */ |
- sftk_FormatDESKey(deskey, 8); |
- return CKR_OK; |
-} |
- |
- |
-/* NSC_DestroyObject destroys an object. */ |
-CK_RV |
-NSC_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) |
-{ |
- SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession); |
- SFTKSession *session; |
- SFTKObject *object; |
- SFTKFreeStatus status; |
- |
- CHECK_FORK(); |
- |
- if (slot == NULL) { |
- return CKR_SESSION_HANDLE_INVALID; |
- } |
- /* |
- * This whole block just makes sure we really can destroy the |
- * requested object. |
- */ |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) { |
- return CKR_SESSION_HANDLE_INVALID; |
- } |
- |
- object = sftk_ObjectFromHandle(hObject,session); |
- if (object == NULL) { |
- sftk_FreeSession(session); |
- return CKR_OBJECT_HANDLE_INVALID; |
- } |
- |
- /* don't destroy a private object if we aren't logged in */ |
- if ((!slot->isLoggedIn) && (slot->needLogin) && |
- (sftk_isTrue(object,CKA_PRIVATE))) { |
- sftk_FreeSession(session); |
- sftk_FreeObject(object); |
- return CKR_USER_NOT_LOGGED_IN; |
- } |
- |
- /* don't destroy a token object if we aren't in a rw session */ |
- |
- if (((session->info.flags & CKF_RW_SESSION) == 0) && |
- (sftk_isTrue(object,CKA_TOKEN))) { |
- sftk_FreeSession(session); |
- sftk_FreeObject(object); |
- return CKR_SESSION_READ_ONLY; |
- } |
- |
- sftk_DeleteObject(session,object); |
- |
- sftk_FreeSession(session); |
- |
- /* |
- * get some indication if the object is destroyed. Note: this is not |
- * 100%. Someone may have an object reference outstanding (though that |
- * should not be the case by here. Also note that the object is "half" |
- * destroyed. Our internal representation is destroyed, but it may still |
- * be in the data base. |
- */ |
- status = sftk_FreeObject(object); |
- |
- return (status != SFTK_DestroyFailure) ? CKR_OK : CKR_DEVICE_ERROR; |
-} |
- |
- |
-/* |
- ************** Crypto Functions: Utilities ************************ |
- */ |
- |
- |
-/* |
- * return a context based on the SFTKContext type. |
- */ |
-SFTKSessionContext * |
-sftk_ReturnContextByType(SFTKSession *session, SFTKContextType type) |
-{ |
- switch (type) { |
- case SFTK_ENCRYPT: |
- case SFTK_DECRYPT: |
- return session->enc_context; |
- case SFTK_HASH: |
- return session->hash_context; |
- case SFTK_SIGN: |
- case SFTK_SIGN_RECOVER: |
- case SFTK_VERIFY: |
- case SFTK_VERIFY_RECOVER: |
- return session->hash_context; |
- } |
- return NULL; |
-} |
- |
-/* |
- * change a context based on the SFTKContext type. |
- */ |
-void |
-sftk_SetContextByType(SFTKSession *session, SFTKContextType type, |
- SFTKSessionContext *context) |
-{ |
- switch (type) { |
- case SFTK_ENCRYPT: |
- case SFTK_DECRYPT: |
- session->enc_context = context; |
- break; |
- case SFTK_HASH: |
- session->hash_context = context; |
- break; |
- case SFTK_SIGN: |
- case SFTK_SIGN_RECOVER: |
- case SFTK_VERIFY: |
- case SFTK_VERIFY_RECOVER: |
- session->hash_context = context; |
- break; |
- } |
- return; |
-} |
- |
-/* |
- * code to grab the context. Needed by every C_XXXUpdate, C_XXXFinal, |
- * and C_XXX function. The function takes a session handle, the context type, |
- * and wether or not the session needs to be multipart. It returns the context, |
- * and optionally returns the session pointer (if sessionPtr != NULL) if session |
- * pointer is returned, the caller is responsible for freeing it. |
- */ |
-static CK_RV |
-sftk_GetContext(CK_SESSION_HANDLE handle,SFTKSessionContext **contextPtr, |
- SFTKContextType type, PRBool needMulti, SFTKSession **sessionPtr) |
-{ |
- SFTKSession *session; |
- SFTKSessionContext *context; |
- |
- session = sftk_SessionFromHandle(handle); |
- if (session == NULL) return CKR_SESSION_HANDLE_INVALID; |
- context = sftk_ReturnContextByType(session,type); |
- /* make sure the context is valid */ |
- if((context==NULL)||(context->type!=type)||(needMulti&&!(context->multi))){ |
- sftk_FreeSession(session); |
- return CKR_OPERATION_NOT_INITIALIZED; |
- } |
- *contextPtr = context; |
- if (sessionPtr != NULL) { |
- *sessionPtr = session; |
- } else { |
- sftk_FreeSession(session); |
- } |
- return CKR_OK; |
-} |
- |
-/** Terminate operation (in the PKCS#11 spec sense). |
- * Intuitive name for FreeContext/SetNullContext pair. |
- */ |
-static void |
-sftk_TerminateOp( SFTKSession *session, SFTKContextType ctype, |
- SFTKSessionContext *context ) |
-{ |
- sftk_FreeContext( context ); |
- sftk_SetContextByType( session, ctype, NULL ); |
-} |
- |
-/* |
- ************** Crypto Functions: Encrypt ************************ |
- */ |
- |
-/* |
- * All the NSC_InitXXX functions have a set of common checks and processing they |
- * all need to do at the beginning. This is done here. |
- */ |
-static CK_RV |
-sftk_InitGeneric(SFTKSession *session,SFTKSessionContext **contextPtr, |
- SFTKContextType ctype,SFTKObject **keyPtr, |
- CK_OBJECT_HANDLE hKey, CK_KEY_TYPE *keyTypePtr, |
- CK_OBJECT_CLASS pubKeyType, CK_ATTRIBUTE_TYPE operation) |
-{ |
- SFTKObject *key = NULL; |
- SFTKAttribute *att; |
- SFTKSessionContext *context; |
- |
- /* We can only init if there is not current context active */ |
- if (sftk_ReturnContextByType(session,ctype) != NULL) { |
- return CKR_OPERATION_ACTIVE; |
- } |
- |
- /* find the key */ |
- if (keyPtr) { |
- key = sftk_ObjectFromHandle(hKey,session); |
- if (key == NULL) { |
- return CKR_KEY_HANDLE_INVALID; |
- } |
- |
- /* make sure it's a valid key for this operation */ |
- if (((key->objclass != CKO_SECRET_KEY) && (key->objclass != pubKeyType)) |
- || !sftk_isTrue(key,operation)) { |
- sftk_FreeObject(key); |
- return CKR_KEY_TYPE_INCONSISTENT; |
- } |
- /* get the key type */ |
- att = sftk_FindAttribute(key,CKA_KEY_TYPE); |
- if (att == NULL) { |
- sftk_FreeObject(key); |
- return CKR_KEY_TYPE_INCONSISTENT; |
- } |
- PORT_Assert(att->attrib.ulValueLen == sizeof(CK_KEY_TYPE)); |
- if (att->attrib.ulValueLen != sizeof(CK_KEY_TYPE)) { |
- sftk_FreeAttribute(att); |
- sftk_FreeObject(key); |
- return CKR_ATTRIBUTE_VALUE_INVALID; |
- } |
- PORT_Memcpy(keyTypePtr, att->attrib.pValue, sizeof(CK_KEY_TYPE)); |
- sftk_FreeAttribute(att); |
- *keyPtr = key; |
- } |
- |
- /* allocate the context structure */ |
- context = (SFTKSessionContext *)PORT_Alloc(sizeof(SFTKSessionContext)); |
- if (context == NULL) { |
- if (key) sftk_FreeObject(key); |
- return CKR_HOST_MEMORY; |
- } |
- context->type = ctype; |
- context->multi = PR_TRUE; |
- context->rsa = PR_FALSE; |
- context->cipherInfo = NULL; |
- context->hashInfo = NULL; |
- context->doPad = PR_FALSE; |
- context->padDataLength = 0; |
- context->key = key; |
- context->blockSize = 0; |
- context->maxLen = 0; |
- |
- *contextPtr = context; |
- return CKR_OK; |
-} |
- |
-static int |
-sftk_aes_mode(CK_MECHANISM_TYPE mechanism) |
-{ |
- switch (mechanism) { |
- case CKM_AES_CBC_PAD: |
- case CKM_AES_CBC: |
- return NSS_AES_CBC; |
- case CKM_AES_ECB: |
- return NSS_AES; |
- case CKM_AES_CTS: |
- return NSS_AES_CTS; |
- case CKM_AES_CTR: |
- return NSS_AES_CTR; |
- case CKM_AES_GCM: |
- return NSS_AES_GCM; |
- } |
- return -1; |
-} |
- |
-static SECStatus |
-sftk_EncryptOAEP(SFTKOAEPEncryptInfo *info, unsigned char *output, |
- unsigned int *outputLen, unsigned int maxLen, |
- unsigned char *input, unsigned int inputLen) |
-{ |
- return RSA_EncryptOAEP(info->params, info->key, output, outputLen, |
- maxLen, input, inputLen); |
-} |
- |
-static SECStatus |
-sftk_DecryptOAEP(SFTKOAEPDecryptInfo *info, unsigned char *output, |
- unsigned int *outputLen, unsigned int maxLen, |
- unsigned char *input, unsigned int inputLen) |
-{ |
- return RSA_DecryptOAEP(info->params, info->key, output, outputLen, |
- maxLen, input, inputLen); |
-} |
- |
-/** NSC_CryptInit initializes an encryption/Decryption operation. |
- * |
- * Always called by NSC_EncryptInit, NSC_DecryptInit, NSC_WrapKey,NSC_UnwrapKey. |
- * Called by NSC_SignInit, NSC_VerifyInit (via sftk_InitCBCMac) only for block |
- * ciphers MAC'ing. |
- */ |
-static CK_RV |
-sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, |
- CK_OBJECT_HANDLE hKey, |
- CK_ATTRIBUTE_TYPE mechUsage, CK_ATTRIBUTE_TYPE keyUsage, |
- SFTKContextType contextType, PRBool isEncrypt) |
-{ |
- SFTKSession *session; |
- SFTKObject *key; |
- SFTKSessionContext *context; |
- SFTKAttribute *att; |
- CK_RC2_CBC_PARAMS *rc2_param; |
-#if NSS_SOFTOKEN_DOES_RC5 |
- CK_RC5_CBC_PARAMS *rc5_param; |
- SECItem rc5Key; |
-#endif |
- CK_KEY_TYPE key_type; |
- CK_RV crv = CKR_OK; |
- unsigned effectiveKeyLength; |
- unsigned char newdeskey[24]; |
- PRBool useNewKey=PR_FALSE; |
- int t; |
- |
- crv = sftk_MechAllowsOperation(pMechanism->mechanism, mechUsage ); |
- if (crv != CKR_OK) |
- return crv; |
- |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) return CKR_SESSION_HANDLE_INVALID; |
- |
- crv = sftk_InitGeneric(session,&context,contextType,&key,hKey,&key_type, |
- isEncrypt ?CKO_PUBLIC_KEY:CKO_PRIVATE_KEY, keyUsage); |
- |
- if (crv != CKR_OK) { |
- sftk_FreeSession(session); |
- return crv; |
- } |
- |
- context->doPad = PR_FALSE; |
- switch(pMechanism->mechanism) { |
- case CKM_RSA_PKCS: |
- case CKM_RSA_X_509: |
- if (key_type != CKK_RSA) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- context->multi = PR_FALSE; |
- context->rsa = PR_TRUE; |
- if (isEncrypt) { |
- NSSLOWKEYPublicKey *pubKey = sftk_GetPubKey(key,CKK_RSA,&crv); |
- if (pubKey == NULL) { |
- crv = CKR_KEY_HANDLE_INVALID; |
- break; |
- } |
- context->maxLen = nsslowkey_PublicModulusLen(pubKey); |
- context->cipherInfo = (void *)pubKey; |
- context->update = (SFTKCipher) |
- (pMechanism->mechanism == CKM_RSA_X_509 |
- ? RSA_EncryptRaw : RSA_EncryptBlock); |
- } else { |
- NSSLOWKEYPrivateKey *privKey = sftk_GetPrivKey(key,CKK_RSA,&crv); |
- if (privKey == NULL) { |
- crv = CKR_KEY_HANDLE_INVALID; |
- break; |
- } |
- context->maxLen = nsslowkey_PrivateModulusLen(privKey); |
- context->cipherInfo = (void *)privKey; |
- context->update = (SFTKCipher) |
- (pMechanism->mechanism == CKM_RSA_X_509 |
- ? RSA_DecryptRaw : RSA_DecryptBlock); |
- } |
- context->destroy = sftk_Null; |
- break; |
-/* XXX: Disabled until unit tests land. |
- case CKM_RSA_PKCS_OAEP: |
- if (key_type != CKK_RSA) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- context->multi = PR_FALSE; |
- context->rsa = PR_TRUE; |
- if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) { |
- crv = CKR_MECHANISM_PARAM_INVALID; |
- break; |
- } |
- /\* XXX: Need Parameter validation here *\/ |
- if (isEncrypt) { |
- SFTKOAEPEncryptInfo *info = PORT_New(SFTKOAEPEncryptInfo); |
- if (info == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- info->params = pMechanism->pParameter; |
- info->key = sftk_GetPubKey(key, CKK_RSA, &crv); |
- if (info->key == NULL) { |
- PORT_Free(info); |
- crv = CKR_KEY_HANDLE_INVALID; |
- break; |
- } |
- context->update = (SFTKCipher) sftk_EncryptOAEP; |
- context->maxLen = nsslowkey_PublicModulusLen(info->key); |
- context->cipherInfo = info; |
- } else { |
- SFTKOAEPDecryptInfo *info = PORT_New(SFTKOAEPDecryptInfo); |
- if (info == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- info->params = pMechanism->pParameter; |
- info->key = sftk_GetPrivKey(key, CKK_RSA, &crv); |
- if (info->key == NULL) { |
- PORT_Free(info); |
- crv = CKR_KEY_HANDLE_INVALID; |
- break; |
- } |
- context->update = (SFTKCipher) sftk_DecryptOAEP; |
- context->maxLen = nsslowkey_PrivateModulusLen(info->key); |
- context->cipherInfo = info; |
- } |
- context->destroy = (SFTKDestroy) sftk_Space; |
- break; |
-*/ |
- case CKM_RC2_CBC_PAD: |
- context->doPad = PR_TRUE; |
- /* fall thru */ |
- case CKM_RC2_ECB: |
- case CKM_RC2_CBC: |
- context->blockSize = 8; |
- if (key_type != CKK_RC2) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- att = sftk_FindAttribute(key,CKA_VALUE); |
- if (att == NULL) { |
- crv = CKR_KEY_HANDLE_INVALID; |
- break; |
- } |
- rc2_param = (CK_RC2_CBC_PARAMS *)pMechanism->pParameter; |
- effectiveKeyLength = (rc2_param->ulEffectiveBits+7)/8; |
- context->cipherInfo = |
- RC2_CreateContext((unsigned char*)att->attrib.pValue, |
- att->attrib.ulValueLen, rc2_param->iv, |
- pMechanism->mechanism == CKM_RC2_ECB ? NSS_RC2 : |
- NSS_RC2_CBC,effectiveKeyLength); |
- sftk_FreeAttribute(att); |
- if (context->cipherInfo == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- context->update = (SFTKCipher) (isEncrypt ? RC2_Encrypt : RC2_Decrypt); |
- context->destroy = (SFTKDestroy) RC2_DestroyContext; |
- break; |
-#if NSS_SOFTOKEN_DOES_RC5 |
- case CKM_RC5_CBC_PAD: |
- context->doPad = PR_TRUE; |
- /* fall thru */ |
- case CKM_RC5_ECB: |
- case CKM_RC5_CBC: |
- if (key_type != CKK_RC5) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- att = sftk_FindAttribute(key,CKA_VALUE); |
- if (att == NULL) { |
- crv = CKR_KEY_HANDLE_INVALID; |
- break; |
- } |
- rc5_param = (CK_RC5_CBC_PARAMS *)pMechanism->pParameter; |
- context->blockSize = rc5_param->ulWordsize*2; |
- rc5Key.data = (unsigned char*)att->attrib.pValue; |
- rc5Key.len = att->attrib.ulValueLen; |
- context->cipherInfo = RC5_CreateContext(&rc5Key,rc5_param->ulRounds, |
- rc5_param->ulWordsize,rc5_param->pIv, |
- pMechanism->mechanism == CKM_RC5_ECB ? NSS_RC5 : NSS_RC5_CBC); |
- sftk_FreeAttribute(att); |
- if (context->cipherInfo == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- context->update = (SFTKCipher) (isEncrypt ? RC5_Encrypt : RC5_Decrypt); |
- context->destroy = (SFTKDestroy) RC5_DestroyContext; |
- break; |
-#endif |
- case CKM_RC4: |
- if (key_type != CKK_RC4) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- att = sftk_FindAttribute(key,CKA_VALUE); |
- if (att == NULL) { |
- crv = CKR_KEY_HANDLE_INVALID; |
- break; |
- } |
- context->cipherInfo = |
- RC4_CreateContext((unsigned char*)att->attrib.pValue, |
- att->attrib.ulValueLen); |
- sftk_FreeAttribute(att); |
- if (context->cipherInfo == NULL) { |
- crv = CKR_HOST_MEMORY; /* WRONG !!! */ |
- break; |
- } |
- context->update = (SFTKCipher) (isEncrypt ? RC4_Encrypt : RC4_Decrypt); |
- context->destroy = (SFTKDestroy) RC4_DestroyContext; |
- break; |
- case CKM_CDMF_CBC_PAD: |
- context->doPad = PR_TRUE; |
- /* fall thru */ |
- case CKM_CDMF_ECB: |
- case CKM_CDMF_CBC: |
- if (key_type != CKK_CDMF) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- t = (pMechanism->mechanism == CKM_CDMF_ECB) ? NSS_DES : NSS_DES_CBC; |
- if (crv != CKR_OK) break; |
- goto finish_des; |
- case CKM_DES_ECB: |
- if (key_type != CKK_DES) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- t = NSS_DES; |
- goto finish_des; |
- case CKM_DES_CBC_PAD: |
- context->doPad = PR_TRUE; |
- /* fall thru */ |
- case CKM_DES_CBC: |
- if (key_type != CKK_DES) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- t = NSS_DES_CBC; |
- goto finish_des; |
- case CKM_DES3_ECB: |
- if ((key_type != CKK_DES2) && (key_type != CKK_DES3)) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- t = NSS_DES_EDE3; |
- goto finish_des; |
- case CKM_DES3_CBC_PAD: |
- context->doPad = PR_TRUE; |
- /* fall thru */ |
- case CKM_DES3_CBC: |
- if ((key_type != CKK_DES2) && (key_type != CKK_DES3)) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- t = NSS_DES_EDE3_CBC; |
-finish_des: |
- context->blockSize = 8; |
- att = sftk_FindAttribute(key,CKA_VALUE); |
- if (att == NULL) { |
- crv = CKR_KEY_HANDLE_INVALID; |
- break; |
- } |
- if (key_type == CKK_DES2 && |
- (t == NSS_DES_EDE3_CBC || t == NSS_DES_EDE3)) { |
- /* extend DES2 key to DES3 key. */ |
- memcpy(newdeskey, att->attrib.pValue, 16); |
- memcpy(newdeskey + 16, newdeskey, 8); |
- useNewKey=PR_TRUE; |
- } else if (key_type == CKK_CDMF) { |
- crv = sftk_cdmf2des((unsigned char*)att->attrib.pValue,newdeskey); |
- if (crv != CKR_OK) { |
- sftk_FreeAttribute(att); |
- break; |
- } |
- useNewKey=PR_TRUE; |
- } |
- context->cipherInfo = DES_CreateContext( |
- useNewKey ? newdeskey : (unsigned char*)att->attrib.pValue, |
- (unsigned char*)pMechanism->pParameter,t, isEncrypt); |
- if (useNewKey) |
- memset(newdeskey, 0, sizeof newdeskey); |
- sftk_FreeAttribute(att); |
- if (context->cipherInfo == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- context->update = (SFTKCipher) (isEncrypt ? DES_Encrypt : DES_Decrypt); |
- context->destroy = (SFTKDestroy) DES_DestroyContext; |
- break; |
- case CKM_SEED_CBC_PAD: |
- context->doPad = PR_TRUE; |
- /* fall thru */ |
- case CKM_SEED_CBC: |
- if (!pMechanism->pParameter || |
- pMechanism->ulParameterLen != 16) { |
- crv = CKR_MECHANISM_PARAM_INVALID; |
- break; |
- } |
- /* fall thru */ |
- case CKM_SEED_ECB: |
- context->blockSize = 16; |
- if (key_type != CKK_SEED) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- att = sftk_FindAttribute(key,CKA_VALUE); |
- if (att == NULL) { |
- crv = CKR_KEY_HANDLE_INVALID; |
- break; |
- } |
- context->cipherInfo = SEED_CreateContext( |
- (unsigned char*)att->attrib.pValue, |
- (unsigned char*)pMechanism->pParameter, |
- pMechanism->mechanism == CKM_SEED_ECB ? NSS_SEED : NSS_SEED_CBC, |
- isEncrypt); |
- sftk_FreeAttribute(att); |
- if (context->cipherInfo == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- context->update = (SFTKCipher)(isEncrypt ? SEED_Encrypt : SEED_Decrypt); |
- context->destroy = (SFTKDestroy) SEED_DestroyContext; |
- break; |
- |
- case CKM_CAMELLIA_CBC_PAD: |
- context->doPad = PR_TRUE; |
- /* fall thru */ |
- case CKM_CAMELLIA_CBC: |
- if (!pMechanism->pParameter || |
- pMechanism->ulParameterLen != 16) { |
- crv = CKR_MECHANISM_PARAM_INVALID; |
- break; |
- } |
- /* fall thru */ |
- case CKM_CAMELLIA_ECB: |
- context->blockSize = 16; |
- if (key_type != CKK_CAMELLIA) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- att = sftk_FindAttribute(key,CKA_VALUE); |
- if (att == NULL) { |
- crv = CKR_KEY_HANDLE_INVALID; |
- break; |
- } |
- context->cipherInfo = Camellia_CreateContext( |
- (unsigned char*)att->attrib.pValue, |
- (unsigned char*)pMechanism->pParameter, |
- pMechanism->mechanism == |
- CKM_CAMELLIA_ECB ? NSS_CAMELLIA : NSS_CAMELLIA_CBC, |
- isEncrypt, att->attrib.ulValueLen); |
- sftk_FreeAttribute(att); |
- if (context->cipherInfo == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- context->update = (SFTKCipher) (isEncrypt ? |
- Camellia_Encrypt : Camellia_Decrypt); |
- context->destroy = (SFTKDestroy) Camellia_DestroyContext; |
- break; |
- |
- case CKM_AES_CBC_PAD: |
- context->doPad = PR_TRUE; |
- /* fall thru */ |
- case CKM_AES_ECB: |
- case CKM_AES_CBC: |
- context->blockSize = 16; |
- case CKM_AES_CTS: |
- case CKM_AES_CTR: |
- case CKM_AES_GCM: |
- if (pMechanism->mechanism == CKM_AES_GCM) { |
- context->multi = PR_FALSE; |
- } |
- if (key_type != CKK_AES) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- att = sftk_FindAttribute(key,CKA_VALUE); |
- if (att == NULL) { |
- crv = CKR_KEY_HANDLE_INVALID; |
- break; |
- } |
- context->cipherInfo = AES_CreateContext( |
- (unsigned char*)att->attrib.pValue, |
- (unsigned char*)pMechanism->pParameter, |
- sftk_aes_mode(pMechanism->mechanism), |
- isEncrypt, att->attrib.ulValueLen, 16); |
- sftk_FreeAttribute(att); |
- if (context->cipherInfo == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- context->update = (SFTKCipher) (isEncrypt ? AES_Encrypt : AES_Decrypt); |
- context->destroy = (SFTKDestroy) AES_DestroyContext; |
- break; |
- |
- case CKM_NETSCAPE_AES_KEY_WRAP_PAD: |
- context->doPad = PR_TRUE; |
- /* fall thru */ |
- case CKM_NETSCAPE_AES_KEY_WRAP: |
- context->multi = PR_FALSE; |
- context->blockSize = 8; |
- if (key_type != CKK_AES) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- att = sftk_FindAttribute(key,CKA_VALUE); |
- if (att == NULL) { |
- crv = CKR_KEY_HANDLE_INVALID; |
- break; |
- } |
- context->cipherInfo = AESKeyWrap_CreateContext( |
- (unsigned char*)att->attrib.pValue, |
- (unsigned char*)pMechanism->pParameter, |
- isEncrypt, att->attrib.ulValueLen); |
- sftk_FreeAttribute(att); |
- if (context->cipherInfo == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- context->update = (SFTKCipher) (isEncrypt ? AESKeyWrap_Encrypt |
- : AESKeyWrap_Decrypt); |
- context->destroy = (SFTKDestroy) AESKeyWrap_DestroyContext; |
- break; |
- |
- default: |
- crv = CKR_MECHANISM_INVALID; |
- break; |
- } |
- |
- if (crv != CKR_OK) { |
- sftk_FreeContext(context); |
- sftk_FreeSession(session); |
- return crv; |
- } |
- sftk_SetContextByType(session, contextType, context); |
- sftk_FreeSession(session); |
- return CKR_OK; |
-} |
- |
-/* NSC_EncryptInit initializes an encryption operation. */ |
-CK_RV NSC_EncryptInit(CK_SESSION_HANDLE hSession, |
- CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) |
-{ |
- CHECK_FORK(); |
- return sftk_CryptInit(hSession, pMechanism, hKey, CKA_ENCRYPT, CKA_ENCRYPT, |
- SFTK_ENCRYPT, PR_TRUE); |
-} |
- |
-/* NSC_EncryptUpdate continues a multiple-part encryption operation. */ |
-CK_RV NSC_EncryptUpdate(CK_SESSION_HANDLE hSession, |
- CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, |
- CK_ULONG_PTR pulEncryptedPartLen) |
-{ |
- SFTKSessionContext *context; |
- unsigned int outlen,i; |
- unsigned int padoutlen = 0; |
- unsigned int maxout = *pulEncryptedPartLen; |
- CK_RV crv; |
- SECStatus rv; |
- |
- CHECK_FORK(); |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_TRUE,NULL); |
- if (crv != CKR_OK) return crv; |
- |
- if (!pEncryptedPart) { |
- if (context->doPad) { |
- CK_ULONG totalDataAvailable = ulPartLen + context->padDataLength; |
- CK_ULONG blocksToSend = totalDataAvailable/context->blockSize; |
- |
- *pulEncryptedPartLen = blocksToSend * context->blockSize; |
- return CKR_OK; |
- } |
- *pulEncryptedPartLen = ulPartLen; |
- return CKR_OK; |
- } |
- |
- /* do padding */ |
- if (context->doPad) { |
- /* deal with previous buffered data */ |
- if (context->padDataLength != 0) { |
- /* fill in the padded to a full block size */ |
- for (i=context->padDataLength; |
- (ulPartLen != 0) && i < context->blockSize; i++) { |
- context->padBuf[i] = *pPart++; |
- ulPartLen--; |
- context->padDataLength++; |
- } |
- |
- /* not enough data to encrypt yet? then return */ |
- if (context->padDataLength != context->blockSize) { |
- *pulEncryptedPartLen = 0; |
- return CKR_OK; |
- } |
- /* encrypt the current padded data */ |
- rv = (*context->update)(context->cipherInfo, pEncryptedPart, |
- &padoutlen, context->blockSize, context->padBuf, |
- context->blockSize); |
- if (rv != SECSuccess) { |
- return sftk_MapCryptError(PORT_GetError()); |
- } |
- pEncryptedPart += padoutlen; |
- maxout -= padoutlen; |
- } |
- /* save the residual */ |
- context->padDataLength = ulPartLen % context->blockSize; |
- if (context->padDataLength) { |
- PORT_Memcpy(context->padBuf, |
- &pPart[ulPartLen-context->padDataLength], |
- context->padDataLength); |
- ulPartLen -= context->padDataLength; |
- } |
- /* if we've exhausted our new buffer, we're done */ |
- if (ulPartLen == 0) { |
- *pulEncryptedPartLen = padoutlen; |
- return CKR_OK; |
- } |
- } |
- |
- |
- /* do it: NOTE: this assumes buf size in is >= buf size out! */ |
- rv = (*context->update)(context->cipherInfo,pEncryptedPart, |
- &outlen, maxout, pPart, ulPartLen); |
- *pulEncryptedPartLen = (CK_ULONG) (outlen + padoutlen); |
- return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError()); |
-} |
- |
- |
-/* NSC_EncryptFinal finishes a multiple-part encryption operation. */ |
-CK_RV NSC_EncryptFinal(CK_SESSION_HANDLE hSession, |
- CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen) |
-{ |
- SFTKSession *session; |
- SFTKSessionContext *context; |
- unsigned int outlen,i; |
- unsigned int maxout = *pulLastEncryptedPartLen; |
- CK_RV crv; |
- SECStatus rv = SECSuccess; |
- PRBool contextFinished = PR_TRUE; |
- |
- CHECK_FORK(); |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession,&context,SFTK_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 && context->doPad) { |
- *pulLastEncryptedPartLen = context->blockSize; |
- contextFinished = PR_FALSE; /* still have padding to go */ |
- } |
- goto finish; |
- } |
- |
- /* do padding */ |
- if (context->doPad) { |
- unsigned char padbyte = (unsigned char) |
- (context->blockSize - context->padDataLength); |
- /* fill out rest of pad buffer with pad magic*/ |
- for (i=context->padDataLength; i < context->blockSize; i++) { |
- context->padBuf[i] = padbyte; |
- } |
- rv = (*context->update)(context->cipherInfo,pLastEncryptedPart, |
- &outlen, maxout, context->padBuf, context->blockSize); |
- if (rv == SECSuccess) *pulLastEncryptedPartLen = (CK_ULONG) outlen; |
- } |
- |
-finish: |
- if (contextFinished) |
- sftk_TerminateOp( session, SFTK_ENCRYPT, context ); |
- sftk_FreeSession(session); |
- return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError()); |
-} |
- |
-/* NSC_Encrypt encrypts single-part data. */ |
-CK_RV NSC_Encrypt (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, |
- CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, |
- CK_ULONG_PTR pulEncryptedDataLen) |
-{ |
- SFTKSession *session; |
- SFTKSessionContext *context; |
- unsigned int outlen; |
- unsigned int maxoutlen = *pulEncryptedDataLen; |
- CK_RV crv; |
- CK_RV crv2; |
- SECStatus rv = SECSuccess; |
- SECItem pText; |
- |
- pText.type = siBuffer; |
- pText.data = pData; |
- pText.len = ulDataLen; |
- |
- CHECK_FORK(); |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_FALSE,&session); |
- if (crv != CKR_OK) return crv; |
- |
- if (!pEncryptedData) { |
- *pulEncryptedDataLen = context->rsa ? context->maxLen : |
- ulDataLen + 2 * context->blockSize; |
- goto finish; |
- } |
- |
- if (context->doPad) { |
- if (context->multi) { |
- CK_ULONG finalLen; |
- /* padding is fairly complicated, have the update and final |
- * code deal with it */ |
- sftk_FreeSession(session); |
- crv = NSC_EncryptUpdate(hSession, pData, ulDataLen, pEncryptedData, |
- pulEncryptedDataLen); |
- if (crv != CKR_OK) |
- *pulEncryptedDataLen = 0; |
- maxoutlen -= *pulEncryptedDataLen; |
- pEncryptedData += *pulEncryptedDataLen; |
- finalLen = maxoutlen; |
- crv2 = NSC_EncryptFinal(hSession, pEncryptedData, &finalLen); |
- if (crv2 == CKR_OK) |
- *pulEncryptedDataLen += finalLen; |
- return crv == CKR_OK ? crv2 : crv; |
- } |
- /* doPad without multi means that padding must be done on the first |
- ** and only update. There will be no final. |
- */ |
- PORT_Assert(context->blockSize > 1); |
- if (context->blockSize > 1) { |
- CK_ULONG remainder = ulDataLen % context->blockSize; |
- CK_ULONG padding = context->blockSize - remainder; |
- pText.len += padding; |
- pText.data = PORT_ZAlloc(pText.len); |
- if (pText.data) { |
- memcpy(pText.data, pData, ulDataLen); |
- memset(pText.data + ulDataLen, padding, padding); |
- } else { |
- crv = CKR_HOST_MEMORY; |
- goto fail; |
- } |
- } |
- } |
- |
- /* do it: NOTE: this assumes buf size is big enough. */ |
- rv = (*context->update)(context->cipherInfo, pEncryptedData, |
- &outlen, maxoutlen, pText.data, pText.len); |
- crv = (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError()); |
- *pulEncryptedDataLen = (CK_ULONG) outlen; |
- if (pText.data != pData) |
- PORT_ZFree(pText.data, pText.len); |
-fail: |
- sftk_TerminateOp( session, SFTK_ENCRYPT, context ); |
-finish: |
- sftk_FreeSession(session); |
- |
- return crv; |
-} |
- |
- |
-/* |
- ************** Crypto Functions: Decrypt ************************ |
- */ |
- |
-/* NSC_DecryptInit initializes a decryption operation. */ |
-CK_RV NSC_DecryptInit( CK_SESSION_HANDLE hSession, |
- CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) |
-{ |
- CHECK_FORK(); |
- return sftk_CryptInit(hSession, pMechanism, hKey, CKA_DECRYPT, CKA_DECRYPT, |
- SFTK_DECRYPT, PR_FALSE); |
-} |
- |
-/* NSC_DecryptUpdate continues a multiple-part decryption operation. */ |
-CK_RV NSC_DecryptUpdate(CK_SESSION_HANDLE hSession, |
- CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, |
- CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) |
-{ |
- SFTKSessionContext *context; |
- unsigned int padoutlen = 0; |
- unsigned int outlen; |
- unsigned int maxout = *pulPartLen; |
- CK_RV crv; |
- SECStatus rv; |
- |
- CHECK_FORK(); |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_TRUE,NULL); |
- if (crv != CKR_OK) return crv; |
- |
- /* this can only happen on an NSS programming error */ |
- PORT_Assert((context->padDataLength == 0) |
- || context->padDataLength == context->blockSize); |
- |
- |
- if (!pPart) { |
- if (context->doPad) { |
- /* we can check the data length here because if we are padding, |
- * then we must be using a block cipher. In the non-padding case |
- * the error will be returned by the underlying decryption |
- * function when do do the actual decrypt. We need to do the |
- * check here to avoid returning a negative length to the caller. |
- */ |
- if ((ulEncryptedPartLen == 0) || |
- (ulEncryptedPartLen % context->blockSize) != 0) { |
- return CKR_ENCRYPTED_DATA_LEN_RANGE; |
- } |
- *pulPartLen = |
- ulEncryptedPartLen + context->padDataLength - context->blockSize; |
- return CKR_OK; |
- } |
- /* for stream ciphers there is are no constraints on ulEncryptedPartLen. |
- * for block ciphers, it must be a multiple of blockSize. The error is |
- * detected when this function is called again do decrypt the output. |
- */ |
- *pulPartLen = ulEncryptedPartLen; |
- return CKR_OK; |
- } |
- |
- if (context->doPad) { |
- /* first decrypt our saved buffer */ |
- if (context->padDataLength != 0) { |
- rv = (*context->update)(context->cipherInfo, pPart, &padoutlen, |
- maxout, context->padBuf, context->blockSize); |
- if (rv != SECSuccess) return sftk_MapDecryptError(PORT_GetError()); |
- pPart += padoutlen; |
- maxout -= padoutlen; |
- } |
- /* now save the final block for the next decrypt or the final */ |
- PORT_Memcpy(context->padBuf,&pEncryptedPart[ulEncryptedPartLen - |
- context->blockSize], context->blockSize); |
- context->padDataLength = context->blockSize; |
- ulEncryptedPartLen -= context->padDataLength; |
- } |
- |
- /* do it: NOTE: this assumes buf size in is >= buf size out! */ |
- rv = (*context->update)(context->cipherInfo,pPart, &outlen, |
- maxout, pEncryptedPart, ulEncryptedPartLen); |
- *pulPartLen = (CK_ULONG) (outlen + padoutlen); |
- return (rv == SECSuccess) ? CKR_OK : sftk_MapDecryptError(PORT_GetError()); |
-} |
- |
- |
-/* NSC_DecryptFinal finishes a multiple-part decryption operation. */ |
-CK_RV NSC_DecryptFinal(CK_SESSION_HANDLE hSession, |
- CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen) |
-{ |
- SFTKSession *session; |
- SFTKSessionContext *context; |
- unsigned int outlen; |
- unsigned int maxout = *pulLastPartLen; |
- CK_RV crv; |
- SECStatus rv = SECSuccess; |
- |
- CHECK_FORK(); |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession,&context,SFTK_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 = context->padDataLength; |
- } |
- goto finish; |
- } |
- |
- if (context->doPad) { |
- /* decrypt our saved buffer */ |
- if (context->padDataLength != 0) { |
- /* this assumes that pLastPart is big enough to hold the *whole* |
- * buffer!!! */ |
- rv = (*context->update)(context->cipherInfo, pLastPart, &outlen, |
- maxout, context->padBuf, context->blockSize); |
- if (rv != SECSuccess) { |
- crv = sftk_MapDecryptError(PORT_GetError()); |
- } else { |
- unsigned int padSize = |
- (unsigned int) pLastPart[context->blockSize-1]; |
- if ((padSize > context->blockSize) || (padSize == 0)) { |
- crv = CKR_ENCRYPTED_DATA_INVALID; |
- } else { |
- unsigned int i; |
- unsigned int badPadding = 0; /* used as a boolean */ |
- for (i = 0; i < padSize; i++) { |
- badPadding |= |
- (unsigned int) pLastPart[context->blockSize-1-i] ^ |
- padSize; |
- } |
- if (badPadding) { |
- crv = CKR_ENCRYPTED_DATA_INVALID; |
- } else { |
- *pulLastPartLen = outlen - padSize; |
- } |
- } |
- } |
- } |
- } |
- |
- sftk_TerminateOp( session, SFTK_DECRYPT, context ); |
-finish: |
- sftk_FreeSession(session); |
- return crv; |
-} |
- |
-/* NSC_Decrypt decrypts encrypted data in a single part. */ |
-CK_RV NSC_Decrypt(CK_SESSION_HANDLE hSession, |
- CK_BYTE_PTR pEncryptedData,CK_ULONG ulEncryptedDataLen,CK_BYTE_PTR pData, |
- CK_ULONG_PTR pulDataLen) |
-{ |
- SFTKSession *session; |
- SFTKSessionContext *context; |
- unsigned int outlen; |
- unsigned int maxoutlen = *pulDataLen; |
- CK_RV crv; |
- CK_RV crv2; |
- SECStatus rv = SECSuccess; |
- |
- CHECK_FORK(); |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_FALSE,&session); |
- if (crv != CKR_OK) return crv; |
- |
- if (!pData) { |
- *pulDataLen = ulEncryptedDataLen + context->blockSize; |
- goto finish; |
- } |
- |
- if (context->doPad && context->multi) { |
- CK_ULONG finalLen; |
- /* padding is fairly complicated, have the update and final |
- * code deal with it */ |
- sftk_FreeSession(session); |
- crv = NSC_DecryptUpdate(hSession,pEncryptedData,ulEncryptedDataLen, |
- pData, pulDataLen); |
- if (crv != CKR_OK) |
- *pulDataLen = 0; |
- maxoutlen -= *pulDataLen; |
- pData += *pulDataLen; |
- finalLen = maxoutlen; |
- crv2 = NSC_DecryptFinal(hSession, pData, &finalLen); |
- if (crv2 == CKR_OK) |
- *pulDataLen += finalLen; |
- return crv == CKR_OK ? crv2 : crv; |
- } |
- |
- rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen, |
- pEncryptedData, ulEncryptedDataLen); |
- /* XXX need to do MUCH better error mapping than this. */ |
- crv = (rv == SECSuccess) ? CKR_OK : sftk_MapDecryptError(PORT_GetError()); |
- if (rv == SECSuccess && context->doPad) { |
- unsigned int padding = pData[outlen - 1]; |
- if (padding > context->blockSize || !padding) { |
- crv = CKR_ENCRYPTED_DATA_INVALID; |
- } else { |
- unsigned int i; |
- unsigned int badPadding = 0; /* used as a boolean */ |
- for (i = 0; i < padding; i++) { |
- badPadding |= (unsigned int) pData[outlen - 1 - i] ^ padding; |
- } |
- if (badPadding) { |
- crv = CKR_ENCRYPTED_DATA_INVALID; |
- } else { |
- outlen -= padding; |
- } |
- } |
- } |
- *pulDataLen = (CK_ULONG) outlen; |
- sftk_TerminateOp( session, SFTK_DECRYPT, context ); |
-finish: |
- sftk_FreeSession(session); |
- return crv; |
-} |
- |
- |
- |
-/* |
- ************** Crypto Functions: Digest (HASH) ************************ |
- */ |
- |
-/* NSC_DigestInit initializes a message-digesting operation. */ |
-CK_RV NSC_DigestInit(CK_SESSION_HANDLE hSession, |
- CK_MECHANISM_PTR pMechanism) |
-{ |
- SFTKSession *session; |
- SFTKSessionContext *context; |
- CK_RV crv = CKR_OK; |
- |
- CHECK_FORK(); |
- |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) |
- return CKR_SESSION_HANDLE_INVALID; |
- crv = sftk_InitGeneric(session,&context,SFTK_HASH,NULL,0,NULL, 0, 0); |
- if (crv != CKR_OK) { |
- sftk_FreeSession(session); |
- return crv; |
- } |
- |
- |
-#define INIT_MECH(mech,mmm) \ |
- case mech: { \ |
- mmm ## Context * mmm ## _ctx = mmm ## _NewContext(); \ |
- context->cipherInfo = (void *)mmm ## _ctx; \ |
- context->cipherInfoLen = mmm ## _FlattenSize(mmm ## _ctx); \ |
- context->currentMech = mech; \ |
- context->hashUpdate = (SFTKHash) mmm ## _Update; \ |
- context->end = (SFTKEnd) mmm ## _End; \ |
- context->destroy = (SFTKDestroy) mmm ## _DestroyContext; \ |
- context->maxLen = mmm ## _LENGTH; \ |
- if (mmm ## _ctx) \ |
- mmm ## _Begin(mmm ## _ctx); \ |
- else \ |
- crv = CKR_HOST_MEMORY; \ |
- break; \ |
- } |
- |
- switch(pMechanism->mechanism) { |
- INIT_MECH(CKM_MD2, MD2) |
- INIT_MECH(CKM_MD5, MD5) |
- INIT_MECH(CKM_SHA_1, SHA1) |
- INIT_MECH(CKM_SHA224, SHA224) |
- INIT_MECH(CKM_SHA256, SHA256) |
- INIT_MECH(CKM_SHA384, SHA384) |
- INIT_MECH(CKM_SHA512, SHA512) |
- |
- default: |
- crv = CKR_MECHANISM_INVALID; |
- break; |
- } |
- |
- if (crv != CKR_OK) { |
- sftk_FreeContext(context); |
- sftk_FreeSession(session); |
- return crv; |
- } |
- sftk_SetContextByType(session, SFTK_HASH, context); |
- sftk_FreeSession(session); |
- return CKR_OK; |
-} |
- |
- |
-/* NSC_Digest digests data in a single part. */ |
-CK_RV NSC_Digest(CK_SESSION_HANDLE hSession, |
- CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, |
- CK_ULONG_PTR pulDigestLen) |
-{ |
- SFTKSession *session; |
- SFTKSessionContext *context; |
- unsigned int digestLen; |
- unsigned int maxout = *pulDigestLen; |
- CK_RV crv; |
- |
- CHECK_FORK(); |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession,&context,SFTK_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 */ |
- (*context->end)(context->cipherInfo, pDigest, &digestLen,maxout); |
- *pulDigestLen = digestLen; |
- |
- sftk_TerminateOp( session, SFTK_HASH, context ); |
-finish: |
- sftk_FreeSession(session); |
- return CKR_OK; |
-} |
- |
- |
-/* NSC_DigestUpdate continues a multiple-part message-digesting operation. */ |
-CK_RV NSC_DigestUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart, |
- CK_ULONG ulPartLen) |
-{ |
- SFTKSessionContext *context; |
- CK_RV crv; |
- |
- CHECK_FORK(); |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession,&context,SFTK_HASH,PR_TRUE,NULL); |
- if (crv != CKR_OK) return crv; |
- /* do it: */ |
- (*context->hashUpdate)(context->cipherInfo, pPart, ulPartLen); |
- return CKR_OK; |
-} |
- |
- |
-/* NSC_DigestFinal finishes a multiple-part message-digesting operation. */ |
-CK_RV NSC_DigestFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pDigest, |
- CK_ULONG_PTR pulDigestLen) |
-{ |
- SFTKSession *session; |
- SFTKSessionContext *context; |
- unsigned int maxout = *pulDigestLen; |
- unsigned int digestLen; |
- CK_RV crv; |
- |
- CHECK_FORK(); |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, &session); |
- if (crv != CKR_OK) return crv; |
- |
- if (pDigest != NULL) { |
- (*context->end)(context->cipherInfo, pDigest, &digestLen, maxout); |
- *pulDigestLen = digestLen; |
- sftk_TerminateOp( session, SFTK_HASH, context ); |
- } else { |
- *pulDigestLen = context->maxLen; |
- } |
- |
- sftk_FreeSession(session); |
- return CKR_OK; |
-} |
- |
-/* |
- * these helper functions are used by Generic Macing and Signing functions |
- * that use hashes as part of their operations. |
- */ |
-#define DOSUB(mmm) \ |
-static CK_RV \ |
-sftk_doSub ## mmm(SFTKSessionContext *context) { \ |
- mmm ## Context * mmm ## _ctx = mmm ## _NewContext(); \ |
- context->hashInfo = (void *) mmm ## _ctx; \ |
- context->hashUpdate = (SFTKHash) mmm ## _Update; \ |
- context->end = (SFTKEnd) mmm ## _End; \ |
- context->hashdestroy = (SFTKDestroy) mmm ## _DestroyContext; \ |
- if (!context->hashInfo) { \ |
- return CKR_HOST_MEMORY; \ |
- } \ |
- mmm ## _Begin( mmm ## _ctx ); \ |
- return CKR_OK; \ |
-} |
- |
-DOSUB(MD2) |
-DOSUB(MD5) |
-DOSUB(SHA1) |
-DOSUB(SHA224) |
-DOSUB(SHA256) |
-DOSUB(SHA384) |
-DOSUB(SHA512) |
- |
-static SECStatus |
-sftk_SignCopy( |
- CK_ULONG *copyLen, |
- void *out, unsigned int *outLength, |
- unsigned int maxLength, |
- const unsigned char *hashResult, |
- unsigned int hashResultLength) |
-{ |
- unsigned int toCopy = *copyLen; |
- if (toCopy > maxLength) { |
- toCopy = maxLength; |
- } |
- if (toCopy > hashResultLength) { |
- toCopy = hashResultLength; |
- } |
- memcpy(out, hashResult, toCopy); |
- if (outLength) { |
- *outLength = toCopy; |
- } |
- return SECSuccess; |
-} |
- |
-/* Verify is just a compare for HMAC */ |
-static SECStatus |
-sftk_HMACCmp(CK_ULONG *copyLen,unsigned char *sig,unsigned int sigLen, |
- unsigned char *hash, unsigned int hashLen) |
-{ |
- return (PORT_Memcmp(sig,hash,*copyLen) == 0) ? SECSuccess : SECFailure ; |
-} |
- |
-/* |
- * common HMAC initalization routine |
- */ |
-static CK_RV |
-sftk_doHMACInit(SFTKSessionContext *context,HASH_HashType hash, |
- SFTKObject *key, CK_ULONG mac_size) |
-{ |
- SFTKAttribute *keyval; |
- HMACContext *HMACcontext; |
- CK_ULONG *intpointer; |
- const SECHashObject *hashObj = HASH_GetRawHashObject(hash); |
- PRBool isFIPS = (key->slot->slotID == FIPS_SLOT_ID); |
- |
- /* required by FIPS 198 Section 4 */ |
- if (isFIPS && (mac_size < 4 || mac_size < hashObj->length/2)) { |
- return CKR_BUFFER_TOO_SMALL; |
- } |
- |
- keyval = sftk_FindAttribute(key,CKA_VALUE); |
- if (keyval == NULL) return CKR_KEY_SIZE_RANGE; |
- |
- HMACcontext = HMAC_Create(hashObj, |
- (const unsigned char*)keyval->attrib.pValue, |
- keyval->attrib.ulValueLen, isFIPS); |
- context->hashInfo = HMACcontext; |
- context->multi = PR_TRUE; |
- sftk_FreeAttribute(keyval); |
- if (context->hashInfo == NULL) { |
- if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) { |
- return CKR_KEY_SIZE_RANGE; |
- } |
- return CKR_HOST_MEMORY; |
- } |
- context->hashUpdate = (SFTKHash) HMAC_Update; |
- context->end = (SFTKEnd) HMAC_Finish; |
- |
- context->hashdestroy = (SFTKDestroy) HMAC_Destroy; |
- intpointer = PORT_New(CK_ULONG); |
- if (intpointer == NULL) { |
- return CKR_HOST_MEMORY; |
- } |
- *intpointer = mac_size; |
- context->cipherInfo = intpointer; |
- context->destroy = (SFTKDestroy) sftk_Space; |
- context->update = (SFTKCipher) sftk_SignCopy; |
- context->verify = (SFTKVerify) sftk_HMACCmp; |
- context->maxLen = hashObj->length; |
- HMAC_Begin(HMACcontext); |
- return CKR_OK; |
-} |
- |
-/* |
- * SSL Macing support. SSL Macs are inited, then update with the base |
- * hashing algorithm, then finalized in sign and verify |
- */ |
- |
-/* |
- * FROM SSL: |
- * 60 bytes is 3 times the maximum length MAC size that is supported. |
- * We probably should have one copy of this table. We still need this table |
- * in ssl to 'sign' the handshake hashes. |
- */ |
-static unsigned char ssl_pad_1 [60] = { |
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, |
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, |
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, |
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, |
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, |
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, |
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, |
- 0x36, 0x36, 0x36, 0x36 |
-}; |
-static unsigned char ssl_pad_2 [60] = { |
- 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, |
- 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, |
- 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, |
- 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, |
- 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, |
- 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, |
- 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, |
- 0x5c, 0x5c, 0x5c, 0x5c |
-}; |
- |
-static SECStatus |
-sftk_SSLMACSign(SFTKSSLMACInfo *info,unsigned char *sig,unsigned int *sigLen, |
- unsigned int maxLen,unsigned char *hash, unsigned int hashLen) |
-{ |
- unsigned char tmpBuf[SFTK_MAX_MAC_LENGTH]; |
- unsigned int out; |
- |
- info->begin(info->hashContext); |
- info->update(info->hashContext,info->key,info->keySize); |
- info->update(info->hashContext,ssl_pad_2,info->padSize); |
- info->update(info->hashContext,hash,hashLen); |
- info->end(info->hashContext,tmpBuf,&out,SFTK_MAX_MAC_LENGTH); |
- PORT_Memcpy(sig,tmpBuf,info->macSize); |
- *sigLen = info->macSize; |
- return SECSuccess; |
-} |
- |
-static SECStatus |
-sftk_SSLMACVerify(SFTKSSLMACInfo *info,unsigned char *sig,unsigned int sigLen, |
- unsigned char *hash, unsigned int hashLen) |
-{ |
- unsigned char tmpBuf[SFTK_MAX_MAC_LENGTH]; |
- unsigned int out; |
- |
- info->begin(info->hashContext); |
- info->update(info->hashContext,info->key,info->keySize); |
- info->update(info->hashContext,ssl_pad_2,info->padSize); |
- info->update(info->hashContext,hash,hashLen); |
- info->end(info->hashContext,tmpBuf,&out,SFTK_MAX_MAC_LENGTH); |
- return (PORT_Memcmp(sig,tmpBuf,info->macSize) == 0) ? |
- SECSuccess : SECFailure; |
-} |
- |
-/* |
- * common HMAC initalization routine |
- */ |
-static CK_RV |
-sftk_doSSLMACInit(SFTKSessionContext *context,SECOidTag oid, |
- SFTKObject *key, CK_ULONG mac_size) |
-{ |
- SFTKAttribute *keyval; |
- SFTKBegin begin; |
- int padSize; |
- SFTKSSLMACInfo *sslmacinfo; |
- CK_RV crv = CKR_MECHANISM_INVALID; |
- |
- if (oid == SEC_OID_SHA1) { |
- crv = sftk_doSubSHA1(context); |
- if (crv != CKR_OK) return crv; |
- begin = (SFTKBegin) SHA1_Begin; |
- padSize = 40; |
- } else { |
- crv = sftk_doSubMD5(context); |
- if (crv != CKR_OK) return crv; |
- begin = (SFTKBegin) MD5_Begin; |
- padSize = 48; |
- } |
- context->multi = PR_TRUE; |
- |
- keyval = sftk_FindAttribute(key,CKA_VALUE); |
- if (keyval == NULL) return CKR_KEY_SIZE_RANGE; |
- |
- context->hashUpdate(context->hashInfo,keyval->attrib.pValue, |
- keyval->attrib.ulValueLen); |
- context->hashUpdate(context->hashInfo,ssl_pad_1,padSize); |
- sslmacinfo = (SFTKSSLMACInfo *) PORT_Alloc(sizeof(SFTKSSLMACInfo)); |
- if (sslmacinfo == NULL) { |
- sftk_FreeAttribute(keyval); |
- return CKR_HOST_MEMORY; |
- } |
- sslmacinfo->macSize = mac_size; |
- sslmacinfo->hashContext = context->hashInfo; |
- PORT_Memcpy(sslmacinfo->key,keyval->attrib.pValue, |
- keyval->attrib.ulValueLen); |
- sslmacinfo->keySize = keyval->attrib.ulValueLen; |
- sslmacinfo->begin = begin; |
- sslmacinfo->end = context->end; |
- sslmacinfo->update = context->hashUpdate; |
- sslmacinfo->padSize = padSize; |
- sftk_FreeAttribute(keyval); |
- context->cipherInfo = (void *) sslmacinfo; |
- context->destroy = (SFTKDestroy) sftk_Space; |
- context->update = (SFTKCipher) sftk_SSLMACSign; |
- context->verify = (SFTKVerify) sftk_SSLMACVerify; |
- context->maxLen = mac_size; |
- return CKR_OK; |
-} |
- |
-/* |
- ************** Crypto Functions: Sign ************************ |
- */ |
- |
-/** |
- * Check if We're using CBCMacing and initialize the session context if we are. |
- * @param contextType SFTK_SIGN or SFTK_VERIFY |
- * @param keyUsage check whether key allows this usage |
- */ |
-static CK_RV |
-sftk_InitCBCMac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, |
- CK_OBJECT_HANDLE hKey, CK_ATTRIBUTE_TYPE keyUsage, |
- SFTKContextType contextType) |
- |
-{ |
- CK_MECHANISM cbc_mechanism; |
- CK_ULONG mac_bytes = SFTK_INVALID_MAC_SIZE; |
- CK_RC2_CBC_PARAMS rc2_params; |
-#if NSS_SOFTOKEN_DOES_RC5 |
- CK_RC5_CBC_PARAMS rc5_params; |
- CK_RC5_MAC_GENERAL_PARAMS *rc5_mac; |
-#endif |
- unsigned char ivBlock[SFTK_MAX_BLOCK_SIZE]; |
- SFTKSessionContext *context; |
- CK_RV crv; |
- unsigned int blockSize; |
- |
- switch (pMechanism->mechanism) { |
- case CKM_RC2_MAC_GENERAL: |
- mac_bytes = |
- ((CK_RC2_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength; |
- /* fall through */ |
- case CKM_RC2_MAC: |
- /* this works because ulEffectiveBits is in the same place in both the |
- * CK_RC2_MAC_GENERAL_PARAMS and CK_RC2_CBC_PARAMS */ |
- rc2_params.ulEffectiveBits = ((CK_RC2_MAC_GENERAL_PARAMS *) |
- pMechanism->pParameter)->ulEffectiveBits; |
- PORT_Memset(rc2_params.iv,0,sizeof(rc2_params.iv)); |
- cbc_mechanism.mechanism = CKM_RC2_CBC; |
- cbc_mechanism.pParameter = &rc2_params; |
- cbc_mechanism.ulParameterLen = sizeof(rc2_params); |
- blockSize = 8; |
- break; |
-#if NSS_SOFTOKEN_DOES_RC5 |
- case CKM_RC5_MAC_GENERAL: |
- mac_bytes = |
- ((CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength; |
- /* fall through */ |
- case CKM_RC5_MAC: |
- /* this works because ulEffectiveBits is in the same place in both the |
- * CK_RC5_MAC_GENERAL_PARAMS and CK_RC5_CBC_PARAMS */ |
- rc5_mac = (CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter; |
- rc5_params.ulWordsize = rc5_mac->ulWordsize; |
- rc5_params.ulRounds = rc5_mac->ulRounds; |
- rc5_params.pIv = ivBlock; |
- if( (blockSize = rc5_mac->ulWordsize*2) > SFTK_MAX_BLOCK_SIZE ) |
- return CKR_MECHANISM_PARAM_INVALID; |
- rc5_params.ulIvLen = blockSize; |
- PORT_Memset(ivBlock,0,blockSize); |
- cbc_mechanism.mechanism = CKM_RC5_CBC; |
- cbc_mechanism.pParameter = &rc5_params; |
- cbc_mechanism.ulParameterLen = sizeof(rc5_params); |
- break; |
-#endif |
- /* add cast and idea later */ |
- case CKM_DES_MAC_GENERAL: |
- mac_bytes = *(CK_ULONG *)pMechanism->pParameter; |
- /* fall through */ |
- case CKM_DES_MAC: |
- blockSize = 8; |
- PORT_Memset(ivBlock,0,blockSize); |
- cbc_mechanism.mechanism = CKM_DES_CBC; |
- cbc_mechanism.pParameter = &ivBlock; |
- cbc_mechanism.ulParameterLen = blockSize; |
- break; |
- case CKM_DES3_MAC_GENERAL: |
- mac_bytes = *(CK_ULONG *)pMechanism->pParameter; |
- /* fall through */ |
- case CKM_DES3_MAC: |
- blockSize = 8; |
- PORT_Memset(ivBlock,0,blockSize); |
- cbc_mechanism.mechanism = CKM_DES3_CBC; |
- cbc_mechanism.pParameter = &ivBlock; |
- cbc_mechanism.ulParameterLen = blockSize; |
- break; |
- case CKM_CDMF_MAC_GENERAL: |
- mac_bytes = *(CK_ULONG *)pMechanism->pParameter; |
- /* fall through */ |
- case CKM_CDMF_MAC: |
- blockSize = 8; |
- PORT_Memset(ivBlock,0,blockSize); |
- cbc_mechanism.mechanism = CKM_CDMF_CBC; |
- cbc_mechanism.pParameter = &ivBlock; |
- cbc_mechanism.ulParameterLen = blockSize; |
- break; |
- case CKM_SEED_MAC_GENERAL: |
- mac_bytes = *(CK_ULONG *)pMechanism->pParameter; |
- /* fall through */ |
- case CKM_SEED_MAC: |
- blockSize = 16; |
- PORT_Memset(ivBlock,0,blockSize); |
- cbc_mechanism.mechanism = CKM_SEED_CBC; |
- cbc_mechanism.pParameter = &ivBlock; |
- cbc_mechanism.ulParameterLen = blockSize; |
- break; |
- case CKM_CAMELLIA_MAC_GENERAL: |
- mac_bytes = *(CK_ULONG *)pMechanism->pParameter; |
- /* fall through */ |
- case CKM_CAMELLIA_MAC: |
- blockSize = 16; |
- PORT_Memset(ivBlock,0,blockSize); |
- cbc_mechanism.mechanism = CKM_CAMELLIA_CBC; |
- cbc_mechanism.pParameter = &ivBlock; |
- cbc_mechanism.ulParameterLen = blockSize; |
- break; |
- case CKM_AES_MAC_GENERAL: |
- mac_bytes = *(CK_ULONG *)pMechanism->pParameter; |
- /* fall through */ |
- case CKM_AES_MAC: |
- blockSize = 16; |
- PORT_Memset(ivBlock,0,blockSize); |
- cbc_mechanism.mechanism = CKM_AES_CBC; |
- cbc_mechanism.pParameter = &ivBlock; |
- cbc_mechanism.ulParameterLen = blockSize; |
- break; |
- default: |
- return CKR_FUNCTION_NOT_SUPPORTED; |
- } |
- |
- /* if MAC size is externally supplied, it should be checked. |
- */ |
- if (mac_bytes == SFTK_INVALID_MAC_SIZE) |
- mac_bytes = blockSize >> 1; |
- else { |
- if( mac_bytes > blockSize ) |
- return CKR_MECHANISM_PARAM_INVALID; |
- } |
- |
- crv = sftk_CryptInit(hSession, &cbc_mechanism, hKey, |
- CKA_ENCRYPT, /* CBC mech is able to ENCRYPT, not SIGN/VERIFY */ |
- keyUsage, contextType, PR_TRUE ); |
- if (crv != CKR_OK) return crv; |
- crv = sftk_GetContext(hSession,&context,contextType,PR_TRUE,NULL); |
- |
- /* this shouldn't happen! */ |
- PORT_Assert(crv == CKR_OK); |
- if (crv != CKR_OK) return crv; |
- context->blockSize = blockSize; |
- context->macSize = mac_bytes; |
- return CKR_OK; |
-} |
- |
-/* |
- * encode RSA PKCS #1 Signature data before signing... |
- */ |
-static SECStatus |
-sftk_HashSign(SFTKHashSignInfo *info,unsigned char *sig,unsigned int *sigLen, |
- unsigned int maxLen,unsigned char *hash, unsigned int hashLen) |
-{ |
- return RSA_HashSign(info->hashOid,info->key,sig,sigLen,maxLen, |
- hash,hashLen); |
-} |
- |
-/* XXX Old template; want to expunge it eventually. */ |
-static DERTemplate SECAlgorithmIDTemplate[] = { |
- { DER_SEQUENCE, |
- 0, NULL, sizeof(SECAlgorithmID) }, |
- { DER_OBJECT_ID, |
- offsetof(SECAlgorithmID,algorithm), }, |
- { DER_OPTIONAL | DER_ANY, |
- offsetof(SECAlgorithmID,parameters), }, |
- { 0, } |
-}; |
- |
-/* |
- * XXX OLD Template. Once all uses have been switched over to new one, |
- * remove this. |
- */ |
-static DERTemplate SGNDigestInfoTemplate[] = { |
- { DER_SEQUENCE, |
- 0, NULL, sizeof(SGNDigestInfo) }, |
- { DER_INLINE, |
- offsetof(SGNDigestInfo,digestAlgorithm), |
- SECAlgorithmIDTemplate, }, |
- { DER_OCTET_STRING, |
- offsetof(SGNDigestInfo,digest), }, |
- { 0, } |
-}; |
- |
-SECStatus |
-RSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key, |
- unsigned char *sig, unsigned int *sigLen, unsigned int maxLen, |
- unsigned char *hash, unsigned int hashLen) |
-{ |
- |
- SECStatus rv = SECFailure; |
- SECItem digder; |
- PLArenaPool *arena = NULL; |
- SGNDigestInfo *di = NULL; |
- |
- digder.data = NULL; |
- |
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
- if ( !arena ) { goto loser; } |
- |
- /* Construct digest info */ |
- di = SGN_CreateDigestInfo(hashOid, hash, hashLen); |
- if (!di) { goto loser; } |
- |
- /* Der encode the digest as a DigestInfo */ |
- rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di); |
- if (rv != SECSuccess) { |
- goto loser; |
- } |
- |
- /* |
- ** Encrypt signature after constructing appropriate PKCS#1 signature |
- ** block |
- */ |
- rv = RSA_Sign(key,sig,sigLen,maxLen,digder.data,digder.len); |
- |
- loser: |
- SGN_DestroyDigestInfo(di); |
- if (arena != NULL) { |
- PORT_FreeArena(arena, PR_FALSE); |
- } |
- return rv; |
-} |
- |
-static SECStatus |
-sftk_SignPSS(SFTKHashSignInfo *info,unsigned char *sig,unsigned int *sigLen, |
- unsigned int maxLen,unsigned char *hash, unsigned int hashLen) |
-{ |
- return RSA_SignPSS(info->params,info->key,sig,sigLen,maxLen, |
- hash,hashLen); |
-} |
- |
-static SECStatus |
-nsc_DSA_Verify_Stub(void *ctx, void *sigBuf, unsigned int sigLen, |
- void *dataBuf, unsigned int dataLen) |
-{ |
- SECItem signature, digest; |
- NSSLOWKEYPublicKey *key = (NSSLOWKEYPublicKey *)ctx; |
- |
- signature.data = (unsigned char *)sigBuf; |
- signature.len = sigLen; |
- digest.data = (unsigned char *)dataBuf; |
- digest.len = dataLen; |
- return DSA_VerifyDigest(&(key->u.dsa), &signature, &digest); |
-} |
- |
-static SECStatus |
-nsc_DSA_Sign_Stub(void *ctx, void *sigBuf, |
- unsigned int *sigLen, unsigned int maxSigLen, |
- void *dataBuf, unsigned int dataLen) |
-{ |
- SECItem signature, digest; |
- SECStatus rv; |
- NSSLOWKEYPrivateKey *key = (NSSLOWKEYPrivateKey *)ctx; |
- |
- signature.data = (unsigned char *)sigBuf; |
- signature.len = maxSigLen; |
- digest.data = (unsigned char *)dataBuf; |
- digest.len = dataLen; |
- rv = DSA_SignDigest(&(key->u.dsa), &signature, &digest); |
- if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) { |
- sftk_fatalError = PR_TRUE; |
- } |
- *sigLen = signature.len; |
- return rv; |
-} |
- |
-#ifdef NSS_ENABLE_ECC |
-static SECStatus |
-nsc_ECDSAVerifyStub(void *ctx, void *sigBuf, unsigned int sigLen, |
- void *dataBuf, unsigned int dataLen) |
-{ |
- SECItem signature, digest; |
- NSSLOWKEYPublicKey *key = (NSSLOWKEYPublicKey *)ctx; |
- |
- signature.data = (unsigned char *)sigBuf; |
- signature.len = sigLen; |
- digest.data = (unsigned char *)dataBuf; |
- digest.len = dataLen; |
- return ECDSA_VerifyDigest(&(key->u.ec), &signature, &digest); |
-} |
- |
-static SECStatus |
-nsc_ECDSASignStub(void *ctx, void *sigBuf, |
- unsigned int *sigLen, unsigned int maxSigLen, |
- void *dataBuf, unsigned int dataLen) |
-{ |
- SECItem signature, digest; |
- SECStatus rv; |
- NSSLOWKEYPrivateKey *key = (NSSLOWKEYPrivateKey *)ctx; |
- |
- signature.data = (unsigned char *)sigBuf; |
- signature.len = maxSigLen; |
- digest.data = (unsigned char *)dataBuf; |
- digest.len = dataLen; |
- rv = ECDSA_SignDigest(&(key->u.ec), &signature, &digest); |
- if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) { |
- sftk_fatalError = PR_TRUE; |
- } |
- *sigLen = signature.len; |
- return rv; |
-} |
-#endif /* NSS_ENABLE_ECC */ |
- |
-/* NSC_SignInit setups up the signing operations. There are three basic |
- * types of signing: |
- * (1) the tradition single part, where "Raw RSA" or "Raw DSA" is applied |
- * to data in a single Sign operation (which often looks a lot like an |
- * encrypt, with data coming in and data going out). |
- * (2) Hash based signing, where we continually hash the data, then apply |
- * some sort of signature to the end. |
- * (3) Block Encryption CBC MAC's, where the Data is encrypted with a key, |
- * and only the final block is part of the mac. |
- * |
- * For case number 3, we initialize a context much like the Encryption Context |
- * (in fact we share code). We detect case 3 in C_SignUpdate, C_Sign, and |
- * C_Final by the following method... if it's not multi-part, and it's doesn't |
- * have a hash context, it must be a block Encryption CBC MAC. |
- * |
- * For case number 2, we initialize a hash structure, as well as make it |
- * multi-part. Updates are simple calls to the hash update function. Final |
- * calls the hashend, then passes the result to the 'update' function (which |
- * operates as a final signature function). In some hash based MAC'ing (as |
- * opposed to hash base signatures), the update function is can be simply a |
- * copy (as is the case with HMAC). |
- */ |
-CK_RV NSC_SignInit(CK_SESSION_HANDLE hSession, |
- CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) |
-{ |
- SFTKSession *session; |
- SFTKObject *key; |
- SFTKSessionContext *context; |
- CK_KEY_TYPE key_type; |
- CK_RV crv = CKR_OK; |
- NSSLOWKEYPrivateKey *privKey; |
- SFTKHashSignInfo *info = NULL; |
- |
- CHECK_FORK(); |
- |
- /* Block Cipher MACing Algorithms use a different Context init method..*/ |
- crv = sftk_InitCBCMac(hSession, pMechanism, hKey, CKA_SIGN, SFTK_SIGN); |
- if (crv != CKR_FUNCTION_NOT_SUPPORTED) return crv; |
- |
- /* we're not using a block cipher mac */ |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) return CKR_SESSION_HANDLE_INVALID; |
- crv = sftk_InitGeneric(session,&context,SFTK_SIGN,&key,hKey,&key_type, |
- CKO_PRIVATE_KEY,CKA_SIGN); |
- if (crv != CKR_OK) { |
- sftk_FreeSession(session); |
- return crv; |
- } |
- |
- context->multi = PR_FALSE; |
- |
-#define INIT_RSA_SIGN_MECH(mmm) \ |
- case CKM_ ## mmm ## _RSA_PKCS: \ |
- context->multi = PR_TRUE; \ |
- crv = sftk_doSub ## mmm (context); \ |
- if (crv != CKR_OK) break; \ |
- context->update = (SFTKCipher) sftk_HashSign; \ |
- info = PORT_New(SFTKHashSignInfo); \ |
- if (info == NULL) { crv = CKR_HOST_MEMORY; break; } \ |
- info->hashOid = SEC_OID_ ## mmm ; \ |
- goto finish_rsa; |
- |
- switch(pMechanism->mechanism) { |
- INIT_RSA_SIGN_MECH(MD5) |
- INIT_RSA_SIGN_MECH(MD2) |
- INIT_RSA_SIGN_MECH(SHA1) |
- INIT_RSA_SIGN_MECH(SHA224) |
- INIT_RSA_SIGN_MECH(SHA256) |
- INIT_RSA_SIGN_MECH(SHA384) |
- INIT_RSA_SIGN_MECH(SHA512) |
- |
- case CKM_RSA_PKCS: |
- context->update = (SFTKCipher) RSA_Sign; |
- goto finish_rsa; |
- case CKM_RSA_X_509: |
- context->update = (SFTKCipher) RSA_SignRaw; |
-finish_rsa: |
- if (key_type != CKK_RSA) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- context->rsa = PR_TRUE; |
- privKey = sftk_GetPrivKey(key,CKK_RSA,&crv); |
- if (privKey == NULL) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- /* OK, info is allocated only if we're doing hash and sign mechanism. |
- * It's necessary to be able to set the correct OID in the final |
- * signature. |
- */ |
- if (info) { |
- info->key = privKey; |
- context->cipherInfo = info; |
- context->destroy = (SFTKDestroy)sftk_Space; |
- } else { |
- context->cipherInfo = privKey; |
- context->destroy = (SFTKDestroy)sftk_Null; |
- } |
- context->maxLen = nsslowkey_PrivateModulusLen(privKey); |
- break; |
- case CKM_RSA_PKCS_PSS: |
- if (key_type != CKK_RSA) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- context->rsa = PR_TRUE; |
- if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) { |
- crv = CKR_MECHANISM_PARAM_INVALID; |
- break; |
- } |
- info = PORT_New(SFTKHashSignInfo); |
- if (info == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- info->params = pMechanism->pParameter; |
- info->key = sftk_GetPrivKey(key,CKK_RSA,&crv); |
- if (info->key == NULL) { |
- PORT_Free(info); |
- break; |
- } |
- context->cipherInfo = info; |
- context->destroy = (SFTKDestroy) sftk_Space; |
- context->update = (SFTKCipher) sftk_SignPSS; |
- context->maxLen = nsslowkey_PrivateModulusLen(info->key); |
- break; |
- |
- case CKM_DSA_SHA1: |
- context->multi = PR_TRUE; |
- crv = sftk_doSubSHA1(context); |
- if (crv != CKR_OK) break; |
- /* fall through */ |
- case CKM_DSA: |
- if (key_type != CKK_DSA) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- privKey = sftk_GetPrivKey(key,CKK_DSA,&crv); |
- if (privKey == NULL) { |
- break; |
- } |
- context->cipherInfo = privKey; |
- context->update = (SFTKCipher) nsc_DSA_Sign_Stub; |
- context->destroy = (privKey == key->objectInfo) ? |
- (SFTKDestroy) sftk_Null:(SFTKDestroy)sftk_FreePrivKey; |
- context->maxLen = DSA_MAX_SIGNATURE_LEN; |
- |
- break; |
- |
-#ifdef NSS_ENABLE_ECC |
- case CKM_ECDSA_SHA1: |
- context->multi = PR_TRUE; |
- crv = sftk_doSubSHA1(context); |
- if (crv != CKR_OK) break; |
- /* fall through */ |
- case CKM_ECDSA: |
- if (key_type != CKK_EC) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- privKey = sftk_GetPrivKey(key,CKK_EC,&crv); |
- if (privKey == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- context->cipherInfo = privKey; |
- context->update = (SFTKCipher) nsc_ECDSASignStub; |
- context->destroy = (privKey == key->objectInfo) ? |
- (SFTKDestroy) sftk_Null:(SFTKDestroy)sftk_FreePrivKey; |
- context->maxLen = MAX_ECKEY_LEN * 2; |
- |
- break; |
-#endif /* NSS_ENABLE_ECC */ |
- |
-#define INIT_HMAC_MECH(mmm) \ |
- case CKM_ ## mmm ## _HMAC_GENERAL: \ |
- crv = sftk_doHMACInit(context, HASH_Alg ## mmm ,key, \ |
- *(CK_ULONG *)pMechanism->pParameter); \ |
- break; \ |
- case CKM_ ## mmm ## _HMAC: \ |
- crv = sftk_doHMACInit(context, HASH_Alg ## mmm ,key, mmm ## _LENGTH); \ |
- break; |
- |
- INIT_HMAC_MECH(MD2) |
- INIT_HMAC_MECH(MD5) |
- INIT_HMAC_MECH(SHA224) |
- INIT_HMAC_MECH(SHA256) |
- INIT_HMAC_MECH(SHA384) |
- INIT_HMAC_MECH(SHA512) |
- |
- case CKM_SHA_1_HMAC_GENERAL: |
- crv = sftk_doHMACInit(context,HASH_AlgSHA1,key, |
- *(CK_ULONG *)pMechanism->pParameter); |
- break; |
- case CKM_SHA_1_HMAC: |
- crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,SHA1_LENGTH); |
- break; |
- |
- case CKM_SSL3_MD5_MAC: |
- crv = sftk_doSSLMACInit(context,SEC_OID_MD5,key, |
- *(CK_ULONG *)pMechanism->pParameter); |
- break; |
- case CKM_SSL3_SHA1_MAC: |
- crv = sftk_doSSLMACInit(context,SEC_OID_SHA1,key, |
- *(CK_ULONG *)pMechanism->pParameter); |
- break; |
- case CKM_TLS_PRF_GENERAL: |
- crv = sftk_TLSPRFInit(context, key, key_type); |
- break; |
- |
- case CKM_NSS_HMAC_CONSTANT_TIME: { |
- sftk_MACConstantTimeCtx *ctx = |
- sftk_HMACConstantTime_New(pMechanism,key); |
- CK_ULONG *intpointer; |
- |
- if (ctx == NULL) { |
- crv = CKR_ARGUMENTS_BAD; |
- break; |
- } |
- intpointer = PORT_New(CK_ULONG); |
- if (intpointer == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- *intpointer = ctx->hash->length; |
- |
- context->cipherInfo = intpointer; |
- context->hashInfo = ctx; |
- context->currentMech = pMechanism->mechanism; |
- context->hashUpdate = sftk_HMACConstantTime_Update; |
- context->hashdestroy = sftk_MACConstantTime_DestroyContext; |
- context->end = sftk_MACConstantTime_EndHash; |
- context->update = sftk_SignCopy; |
- context->destroy = sftk_Space; |
- context->maxLen = 64; |
- context->multi = PR_TRUE; |
- break; |
- } |
- |
- case CKM_NSS_SSL3_MAC_CONSTANT_TIME: { |
- sftk_MACConstantTimeCtx *ctx = |
- sftk_SSLv3MACConstantTime_New(pMechanism,key); |
- CK_ULONG *intpointer; |
- |
- if (ctx == NULL) { |
- crv = CKR_ARGUMENTS_BAD; |
- break; |
- } |
- intpointer = PORT_New(CK_ULONG); |
- if (intpointer == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- *intpointer = ctx->hash->length; |
- |
- context->cipherInfo = intpointer; |
- context->hashInfo = ctx; |
- context->currentMech = pMechanism->mechanism; |
- context->hashUpdate = sftk_SSLv3MACConstantTime_Update; |
- context->hashdestroy = sftk_MACConstantTime_DestroyContext; |
- context->end = sftk_MACConstantTime_EndHash; |
- context->update = sftk_SignCopy; |
- context->destroy = sftk_Space; |
- context->maxLen = 64; |
- context->multi = PR_TRUE; |
- break; |
- } |
- |
- default: |
- crv = CKR_MECHANISM_INVALID; |
- break; |
- } |
- |
- if (crv != CKR_OK) { |
- if (info) PORT_Free(info); |
- sftk_FreeContext(context); |
- sftk_FreeSession(session); |
- return crv; |
- } |
- sftk_SetContextByType(session, SFTK_SIGN, context); |
- sftk_FreeSession(session); |
- return CKR_OK; |
-} |
- |
-/** MAC one block of data by block cipher |
- */ |
-static CK_RV |
-sftk_MACBlock( SFTKSessionContext *ctx, void *blk ) |
-{ |
- unsigned int outlen; |
- return ( SECSuccess == (ctx->update)( ctx->cipherInfo, ctx->macBuf, &outlen, |
- SFTK_MAX_BLOCK_SIZE, blk, ctx->blockSize )) |
- ? CKR_OK : sftk_MapCryptError(PORT_GetError()); |
-} |
- |
-/** MAC last (incomplete) block of data by block cipher |
- * |
- * Call once, then terminate MACing operation. |
- */ |
-static CK_RV |
-sftk_MACFinal( SFTKSessionContext *ctx ) |
-{ |
- unsigned int padLen = ctx->padDataLength; |
- /* pad and proceed the residual */ |
- if( padLen ) { |
- /* shd clr ctx->padLen to make sftk_MACFinal idempotent */ |
- PORT_Memset( ctx->padBuf + padLen, 0, ctx->blockSize - padLen ); |
- return sftk_MACBlock( ctx, ctx->padBuf ); |
- } else |
- return CKR_OK; |
-} |
- |
-/** The common implementation for {Sign,Verify}Update. (S/V only vary in their |
- * setup and final operations). |
- * |
- * A call which results in an error terminates the operation [PKCS#11,v2.11] |
- */ |
-static CK_RV |
-sftk_MACUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart, |
- CK_ULONG ulPartLen,SFTKContextType type) |
-{ |
- SFTKSession *session; |
- SFTKSessionContext *context; |
- CK_RV crv; |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession,&context,type, PR_TRUE, &session ); |
- if (crv != CKR_OK) return crv; |
- |
- if (context->hashInfo) { |
- (*context->hashUpdate)(context->hashInfo, pPart, ulPartLen); |
- } else { |
- /* must be block cipher MACing */ |
- |
- unsigned int blkSize = context->blockSize; |
- unsigned char *residual = /* free room in context->padBuf */ |
- context->padBuf + context->padDataLength; |
- unsigned int minInput = /* min input for MACing at least one block */ |
- blkSize - context->padDataLength; |
- |
- /* not enough data even for one block */ |
- if( ulPartLen < minInput ) { |
- PORT_Memcpy( residual, pPart, ulPartLen ); |
- context->padDataLength += ulPartLen; |
- goto cleanup; |
- } |
- /* MACing residual */ |
- if( context->padDataLength ) { |
- PORT_Memcpy( residual, pPart, minInput ); |
- ulPartLen -= minInput; |
- pPart += minInput; |
- if( CKR_OK != (crv = sftk_MACBlock( context, context->padBuf )) ) |
- goto terminate; |
- } |
- /* MACing full blocks */ |
- while( ulPartLen >= blkSize ) |
- { |
- if( CKR_OK != (crv = sftk_MACBlock( context, pPart )) ) |
- goto terminate; |
- ulPartLen -= blkSize; |
- pPart += blkSize; |
- } |
- /* save the residual */ |
- if( (context->padDataLength = ulPartLen) ) |
- PORT_Memcpy( context->padBuf, pPart, ulPartLen ); |
- } /* blk cipher MACing */ |
- |
- goto cleanup; |
- |
-terminate: |
- sftk_TerminateOp( session, type, context ); |
-cleanup: |
- sftk_FreeSession(session); |
- return crv; |
-} |
- |
-/* NSC_SignUpdate continues a multiple-part signature operation, |
- * where the signature is (will be) an appendix to the data, |
- * and plaintext cannot be recovered from the signature |
- * |
- * A call which results in an error terminates the operation [PKCS#11,v2.11] |
- */ |
-CK_RV NSC_SignUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart, |
- CK_ULONG ulPartLen) |
-{ |
- CHECK_FORK(); |
- return sftk_MACUpdate(hSession, pPart, ulPartLen, SFTK_SIGN); |
-} |
- |
- |
-/* NSC_SignFinal finishes a multiple-part signature operation, |
- * returning the signature. */ |
-CK_RV NSC_SignFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pSignature, |
- CK_ULONG_PTR pulSignatureLen) |
-{ |
- SFTKSession *session; |
- SFTKSessionContext *context; |
- unsigned int outlen; |
- unsigned int maxoutlen = *pulSignatureLen; |
- CK_RV crv; |
- |
- CHECK_FORK(); |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession,&context,SFTK_SIGN,PR_TRUE,&session); |
- if (crv != CKR_OK) return crv; |
- |
- if (context->hashInfo) { |
- unsigned int digestLen; |
- unsigned char tmpbuf[SFTK_MAX_MAC_LENGTH]; |
- |
- if( !pSignature ) { |
- outlen = context->maxLen; goto finish; |
- } |
- (*context->end)(context->hashInfo, tmpbuf, &digestLen, sizeof(tmpbuf)); |
- if( SECSuccess != (context->update)(context->cipherInfo, pSignature, |
- &outlen, maxoutlen, tmpbuf, digestLen)) |
- crv = sftk_MapCryptError(PORT_GetError()); |
- /* CKR_BUFFER_TOO_SMALL here isn't continuable, let operation terminate. |
- * Keeping "too small" CK_RV intact is a standard violation, but allows |
- * application read EXACT signature length */ |
- } else { |
- /* must be block cipher MACing */ |
- outlen = context->macSize; |
- /* null or "too small" buf doesn't terminate operation [PKCS#11,v2.11]*/ |
- if( !pSignature || maxoutlen < outlen ) { |
- if( pSignature ) crv = CKR_BUFFER_TOO_SMALL; |
- goto finish; |
- } |
- if( CKR_OK == (crv = sftk_MACFinal( context )) ) |
- PORT_Memcpy(pSignature, context->macBuf, outlen ); |
- } |
- |
- sftk_TerminateOp( session, SFTK_SIGN, context ); |
-finish: |
- *pulSignatureLen = outlen; |
- sftk_FreeSession(session); |
- return crv; |
-} |
- |
-/* NSC_Sign signs (encrypts with private key) data in a single part, |
- * where the signature is (will be) an appendix to the data, |
- * and plaintext cannot be recovered from the signature */ |
-CK_RV NSC_Sign(CK_SESSION_HANDLE hSession, |
- CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSignature, |
- CK_ULONG_PTR pulSignatureLen) |
-{ |
- SFTKSession *session; |
- SFTKSessionContext *context; |
- CK_RV crv; |
- |
- CHECK_FORK(); |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession,&context,SFTK_SIGN,PR_FALSE,&session); |
- if (crv != CKR_OK) return crv; |
- |
- if (!pSignature) { |
- /* see also how C_SignUpdate implements this */ |
- *pulSignatureLen = (!context->multi || context->hashInfo) |
- ? context->maxLen |
- : context->macSize; /* must be block cipher MACing */ |
- goto finish; |
- } |
- |
- /* multi part Signing are completely implemented by SignUpdate and |
- * sign Final */ |
- if (context->multi) { |
- /* SignFinal can't follow failed SignUpdate */ |
- if( CKR_OK == (crv = NSC_SignUpdate(hSession,pData,ulDataLen) )) |
- crv = NSC_SignFinal(hSession, pSignature, pulSignatureLen); |
- } else { |
- /* single-part PKC signature (e.g. CKM_ECDSA) */ |
- unsigned int outlen; |
- unsigned int maxoutlen = *pulSignatureLen; |
- if( SECSuccess != (*context->update)(context->cipherInfo, pSignature, |
- &outlen, maxoutlen, pData, ulDataLen)) |
- crv = sftk_MapCryptError(PORT_GetError()); |
- *pulSignatureLen = (CK_ULONG) outlen; |
- /* "too small" here is certainly continuable */ |
- if( crv != CKR_BUFFER_TOO_SMALL ) |
- sftk_TerminateOp(session, SFTK_SIGN, context); |
- } /* single-part */ |
- |
-finish: |
- sftk_FreeSession(session); |
- return crv; |
-} |
- |
- |
-/* |
- ************** Crypto Functions: Sign Recover ************************ |
- */ |
-/* NSC_SignRecoverInit initializes a signature operation, |
- * where the (digest) data can be recovered from the signature. |
- * E.g. encryption with the user's private key */ |
-CK_RV NSC_SignRecoverInit(CK_SESSION_HANDLE hSession, |
- CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey) |
-{ |
- CHECK_FORK(); |
- |
- switch (pMechanism->mechanism) { |
- case CKM_RSA_PKCS: |
- case CKM_RSA_X_509: |
- return NSC_SignInit(hSession,pMechanism,hKey); |
- default: |
- break; |
- } |
- return CKR_MECHANISM_INVALID; |
-} |
- |
- |
-/* NSC_SignRecover signs data in a single operation |
- * where the (digest) data can be recovered from the signature. |
- * E.g. encryption with the user's private key */ |
-CK_RV NSC_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, |
- CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) |
-{ |
- CHECK_FORK(); |
- |
- return NSC_Sign(hSession,pData,ulDataLen,pSignature,pulSignatureLen); |
-} |
- |
-/* |
- ************** Crypto Functions: verify ************************ |
- */ |
- |
-/* Handle RSA Signature formatting */ |
-static SECStatus |
-sftk_hashCheckSign(SFTKHashVerifyInfo *info, unsigned char *sig, |
- unsigned int sigLen, unsigned char *digest, unsigned int digestLen) |
-{ |
- return RSA_HashCheckSign(info->hashOid, info->key, sig, sigLen, |
- digest, digestLen); |
-} |
- |
-SECStatus |
-RSA_HashCheckSign(SECOidTag hashOid, NSSLOWKEYPublicKey *key, |
- unsigned char *sig, unsigned int sigLen, |
- unsigned char *digest, unsigned int digestLen) |
-{ |
- |
- SECItem it; |
- SGNDigestInfo *di = NULL; |
- SECStatus rv = SECSuccess; |
- |
- it.data = NULL; |
- |
- if (key == NULL) goto loser; |
- |
- it.len = nsslowkey_PublicModulusLen(key); |
- if (!it.len) goto loser; |
- |
- it.data = (unsigned char *) PORT_Alloc(it.len); |
- if (it.data == NULL) goto loser; |
- |
- /* decrypt the block */ |
- rv = RSA_CheckSignRecover(key, it.data, &it.len, it.len, sig, sigLen); |
- if (rv != SECSuccess) goto loser; |
- |
- di = SGN_DecodeDigestInfo(&it); |
- if (di == NULL) goto loser; |
- if (di->digest.len != digestLen) goto loser; |
- |
- /* make sure the tag is OK */ |
- if (SECOID_GetAlgorithmTag(&di->digestAlgorithm) != hashOid) { |
- goto loser; |
- } |
- /* make sure the "parameters" are not too bogus. */ |
- if (di->digestAlgorithm.parameters.len > 2) { |
- goto loser; |
- } |
- /* Now check the signature */ |
- if (PORT_Memcmp(digest, di->digest.data, di->digest.len) == 0) { |
- goto done; |
- } |
- |
- loser: |
- PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
- rv = SECFailure; |
- |
- done: |
- if (it.data != NULL) PORT_Free(it.data); |
- if (di != NULL) SGN_DestroyDigestInfo(di); |
- |
- return rv; |
-} |
- |
-static SECStatus |
-sftk_CheckSignPSS(SFTKHashVerifyInfo *info, unsigned char *sig, |
- unsigned int sigLen, unsigned char *digest, unsigned int digestLen) |
-{ |
- return RSA_CheckSignPSS(info->params, info->key, sig, sigLen, |
- digest, digestLen); |
-} |
- |
-/* NSC_VerifyInit initializes a verification operation, |
- * where the signature is an appendix to the data, |
- * and plaintext cannot be recovered from the signature (e.g. DSA) */ |
-CK_RV NSC_VerifyInit(CK_SESSION_HANDLE hSession, |
- CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey) |
-{ |
- SFTKSession *session; |
- SFTKObject *key; |
- SFTKSessionContext *context; |
- CK_KEY_TYPE key_type; |
- CK_RV crv = CKR_OK; |
- NSSLOWKEYPublicKey *pubKey; |
- SFTKHashVerifyInfo *info = NULL; |
- |
- CHECK_FORK(); |
- |
- /* Block Cipher MACing Algorithms use a different Context init method..*/ |
- crv = sftk_InitCBCMac(hSession, pMechanism, hKey, CKA_VERIFY, SFTK_VERIFY); |
- if (crv != CKR_FUNCTION_NOT_SUPPORTED) return crv; |
- |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) return CKR_SESSION_HANDLE_INVALID; |
- crv = sftk_InitGeneric(session,&context,SFTK_VERIFY,&key,hKey,&key_type, |
- CKO_PUBLIC_KEY,CKA_VERIFY); |
- if (crv != CKR_OK) { |
- sftk_FreeSession(session); |
- return crv; |
- } |
- |
- context->multi = PR_FALSE; |
- |
-#define INIT_RSA_VFY_MECH(mmm) \ |
- case CKM_ ## mmm ## _RSA_PKCS: \ |
- context->multi = PR_TRUE; \ |
- crv = sftk_doSub ## mmm (context); \ |
- if (crv != CKR_OK) break; \ |
- context->verify = (SFTKVerify) sftk_hashCheckSign; \ |
- info = PORT_New(SFTKHashVerifyInfo); \ |
- if (info == NULL) { crv = CKR_HOST_MEMORY; break; } \ |
- info->hashOid = SEC_OID_ ## mmm ; \ |
- goto finish_rsa; |
- |
- switch(pMechanism->mechanism) { |
- INIT_RSA_VFY_MECH(MD5) |
- INIT_RSA_VFY_MECH(MD2) |
- INIT_RSA_VFY_MECH(SHA1) |
- INIT_RSA_VFY_MECH(SHA224) |
- INIT_RSA_VFY_MECH(SHA256) |
- INIT_RSA_VFY_MECH(SHA384) |
- INIT_RSA_VFY_MECH(SHA512) |
- |
- case CKM_RSA_PKCS: |
- context->verify = (SFTKVerify) RSA_CheckSign; |
- goto finish_rsa; |
- case CKM_RSA_X_509: |
- context->verify = (SFTKVerify) RSA_CheckSignRaw; |
-finish_rsa: |
- if (key_type != CKK_RSA) { |
- if (info) PORT_Free(info); |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- context->rsa = PR_TRUE; |
- pubKey = sftk_GetPubKey(key,CKK_RSA,&crv); |
- if (pubKey == NULL) { |
- if (info) PORT_Free(info); |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- if (info) { |
- info->key = pubKey; |
- context->cipherInfo = info; |
- context->destroy = sftk_Space; |
- } else { |
- context->cipherInfo = pubKey; |
- context->destroy = sftk_Null; |
- } |
- break; |
- case CKM_RSA_PKCS_PSS: |
- if (key_type != CKK_RSA) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- context->rsa = PR_TRUE; |
- if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) { |
- crv = CKR_MECHANISM_PARAM_INVALID; |
- break; |
- } |
- info = PORT_New(SFTKHashVerifyInfo); |
- if (info == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- info->params = pMechanism->pParameter; |
- info->key = sftk_GetPubKey(key,CKK_RSA,&crv); |
- if (info->key == NULL) { |
- PORT_Free(info); |
- break; |
- } |
- context->cipherInfo = info; |
- context->destroy = (SFTKDestroy) sftk_Space; |
- context->verify = (SFTKVerify) sftk_CheckSignPSS; |
- break; |
- case CKM_DSA_SHA1: |
- context->multi = PR_TRUE; |
- crv = sftk_doSubSHA1(context); |
- if (crv != CKR_OK) break; |
- /* fall through */ |
- case CKM_DSA: |
- if (key_type != CKK_DSA) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- pubKey = sftk_GetPubKey(key,CKK_DSA,&crv); |
- if (pubKey == NULL) { |
- break; |
- } |
- context->cipherInfo = pubKey; |
- context->verify = (SFTKVerify) nsc_DSA_Verify_Stub; |
- context->destroy = sftk_Null; |
- break; |
-#ifdef NSS_ENABLE_ECC |
- case CKM_ECDSA_SHA1: |
- context->multi = PR_TRUE; |
- crv = sftk_doSubSHA1(context); |
- if (crv != CKR_OK) break; |
- /* fall through */ |
- case CKM_ECDSA: |
- if (key_type != CKK_EC) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- pubKey = sftk_GetPubKey(key,CKK_EC,&crv); |
- if (pubKey == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- context->cipherInfo = pubKey; |
- context->verify = (SFTKVerify) nsc_ECDSAVerifyStub; |
- context->destroy = sftk_Null; |
- break; |
-#endif /* NSS_ENABLE_ECC */ |
- |
- INIT_HMAC_MECH(MD2) |
- INIT_HMAC_MECH(MD5) |
- INIT_HMAC_MECH(SHA224) |
- INIT_HMAC_MECH(SHA256) |
- INIT_HMAC_MECH(SHA384) |
- INIT_HMAC_MECH(SHA512) |
- |
- case CKM_SHA_1_HMAC_GENERAL: |
- crv = sftk_doHMACInit(context,HASH_AlgSHA1,key, |
- *(CK_ULONG *)pMechanism->pParameter); |
- break; |
- case CKM_SHA_1_HMAC: |
- crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,SHA1_LENGTH); |
- break; |
- |
- case CKM_SSL3_MD5_MAC: |
- crv = sftk_doSSLMACInit(context,SEC_OID_MD5,key, |
- *(CK_ULONG *)pMechanism->pParameter); |
- break; |
- case CKM_SSL3_SHA1_MAC: |
- crv = sftk_doSSLMACInit(context,SEC_OID_SHA1,key, |
- *(CK_ULONG *)pMechanism->pParameter); |
- break; |
- case CKM_TLS_PRF_GENERAL: |
- crv = sftk_TLSPRFInit(context, key, key_type); |
- break; |
- |
- default: |
- crv = CKR_MECHANISM_INVALID; |
- break; |
- } |
- |
- if (crv != CKR_OK) { |
- if (info) PORT_Free(info); |
- sftk_FreeContext(context); |
- sftk_FreeSession(session); |
- return crv; |
- } |
- sftk_SetContextByType(session, SFTK_VERIFY, context); |
- sftk_FreeSession(session); |
- return CKR_OK; |
-} |
- |
-/* NSC_Verify verifies a signature in a single-part operation, |
- * where the signature is an appendix to the data, |
- * and plaintext cannot be recovered from the signature */ |
-CK_RV NSC_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, |
- CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) |
-{ |
- SFTKSession *session; |
- SFTKSessionContext *context; |
- CK_RV crv; |
- |
- CHECK_FORK(); |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession,&context,SFTK_VERIFY,PR_FALSE,&session); |
- if (crv != CKR_OK) return crv; |
- |
- /* multi part Verifying are completely implemented by VerifyUpdate and |
- * VerifyFinal */ |
- if (context->multi) { |
- /* VerifyFinal can't follow failed VerifyUpdate */ |
- if( CKR_OK == (crv = NSC_VerifyUpdate(hSession, pData, ulDataLen))) |
- crv = NSC_VerifyFinal(hSession, pSignature, ulSignatureLen); |
- } else { |
- if (SECSuccess != (*context->verify)(context->cipherInfo,pSignature, |
- ulSignatureLen, pData, ulDataLen)) |
- crv = sftk_MapCryptError(PORT_GetError()); |
- |
- sftk_TerminateOp( session, SFTK_VERIFY, context ); |
- } |
- sftk_FreeSession(session); |
- return crv; |
-} |
- |
- |
-/* NSC_VerifyUpdate continues a multiple-part verification operation, |
- * where the signature is an appendix to the data, |
- * and plaintext cannot be recovered from the signature |
- * |
- * A call which results in an error terminates the operation [PKCS#11,v2.11] |
- */ |
-CK_RV NSC_VerifyUpdate( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, |
- CK_ULONG ulPartLen) |
-{ |
- CHECK_FORK(); |
- return sftk_MACUpdate(hSession, pPart, ulPartLen, SFTK_VERIFY); |
-} |
- |
- |
-/* NSC_VerifyFinal finishes a multiple-part verification operation, |
- * checking the signature. */ |
-CK_RV NSC_VerifyFinal(CK_SESSION_HANDLE hSession, |
- CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen) |
-{ |
- SFTKSession *session; |
- SFTKSessionContext *context; |
- CK_RV crv; |
- |
- CHECK_FORK(); |
- |
- if (!pSignature) |
- return CKR_ARGUMENTS_BAD; |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession,&context,SFTK_VERIFY,PR_TRUE,&session); |
- if (crv != CKR_OK) |
- return crv; |
- |
- if (context->hashInfo) { |
- unsigned int digestLen; |
- unsigned char tmpbuf[SFTK_MAX_MAC_LENGTH]; |
- |
- (*context->end)(context->hashInfo, tmpbuf, &digestLen, sizeof(tmpbuf)); |
- if( SECSuccess != (context->verify)(context->cipherInfo, pSignature, |
- ulSignatureLen, tmpbuf, digestLen)) |
- crv = sftk_MapCryptError(PORT_GetError()); |
- } else if (ulSignatureLen != context->macSize) { |
- /* must be block cipher MACing */ |
- crv = CKR_SIGNATURE_LEN_RANGE; |
- } else if (CKR_OK == (crv = sftk_MACFinal(context))) { |
- if (PORT_Memcmp(pSignature, context->macBuf, ulSignatureLen)) |
- crv = CKR_SIGNATURE_INVALID; |
- } |
- |
- sftk_TerminateOp( session, SFTK_VERIFY, context ); |
- sftk_FreeSession(session); |
- return crv; |
- |
-} |
- |
-/* |
- ************** Crypto Functions: Verify Recover ************************ |
- */ |
- |
-/* NSC_VerifyRecoverInit initializes a signature verification operation, |
- * where the data is recovered from the signature. |
- * E.g. Decryption with the user's public key */ |
-CK_RV NSC_VerifyRecoverInit(CK_SESSION_HANDLE hSession, |
- CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey) |
-{ |
- SFTKSession *session; |
- SFTKObject *key; |
- SFTKSessionContext *context; |
- CK_KEY_TYPE key_type; |
- CK_RV crv = CKR_OK; |
- NSSLOWKEYPublicKey *pubKey; |
- |
- CHECK_FORK(); |
- |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) return CKR_SESSION_HANDLE_INVALID; |
- crv = sftk_InitGeneric(session,&context,SFTK_VERIFY_RECOVER, |
- &key,hKey,&key_type,CKO_PUBLIC_KEY,CKA_VERIFY_RECOVER); |
- if (crv != CKR_OK) { |
- sftk_FreeSession(session); |
- return crv; |
- } |
- |
- context->multi = PR_TRUE; |
- |
- switch(pMechanism->mechanism) { |
- case CKM_RSA_PKCS: |
- case CKM_RSA_X_509: |
- if (key_type != CKK_RSA) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- context->multi = PR_FALSE; |
- context->rsa = PR_TRUE; |
- pubKey = sftk_GetPubKey(key,CKK_RSA,&crv); |
- if (pubKey == NULL) { |
- break; |
- } |
- context->cipherInfo = pubKey; |
- context->update = (SFTKCipher) (pMechanism->mechanism == CKM_RSA_X_509 |
- ? RSA_CheckSignRecoverRaw : RSA_CheckSignRecover); |
- context->destroy = sftk_Null; |
- break; |
- default: |
- crv = CKR_MECHANISM_INVALID; |
- break; |
- } |
- |
- if (crv != CKR_OK) { |
- PORT_Free(context); |
- sftk_FreeSession(session); |
- return crv; |
- } |
- sftk_SetContextByType(session, SFTK_VERIFY_RECOVER, context); |
- sftk_FreeSession(session); |
- return CKR_OK; |
-} |
- |
- |
-/* NSC_VerifyRecover verifies a signature in a single-part operation, |
- * where the data is recovered from the signature. |
- * E.g. Decryption with the user's public key */ |
-CK_RV NSC_VerifyRecover(CK_SESSION_HANDLE hSession, |
- CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen, |
- CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen) |
-{ |
- SFTKSession *session; |
- SFTKSessionContext *context; |
- unsigned int outlen; |
- unsigned int maxoutlen = *pulDataLen; |
- CK_RV crv; |
- SECStatus rv; |
- |
- CHECK_FORK(); |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession,&context,SFTK_VERIFY_RECOVER, |
- PR_FALSE,&session); |
- if (crv != CKR_OK) return crv; |
- if (pData == NULL) { |
- /* to return the actual size, we need to do the decrypt, just return |
- * the max size, which is the size of the input signature. */ |
- *pulDataLen = ulSignatureLen; |
- rv = SECSuccess; |
- goto finish; |
- } |
- |
- rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen, |
- pSignature, ulSignatureLen); |
- *pulDataLen = (CK_ULONG) outlen; |
- |
- sftk_TerminateOp(session, SFTK_VERIFY_RECOVER, context); |
-finish: |
- sftk_FreeSession(session); |
- return (rv == SECSuccess) ? CKR_OK : sftk_MapVerifyError(PORT_GetError()); |
-} |
- |
-/* |
- **************************** Random Functions: ************************ |
- */ |
- |
-/* NSC_SeedRandom mixes additional seed material into the token's random number |
- * generator. */ |
-CK_RV NSC_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, |
- CK_ULONG ulSeedLen) |
-{ |
- SECStatus rv; |
- |
- CHECK_FORK(); |
- |
- rv = RNG_RandomUpdate(pSeed, ulSeedLen); |
- return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError()); |
-} |
- |
-/* NSC_GenerateRandom generates random data. */ |
-CK_RV NSC_GenerateRandom(CK_SESSION_HANDLE hSession, |
- CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen) |
-{ |
- SECStatus rv; |
- |
- CHECK_FORK(); |
- |
- rv = RNG_GenerateGlobalRandomBytes(pRandomData, ulRandomLen); |
- /* |
- * This may fail with SEC_ERROR_NEED_RANDOM, which means the RNG isn't |
- * seeded with enough entropy. |
- */ |
- return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError()); |
-} |
- |
-/* |
- **************************** Key Functions: ************************ |
- */ |
- |
- |
-/* |
- * generate a password based encryption key. This code uses |
- * PKCS5 to do the work. |
- */ |
-static CK_RV |
-nsc_pbe_key_gen(NSSPKCS5PBEParameter *pkcs5_pbe, CK_MECHANISM_PTR pMechanism, |
- void *buf, CK_ULONG *key_length, PRBool faulty3DES) |
-{ |
- SECItem *pbe_key = NULL, iv, pwitem; |
- CK_PBE_PARAMS *pbe_params = NULL; |
- CK_PKCS5_PBKD2_PARAMS *pbkd2_params = NULL; |
- |
- *key_length = 0; |
- iv.data = NULL; iv.len = 0; |
- |
- if (pMechanism->mechanism == CKM_PKCS5_PBKD2) { |
- pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter; |
- pwitem.data = (unsigned char *)pbkd2_params->pPassword; |
- /* was this a typo in the PKCS #11 spec? */ |
- pwitem.len = *pbkd2_params->ulPasswordLen; |
- } else { |
- pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter; |
- pwitem.data = (unsigned char *)pbe_params->pPassword; |
- pwitem.len = pbe_params->ulPasswordLen; |
- } |
- pbe_key = nsspkcs5_ComputeKeyAndIV(pkcs5_pbe, &pwitem, &iv, faulty3DES); |
- if (pbe_key == NULL) { |
- return CKR_HOST_MEMORY; |
- } |
- |
- PORT_Memcpy(buf, pbe_key->data, pbe_key->len); |
- *key_length = pbe_key->len; |
- SECITEM_ZfreeItem(pbe_key, PR_TRUE); |
- pbe_key = NULL; |
- |
- if (iv.data) { |
- if (pbe_params && pbe_params->pInitVector != NULL) { |
- PORT_Memcpy(pbe_params->pInitVector, iv.data, iv.len); |
- } |
- PORT_Free(iv.data); |
- } |
- |
- return CKR_OK; |
-} |
- |
-/* |
- * this is coded for "full" support. These selections will be limitted to |
- * the official subset by freebl. |
- */ |
-static unsigned int |
-sftk_GetSubPrimeFromPrime(unsigned int primeBits) |
-{ |
- if (primeBits <= 1024) { |
- return 160; |
- } else if (primeBits <= 2048) { |
- return 224; |
- } else if (primeBits <= 3072) { |
- return 256; |
- } else if (primeBits <= 7680) { |
- return 384; |
- } else { |
- return 512; |
- } |
-} |
- |
-static CK_RV |
-nsc_parameter_gen(CK_KEY_TYPE key_type, SFTKObject *key) |
-{ |
- SFTKAttribute *attribute; |
- CK_ULONG counter; |
- unsigned int seedBits = 0; |
- unsigned int subprimeBits = 0; |
- unsigned int primeBits; |
- unsigned int j = 8; /* default to 1024 bits */ |
- CK_RV crv = CKR_OK; |
- PQGParams *params = NULL; |
- PQGVerify *vfy = NULL; |
- SECStatus rv; |
- |
- attribute = sftk_FindAttribute(key, CKA_PRIME_BITS); |
- if (attribute == NULL) { |
- return CKR_TEMPLATE_INCOMPLETE; |
- } |
- primeBits = (unsigned int) *(CK_ULONG *)attribute->attrib.pValue; |
- sftk_FreeAttribute(attribute); |
- if (primeBits < 1024) { |
- j = PQG_PBITS_TO_INDEX(primeBits); |
- if (j == (unsigned int)-1) { |
- return CKR_ATTRIBUTE_VALUE_INVALID; |
- } |
- } |
- |
- attribute = sftk_FindAttribute(key, CKA_NETSCAPE_PQG_SEED_BITS); |
- if (attribute != NULL) { |
- seedBits = (unsigned int) *(CK_ULONG *)attribute->attrib.pValue; |
- sftk_FreeAttribute(attribute); |
- } |
- |
- attribute = sftk_FindAttribute(key, CKA_SUBPRIME_BITS); |
- if (attribute != NULL) { |
- subprimeBits = (unsigned int) *(CK_ULONG *)attribute->attrib.pValue; |
- sftk_FreeAttribute(attribute); |
- } |
- |
- sftk_DeleteAttributeType(key,CKA_PRIME_BITS); |
- sftk_DeleteAttributeType(key,CKA_SUBPRIME_BITS); |
- sftk_DeleteAttributeType(key,CKA_NETSCAPE_PQG_SEED_BITS); |
- |
- /* use the old PQG interface if we have old input data */ |
- if ((primeBits < 1024) || ((primeBits == 1024) && (subprimeBits == 0))) { |
- if (seedBits == 0) { |
- rv = PQG_ParamGen(j, ¶ms, &vfy); |
- } else { |
- rv = PQG_ParamGenSeedLen(j,seedBits/8, ¶ms, &vfy); |
- } |
- } else { |
- if (subprimeBits == 0) { |
- subprimeBits = sftk_GetSubPrimeFromPrime(primeBits); |
- } |
- if (seedBits == 0) { |
- seedBits = primeBits; |
- } |
- rv = PQG_ParamGenV2(primeBits, subprimeBits, seedBits/8, ¶ms, &vfy); |
- } |
- |
- |
- |
- if (rv != SECSuccess) { |
- if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) { |
- sftk_fatalError = PR_TRUE; |
- } |
- return sftk_MapCryptError(PORT_GetError()); |
- } |
- crv = sftk_AddAttributeType(key,CKA_PRIME, |
- params->prime.data, params->prime.len); |
- if (crv != CKR_OK) goto loser; |
- crv = sftk_AddAttributeType(key,CKA_SUBPRIME, |
- params->subPrime.data, params->subPrime.len); |
- if (crv != CKR_OK) goto loser; |
- crv = sftk_AddAttributeType(key,CKA_BASE, |
- params->base.data, params->base.len); |
- if (crv != CKR_OK) goto loser; |
- counter = vfy->counter; |
- crv = sftk_AddAttributeType(key,CKA_NETSCAPE_PQG_COUNTER, |
- &counter, sizeof(counter)); |
- crv = sftk_AddAttributeType(key,CKA_NETSCAPE_PQG_SEED, |
- vfy->seed.data, vfy->seed.len); |
- if (crv != CKR_OK) goto loser; |
- crv = sftk_AddAttributeType(key,CKA_NETSCAPE_PQG_H, |
- vfy->h.data, vfy->h.len); |
- if (crv != CKR_OK) goto loser; |
- |
-loser: |
- PQG_DestroyParams(params); |
- |
- if (vfy) { |
- PQG_DestroyVerify(vfy); |
- } |
- return crv; |
-} |
- |
- |
-static CK_RV |
-nsc_SetupBulkKeyGen(CK_MECHANISM_TYPE mechanism, CK_KEY_TYPE *key_type, |
- CK_ULONG *key_length) |
-{ |
- CK_RV crv = CKR_OK; |
- |
- switch (mechanism) { |
- case CKM_RC2_KEY_GEN: |
- *key_type = CKK_RC2; |
- if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE; |
- break; |
-#if NSS_SOFTOKEN_DOES_RC5 |
- case CKM_RC5_KEY_GEN: |
- *key_type = CKK_RC5; |
- if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE; |
- break; |
-#endif |
- case CKM_RC4_KEY_GEN: |
- *key_type = CKK_RC4; |
- if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE; |
- break; |
- case CKM_GENERIC_SECRET_KEY_GEN: |
- *key_type = CKK_GENERIC_SECRET; |
- if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE; |
- break; |
- case CKM_CDMF_KEY_GEN: |
- *key_type = CKK_CDMF; |
- *key_length = 8; |
- break; |
- case CKM_DES_KEY_GEN: |
- *key_type = CKK_DES; |
- *key_length = 8; |
- break; |
- case CKM_DES2_KEY_GEN: |
- *key_type = CKK_DES2; |
- *key_length = 16; |
- break; |
- case CKM_DES3_KEY_GEN: |
- *key_type = CKK_DES3; |
- *key_length = 24; |
- break; |
- case CKM_SEED_KEY_GEN: |
- *key_type = CKK_SEED; |
- *key_length = 16; |
- break; |
- case CKM_CAMELLIA_KEY_GEN: |
- *key_type = CKK_CAMELLIA; |
- if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE; |
- break; |
- case CKM_AES_KEY_GEN: |
- *key_type = CKK_AES; |
- if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE; |
- break; |
- default: |
- PORT_Assert(0); |
- crv = CKR_MECHANISM_INVALID; |
- break; |
- } |
- |
- return crv; |
-} |
- |
-CK_RV |
-nsc_SetupHMACKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe) |
-{ |
- SECItem salt; |
- CK_PBE_PARAMS *pbe_params = NULL; |
- NSSPKCS5PBEParameter *params; |
- PRArenaPool *arena = NULL; |
- SECStatus rv; |
- |
- *pbe = NULL; |
- |
- arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
- if (arena == NULL) { |
- return CKR_HOST_MEMORY; |
- } |
- |
- params = (NSSPKCS5PBEParameter *) PORT_ArenaZAlloc(arena, |
- sizeof(NSSPKCS5PBEParameter)); |
- if (params == NULL) { |
- PORT_FreeArena(arena,PR_TRUE); |
- return CKR_HOST_MEMORY; |
- } |
- |
- params->poolp = arena; |
- params->ivLen = 0; |
- params->pbeType = NSSPKCS5_PKCS12_V2; |
- params->hashType = HASH_AlgSHA1; |
- params->encAlg = SEC_OID_SHA1; /* any invalid value */ |
- params->is2KeyDES = PR_FALSE; |
- params->keyID = pbeBitGenIntegrityKey; |
- pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter; |
- params->iter = pbe_params->ulIteration; |
- |
- salt.data = (unsigned char *)pbe_params->pSalt; |
- salt.len = (unsigned int)pbe_params->ulSaltLen; |
- rv = SECITEM_CopyItem(arena,¶ms->salt,&salt); |
- if (rv != SECSuccess) { |
- PORT_FreeArena(arena,PR_TRUE); |
- return CKR_HOST_MEMORY; |
- } |
- switch (pMechanism->mechanism) { |
- case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN: |
- case CKM_PBA_SHA1_WITH_SHA1_HMAC: |
- params->hashType = HASH_AlgSHA1; |
- params->keyLen = 20; |
- break; |
- case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN: |
- params->hashType = HASH_AlgMD5; |
- params->keyLen = 16; |
- break; |
- case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN: |
- params->hashType = HASH_AlgMD2; |
- params->keyLen = 16; |
- break; |
- default: |
- PORT_FreeArena(arena,PR_TRUE); |
- return CKR_MECHANISM_INVALID; |
- } |
- *pbe = params; |
- return CKR_OK; |
-} |
- |
-/* maybe this should be table driven? */ |
-static CK_RV |
-nsc_SetupPBEKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe, |
- CK_KEY_TYPE *key_type, CK_ULONG *key_length) |
-{ |
- CK_RV crv = CKR_OK; |
- SECOidData *oid; |
- CK_PBE_PARAMS *pbe_params = NULL; |
- NSSPKCS5PBEParameter *params = NULL; |
- CK_PKCS5_PBKD2_PARAMS *pbkd2_params = NULL; |
- SECItem salt; |
- CK_ULONG iteration = 0; |
- |
- *pbe = NULL; |
- |
- oid = SECOID_FindOIDByMechanism(pMechanism->mechanism); |
- if (oid == NULL) { |
- return CKR_MECHANISM_INVALID; |
- } |
- |
- if (pMechanism->mechanism == CKM_PKCS5_PBKD2) { |
- pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter; |
- if (pbkd2_params->saltSource != CKZ_SALT_SPECIFIED) { |
- return CKR_MECHANISM_PARAM_INVALID; |
- } |
- salt.data = (unsigned char *)pbkd2_params->pSaltSourceData; |
- salt.len = (unsigned int)pbkd2_params->ulSaltSourceDataLen; |
- iteration = pbkd2_params->iterations; |
- } else { |
- pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter; |
- salt.data = (unsigned char *)pbe_params->pSalt; |
- salt.len = (unsigned int)pbe_params->ulSaltLen; |
- iteration = pbe_params->ulIteration; |
- } |
- params=nsspkcs5_NewParam(oid->offset, &salt, iteration); |
- if (params == NULL) { |
- return CKR_MECHANISM_INVALID; |
- } |
- |
- switch (params->encAlg) { |
- case SEC_OID_DES_CBC: |
- *key_type = CKK_DES; |
- *key_length = params->keyLen; |
- break; |
- case SEC_OID_DES_EDE3_CBC: |
- *key_type = params->is2KeyDES ? CKK_DES2 : CKK_DES3; |
- *key_length = params->keyLen; |
- break; |
- case SEC_OID_RC2_CBC: |
- *key_type = CKK_RC2; |
- *key_length = params->keyLen; |
- break; |
- case SEC_OID_RC4: |
- *key_type = CKK_RC4; |
- *key_length = params->keyLen; |
- break; |
- case SEC_OID_PKCS5_PBKDF2: |
- /* sigh, PKCS #11 currently only defines SHA1 for the KDF hash type. |
- * we do the check here because this where we would handle multiple |
- * hash types in the future */ |
- if (pbkd2_params == NULL || |
- pbkd2_params->prf != CKP_PKCS5_PBKD2_HMAC_SHA1) { |
- crv = CKR_MECHANISM_PARAM_INVALID; |
- break; |
- } |
- /* key type must already be set */ |
- if (*key_type == CKK_INVALID_KEY_TYPE) { |
- crv = CKR_TEMPLATE_INCOMPLETE; |
- break; |
- } |
- /* PBKDF2 needs to calculate the key length from the other parameters |
- */ |
- if (*key_length == 0) { |
- *key_length = sftk_MapKeySize(*key_type); |
- } |
- if (*key_length == 0) { |
- crv = CKR_TEMPLATE_INCOMPLETE; |
- break; |
- } |
- params->keyLen = *key_length; |
- break; |
- default: |
- crv = CKR_MECHANISM_INVALID; |
- nsspkcs5_DestroyPBEParameter(params); |
- break; |
- } |
- if (crv == CKR_OK) { |
- *pbe = params; |
- } |
- return crv; |
-} |
- |
-/* NSC_GenerateKey generates a secret key, creating a new key object. */ |
-CK_RV NSC_GenerateKey(CK_SESSION_HANDLE hSession, |
- CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount, |
- CK_OBJECT_HANDLE_PTR phKey) |
-{ |
- SFTKObject *key; |
- SFTKSession *session; |
- PRBool checkWeak = PR_FALSE; |
- CK_ULONG key_length = 0; |
- CK_KEY_TYPE key_type = CKK_INVALID_KEY_TYPE; |
- CK_OBJECT_CLASS objclass = CKO_SECRET_KEY; |
- CK_RV crv = CKR_OK; |
- CK_BBOOL cktrue = CK_TRUE; |
- int i; |
- SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession); |
- unsigned char buf[MAX_KEY_LEN]; |
- enum {nsc_pbe, nsc_ssl, nsc_bulk, nsc_param, nsc_jpake} key_gen_type; |
- NSSPKCS5PBEParameter *pbe_param; |
- SSL3RSAPreMasterSecret *rsa_pms; |
- CK_VERSION *version; |
- /* in very old versions of NSS, there were implementation errors with key |
- * generation methods. We want to beable to read these, but not |
- * produce them any more. The affected algorithm was 3DES. |
- */ |
- PRBool faultyPBE3DES = PR_FALSE; |
- HASH_HashType hashType; |
- |
- CHECK_FORK(); |
- |
- if (!slot) { |
- return CKR_SESSION_HANDLE_INVALID; |
- } |
- /* |
- * now lets create an object to hang the attributes off of |
- */ |
- key = sftk_NewObject(slot); /* fill in the handle later */ |
- if (key == NULL) { |
- return CKR_HOST_MEMORY; |
- } |
- |
- /* |
- * load the template values into the object |
- */ |
- for (i=0; i < (int) ulCount; i++) { |
- if (pTemplate[i].type == CKA_VALUE_LEN) { |
- key_length = *(CK_ULONG *)pTemplate[i].pValue; |
- continue; |
- } |
- /* some algorithms need keytype specified */ |
- if (pTemplate[i].type == CKA_KEY_TYPE) { |
- key_type = *(CK_ULONG *)pTemplate[i].pValue; |
- continue; |
- } |
- |
- crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i])); |
- if (crv != CKR_OK) break; |
- } |
- if (crv != CKR_OK) { |
- sftk_FreeObject(key); |
- return crv; |
- } |
- |
- /* make sure we don't have any class, key_type, or value fields */ |
- sftk_DeleteAttributeType(key,CKA_CLASS); |
- sftk_DeleteAttributeType(key,CKA_KEY_TYPE); |
- sftk_DeleteAttributeType(key,CKA_VALUE); |
- |
- /* Now Set up the parameters to generate the key (based on mechanism) */ |
- key_gen_type = nsc_bulk; /* bulk key by default */ |
- switch (pMechanism->mechanism) { |
- case CKM_CDMF_KEY_GEN: |
- case CKM_DES_KEY_GEN: |
- case CKM_DES2_KEY_GEN: |
- case CKM_DES3_KEY_GEN: |
- checkWeak = PR_TRUE; |
- case CKM_RC2_KEY_GEN: |
- case CKM_RC4_KEY_GEN: |
- case CKM_GENERIC_SECRET_KEY_GEN: |
- case CKM_SEED_KEY_GEN: |
- case CKM_CAMELLIA_KEY_GEN: |
- case CKM_AES_KEY_GEN: |
-#if NSS_SOFTOKEN_DOES_RC5 |
- case CKM_RC5_KEY_GEN: |
-#endif |
- crv = nsc_SetupBulkKeyGen(pMechanism->mechanism,&key_type,&key_length); |
- break; |
- case CKM_SSL3_PRE_MASTER_KEY_GEN: |
- key_type = CKK_GENERIC_SECRET; |
- key_length = 48; |
- key_gen_type = nsc_ssl; |
- break; |
- case CKM_PBA_SHA1_WITH_SHA1_HMAC: |
- case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN: |
- case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN: |
- case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN: |
- key_gen_type = nsc_pbe; |
- key_type = CKK_GENERIC_SECRET; |
- crv = nsc_SetupHMACKeyGen(pMechanism, &pbe_param); |
- break; |
- case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: |
- faultyPBE3DES = PR_TRUE; |
- case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: |
- case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: |
- case CKM_NETSCAPE_PBE_SHA1_DES_CBC: |
- case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: |
- case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: |
- case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: |
- case CKM_PBE_SHA1_DES3_EDE_CBC: |
- case CKM_PBE_SHA1_DES2_EDE_CBC: |
- case CKM_PBE_SHA1_RC2_128_CBC: |
- case CKM_PBE_SHA1_RC2_40_CBC: |
- case CKM_PBE_SHA1_RC4_128: |
- case CKM_PBE_SHA1_RC4_40: |
- case CKM_PBE_MD5_DES_CBC: |
- case CKM_PBE_MD2_DES_CBC: |
- case CKM_PKCS5_PBKD2: |
- key_gen_type = nsc_pbe; |
- crv = nsc_SetupPBEKeyGen(pMechanism,&pbe_param, &key_type, &key_length); |
- break; |
- case CKM_DSA_PARAMETER_GEN: |
- key_gen_type = nsc_param; |
- key_type = CKK_DSA; |
- objclass = CKO_KG_PARAMETERS; |
- crv = CKR_OK; |
- break; |
- case CKM_NSS_JPAKE_ROUND1_SHA1: hashType = HASH_AlgSHA1; goto jpake1; |
- case CKM_NSS_JPAKE_ROUND1_SHA256: hashType = HASH_AlgSHA256; goto jpake1; |
- case CKM_NSS_JPAKE_ROUND1_SHA384: hashType = HASH_AlgSHA384; goto jpake1; |
- case CKM_NSS_JPAKE_ROUND1_SHA512: hashType = HASH_AlgSHA512; goto jpake1; |
-jpake1: |
- key_gen_type = nsc_jpake; |
- key_type = CKK_NSS_JPAKE_ROUND1; |
- objclass = CKO_PRIVATE_KEY; |
- if (pMechanism->pParameter == NULL || |
- pMechanism->ulParameterLen != sizeof(CK_NSS_JPAKERound1Params)) { |
- crv = CKR_MECHANISM_PARAM_INVALID; |
- break; |
- } |
- if (sftk_isTrue(key, CKA_TOKEN)) { |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- } |
- crv = CKR_OK; |
- break; |
- default: |
- crv = CKR_MECHANISM_INVALID; |
- break; |
- } |
- |
- /* make sure we aren't going to overflow the buffer */ |
- if (sizeof(buf) < key_length) { |
- /* someone is getting pretty optimistic about how big their key can |
- * be... */ |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- } |
- |
- if (crv != CKR_OK) { sftk_FreeObject(key); return crv; } |
- |
- /* if there was no error, |
- * key_type *MUST* be set in the switch statement above */ |
- PORT_Assert( key_type != CKK_INVALID_KEY_TYPE ); |
- |
- /* |
- * now to the actual key gen. |
- */ |
- switch (key_gen_type) { |
- case nsc_pbe: |
- crv = nsc_pbe_key_gen(pbe_param, pMechanism, buf, &key_length, |
- faultyPBE3DES); |
- nsspkcs5_DestroyPBEParameter(pbe_param); |
- break; |
- case nsc_ssl: |
- rsa_pms = (SSL3RSAPreMasterSecret *)buf; |
- version = (CK_VERSION *)pMechanism->pParameter; |
- rsa_pms->client_version[0] = version->major; |
- rsa_pms->client_version[1] = version->minor; |
- crv = |
- NSC_GenerateRandom(0,&rsa_pms->random[0], sizeof(rsa_pms->random)); |
- break; |
- case nsc_bulk: |
- /* get the key, check for weak keys and repeat if found */ |
- do { |
- crv = NSC_GenerateRandom(0, buf, key_length); |
- } while (crv == CKR_OK && checkWeak && sftk_IsWeakKey(buf,key_type)); |
- break; |
- case nsc_param: |
- /* generate parameters */ |
- *buf = 0; |
- crv = nsc_parameter_gen(key_type,key); |
- break; |
- case nsc_jpake: |
- crv = jpake_Round1(hashType, |
- (CK_NSS_JPAKERound1Params *) pMechanism->pParameter, |
- key); |
- break; |
- } |
- |
- if (crv != CKR_OK) { sftk_FreeObject(key); return crv; } |
- |
- /* Add the class, key_type, and value */ |
- crv = sftk_AddAttributeType(key,CKA_CLASS,&objclass,sizeof(CK_OBJECT_CLASS)); |
- if (crv != CKR_OK) { sftk_FreeObject(key); return crv; } |
- crv = sftk_AddAttributeType(key,CKA_KEY_TYPE,&key_type,sizeof(CK_KEY_TYPE)); |
- if (crv != CKR_OK) { sftk_FreeObject(key); return crv; } |
- if (key_length != 0) { |
- crv = sftk_AddAttributeType(key,CKA_VALUE,buf,key_length); |
- if (crv != CKR_OK) { sftk_FreeObject(key); return crv; } |
- } |
- |
- /* get the session */ |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) { |
- sftk_FreeObject(key); |
- return CKR_SESSION_HANDLE_INVALID; |
- } |
- |
- /* |
- * handle the base object stuff |
- */ |
- crv = sftk_handleObject(key,session); |
- sftk_FreeSession(session); |
- if (sftk_isTrue(key,CKA_SENSITIVE)) { |
- sftk_forceAttribute(key,CKA_ALWAYS_SENSITIVE,&cktrue,sizeof(CK_BBOOL)); |
- } |
- if (!sftk_isTrue(key,CKA_EXTRACTABLE)) { |
- sftk_forceAttribute(key,CKA_NEVER_EXTRACTABLE,&cktrue,sizeof(CK_BBOOL)); |
- } |
- |
- *phKey = key->handle; |
- sftk_FreeObject(key); |
- return crv; |
-} |
- |
-#define PAIRWISE_DIGEST_LENGTH SHA1_LENGTH /* 160-bits */ |
-#define PAIRWISE_MESSAGE_LENGTH 20 /* 160-bits */ |
- |
-/* |
- * FIPS 140-2 pairwise consistency check utilized to validate key pair. |
- * |
- * This function returns |
- * CKR_OK if pairwise consistency check passed |
- * CKR_GENERAL_ERROR if pairwise consistency check failed |
- * other error codes if paiswise consistency check could not be |
- * performed, for example, CKR_HOST_MEMORY. |
- */ |
-static CK_RV |
-sftk_PairwiseConsistencyCheck(CK_SESSION_HANDLE hSession, |
- SFTKObject *publicKey, SFTKObject *privateKey, CK_KEY_TYPE keyType) |
-{ |
- /* |
- * Key type Mechanism type |
- * -------------------------------- |
- * For encrypt/decrypt: CKK_RSA => CKM_RSA_PKCS |
- * others => CKM_INVALID_MECHANISM |
- * |
- * For sign/verify: CKK_RSA => CKM_RSA_PKCS |
- * CKK_DSA => CKM_DSA |
- * CKK_EC => CKM_ECDSA |
- * others => CKM_INVALID_MECHANISM |
- * |
- * None of these mechanisms has a parameter. |
- */ |
- CK_MECHANISM mech = {0, NULL, 0}; |
- |
- CK_ULONG modulusLen; |
- CK_ULONG subPrimeLen; |
- PRBool isEncryptable = PR_FALSE; |
- PRBool canSignVerify = PR_FALSE; |
- PRBool isDerivable = PR_FALSE; |
- CK_RV crv; |
- |
- /* Variables used for Encrypt/Decrypt functions. */ |
- unsigned char *known_message = (unsigned char *)"Known Crypto Message"; |
- unsigned char plaintext[PAIRWISE_MESSAGE_LENGTH]; |
- CK_ULONG bytes_decrypted; |
- unsigned char *ciphertext; |
- unsigned char *text_compared; |
- CK_ULONG bytes_encrypted; |
- CK_ULONG bytes_compared; |
- CK_ULONG pairwise_digest_length = PAIRWISE_DIGEST_LENGTH; |
- |
- /* Variables used for Signature/Verification functions. */ |
- /* Must be at least 256 bits for DSA2 digest */ |
- unsigned char *known_digest = (unsigned char *) |
- "Mozilla Rules the World through NSS!"; |
- unsigned char *signature; |
- CK_ULONG signature_length; |
- |
- if (keyType == CKK_RSA) { |
- SFTKAttribute *attribute; |
- |
- /* Get modulus length of private key. */ |
- attribute = sftk_FindAttribute(privateKey, CKA_MODULUS); |
- if (attribute == NULL) { |
- return CKR_DEVICE_ERROR; |
- } |
- modulusLen = attribute->attrib.ulValueLen; |
- if (*(unsigned char *)attribute->attrib.pValue == 0) { |
- modulusLen--; |
- } |
- sftk_FreeAttribute(attribute); |
- } else if (keyType == CKK_DSA) { |
- SFTKAttribute *attribute; |
- |
- /* Get subprime length of private key. */ |
- attribute = sftk_FindAttribute(privateKey, CKA_SUBPRIME); |
- if (attribute == NULL) { |
- return CKR_DEVICE_ERROR; |
- } |
- subPrimeLen = attribute->attrib.ulValueLen; |
- if (subPrimeLen > 1 && *(unsigned char *)attribute->attrib.pValue == 0) { |
- subPrimeLen--; |
- } |
- sftk_FreeAttribute(attribute); |
- } |
- |
- /**************************************************/ |
- /* Pairwise Consistency Check of Encrypt/Decrypt. */ |
- /**************************************************/ |
- |
- isEncryptable = sftk_isTrue(privateKey, CKA_DECRYPT); |
- |
- /* |
- * If the decryption attribute is set, attempt to encrypt |
- * with the public key and decrypt with the private key. |
- */ |
- if (isEncryptable) { |
- if (keyType != CKK_RSA) { |
- return CKR_DEVICE_ERROR; |
- } |
- bytes_encrypted = modulusLen; |
- mech.mechanism = CKM_RSA_PKCS; |
- |
- /* Allocate space for ciphertext. */ |
- ciphertext = (unsigned char *) PORT_ZAlloc(bytes_encrypted); |
- if (ciphertext == NULL) { |
- return CKR_HOST_MEMORY; |
- } |
- |
- /* Prepare for encryption using the public key. */ |
- crv = NSC_EncryptInit(hSession, &mech, publicKey->handle); |
- if (crv != CKR_OK) { |
- PORT_Free(ciphertext); |
- return crv; |
- } |
- |
- /* Encrypt using the public key. */ |
- crv = NSC_Encrypt(hSession, |
- known_message, |
- PAIRWISE_MESSAGE_LENGTH, |
- ciphertext, |
- &bytes_encrypted); |
- if (crv != CKR_OK) { |
- PORT_Free(ciphertext); |
- return crv; |
- } |
- |
- /* Always use the smaller of these two values . . . */ |
- bytes_compared = PR_MIN(bytes_encrypted, PAIRWISE_MESSAGE_LENGTH); |
- |
- /* |
- * If there was a failure, the plaintext |
- * goes at the end, therefore . . . |
- */ |
- text_compared = ciphertext + bytes_encrypted - bytes_compared; |
- |
- /* |
- * Check to ensure that ciphertext does |
- * NOT EQUAL known input message text |
- * per FIPS PUB 140-2 directive. |
- */ |
- if (PORT_Memcmp(text_compared, known_message, |
- bytes_compared) == 0) { |
- /* Set error to Invalid PRIVATE Key. */ |
- PORT_SetError(SEC_ERROR_INVALID_KEY); |
- PORT_Free(ciphertext); |
- return CKR_GENERAL_ERROR; |
- } |
- |
- /* Prepare for decryption using the private key. */ |
- crv = NSC_DecryptInit(hSession, &mech, privateKey->handle); |
- if (crv != CKR_OK) { |
- PORT_Free(ciphertext); |
- return crv; |
- } |
- |
- memset(plaintext, 0, PAIRWISE_MESSAGE_LENGTH); |
- |
- /* |
- * Initialize bytes decrypted to be the |
- * expected PAIRWISE_MESSAGE_LENGTH. |
- */ |
- bytes_decrypted = PAIRWISE_MESSAGE_LENGTH; |
- |
- /* |
- * Decrypt using the private key. |
- * NOTE: No need to reset the |
- * value of bytes_encrypted. |
- */ |
- crv = NSC_Decrypt(hSession, |
- ciphertext, |
- bytes_encrypted, |
- plaintext, |
- &bytes_decrypted); |
- |
- /* Finished with ciphertext; free it. */ |
- PORT_Free(ciphertext); |
- |
- if (crv != CKR_OK) { |
- return crv; |
- } |
- |
- /* |
- * Check to ensure that the output plaintext |
- * does EQUAL known input message text. |
- */ |
- if ((bytes_decrypted != PAIRWISE_MESSAGE_LENGTH) || |
- (PORT_Memcmp(plaintext, known_message, |
- PAIRWISE_MESSAGE_LENGTH) != 0)) { |
- /* Set error to Bad PUBLIC Key. */ |
- PORT_SetError(SEC_ERROR_BAD_KEY); |
- return CKR_GENERAL_ERROR; |
- } |
- } |
- |
- /**********************************************/ |
- /* Pairwise Consistency Check of Sign/Verify. */ |
- /**********************************************/ |
- |
- canSignVerify = sftk_isTrue(privateKey, CKA_SIGN); |
- |
- if (canSignVerify) { |
- /* Determine length of signature. */ |
- switch (keyType) { |
- case CKK_RSA: |
- signature_length = modulusLen; |
- mech.mechanism = CKM_RSA_PKCS; |
- break; |
- case CKK_DSA: |
- signature_length = DSA_MAX_SIGNATURE_LEN; |
- pairwise_digest_length = subPrimeLen; |
- mech.mechanism = CKM_DSA; |
- break; |
-#ifdef NSS_ENABLE_ECC |
- case CKK_EC: |
- signature_length = MAX_ECKEY_LEN * 2; |
- mech.mechanism = CKM_ECDSA; |
- break; |
-#endif |
- default: |
- return CKR_DEVICE_ERROR; |
- } |
- |
- /* Allocate space for signature data. */ |
- signature = (unsigned char *) PORT_ZAlloc(signature_length); |
- if (signature == NULL) { |
- return CKR_HOST_MEMORY; |
- } |
- |
- /* Sign the known hash using the private key. */ |
- crv = NSC_SignInit(hSession, &mech, privateKey->handle); |
- if (crv != CKR_OK) { |
- PORT_Free(signature); |
- return crv; |
- } |
- |
- crv = NSC_Sign(hSession, |
- known_digest, |
- pairwise_digest_length, |
- signature, |
- &signature_length); |
- if (crv != CKR_OK) { |
- PORT_Free(signature); |
- return crv; |
- } |
- |
- /* Verify the known hash using the public key. */ |
- crv = NSC_VerifyInit(hSession, &mech, publicKey->handle); |
- if (crv != CKR_OK) { |
- PORT_Free(signature); |
- return crv; |
- } |
- |
- crv = NSC_Verify(hSession, |
- known_digest, |
- pairwise_digest_length, |
- signature, |
- signature_length); |
- |
- /* Free signature data. */ |
- PORT_Free(signature); |
- |
- if ((crv == CKR_SIGNATURE_LEN_RANGE) || |
- (crv == CKR_SIGNATURE_INVALID)) { |
- return CKR_GENERAL_ERROR; |
- } |
- if (crv != CKR_OK) { |
- return crv; |
- } |
- } |
- |
- /**********************************************/ |
- /* Pairwise Consistency Check for Derivation */ |
- /**********************************************/ |
- |
- isDerivable = sftk_isTrue(privateKey, CKA_DERIVE); |
- |
- if (isDerivable) { |
- /* |
- * We are not doing consistency check for Diffie-Hellman Key - |
- * otherwise it would be here |
- * This is also true for Elliptic Curve Diffie-Hellman keys |
- * NOTE: EC keys are currently subjected to pairwise |
- * consistency check for signing/verification. |
- */ |
- /* |
- * FIPS 140-2 had the following pairwise consistency test for |
- * public and private keys used for key agreement: |
- * If the keys are used to perform key agreement, then the |
- * cryptographic module shall create a second, compatible |
- * key pair. The cryptographic module shall perform both |
- * sides of the key agreement algorithm and shall compare |
- * the resulting shared values. If the shared values are |
- * not equal, the test shall fail. |
- * This test was removed in Change Notice 3. |
- */ |
- |
- } |
- |
- return CKR_OK; |
-} |
- |
-/* NSC_GenerateKeyPair generates a public-key/private-key pair, |
- * creating new key objects. */ |
-CK_RV NSC_GenerateKeyPair (CK_SESSION_HANDLE hSession, |
- CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, |
- CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, |
- CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey, |
- CK_OBJECT_HANDLE_PTR phPrivateKey) |
-{ |
- SFTKObject * publicKey,*privateKey; |
- SFTKSession * session; |
- CK_KEY_TYPE key_type; |
- CK_RV crv = CKR_OK; |
- CK_BBOOL cktrue = CK_TRUE; |
- SECStatus rv; |
- CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; |
- CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY; |
- int i; |
- SFTKSlot * slot = sftk_SlotFromSessionHandle(hSession); |
- unsigned int bitSize; |
- |
- /* RSA */ |
- int public_modulus_bits = 0; |
- SECItem pubExp; |
- RSAPrivateKey * rsaPriv; |
- |
- /* DSA */ |
- PQGParams pqgParam; |
- DHParams dhParam; |
- DSAPrivateKey * dsaPriv; |
- |
- /* Diffie Hellman */ |
- int private_value_bits = 0; |
- DHPrivateKey * dhPriv; |
- |
-#ifdef NSS_ENABLE_ECC |
- /* Elliptic Curve Cryptography */ |
- SECItem ecEncodedParams; /* DER Encoded parameters */ |
- ECPrivateKey * ecPriv; |
- ECParams * ecParams; |
-#endif /* NSS_ENABLE_ECC */ |
- |
- CHECK_FORK(); |
- |
- if (!slot) { |
- return CKR_SESSION_HANDLE_INVALID; |
- } |
- /* |
- * now lets create an object to hang the attributes off of |
- */ |
- publicKey = sftk_NewObject(slot); /* fill in the handle later */ |
- if (publicKey == NULL) { |
- return CKR_HOST_MEMORY; |
- } |
- |
- /* |
- * load the template values into the publicKey |
- */ |
- for (i=0; i < (int) ulPublicKeyAttributeCount; i++) { |
- if (pPublicKeyTemplate[i].type == CKA_MODULUS_BITS) { |
- public_modulus_bits = *(CK_ULONG *)pPublicKeyTemplate[i].pValue; |
- continue; |
- } |
- |
- crv = sftk_AddAttributeType(publicKey, |
- sftk_attr_expand(&pPublicKeyTemplate[i])); |
- if (crv != CKR_OK) break; |
- } |
- |
- if (crv != CKR_OK) { |
- sftk_FreeObject(publicKey); |
- return CKR_HOST_MEMORY; |
- } |
- |
- privateKey = sftk_NewObject(slot); /* fill in the handle later */ |
- if (privateKey == NULL) { |
- sftk_FreeObject(publicKey); |
- return CKR_HOST_MEMORY; |
- } |
- /* |
- * now load the private key template |
- */ |
- for (i=0; i < (int) ulPrivateKeyAttributeCount; i++) { |
- if (pPrivateKeyTemplate[i].type == CKA_VALUE_BITS) { |
- private_value_bits = *(CK_ULONG *)pPrivateKeyTemplate[i].pValue; |
- continue; |
- } |
- |
- crv = sftk_AddAttributeType(privateKey, |
- sftk_attr_expand(&pPrivateKeyTemplate[i])); |
- if (crv != CKR_OK) break; |
- } |
- |
- if (crv != CKR_OK) { |
- sftk_FreeObject(publicKey); |
- sftk_FreeObject(privateKey); |
- return CKR_HOST_MEMORY; |
- } |
- sftk_DeleteAttributeType(privateKey,CKA_CLASS); |
- sftk_DeleteAttributeType(privateKey,CKA_KEY_TYPE); |
- sftk_DeleteAttributeType(privateKey,CKA_VALUE); |
- sftk_DeleteAttributeType(publicKey,CKA_CLASS); |
- sftk_DeleteAttributeType(publicKey,CKA_KEY_TYPE); |
- sftk_DeleteAttributeType(publicKey,CKA_VALUE); |
- |
- /* Now Set up the parameters to generate the key (based on mechanism) */ |
- switch (pMechanism->mechanism) { |
- case CKM_RSA_PKCS_KEY_PAIR_GEN: |
- /* format the keys */ |
- sftk_DeleteAttributeType(publicKey,CKA_MODULUS); |
- sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB); |
- sftk_DeleteAttributeType(privateKey,CKA_MODULUS); |
- sftk_DeleteAttributeType(privateKey,CKA_PRIVATE_EXPONENT); |
- sftk_DeleteAttributeType(privateKey,CKA_PUBLIC_EXPONENT); |
- sftk_DeleteAttributeType(privateKey,CKA_PRIME_1); |
- sftk_DeleteAttributeType(privateKey,CKA_PRIME_2); |
- sftk_DeleteAttributeType(privateKey,CKA_EXPONENT_1); |
- sftk_DeleteAttributeType(privateKey,CKA_EXPONENT_2); |
- sftk_DeleteAttributeType(privateKey,CKA_COEFFICIENT); |
- key_type = CKK_RSA; |
- if (public_modulus_bits == 0) { |
- crv = CKR_TEMPLATE_INCOMPLETE; |
- break; |
- } |
- if (public_modulus_bits < RSA_MIN_MODULUS_BITS) { |
- crv = CKR_ATTRIBUTE_VALUE_INVALID; |
- break; |
- } |
- if (public_modulus_bits % 2 != 0) { |
- crv = CKR_ATTRIBUTE_VALUE_INVALID; |
- break; |
- } |
- |
- /* extract the exponent */ |
- crv=sftk_Attribute2SSecItem(NULL,&pubExp,publicKey,CKA_PUBLIC_EXPONENT); |
- if (crv != CKR_OK) break; |
- bitSize = sftk_GetLengthInBits(pubExp.data, pubExp.len); |
- if (bitSize < 2) { |
- crv = CKR_ATTRIBUTE_VALUE_INVALID; |
- break; |
- } |
- crv = sftk_AddAttributeType(privateKey,CKA_PUBLIC_EXPONENT, |
- sftk_item_expand(&pubExp)); |
- if (crv != CKR_OK) { |
- PORT_Free(pubExp.data); |
- break; |
- } |
- |
- rsaPriv = RSA_NewKey(public_modulus_bits, &pubExp); |
- PORT_Free(pubExp.data); |
- if (rsaPriv == NULL) { |
- if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) { |
- sftk_fatalError = PR_TRUE; |
- } |
- crv = sftk_MapCryptError(PORT_GetError()); |
- break; |
- } |
- /* now fill in the RSA dependent paramenters in the public key */ |
- crv = sftk_AddAttributeType(publicKey,CKA_MODULUS, |
- sftk_item_expand(&rsaPriv->modulus)); |
- if (crv != CKR_OK) goto kpg_done; |
- /* now fill in the RSA dependent paramenters in the private key */ |
- crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB, |
- sftk_item_expand(&rsaPriv->modulus)); |
- if (crv != CKR_OK) goto kpg_done; |
- crv = sftk_AddAttributeType(privateKey,CKA_MODULUS, |
- sftk_item_expand(&rsaPriv->modulus)); |
- if (crv != CKR_OK) goto kpg_done; |
- crv = sftk_AddAttributeType(privateKey,CKA_PRIVATE_EXPONENT, |
- sftk_item_expand(&rsaPriv->privateExponent)); |
- if (crv != CKR_OK) goto kpg_done; |
- crv = sftk_AddAttributeType(privateKey,CKA_PRIME_1, |
- sftk_item_expand(&rsaPriv->prime1)); |
- if (crv != CKR_OK) goto kpg_done; |
- crv = sftk_AddAttributeType(privateKey,CKA_PRIME_2, |
- sftk_item_expand(&rsaPriv->prime2)); |
- if (crv != CKR_OK) goto kpg_done; |
- crv = sftk_AddAttributeType(privateKey,CKA_EXPONENT_1, |
- sftk_item_expand(&rsaPriv->exponent1)); |
- if (crv != CKR_OK) goto kpg_done; |
- crv = sftk_AddAttributeType(privateKey,CKA_EXPONENT_2, |
- sftk_item_expand(&rsaPriv->exponent2)); |
- if (crv != CKR_OK) goto kpg_done; |
- crv = sftk_AddAttributeType(privateKey,CKA_COEFFICIENT, |
- sftk_item_expand(&rsaPriv->coefficient)); |
-kpg_done: |
- /* Should zeroize the contents first, since this func doesn't. */ |
- PORT_FreeArena(rsaPriv->arena, PR_TRUE); |
- break; |
- case CKM_DSA_KEY_PAIR_GEN: |
- sftk_DeleteAttributeType(publicKey,CKA_VALUE); |
- sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB); |
- sftk_DeleteAttributeType(privateKey,CKA_PRIME); |
- sftk_DeleteAttributeType(privateKey,CKA_SUBPRIME); |
- sftk_DeleteAttributeType(privateKey,CKA_BASE); |
- key_type = CKK_DSA; |
- |
- /* extract the necessary parameters and copy them to the private key */ |
- crv=sftk_Attribute2SSecItem(NULL,&pqgParam.prime,publicKey,CKA_PRIME); |
- if (crv != CKR_OK) break; |
- crv=sftk_Attribute2SSecItem(NULL,&pqgParam.subPrime,publicKey, |
- CKA_SUBPRIME); |
- if (crv != CKR_OK) { |
- PORT_Free(pqgParam.prime.data); |
- break; |
- } |
- crv=sftk_Attribute2SSecItem(NULL,&pqgParam.base,publicKey,CKA_BASE); |
- if (crv != CKR_OK) { |
- PORT_Free(pqgParam.prime.data); |
- PORT_Free(pqgParam.subPrime.data); |
- break; |
- } |
- crv = sftk_AddAttributeType(privateKey,CKA_PRIME, |
- sftk_item_expand(&pqgParam.prime)); |
- if (crv != CKR_OK) { |
- PORT_Free(pqgParam.prime.data); |
- PORT_Free(pqgParam.subPrime.data); |
- PORT_Free(pqgParam.base.data); |
- break; |
- } |
- crv = sftk_AddAttributeType(privateKey,CKA_SUBPRIME, |
- sftk_item_expand(&pqgParam.subPrime)); |
- if (crv != CKR_OK) { |
- PORT_Free(pqgParam.prime.data); |
- PORT_Free(pqgParam.subPrime.data); |
- PORT_Free(pqgParam.base.data); |
- break; |
- } |
- crv = sftk_AddAttributeType(privateKey,CKA_BASE, |
- sftk_item_expand(&pqgParam.base)); |
- if (crv != CKR_OK) { |
- PORT_Free(pqgParam.prime.data); |
- PORT_Free(pqgParam.subPrime.data); |
- PORT_Free(pqgParam.base.data); |
- break; |
- } |
- |
- /* |
- * these are checked by DSA_NewKey |
- */ |
- bitSize = sftk_GetLengthInBits(pqgParam.subPrime.data, |
- pqgParam.subPrime.len); |
- if ((bitSize < DSA_MIN_Q_BITS) || (bitSize > DSA_MAX_Q_BITS)) { |
- crv = CKR_TEMPLATE_INCOMPLETE; |
- PORT_Free(pqgParam.prime.data); |
- PORT_Free(pqgParam.subPrime.data); |
- PORT_Free(pqgParam.base.data); |
- break; |
- } |
- bitSize = sftk_GetLengthInBits(pqgParam.prime.data,pqgParam.prime.len); |
- if ((bitSize < DSA_MIN_P_BITS) || (bitSize > DSA_MAX_P_BITS)) { |
- crv = CKR_TEMPLATE_INCOMPLETE; |
- PORT_Free(pqgParam.prime.data); |
- PORT_Free(pqgParam.subPrime.data); |
- PORT_Free(pqgParam.base.data); |
- break; |
- } |
- bitSize = sftk_GetLengthInBits(pqgParam.base.data,pqgParam.base.len); |
- if ((bitSize < 2) || (bitSize > DSA_MAX_P_BITS)) { |
- crv = CKR_TEMPLATE_INCOMPLETE; |
- PORT_Free(pqgParam.prime.data); |
- PORT_Free(pqgParam.subPrime.data); |
- PORT_Free(pqgParam.base.data); |
- break; |
- } |
- |
- /* Generate the key */ |
- rv = DSA_NewKey(&pqgParam, &dsaPriv); |
- |
- PORT_Free(pqgParam.prime.data); |
- PORT_Free(pqgParam.subPrime.data); |
- PORT_Free(pqgParam.base.data); |
- |
- if (rv != SECSuccess) { |
- if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) { |
- sftk_fatalError = PR_TRUE; |
- } |
- crv = sftk_MapCryptError(PORT_GetError()); |
- break; |
- } |
- |
- /* store the generated key into the attributes */ |
- crv = sftk_AddAttributeType(publicKey,CKA_VALUE, |
- sftk_item_expand(&dsaPriv->publicValue)); |
- if (crv != CKR_OK) goto dsagn_done; |
- |
- /* now fill in the RSA dependent paramenters in the private key */ |
- crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB, |
- sftk_item_expand(&dsaPriv->publicValue)); |
- if (crv != CKR_OK) goto dsagn_done; |
- crv = sftk_AddAttributeType(privateKey,CKA_VALUE, |
- sftk_item_expand(&dsaPriv->privateValue)); |
- |
-dsagn_done: |
- /* should zeroize, since this function doesn't. */ |
- PORT_FreeArena(dsaPriv->params.arena, PR_TRUE); |
- break; |
- |
- case CKM_DH_PKCS_KEY_PAIR_GEN: |
- sftk_DeleteAttributeType(privateKey,CKA_PRIME); |
- sftk_DeleteAttributeType(privateKey,CKA_BASE); |
- sftk_DeleteAttributeType(privateKey,CKA_VALUE); |
- sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB); |
- key_type = CKK_DH; |
- |
- /* extract the necessary parameters and copy them to private keys */ |
- crv = sftk_Attribute2SSecItem(NULL, &dhParam.prime, publicKey, |
- CKA_PRIME); |
- if (crv != CKR_OK) break; |
- crv = sftk_Attribute2SSecItem(NULL, &dhParam.base, publicKey, CKA_BASE); |
- if (crv != CKR_OK) { |
- PORT_Free(dhParam.prime.data); |
- break; |
- } |
- crv = sftk_AddAttributeType(privateKey, CKA_PRIME, |
- sftk_item_expand(&dhParam.prime)); |
- if (crv != CKR_OK) { |
- PORT_Free(dhParam.prime.data); |
- PORT_Free(dhParam.base.data); |
- break; |
- } |
- crv = sftk_AddAttributeType(privateKey, CKA_BASE, |
- sftk_item_expand(&dhParam.base)); |
- if (crv != CKR_OK) { |
- PORT_Free(dhParam.prime.data); |
- PORT_Free(dhParam.base.data); |
- break; |
- } |
- bitSize = sftk_GetLengthInBits(dhParam.prime.data,dhParam.prime.len); |
- if ((bitSize < DH_MIN_P_BITS) || (bitSize > DH_MAX_P_BITS)) { |
- crv = CKR_TEMPLATE_INCOMPLETE; |
- PORT_Free(dhParam.prime.data); |
- PORT_Free(dhParam.base.data); |
- break; |
- } |
- bitSize = sftk_GetLengthInBits(dhParam.base.data,dhParam.base.len); |
- if ((bitSize < 1) || (bitSize > DH_MAX_P_BITS)) { |
- crv = CKR_TEMPLATE_INCOMPLETE; |
- PORT_Free(dhParam.prime.data); |
- PORT_Free(dhParam.base.data); |
- break; |
- } |
- |
- rv = DH_NewKey(&dhParam, &dhPriv); |
- PORT_Free(dhParam.prime.data); |
- PORT_Free(dhParam.base.data); |
- if (rv != SECSuccess) { |
- if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) { |
- sftk_fatalError = PR_TRUE; |
- } |
- crv = sftk_MapCryptError(PORT_GetError()); |
- break; |
- } |
- |
- crv=sftk_AddAttributeType(publicKey, CKA_VALUE, |
- sftk_item_expand(&dhPriv->publicValue)); |
- if (crv != CKR_OK) goto dhgn_done; |
- |
- crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB, |
- sftk_item_expand(&dhPriv->publicValue)); |
- if (crv != CKR_OK) goto dhgn_done; |
- |
- crv=sftk_AddAttributeType(privateKey, CKA_VALUE, |
- sftk_item_expand(&dhPriv->privateValue)); |
- |
-dhgn_done: |
- /* should zeroize, since this function doesn't. */ |
- PORT_FreeArena(dhPriv->arena, PR_TRUE); |
- break; |
- |
-#ifdef NSS_ENABLE_ECC |
- case CKM_EC_KEY_PAIR_GEN: |
- sftk_DeleteAttributeType(privateKey,CKA_EC_PARAMS); |
- sftk_DeleteAttributeType(privateKey,CKA_VALUE); |
- sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB); |
- key_type = CKK_EC; |
- |
- /* extract the necessary parameters and copy them to private keys */ |
- crv = sftk_Attribute2SSecItem(NULL, &ecEncodedParams, publicKey, |
- CKA_EC_PARAMS); |
- if (crv != CKR_OK) break; |
- |
- crv = sftk_AddAttributeType(privateKey, CKA_EC_PARAMS, |
- sftk_item_expand(&ecEncodedParams)); |
- if (crv != CKR_OK) { |
- PORT_Free(ecEncodedParams.data); |
- break; |
- } |
- |
- /* Decode ec params before calling EC_NewKey */ |
- rv = EC_DecodeParams(&ecEncodedParams, &ecParams); |
- PORT_Free(ecEncodedParams.data); |
- if (rv != SECSuccess) { |
- crv = sftk_MapCryptError(PORT_GetError()); |
- break; |
- } |
- rv = EC_NewKey(ecParams, &ecPriv); |
- PORT_FreeArena(ecParams->arena, PR_TRUE); |
- if (rv != SECSuccess) { |
- if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) { |
- sftk_fatalError = PR_TRUE; |
- } |
- crv = sftk_MapCryptError(PORT_GetError()); |
- break; |
- } |
- |
- if (getenv("NSS_USE_DECODED_CKA_EC_POINT")) { |
- crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT, |
- sftk_item_expand(&ecPriv->publicValue)); |
- } else { |
- SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL, |
- &ecPriv->publicValue, |
- SEC_ASN1_GET(SEC_OctetStringTemplate)); |
- if (!pubValue) { |
- crv = CKR_ARGUMENTS_BAD; |
- goto ecgn_done; |
- } |
- crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT, |
- sftk_item_expand(pubValue)); |
- SECITEM_FreeItem(pubValue, PR_TRUE); |
- } |
- if (crv != CKR_OK) goto ecgn_done; |
- |
- crv = sftk_AddAttributeType(privateKey, CKA_VALUE, |
- sftk_item_expand(&ecPriv->privateValue)); |
- if (crv != CKR_OK) goto ecgn_done; |
- |
- crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB, |
- sftk_item_expand(&ecPriv->publicValue)); |
-ecgn_done: |
- /* should zeroize, since this function doesn't. */ |
- PORT_FreeArena(ecPriv->ecParams.arena, PR_TRUE); |
- break; |
-#endif /* NSS_ENABLE_ECC */ |
- |
- default: |
- crv = CKR_MECHANISM_INVALID; |
- } |
- |
- if (crv != CKR_OK) { |
- sftk_FreeObject(privateKey); |
- sftk_FreeObject(publicKey); |
- return crv; |
- } |
- |
- |
- /* Add the class, key_type The loop lets us check errors blow out |
- * on errors and clean up at the bottom */ |
- session = NULL; /* make pedtantic happy... session cannot leave the*/ |
- /* loop below NULL unless an error is set... */ |
- do { |
- crv = sftk_AddAttributeType(privateKey,CKA_CLASS,&privClass, |
- sizeof(CK_OBJECT_CLASS)); |
- if (crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(publicKey,CKA_CLASS,&pubClass, |
- sizeof(CK_OBJECT_CLASS)); |
- if (crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(privateKey,CKA_KEY_TYPE,&key_type, |
- sizeof(CK_KEY_TYPE)); |
- if (crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(publicKey,CKA_KEY_TYPE,&key_type, |
- sizeof(CK_KEY_TYPE)); |
- if (crv != CKR_OK) break; |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) crv = CKR_SESSION_HANDLE_INVALID; |
- } while (0); |
- |
- if (crv != CKR_OK) { |
- sftk_FreeObject(privateKey); |
- sftk_FreeObject(publicKey); |
- return crv; |
- } |
- |
- /* |
- * handle the base object cleanup for the public Key |
- */ |
- crv = sftk_handleObject(privateKey,session); |
- if (crv != CKR_OK) { |
- sftk_FreeSession(session); |
- sftk_FreeObject(privateKey); |
- sftk_FreeObject(publicKey); |
- return crv; |
- } |
- |
- /* |
- * handle the base object cleanup for the private Key |
- * If we have any problems, we destroy the public Key we've |
- * created and linked. |
- */ |
- crv = sftk_handleObject(publicKey,session); |
- sftk_FreeSession(session); |
- if (crv != CKR_OK) { |
- sftk_FreeObject(publicKey); |
- NSC_DestroyObject(hSession,privateKey->handle); |
- sftk_FreeObject(privateKey); |
- return crv; |
- } |
- if (sftk_isTrue(privateKey,CKA_SENSITIVE)) { |
- sftk_forceAttribute(privateKey,CKA_ALWAYS_SENSITIVE, |
- &cktrue,sizeof(CK_BBOOL)); |
- } |
- if (sftk_isTrue(publicKey,CKA_SENSITIVE)) { |
- sftk_forceAttribute(publicKey,CKA_ALWAYS_SENSITIVE, |
- &cktrue,sizeof(CK_BBOOL)); |
- } |
- if (!sftk_isTrue(privateKey,CKA_EXTRACTABLE)) { |
- sftk_forceAttribute(privateKey,CKA_NEVER_EXTRACTABLE, |
- &cktrue,sizeof(CK_BBOOL)); |
- } |
- if (!sftk_isTrue(publicKey,CKA_EXTRACTABLE)) { |
- sftk_forceAttribute(publicKey,CKA_NEVER_EXTRACTABLE, |
- &cktrue,sizeof(CK_BBOOL)); |
- } |
- |
- /* Perform FIPS 140-2 pairwise consistency check. */ |
- crv = sftk_PairwiseConsistencyCheck(hSession, |
- publicKey, privateKey, key_type); |
- if (crv != CKR_OK) { |
- NSC_DestroyObject(hSession,publicKey->handle); |
- sftk_FreeObject(publicKey); |
- NSC_DestroyObject(hSession,privateKey->handle); |
- sftk_FreeObject(privateKey); |
- if (sftk_audit_enabled) { |
- char msg[128]; |
- PR_snprintf(msg,sizeof msg, |
- "C_GenerateKeyPair(hSession=0x%08lX, " |
- "pMechanism->mechanism=0x%08lX)=0x%08lX " |
- "self-test: pair-wise consistency test failed", |
- (PRUint32)hSession,(PRUint32)pMechanism->mechanism, |
- (PRUint32)crv); |
- sftk_LogAuditMessage(NSS_AUDIT_ERROR, NSS_AUDIT_SELF_TEST, msg); |
- } |
- return crv; |
- } |
- |
- *phPrivateKey = privateKey->handle; |
- *phPublicKey = publicKey->handle; |
- sftk_FreeObject(publicKey); |
- sftk_FreeObject(privateKey); |
- |
- return CKR_OK; |
-} |
- |
-static SECItem *sftk_PackagePrivateKey(SFTKObject *key, CK_RV *crvp) |
-{ |
- NSSLOWKEYPrivateKey *lk = NULL; |
- NSSLOWKEYPrivateKeyInfo *pki = NULL; |
- SFTKAttribute *attribute = NULL; |
- PLArenaPool *arena = NULL; |
- SECOidTag algorithm = SEC_OID_UNKNOWN; |
- void *dummy, *param = NULL; |
- SECStatus rv = SECSuccess; |
- SECItem *encodedKey = NULL; |
-#ifdef NSS_ENABLE_ECC |
- SECItem *fordebug; |
- int savelen; |
-#endif |
- |
- if(!key) { |
- *crvp = CKR_KEY_HANDLE_INVALID; /* really can't happen */ |
- return NULL; |
- } |
- |
- attribute = sftk_FindAttribute(key, CKA_KEY_TYPE); |
- if(!attribute) { |
- *crvp = CKR_KEY_TYPE_INCONSISTENT; |
- return NULL; |
- } |
- |
- lk = sftk_GetPrivKey(key, *(CK_KEY_TYPE *)attribute->attrib.pValue, crvp); |
- sftk_FreeAttribute(attribute); |
- if(!lk) { |
- return NULL; |
- } |
- |
- arena = PORT_NewArena(2048); /* XXX different size? */ |
- if(!arena) { |
- *crvp = CKR_HOST_MEMORY; |
- rv = SECFailure; |
- goto loser; |
- } |
- |
- pki = (NSSLOWKEYPrivateKeyInfo*)PORT_ArenaZAlloc(arena, |
- sizeof(NSSLOWKEYPrivateKeyInfo)); |
- if(!pki) { |
- *crvp = CKR_HOST_MEMORY; |
- rv = SECFailure; |
- goto loser; |
- } |
- pki->arena = arena; |
- |
- param = NULL; |
- switch(lk->keyType) { |
- case NSSLOWKEYRSAKey: |
- prepare_low_rsa_priv_key_for_asn1(lk); |
- dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk, |
- nsslowkey_RSAPrivateKeyTemplate); |
- algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION; |
- break; |
- case NSSLOWKEYDSAKey: |
- prepare_low_dsa_priv_key_export_for_asn1(lk); |
- dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk, |
- nsslowkey_DSAPrivateKeyExportTemplate); |
- prepare_low_pqg_params_for_asn1(&lk->u.dsa.params); |
- param = SEC_ASN1EncodeItem(NULL, NULL, &(lk->u.dsa.params), |
- nsslowkey_PQGParamsTemplate); |
- algorithm = SEC_OID_ANSIX9_DSA_SIGNATURE; |
- break; |
-#ifdef NSS_ENABLE_ECC |
- case NSSLOWKEYECKey: |
- prepare_low_ec_priv_key_for_asn1(lk); |
- /* Public value is encoded as a bit string so adjust length |
- * to be in bits before ASN encoding and readjust |
- * immediately after. |
- * |
- * Since the SECG specification recommends not including the |
- * parameters as part of ECPrivateKey, we zero out the curveOID |
- * length before encoding and restore it later. |
- */ |
- lk->u.ec.publicValue.len <<= 3; |
- savelen = lk->u.ec.ecParams.curveOID.len; |
- lk->u.ec.ecParams.curveOID.len = 0; |
- dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk, |
- nsslowkey_ECPrivateKeyTemplate); |
- lk->u.ec.ecParams.curveOID.len = savelen; |
- lk->u.ec.publicValue.len >>= 3; |
- |
- fordebug = &pki->privateKey; |
- SEC_PRINT("sftk_PackagePrivateKey()", "PrivateKey", lk->keyType, |
- fordebug); |
- |
- param = SECITEM_DupItem(&lk->u.ec.ecParams.DEREncoding); |
- |
- algorithm = SEC_OID_ANSIX962_EC_PUBLIC_KEY; |
- break; |
-#endif /* NSS_ENABLE_ECC */ |
- case NSSLOWKEYDHKey: |
- default: |
- dummy = NULL; |
- break; |
- } |
- |
- if(!dummy || ((lk->keyType == NSSLOWKEYDSAKey) && !param)) { |
- *crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */ |
- rv = SECFailure; |
- goto loser; |
- } |
- |
- rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, algorithm, |
- (SECItem*)param); |
- if(rv != SECSuccess) { |
- *crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */ |
- rv = SECFailure; |
- goto loser; |
- } |
- |
- dummy = SEC_ASN1EncodeInteger(arena, &pki->version, |
- NSSLOWKEY_PRIVATE_KEY_INFO_VERSION); |
- if(!dummy) { |
- *crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */ |
- rv = SECFailure; |
- goto loser; |
- } |
- |
- encodedKey = SEC_ASN1EncodeItem(NULL, NULL, pki, |
- nsslowkey_PrivateKeyInfoTemplate); |
- *crvp = encodedKey ? CKR_OK : CKR_DEVICE_ERROR; |
- |
-#ifdef NSS_ENABLE_ECC |
- fordebug = encodedKey; |
- SEC_PRINT("sftk_PackagePrivateKey()", "PrivateKeyInfo", lk->keyType, |
- fordebug); |
-#endif |
-loser: |
- if(arena) { |
- PORT_FreeArena(arena, PR_TRUE); |
- } |
- |
- if(lk && (lk != key->objectInfo)) { |
- nsslowkey_DestroyPrivateKey(lk); |
- } |
- |
- if(param) { |
- SECITEM_ZfreeItem((SECItem*)param, PR_TRUE); |
- } |
- |
- if(rv != SECSuccess) { |
- return NULL; |
- } |
- |
- return encodedKey; |
-} |
- |
-/* it doesn't matter yet, since we colapse error conditions in the |
- * level above, but we really should map those few key error differences */ |
-static CK_RV |
-sftk_mapWrap(CK_RV crv) |
-{ |
- switch (crv) { |
- case CKR_ENCRYPTED_DATA_INVALID: crv = CKR_WRAPPED_KEY_INVALID; break; |
- } |
- return crv; |
-} |
- |
-/* NSC_WrapKey wraps (i.e., encrypts) a key. */ |
-CK_RV NSC_WrapKey(CK_SESSION_HANDLE hSession, |
- CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, |
- CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey, |
- CK_ULONG_PTR pulWrappedKeyLen) |
-{ |
- SFTKSession *session; |
- SFTKAttribute *attribute; |
- SFTKObject *key; |
- CK_RV crv; |
- |
- CHECK_FORK(); |
- |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) { |
- return CKR_SESSION_HANDLE_INVALID; |
- } |
- |
- key = sftk_ObjectFromHandle(hKey,session); |
- sftk_FreeSession(session); |
- if (key == NULL) { |
- return CKR_KEY_HANDLE_INVALID; |
- } |
- |
- switch(key->objclass) { |
- case CKO_SECRET_KEY: |
- { |
- SFTKSessionContext *context = NULL; |
- SECItem pText; |
- |
- attribute = sftk_FindAttribute(key,CKA_VALUE); |
- |
- if (attribute == NULL) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- crv = sftk_CryptInit(hSession, pMechanism, hWrappingKey, |
- CKA_WRAP, CKA_WRAP, SFTK_ENCRYPT, PR_TRUE); |
- if (crv != CKR_OK) { |
- sftk_FreeAttribute(attribute); |
- break; |
- } |
- |
- pText.type = siBuffer; |
- pText.data = (unsigned char *)attribute->attrib.pValue; |
- pText.len = attribute->attrib.ulValueLen; |
- |
- /* Find out if this is a block cipher. */ |
- crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_FALSE,NULL); |
- if (crv != CKR_OK || !context) |
- break; |
- if (context->blockSize > 1) { |
- unsigned int remainder = pText.len % context->blockSize; |
- if (!context->doPad && remainder) { |
- /* When wrapping secret keys with unpadded block ciphers, |
- ** the keys are zero padded, if necessary, to fill out |
- ** a full block. |
- */ |
- pText.len += context->blockSize - remainder; |
- pText.data = PORT_ZAlloc(pText.len); |
- if (pText.data) |
- memcpy(pText.data, attribute->attrib.pValue, |
- attribute->attrib.ulValueLen); |
- else { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- } |
- } |
- |
- crv = NSC_Encrypt(hSession, (CK_BYTE_PTR)pText.data, |
- pText.len, pWrappedKey, pulWrappedKeyLen); |
- /* always force a finalize, both on errors and when |
- * we are just getting the size */ |
- if (crv != CKR_OK || pWrappedKey == NULL) { |
- CK_RV lcrv ; |
- lcrv = sftk_GetContext(hSession,&context, |
- SFTK_ENCRYPT,PR_FALSE,NULL); |
- sftk_SetContextByType(session, SFTK_ENCRYPT, NULL); |
- if (lcrv == CKR_OK && context) { |
- sftk_FreeContext(context); |
- } |
- } |
- |
- if (pText.data != (unsigned char *)attribute->attrib.pValue) |
- PORT_ZFree(pText.data, pText.len); |
- sftk_FreeAttribute(attribute); |
- break; |
- } |
- |
- case CKO_PRIVATE_KEY: |
- { |
- SECItem *bpki = sftk_PackagePrivateKey(key, &crv); |
- SFTKSessionContext *context = NULL; |
- |
- if(!bpki) { |
- break; |
- } |
- |
- crv = sftk_CryptInit(hSession, pMechanism, hWrappingKey, |
- CKA_WRAP, CKA_WRAP, SFTK_ENCRYPT, PR_TRUE); |
- if(crv != CKR_OK) { |
- SECITEM_ZfreeItem(bpki, PR_TRUE); |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- |
- crv = NSC_Encrypt(hSession, bpki->data, bpki->len, |
- pWrappedKey, pulWrappedKeyLen); |
- /* always force a finalize */ |
- if (crv != CKR_OK || pWrappedKey == NULL) { |
- CK_RV lcrv ; |
- lcrv = sftk_GetContext(hSession,&context, |
- SFTK_ENCRYPT,PR_FALSE,NULL); |
- sftk_SetContextByType(session, SFTK_ENCRYPT, NULL); |
- if (lcrv == CKR_OK && context) { |
- sftk_FreeContext(context); |
- } |
- } |
- SECITEM_ZfreeItem(bpki, PR_TRUE); |
- break; |
- } |
- |
- default: |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- sftk_FreeObject(key); |
- |
- return sftk_mapWrap(crv); |
-} |
- |
-/* |
- * import a pprivate key info into the desired slot |
- */ |
-static SECStatus |
-sftk_unwrapPrivateKey(SFTKObject *key, SECItem *bpki) |
-{ |
- CK_BBOOL cktrue = CK_TRUE; |
- CK_KEY_TYPE keyType = CKK_RSA; |
- SECStatus rv = SECFailure; |
- const SEC_ASN1Template *keyTemplate, *paramTemplate; |
- void *paramDest = NULL; |
- PLArenaPool *arena; |
- NSSLOWKEYPrivateKey *lpk = NULL; |
- NSSLOWKEYPrivateKeyInfo *pki = NULL; |
- CK_RV crv = CKR_KEY_TYPE_INCONSISTENT; |
- |
- arena = PORT_NewArena(2048); |
- if(!arena) { |
- return SECFailure; |
- } |
- |
- pki = (NSSLOWKEYPrivateKeyInfo*)PORT_ArenaZAlloc(arena, |
- sizeof(NSSLOWKEYPrivateKeyInfo)); |
- if(!pki) { |
- PORT_FreeArena(arena, PR_FALSE); |
- return SECFailure; |
- } |
- |
- if(SEC_ASN1DecodeItem(arena, pki, nsslowkey_PrivateKeyInfoTemplate, bpki) |
- != SECSuccess) { |
- PORT_FreeArena(arena, PR_TRUE); |
- return SECFailure; |
- } |
- |
- lpk = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(arena, |
- sizeof(NSSLOWKEYPrivateKey)); |
- if(lpk == NULL) { |
- goto loser; |
- } |
- lpk->arena = arena; |
- |
- switch(SECOID_GetAlgorithmTag(&pki->algorithm)) { |
- case SEC_OID_PKCS1_RSA_ENCRYPTION: |
- keyTemplate = nsslowkey_RSAPrivateKeyTemplate; |
- paramTemplate = NULL; |
- paramDest = NULL; |
- lpk->keyType = NSSLOWKEYRSAKey; |
- prepare_low_rsa_priv_key_for_asn1(lpk); |
- break; |
- case SEC_OID_ANSIX9_DSA_SIGNATURE: |
- keyTemplate = nsslowkey_DSAPrivateKeyExportTemplate; |
- paramTemplate = nsslowkey_PQGParamsTemplate; |
- paramDest = &(lpk->u.dsa.params); |
- lpk->keyType = NSSLOWKEYDSAKey; |
- prepare_low_dsa_priv_key_export_for_asn1(lpk); |
- prepare_low_pqg_params_for_asn1(&lpk->u.dsa.params); |
- break; |
- /* case NSSLOWKEYDHKey: */ |
-#ifdef NSS_ENABLE_ECC |
- case SEC_OID_ANSIX962_EC_PUBLIC_KEY: |
- keyTemplate = nsslowkey_ECPrivateKeyTemplate; |
- paramTemplate = NULL; |
- paramDest = &(lpk->u.ec.ecParams.DEREncoding); |
- lpk->keyType = NSSLOWKEYECKey; |
- prepare_low_ec_priv_key_for_asn1(lpk); |
- prepare_low_ecparams_for_asn1(&lpk->u.ec.ecParams); |
- break; |
-#endif /* NSS_ENABLE_ECC */ |
- default: |
- keyTemplate = NULL; |
- paramTemplate = NULL; |
- paramDest = NULL; |
- break; |
- } |
- |
- if(!keyTemplate) { |
- goto loser; |
- } |
- |
- /* decode the private key and any algorithm parameters */ |
- rv = SEC_QuickDERDecodeItem(arena, lpk, keyTemplate, &pki->privateKey); |
- |
-#ifdef NSS_ENABLE_ECC |
- if (lpk->keyType == NSSLOWKEYECKey) { |
- /* convert length in bits to length in bytes */ |
- lpk->u.ec.publicValue.len >>= 3; |
- rv = SECITEM_CopyItem(arena, |
- &(lpk->u.ec.ecParams.DEREncoding), |
- &(pki->algorithm.parameters)); |
- if(rv != SECSuccess) { |
- goto loser; |
- } |
- } |
-#endif /* NSS_ENABLE_ECC */ |
- |
- if(rv != SECSuccess) { |
- goto loser; |
- } |
- if(paramDest && paramTemplate) { |
- rv = SEC_QuickDERDecodeItem(arena, paramDest, paramTemplate, |
- &(pki->algorithm.parameters)); |
- if(rv != SECSuccess) { |
- goto loser; |
- } |
- } |
- |
- rv = SECFailure; |
- |
- switch (lpk->keyType) { |
- case NSSLOWKEYRSAKey: |
- keyType = CKK_RSA; |
- if(sftk_hasAttribute(key, CKA_NETSCAPE_DB)) { |
- sftk_DeleteAttributeType(key, CKA_NETSCAPE_DB); |
- } |
- crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, |
- sizeof(keyType)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_UNWRAP, &cktrue, |
- sizeof(CK_BBOOL)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_DECRYPT, &cktrue, |
- sizeof(CK_BBOOL)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, |
- sizeof(CK_BBOOL)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue, |
- sizeof(CK_BBOOL)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_MODULUS, |
- sftk_item_expand(&lpk->u.rsa.modulus)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_PUBLIC_EXPONENT, |
- sftk_item_expand(&lpk->u.rsa.publicExponent)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_PRIVATE_EXPONENT, |
- sftk_item_expand(&lpk->u.rsa.privateExponent)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_PRIME_1, |
- sftk_item_expand(&lpk->u.rsa.prime1)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_PRIME_2, |
- sftk_item_expand(&lpk->u.rsa.prime2)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_EXPONENT_1, |
- sftk_item_expand(&lpk->u.rsa.exponent1)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_EXPONENT_2, |
- sftk_item_expand(&lpk->u.rsa.exponent2)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_COEFFICIENT, |
- sftk_item_expand(&lpk->u.rsa.coefficient)); |
- break; |
- case NSSLOWKEYDSAKey: |
- keyType = CKK_DSA; |
- crv = (sftk_hasAttribute(key, CKA_NETSCAPE_DB)) ? CKR_OK : |
- CKR_KEY_TYPE_INCONSISTENT; |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, |
- sizeof(keyType)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, |
- sizeof(CK_BBOOL)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue, |
- sizeof(CK_BBOOL)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_PRIME, |
- sftk_item_expand(&lpk->u.dsa.params.prime)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_SUBPRIME, |
- sftk_item_expand(&lpk->u.dsa.params.subPrime)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_BASE, |
- sftk_item_expand(&lpk->u.dsa.params.base)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_VALUE, |
- sftk_item_expand(&lpk->u.dsa.privateValue)); |
- if(crv != CKR_OK) break; |
- break; |
-#ifdef notdef |
- case NSSLOWKEYDHKey: |
- template = dhTemplate; |
- templateCount = sizeof(dhTemplate)/sizeof(CK_ATTRIBUTE); |
- keyType = CKK_DH; |
- break; |
-#endif |
- /* what about fortezza??? */ |
-#ifdef NSS_ENABLE_ECC |
- case NSSLOWKEYECKey: |
- keyType = CKK_EC; |
- crv = (sftk_hasAttribute(key, CKA_NETSCAPE_DB)) ? CKR_OK : |
- CKR_KEY_TYPE_INCONSISTENT; |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, |
- sizeof(keyType)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, |
- sizeof(CK_BBOOL)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue, |
- sizeof(CK_BBOOL)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_DERIVE, &cktrue, |
- sizeof(CK_BBOOL)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_EC_PARAMS, |
- sftk_item_expand(&lpk->u.ec.ecParams.DEREncoding)); |
- if(crv != CKR_OK) break; |
- crv = sftk_AddAttributeType(key, CKA_VALUE, |
- sftk_item_expand(&lpk->u.ec.privateValue)); |
- if(crv != CKR_OK) break; |
- /* XXX Do we need to decode the EC Params here ?? */ |
- break; |
-#endif /* NSS_ENABLE_ECC */ |
- default: |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- |
-loser: |
- if(lpk) { |
- nsslowkey_DestroyPrivateKey(lpk); |
- } |
- |
- if(crv != CKR_OK) { |
- return SECFailure; |
- } |
- |
- return SECSuccess; |
-} |
- |
- |
-/* NSC_UnwrapKey unwraps (decrypts) a wrapped key, creating a new key object. */ |
-CK_RV NSC_UnwrapKey(CK_SESSION_HANDLE hSession, |
- CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey, |
- CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, |
- CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, |
- CK_OBJECT_HANDLE_PTR phKey) |
-{ |
- SFTKObject *key = NULL; |
- SFTKSession *session; |
- CK_ULONG key_length = 0; |
- unsigned char * buf = NULL; |
- CK_RV crv = CKR_OK; |
- int i; |
- CK_ULONG bsize = ulWrappedKeyLen; |
- SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession); |
- SECItem bpki; |
- CK_OBJECT_CLASS target_type = CKO_SECRET_KEY; |
- |
- CHECK_FORK(); |
- |
- if (!slot) { |
- return CKR_SESSION_HANDLE_INVALID; |
- } |
- /* |
- * now lets create an object to hang the attributes off of |
- */ |
- key = sftk_NewObject(slot); /* fill in the handle later */ |
- if (key == NULL) { |
- return CKR_HOST_MEMORY; |
- } |
- |
- /* |
- * load the template values into the object |
- */ |
- for (i=0; i < (int) ulAttributeCount; i++) { |
- if (pTemplate[i].type == CKA_VALUE_LEN) { |
- key_length = *(CK_ULONG *)pTemplate[i].pValue; |
- continue; |
- } |
- if (pTemplate[i].type == CKA_CLASS) { |
- target_type = *(CK_OBJECT_CLASS *)pTemplate[i].pValue; |
- } |
- crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i])); |
- if (crv != CKR_OK) break; |
- } |
- if (crv != CKR_OK) { |
- sftk_FreeObject(key); |
- return crv; |
- } |
- |
- crv = sftk_CryptInit(hSession,pMechanism,hUnwrappingKey,CKA_UNWRAP, |
- CKA_UNWRAP, SFTK_DECRYPT, PR_FALSE); |
- if (crv != CKR_OK) { |
- sftk_FreeObject(key); |
- return sftk_mapWrap(crv); |
- } |
- |
- /* allocate the buffer to decrypt into |
- * this assumes the unwrapped key is never larger than the |
- * wrapped key. For all the mechanisms we support this is true */ |
- buf = (unsigned char *)PORT_Alloc( ulWrappedKeyLen); |
- bsize = ulWrappedKeyLen; |
- |
- crv = NSC_Decrypt(hSession, pWrappedKey, ulWrappedKeyLen, buf, &bsize); |
- if (crv != CKR_OK) { |
- sftk_FreeObject(key); |
- PORT_Free(buf); |
- return sftk_mapWrap(crv); |
- } |
- |
- switch(target_type) { |
- case CKO_SECRET_KEY: |
- if (!sftk_hasAttribute(key,CKA_KEY_TYPE)) { |
- crv = CKR_TEMPLATE_INCOMPLETE; |
- break; |
- } |
- |
- if (key_length == 0 || key_length > bsize) { |
- key_length = bsize; |
- } |
- if (key_length > MAX_KEY_LEN) { |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- break; |
- } |
- |
- /* add the value */ |
- crv = sftk_AddAttributeType(key,CKA_VALUE,buf,key_length); |
- break; |
- case CKO_PRIVATE_KEY: |
- bpki.data = (unsigned char *)buf; |
- bpki.len = bsize; |
- crv = CKR_OK; |
- if(sftk_unwrapPrivateKey(key, &bpki) != SECSuccess) { |
- crv = CKR_TEMPLATE_INCOMPLETE; |
- } |
- break; |
- default: |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- break; |
- } |
- |
- PORT_ZFree(buf, bsize); |
- if (crv != CKR_OK) { sftk_FreeObject(key); return crv; } |
- |
- /* get the session */ |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) { |
- sftk_FreeObject(key); |
- return CKR_SESSION_HANDLE_INVALID; |
- } |
- |
- /* |
- * handle the base object stuff |
- */ |
- crv = sftk_handleObject(key,session); |
- *phKey = key->handle; |
- sftk_FreeSession(session); |
- sftk_FreeObject(key); |
- |
- return crv; |
- |
-} |
- |
-/* |
- * The SSL key gen mechanism create's lots of keys. This function handles the |
- * details of each of these key creation. |
- */ |
-static CK_RV |
-sftk_buildSSLKey(CK_SESSION_HANDLE hSession, SFTKObject *baseKey, |
- PRBool isMacKey, unsigned char *keyBlock, unsigned int keySize, |
- CK_OBJECT_HANDLE *keyHandle) |
-{ |
- SFTKObject *key; |
- SFTKSession *session; |
- CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; |
- CK_BBOOL cktrue = CK_TRUE; |
- CK_BBOOL ckfalse = CK_FALSE; |
- CK_RV crv = CKR_HOST_MEMORY; |
- |
- /* |
- * now lets create an object to hang the attributes off of |
- */ |
- *keyHandle = CK_INVALID_HANDLE; |
- key = sftk_NewObject(baseKey->slot); |
- if (key == NULL) return CKR_HOST_MEMORY; |
- sftk_narrowToSessionObject(key)->wasDerived = PR_TRUE; |
- |
- crv = sftk_CopyObject(key,baseKey); |
- if (crv != CKR_OK) goto loser; |
- if (isMacKey) { |
- crv = sftk_forceAttribute(key,CKA_KEY_TYPE,&keyType,sizeof(keyType)); |
- if (crv != CKR_OK) goto loser; |
- crv = sftk_forceAttribute(key,CKA_DERIVE,&cktrue,sizeof(CK_BBOOL)); |
- if (crv != CKR_OK) goto loser; |
- crv = sftk_forceAttribute(key,CKA_ENCRYPT,&ckfalse,sizeof(CK_BBOOL)); |
- if (crv != CKR_OK) goto loser; |
- crv = sftk_forceAttribute(key,CKA_DECRYPT,&ckfalse,sizeof(CK_BBOOL)); |
- if (crv != CKR_OK) goto loser; |
- crv = sftk_forceAttribute(key,CKA_SIGN,&cktrue,sizeof(CK_BBOOL)); |
- if (crv != CKR_OK) goto loser; |
- crv = sftk_forceAttribute(key,CKA_VERIFY,&cktrue,sizeof(CK_BBOOL)); |
- if (crv != CKR_OK) goto loser; |
- crv = sftk_forceAttribute(key,CKA_WRAP,&ckfalse,sizeof(CK_BBOOL)); |
- if (crv != CKR_OK) goto loser; |
- crv = sftk_forceAttribute(key,CKA_UNWRAP,&ckfalse,sizeof(CK_BBOOL)); |
- if (crv != CKR_OK) goto loser; |
- } |
- crv = sftk_forceAttribute(key,CKA_VALUE,keyBlock,keySize); |
- if (crv != CKR_OK) goto loser; |
- |
- /* get the session */ |
- crv = CKR_HOST_MEMORY; |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) { goto loser; } |
- |
- crv = sftk_handleObject(key,session); |
- sftk_FreeSession(session); |
- *keyHandle = key->handle; |
-loser: |
- if (key) sftk_FreeObject(key); |
- return crv; |
-} |
- |
-/* |
- * if there is an error, we need to free the keys we already created in SSL |
- * This is the routine that will do it.. |
- */ |
-static void |
-sftk_freeSSLKeys(CK_SESSION_HANDLE session, |
- CK_SSL3_KEY_MAT_OUT *returnedMaterial ) |
-{ |
- if (returnedMaterial->hClientMacSecret != CK_INVALID_HANDLE) { |
- NSC_DestroyObject(session,returnedMaterial->hClientMacSecret); |
- } |
- if (returnedMaterial->hServerMacSecret != CK_INVALID_HANDLE) { |
- NSC_DestroyObject(session, returnedMaterial->hServerMacSecret); |
- } |
- if (returnedMaterial->hClientKey != CK_INVALID_HANDLE) { |
- NSC_DestroyObject(session, returnedMaterial->hClientKey); |
- } |
- if (returnedMaterial->hServerKey != CK_INVALID_HANDLE) { |
- NSC_DestroyObject(session, returnedMaterial->hServerKey); |
- } |
-} |
- |
-/* |
- * when deriving from sensitive and extractable keys, we need to preserve some |
- * of the semantics in the derived key. This helper routine maintains these |
- * semantics. |
- */ |
-static CK_RV |
-sftk_DeriveSensitiveCheck(SFTKObject *baseKey,SFTKObject *destKey) |
-{ |
- PRBool hasSensitive; |
- PRBool sensitive = PR_FALSE; |
- PRBool hasExtractable; |
- PRBool extractable = PR_TRUE; |
- CK_RV crv = CKR_OK; |
- SFTKAttribute *att; |
- |
- hasSensitive = PR_FALSE; |
- att = sftk_FindAttribute(destKey,CKA_SENSITIVE); |
- if (att) { |
- hasSensitive = PR_TRUE; |
- sensitive = (PRBool) *(CK_BBOOL *)att->attrib.pValue; |
- sftk_FreeAttribute(att); |
- } |
- |
- hasExtractable = PR_FALSE; |
- att = sftk_FindAttribute(destKey,CKA_EXTRACTABLE); |
- if (att) { |
- hasExtractable = PR_TRUE; |
- extractable = (PRBool) *(CK_BBOOL *)att->attrib.pValue; |
- sftk_FreeAttribute(att); |
- } |
- |
- |
- /* don't make a key more accessible */ |
- if (sftk_isTrue(baseKey,CKA_SENSITIVE) && hasSensitive && |
- (sensitive == PR_FALSE)) { |
- return CKR_KEY_FUNCTION_NOT_PERMITTED; |
- } |
- if (!sftk_isTrue(baseKey,CKA_EXTRACTABLE) && hasExtractable && |
- (extractable == PR_TRUE)) { |
- return CKR_KEY_FUNCTION_NOT_PERMITTED; |
- } |
- |
- /* inherit parent's sensitivity */ |
- if (!hasSensitive) { |
- att = sftk_FindAttribute(baseKey,CKA_SENSITIVE); |
- if (att == NULL) return CKR_KEY_TYPE_INCONSISTENT; |
- crv = sftk_defaultAttribute(destKey,sftk_attr_expand(&att->attrib)); |
- sftk_FreeAttribute(att); |
- if (crv != CKR_OK) return crv; |
- } |
- if (!hasExtractable) { |
- att = sftk_FindAttribute(baseKey,CKA_EXTRACTABLE); |
- if (att == NULL) return CKR_KEY_TYPE_INCONSISTENT; |
- crv = sftk_defaultAttribute(destKey,sftk_attr_expand(&att->attrib)); |
- sftk_FreeAttribute(att); |
- if (crv != CKR_OK) return crv; |
- } |
- |
- /* we should inherit the parent's always extractable/ never sensitive info, |
- * but handleObject always forces this attributes, so we would need to do |
- * something special. */ |
- return CKR_OK; |
-} |
- |
-/* |
- * make known fixed PKCS #11 key types to their sizes in bytes |
- */ |
-unsigned long |
-sftk_MapKeySize(CK_KEY_TYPE keyType) |
-{ |
- switch (keyType) { |
- case CKK_CDMF: |
- return 8; |
- case CKK_DES: |
- return 8; |
- case CKK_DES2: |
- return 16; |
- case CKK_DES3: |
- return 24; |
- /* IDEA and CAST need to be added */ |
- default: |
- break; |
- } |
- return 0; |
-} |
- |
-/* Inputs: |
- * key_len: Length of derived key to be generated. |
- * SharedSecret: a shared secret that is the output of a key agreement primitive. |
- * SharedInfo: (Optional) some data shared by the entities computing the secret key. |
- * SharedInfoLen: the length in octets of SharedInfo |
- * Hash: The hash function to be used in the KDF |
- * HashLen: the length in octets of the output of Hash |
- * Output: |
- * key: Pointer to a buffer containing derived key, if return value is SECSuccess. |
- */ |
-static CK_RV sftk_compute_ANSI_X9_63_kdf(CK_BYTE **key, CK_ULONG key_len, SECItem *SharedSecret, |
- CK_BYTE_PTR SharedInfo, CK_ULONG SharedInfoLen, |
- SECStatus Hash(unsigned char *, const unsigned char *, uint32), |
- CK_ULONG HashLen) |
-{ |
- unsigned char *buffer = NULL, *output_buffer = NULL; |
- uint32 buffer_len, max_counter, i; |
- SECStatus rv; |
- |
- /* Check that key_len isn't too long. The maximum key length could be |
- * greatly increased if the code below did not limit the 4-byte counter |
- * to a maximum value of 255. */ |
- if (key_len > 254 * HashLen) |
- return SEC_ERROR_INVALID_ARGS; |
- |
- if (SharedInfo == NULL) |
- SharedInfoLen = 0; |
- |
- buffer_len = SharedSecret->len + 4 + SharedInfoLen; |
- buffer = (CK_BYTE *)PORT_Alloc(buffer_len); |
- if (buffer == NULL) { |
- rv = SEC_ERROR_NO_MEMORY; |
- goto loser; |
- } |
- |
- max_counter = key_len/HashLen; |
- if (key_len > max_counter * HashLen) |
- max_counter++; |
- |
- output_buffer = (CK_BYTE *)PORT_Alloc(max_counter * HashLen); |
- if (output_buffer == NULL) { |
- rv = SEC_ERROR_NO_MEMORY; |
- goto loser; |
- } |
- |
- /* Populate buffer with SharedSecret || Counter || [SharedInfo] |
- * where Counter is 0x00000001 */ |
- PORT_Memcpy(buffer, SharedSecret->data, SharedSecret->len); |
- buffer[SharedSecret->len] = 0; |
- buffer[SharedSecret->len + 1] = 0; |
- buffer[SharedSecret->len + 2] = 0; |
- buffer[SharedSecret->len + 3] = 1; |
- if (SharedInfo) { |
- PORT_Memcpy(&buffer[SharedSecret->len + 4], SharedInfo, SharedInfoLen); |
- } |
- |
- for(i=0; i < max_counter; i++) { |
- rv = Hash(&output_buffer[i * HashLen], buffer, buffer_len); |
- if (rv != SECSuccess) |
- goto loser; |
- |
- /* Increment counter (assumes max_counter < 255) */ |
- buffer[SharedSecret->len + 3]++; |
- } |
- |
- PORT_ZFree(buffer, buffer_len); |
- if (key_len < max_counter * HashLen) { |
- PORT_Memset(output_buffer + key_len, 0, max_counter * HashLen - key_len); |
- } |
- *key = output_buffer; |
- |
- return SECSuccess; |
- |
- loser: |
- if (buffer) { |
- PORT_ZFree(buffer, buffer_len); |
- } |
- if (output_buffer) { |
- PORT_ZFree(output_buffer, max_counter * HashLen); |
- } |
- return rv; |
-} |
- |
-static CK_RV sftk_ANSI_X9_63_kdf(CK_BYTE **key, CK_ULONG key_len, |
- SECItem *SharedSecret, |
- CK_BYTE_PTR SharedInfo, CK_ULONG SharedInfoLen, |
- CK_EC_KDF_TYPE kdf) |
-{ |
- if (kdf == CKD_SHA1_KDF) |
- return sftk_compute_ANSI_X9_63_kdf(key, key_len, SharedSecret, SharedInfo, |
- SharedInfoLen, SHA1_HashBuf, SHA1_LENGTH); |
- else if (kdf == CKD_SHA224_KDF) |
- return sftk_compute_ANSI_X9_63_kdf(key, key_len, SharedSecret, SharedInfo, |
- SharedInfoLen, SHA224_HashBuf, SHA224_LENGTH); |
- else if (kdf == CKD_SHA256_KDF) |
- return sftk_compute_ANSI_X9_63_kdf(key, key_len, SharedSecret, SharedInfo, |
- SharedInfoLen, SHA256_HashBuf, SHA256_LENGTH); |
- else if (kdf == CKD_SHA384_KDF) |
- return sftk_compute_ANSI_X9_63_kdf(key, key_len, SharedSecret, SharedInfo, |
- SharedInfoLen, SHA384_HashBuf, SHA384_LENGTH); |
- else if (kdf == CKD_SHA512_KDF) |
- return sftk_compute_ANSI_X9_63_kdf(key, key_len, SharedSecret, SharedInfo, |
- SharedInfoLen, SHA512_HashBuf, SHA512_LENGTH); |
- else |
- return SEC_ERROR_INVALID_ALGORITHM; |
-} |
- |
-/* |
- * SSL Key generation given pre master secret |
- */ |
-#define NUM_MIXERS 9 |
-static const char * const mixers[NUM_MIXERS] = { |
- "A", |
- "BB", |
- "CCC", |
- "DDDD", |
- "EEEEE", |
- "FFFFFF", |
- "GGGGGGG", |
- "HHHHHHHH", |
- "IIIIIIIII" }; |
-#define SSL3_PMS_LENGTH 48 |
-#define SSL3_MASTER_SECRET_LENGTH 48 |
-#define SSL3_RANDOM_LENGTH 32 |
- |
- |
-/* NSC_DeriveKey derives a key from a base key, creating a new key object. */ |
-CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, |
- CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, |
- CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, |
- CK_OBJECT_HANDLE_PTR phKey) |
-{ |
- SFTKSession * session; |
- SFTKSlot * slot = sftk_SlotFromSessionHandle(hSession); |
- SFTKObject * key; |
- SFTKObject * sourceKey; |
- SFTKAttribute * att = NULL; |
- SFTKAttribute * att2 = NULL; |
- unsigned char * buf; |
- SHA1Context * sha; |
- MD5Context * md5; |
- MD2Context * md2; |
- CK_ULONG macSize; |
- CK_ULONG tmpKeySize; |
- CK_ULONG IVSize; |
- CK_ULONG keySize = 0; |
- CK_RV crv = CKR_OK; |
- CK_BBOOL cktrue = CK_TRUE; |
- CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; |
- CK_OBJECT_CLASS classType = CKO_SECRET_KEY; |
- CK_KEY_DERIVATION_STRING_DATA *stringPtr; |
- PRBool isTLS = PR_FALSE; |
- PRBool isDH = PR_FALSE; |
- SECStatus rv; |
- int i; |
- unsigned int outLen; |
- unsigned char sha_out[SHA1_LENGTH]; |
- unsigned char key_block[NUM_MIXERS * MD5_LENGTH]; |
- unsigned char key_block2[MD5_LENGTH]; |
- PRBool isFIPS; |
- HASH_HashType hashType; |
- PRBool extractValue = PR_TRUE; |
- |
- CHECK_FORK(); |
- |
- if (!slot) { |
- return CKR_SESSION_HANDLE_INVALID; |
- } |
- /* |
- * now lets create an object to hang the attributes off of |
- */ |
- if (phKey) *phKey = CK_INVALID_HANDLE; |
- |
- key = sftk_NewObject(slot); /* fill in the handle later */ |
- if (key == NULL) { |
- return CKR_HOST_MEMORY; |
- } |
- isFIPS = (slot->slotID == FIPS_SLOT_ID); |
- |
- /* |
- * load the template values into the object |
- */ |
- for (i=0; i < (int) ulAttributeCount; i++) { |
- crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i])); |
- if (crv != CKR_OK) break; |
- |
- if (pTemplate[i].type == CKA_KEY_TYPE) { |
- keyType = *(CK_KEY_TYPE *)pTemplate[i].pValue; |
- } |
- if (pTemplate[i].type == CKA_VALUE_LEN) { |
- keySize = *(CK_ULONG *)pTemplate[i].pValue; |
- } |
- } |
- if (crv != CKR_OK) { sftk_FreeObject(key); return crv; } |
- |
- if (keySize == 0) { |
- keySize = sftk_MapKeySize(keyType); |
- } |
- |
- switch (pMechanism->mechanism) { |
- case CKM_NSS_JPAKE_ROUND2_SHA1: /* fall through */ |
- case CKM_NSS_JPAKE_ROUND2_SHA256: /* fall through */ |
- case CKM_NSS_JPAKE_ROUND2_SHA384: /* fall through */ |
- case CKM_NSS_JPAKE_ROUND2_SHA512: |
- extractValue = PR_FALSE; |
- classType = CKO_PRIVATE_KEY; |
- break; |
- case CKM_NSS_JPAKE_FINAL_SHA1: /* fall through */ |
- case CKM_NSS_JPAKE_FINAL_SHA256: /* fall through */ |
- case CKM_NSS_JPAKE_FINAL_SHA384: /* fall through */ |
- case CKM_NSS_JPAKE_FINAL_SHA512: |
- extractValue = PR_FALSE; |
- /* fall through */ |
- default: |
- classType = CKO_SECRET_KEY; |
- } |
- |
- crv = sftk_forceAttribute (key,CKA_CLASS,&classType,sizeof(classType)); |
- if (crv != CKR_OK) { |
- sftk_FreeObject(key); |
- return crv; |
- } |
- |
- /* look up the base key we're deriving with */ |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) { |
- sftk_FreeObject(key); |
- return CKR_SESSION_HANDLE_INVALID; |
- } |
- |
- sourceKey = sftk_ObjectFromHandle(hBaseKey,session); |
- sftk_FreeSession(session); |
- if (sourceKey == NULL) { |
- sftk_FreeObject(key); |
- return CKR_KEY_HANDLE_INVALID; |
- } |
- |
- if (extractValue) { |
- /* get the value of the base key */ |
- att = sftk_FindAttribute(sourceKey,CKA_VALUE); |
- if (att == NULL) { |
- sftk_FreeObject(key); |
- sftk_FreeObject(sourceKey); |
- return CKR_KEY_HANDLE_INVALID; |
- } |
- } |
- |
- switch (pMechanism->mechanism) { |
- /* |
- * generate the master secret |
- */ |
- case CKM_TLS_MASTER_KEY_DERIVE: |
- case CKM_TLS_MASTER_KEY_DERIVE_DH: |
- isTLS = PR_TRUE; |
- /* fall thru */ |
- case CKM_SSL3_MASTER_KEY_DERIVE: |
- case CKM_SSL3_MASTER_KEY_DERIVE_DH: |
- { |
- CK_SSL3_MASTER_KEY_DERIVE_PARAMS *ssl3_master; |
- SSL3RSAPreMasterSecret * rsa_pms; |
- unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2]; |
- |
- if ((pMechanism->mechanism == CKM_SSL3_MASTER_KEY_DERIVE_DH) || |
- (pMechanism->mechanism == CKM_TLS_MASTER_KEY_DERIVE_DH)) |
- isDH = PR_TRUE; |
- |
- /* first do the consistancy checks */ |
- if (!isDH && (att->attrib.ulValueLen != SSL3_PMS_LENGTH)) { |
- crv = CKR_KEY_TYPE_INCONSISTENT; |
- break; |
- } |
- att2 = sftk_FindAttribute(sourceKey,CKA_KEY_TYPE); |
- if ((att2 == NULL) || (*(CK_KEY_TYPE *)att2->attrib.pValue != |
- CKK_GENERIC_SECRET)) { |
- if (att2) sftk_FreeAttribute(att2); |
- crv = CKR_KEY_FUNCTION_NOT_PERMITTED; |
- break; |
- } |
- sftk_FreeAttribute(att2); |
- if (keyType != CKK_GENERIC_SECRET) { |
- crv = CKR_KEY_FUNCTION_NOT_PERMITTED; |
- break; |
- } |
- if ((keySize != 0) && (keySize != SSL3_MASTER_SECRET_LENGTH)) { |
- crv = CKR_KEY_FUNCTION_NOT_PERMITTED; |
- break; |
- } |
- |
- /* finally do the key gen */ |
- ssl3_master = (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *) |
- pMechanism->pParameter; |
- |
- PORT_Memcpy(crsrdata, |
- ssl3_master->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH); |
- PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, |
- ssl3_master->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH); |
- |
- if (ssl3_master->pVersion) { |
- SFTKSessionObject *sessKey = sftk_narrowToSessionObject(key); |
- rsa_pms = (SSL3RSAPreMasterSecret *) att->attrib.pValue; |
- /* don't leak more key material then necessary for SSL to work */ |
- if ((sessKey == NULL) || sessKey->wasDerived) { |
- ssl3_master->pVersion->major = 0xff; |
- ssl3_master->pVersion->minor = 0xff; |
- } else { |
- ssl3_master->pVersion->major = rsa_pms->client_version[0]; |
- ssl3_master->pVersion->minor = rsa_pms->client_version[1]; |
- } |
- } |
- if (ssl3_master->RandomInfo.ulClientRandomLen != SSL3_RANDOM_LENGTH) { |
- crv = CKR_MECHANISM_PARAM_INVALID; |
- break; |
- } |
- if (ssl3_master->RandomInfo.ulServerRandomLen != SSL3_RANDOM_LENGTH) { |
- crv = CKR_MECHANISM_PARAM_INVALID; |
- break; |
- } |
- |
- if (isTLS) { |
- SECStatus status; |
- SECItem crsr = { siBuffer, NULL, 0 }; |
- SECItem master = { siBuffer, NULL, 0 }; |
- SECItem pms = { siBuffer, NULL, 0 }; |
- |
- crsr.data = crsrdata; |
- crsr.len = sizeof crsrdata; |
- master.data = key_block; |
- master.len = SSL3_MASTER_SECRET_LENGTH; |
- pms.data = (unsigned char*)att->attrib.pValue; |
- pms.len = att->attrib.ulValueLen; |
- |
- status = TLS_PRF(&pms, "master secret", &crsr, &master, isFIPS); |
- if (status != SECSuccess) { |
- crv = CKR_FUNCTION_FAILED; |
- break; |
- } |
- } else { |
- /* now allocate the hash contexts */ |
- md5 = MD5_NewContext(); |
- if (md5 == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- sha = SHA1_NewContext(); |
- if (sha == NULL) { |
- PORT_Free(md5); |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- for (i = 0; i < 3; i++) { |
- SHA1_Begin(sha); |
- SHA1_Update(sha, (unsigned char*) mixers[i], strlen(mixers[i])); |
- SHA1_Update(sha, (const unsigned char*)att->attrib.pValue, |
- att->attrib.ulValueLen); |
- SHA1_Update(sha, crsrdata, sizeof crsrdata); |
- SHA1_End(sha, sha_out, &outLen, SHA1_LENGTH); |
- PORT_Assert(outLen == SHA1_LENGTH); |
- |
- MD5_Begin(md5); |
- MD5_Update(md5, (const unsigned char*)att->attrib.pValue, |
- att->attrib.ulValueLen); |
- MD5_Update(md5, sha_out, outLen); |
- MD5_End(md5, &key_block[i*MD5_LENGTH], &outLen, MD5_LENGTH); |
- PORT_Assert(outLen == MD5_LENGTH); |
- } |
- PORT_Free(md5); |
- PORT_Free(sha); |
- } |
- |
- /* store the results */ |
- crv = sftk_forceAttribute |
- (key,CKA_VALUE,key_block,SSL3_MASTER_SECRET_LENGTH); |
- if (crv != CKR_OK) break; |
- keyType = CKK_GENERIC_SECRET; |
- crv = sftk_forceAttribute (key,CKA_KEY_TYPE,&keyType,sizeof(keyType)); |
- if (isTLS) { |
- /* TLS's master secret is used to "sign" finished msgs with PRF. */ |
- /* XXX This seems like a hack. But SFTK_Derive only accepts |
- * one "operation" argument. */ |
- crv = sftk_forceAttribute(key,CKA_SIGN, &cktrue,sizeof(CK_BBOOL)); |
- if (crv != CKR_OK) break; |
- crv = sftk_forceAttribute(key,CKA_VERIFY,&cktrue,sizeof(CK_BBOOL)); |
- if (crv != CKR_OK) break; |
- /* While we're here, we might as well force this, too. */ |
- crv = sftk_forceAttribute(key,CKA_DERIVE,&cktrue,sizeof(CK_BBOOL)); |
- if (crv != CKR_OK) break; |
- } |
- break; |
- } |
- |
- case CKM_TLS_KEY_AND_MAC_DERIVE: |
- isTLS = PR_TRUE; |
- /* fall thru */ |
- case CKM_SSL3_KEY_AND_MAC_DERIVE: |
- { |
- CK_SSL3_KEY_MAT_PARAMS *ssl3_keys; |
- CK_SSL3_KEY_MAT_OUT * ssl3_keys_out; |
- CK_ULONG effKeySize; |
- unsigned int block_needed; |
- unsigned char srcrdata[SSL3_RANDOM_LENGTH * 2]; |
- unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2]; |
- |
- crv = sftk_DeriveSensitiveCheck(sourceKey,key); |
- if (crv != CKR_OK) break; |
- |
- if (att->attrib.ulValueLen != SSL3_MASTER_SECRET_LENGTH) { |
- crv = CKR_KEY_FUNCTION_NOT_PERMITTED; |
- break; |
- } |
- att2 = sftk_FindAttribute(sourceKey,CKA_KEY_TYPE); |
- if ((att2 == NULL) || (*(CK_KEY_TYPE *)att2->attrib.pValue != |
- CKK_GENERIC_SECRET)) { |
- if (att2) sftk_FreeAttribute(att2); |
- crv = CKR_KEY_FUNCTION_NOT_PERMITTED; |
- break; |
- } |
- sftk_FreeAttribute(att2); |
- md5 = MD5_NewContext(); |
- if (md5 == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- sha = SHA1_NewContext(); |
- if (sha == NULL) { |
- PORT_Free(md5); |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- ssl3_keys = (CK_SSL3_KEY_MAT_PARAMS *) pMechanism->pParameter; |
- |
- PORT_Memcpy(srcrdata, |
- ssl3_keys->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH); |
- PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, |
- ssl3_keys->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH); |
- |
- PORT_Memcpy(crsrdata, |
- ssl3_keys->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH); |
- PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, |
- ssl3_keys->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH); |
- |
- /* |
- * clear out our returned keys so we can recover on failure |
- */ |
- ssl3_keys_out = ssl3_keys->pReturnedKeyMaterial; |
- ssl3_keys_out->hClientMacSecret = CK_INVALID_HANDLE; |
- ssl3_keys_out->hServerMacSecret = CK_INVALID_HANDLE; |
- ssl3_keys_out->hClientKey = CK_INVALID_HANDLE; |
- ssl3_keys_out->hServerKey = CK_INVALID_HANDLE; |
- |
- /* |
- * How much key material do we need? |
- */ |
- macSize = ssl3_keys->ulMacSizeInBits/8; |
- effKeySize = ssl3_keys->ulKeySizeInBits/8; |
- IVSize = ssl3_keys->ulIVSizeInBits/8; |
- if (keySize == 0) { |
- effKeySize = keySize; |
- } |
- block_needed = 2 * (macSize + effKeySize + |
- ((!ssl3_keys->bIsExport) * IVSize)); |
- PORT_Assert(block_needed <= sizeof key_block); |
- if (block_needed > sizeof key_block) |
- block_needed = sizeof key_block; |
- |
- /* |
- * generate the key material: This looks amazingly similar to the |
- * PMS code, and is clearly crying out for a function to provide it. |
- */ |
- if (isTLS) { |
- SECStatus status; |
- SECItem srcr = { siBuffer, NULL, 0 }; |
- SECItem keyblk = { siBuffer, NULL, 0 }; |
- SECItem master = { siBuffer, NULL, 0 }; |
- |
- srcr.data = srcrdata; |
- srcr.len = sizeof srcrdata; |
- keyblk.data = key_block; |
- keyblk.len = block_needed; |
- master.data = (unsigned char*)att->attrib.pValue; |
- master.len = att->attrib.ulValueLen; |
- |
- status = TLS_PRF(&master, "key expansion", &srcr, &keyblk, |
- isFIPS); |
- if (status != SECSuccess) { |
- goto key_and_mac_derive_fail; |
- } |
- } else { |
- unsigned int block_bytes = 0; |
- /* key_block = |
- * MD5(master_secret + SHA('A' + master_secret + |
- * ServerHello.random + ClientHello.random)) + |
- * MD5(master_secret + SHA('BB' + master_secret + |
- * ServerHello.random + ClientHello.random)) + |
- * MD5(master_secret + SHA('CCC' + master_secret + |
- * ServerHello.random + ClientHello.random)) + |
- * [...]; |
- */ |
- for (i = 0; i < NUM_MIXERS && block_bytes < block_needed; i++) { |
- SHA1_Begin(sha); |
- SHA1_Update(sha, (unsigned char*) mixers[i], strlen(mixers[i])); |
- SHA1_Update(sha, (const unsigned char*)att->attrib.pValue, |
- att->attrib.ulValueLen); |
- SHA1_Update(sha, srcrdata, sizeof srcrdata); |
- SHA1_End(sha, sha_out, &outLen, SHA1_LENGTH); |
- PORT_Assert(outLen == SHA1_LENGTH); |
- MD5_Begin(md5); |
- MD5_Update(md5, (const unsigned char*)att->attrib.pValue, |
- att->attrib.ulValueLen); |
- MD5_Update(md5, sha_out, outLen); |
- MD5_End(md5, &key_block[i*MD5_LENGTH], &outLen, MD5_LENGTH); |
- PORT_Assert(outLen == MD5_LENGTH); |
- block_bytes += outLen; |
- } |
- } |
- |
- /* |
- * Put the key material where it goes. |
- */ |
- i = 0; /* now shows how much consumed */ |
- |
- /* |
- * The key_block is partitioned as follows: |
- * client_write_MAC_secret[CipherSpec.hash_size] |
- */ |
- crv = sftk_buildSSLKey(hSession,key,PR_TRUE,&key_block[i],macSize, |
- &ssl3_keys_out->hClientMacSecret); |
- if (crv != CKR_OK) |
- goto key_and_mac_derive_fail; |
- |
- i += macSize; |
- |
- /* |
- * server_write_MAC_secret[CipherSpec.hash_size] |
- */ |
- crv = sftk_buildSSLKey(hSession,key,PR_TRUE,&key_block[i],macSize, |
- &ssl3_keys_out->hServerMacSecret); |
- if (crv != CKR_OK) { |
- goto key_and_mac_derive_fail; |
- } |
- i += macSize; |
- |
- if (keySize) { |
- if (!ssl3_keys->bIsExport) { |
- /* |
- ** Generate Domestic write keys and IVs. |
- ** client_write_key[CipherSpec.key_material] |
- */ |
- crv = sftk_buildSSLKey(hSession,key,PR_FALSE,&key_block[i], |
- keySize, &ssl3_keys_out->hClientKey); |
- if (crv != CKR_OK) { |
- goto key_and_mac_derive_fail; |
- } |
- i += keySize; |
- |
- /* |
- ** server_write_key[CipherSpec.key_material] |
- */ |
- crv = sftk_buildSSLKey(hSession,key,PR_FALSE,&key_block[i], |
- keySize, &ssl3_keys_out->hServerKey); |
- if (crv != CKR_OK) { |
- goto key_and_mac_derive_fail; |
- } |
- i += keySize; |
- |
- /* |
- ** client_write_IV[CipherSpec.IV_size] |
- */ |
- if (IVSize > 0) { |
- PORT_Memcpy(ssl3_keys_out->pIVClient, |
- &key_block[i], IVSize); |
- i += IVSize; |
- } |
- |
- /* |
- ** server_write_IV[CipherSpec.IV_size] |
- */ |
- if (IVSize > 0) { |
- PORT_Memcpy(ssl3_keys_out->pIVServer, |
- &key_block[i], IVSize); |
- i += IVSize; |
- } |
- PORT_Assert(i <= sizeof key_block); |
- |
- } else if (!isTLS) { |
- |
- /* |
- ** Generate SSL3 Export write keys and IVs. |
- ** client_write_key[CipherSpec.key_material] |
- ** final_client_write_key = MD5(client_write_key + |
- ** ClientHello.random + ServerHello.random); |
- */ |
- MD5_Begin(md5); |
- MD5_Update(md5, &key_block[i], effKeySize); |
- MD5_Update(md5, crsrdata, sizeof crsrdata); |
- MD5_End(md5, key_block2, &outLen, MD5_LENGTH); |
- i += effKeySize; |
- crv = sftk_buildSSLKey(hSession,key,PR_FALSE,key_block2, |
- keySize,&ssl3_keys_out->hClientKey); |
- if (crv != CKR_OK) { |
- goto key_and_mac_derive_fail; |
- } |
- |
- /* |
- ** server_write_key[CipherSpec.key_material] |
- ** final_server_write_key = MD5(server_write_key + |
- ** ServerHello.random + ClientHello.random); |
- */ |
- MD5_Begin(md5); |
- MD5_Update(md5, &key_block[i], effKeySize); |
- MD5_Update(md5, srcrdata, sizeof srcrdata); |
- MD5_End(md5, key_block2, &outLen, MD5_LENGTH); |
- i += effKeySize; |
- crv = sftk_buildSSLKey(hSession,key,PR_FALSE,key_block2, |
- keySize,&ssl3_keys_out->hServerKey); |
- if (crv != CKR_OK) { |
- goto key_and_mac_derive_fail; |
- } |
- |
- /* |
- ** client_write_IV = |
- ** MD5(ClientHello.random + ServerHello.random); |
- */ |
- MD5_Begin(md5); |
- MD5_Update(md5, crsrdata, sizeof crsrdata); |
- MD5_End(md5, key_block2, &outLen, MD5_LENGTH); |
- PORT_Memcpy(ssl3_keys_out->pIVClient, key_block2, IVSize); |
- |
- /* |
- ** server_write_IV = |
- ** MD5(ServerHello.random + ClientHello.random); |
- */ |
- MD5_Begin(md5); |
- MD5_Update(md5, srcrdata, sizeof srcrdata); |
- MD5_End(md5, key_block2, &outLen, MD5_LENGTH); |
- PORT_Memcpy(ssl3_keys_out->pIVServer, key_block2, IVSize); |
- |
- } else { |
- |
- /* |
- ** Generate TLS Export write keys and IVs. |
- */ |
- SECStatus status; |
- SECItem secret = { siBuffer, NULL, 0 }; |
- SECItem crsr = { siBuffer, NULL, 0 }; |
- SECItem keyblk = { siBuffer, NULL, 0 }; |
- |
- /* |
- ** client_write_key[CipherSpec.key_material] |
- ** final_client_write_key = PRF(client_write_key, |
- ** "client write key", |
- ** client_random + server_random); |
- */ |
- secret.data = &key_block[i]; |
- secret.len = effKeySize; |
- i += effKeySize; |
- crsr.data = crsrdata; |
- crsr.len = sizeof crsrdata; |
- keyblk.data = key_block2; |
- keyblk.len = sizeof key_block2; |
- status = TLS_PRF(&secret, "client write key", &crsr, &keyblk, |
- isFIPS); |
- if (status != SECSuccess) { |
- goto key_and_mac_derive_fail; |
- } |
- crv = sftk_buildSSLKey(hSession, key, PR_FALSE, key_block2, |
- keySize, &ssl3_keys_out->hClientKey); |
- if (crv != CKR_OK) { |
- goto key_and_mac_derive_fail; |
- } |
- |
- /* |
- ** server_write_key[CipherSpec.key_material] |
- ** final_server_write_key = PRF(server_write_key, |
- ** "server write key", |
- ** client_random + server_random); |
- */ |
- secret.data = &key_block[i]; |
- secret.len = effKeySize; |
- i += effKeySize; |
- keyblk.data = key_block2; |
- keyblk.len = sizeof key_block2; |
- status = TLS_PRF(&secret, "server write key", &crsr, &keyblk, |
- isFIPS); |
- if (status != SECSuccess) { |
- goto key_and_mac_derive_fail; |
- } |
- crv = sftk_buildSSLKey(hSession, key, PR_FALSE, key_block2, |
- keySize, &ssl3_keys_out->hServerKey); |
- if (crv != CKR_OK) { |
- goto key_and_mac_derive_fail; |
- } |
- |
- /* |
- ** iv_block = PRF("", "IV block", |
- ** client_random + server_random); |
- ** client_write_IV[SecurityParameters.IV_size] |
- ** server_write_IV[SecurityParameters.IV_size] |
- */ |
- if (IVSize) { |
- secret.data = NULL; |
- secret.len = 0; |
- keyblk.data = &key_block[i]; |
- keyblk.len = 2 * IVSize; |
- status = TLS_PRF(&secret, "IV block", &crsr, &keyblk, |
- isFIPS); |
- if (status != SECSuccess) { |
- goto key_and_mac_derive_fail; |
- } |
- PORT_Memcpy(ssl3_keys_out->pIVClient, keyblk.data, IVSize); |
- PORT_Memcpy(ssl3_keys_out->pIVServer, keyblk.data + IVSize, |
- IVSize); |
- } |
- } |
- } |
- |
- crv = CKR_OK; |
- |
- if (0) { |
-key_and_mac_derive_fail: |
- if (crv == CKR_OK) |
- crv = CKR_FUNCTION_FAILED; |
- sftk_freeSSLKeys(hSession, ssl3_keys_out); |
- } |
- MD5_DestroyContext(md5, PR_TRUE); |
- SHA1_DestroyContext(sha, PR_TRUE); |
- sftk_FreeObject(key); |
- key = NULL; |
- break; |
- } |
- |
- case CKM_CONCATENATE_BASE_AND_KEY: |
- { |
- SFTKObject *newKey; |
- |
- crv = sftk_DeriveSensitiveCheck(sourceKey,key); |
- if (crv != CKR_OK) break; |
- |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) { |
- crv = CKR_SESSION_HANDLE_INVALID; |
- break; |
- } |
- |
- newKey = sftk_ObjectFromHandle(*(CK_OBJECT_HANDLE *) |
- pMechanism->pParameter,session); |
- sftk_FreeSession(session); |
- if ( newKey == NULL) { |
- crv = CKR_KEY_HANDLE_INVALID; |
- break; |
- } |
- |
- if (sftk_isTrue(newKey,CKA_SENSITIVE)) { |
- crv = sftk_forceAttribute(newKey,CKA_SENSITIVE,&cktrue, |
- sizeof(CK_BBOOL)); |
- if (crv != CKR_OK) { |
- sftk_FreeObject(newKey); |
- break; |
- } |
- } |
- |
- att2 = sftk_FindAttribute(newKey,CKA_VALUE); |
- if (att2 == NULL) { |
- sftk_FreeObject(newKey); |
- crv = CKR_KEY_HANDLE_INVALID; |
- break; |
- } |
- tmpKeySize = att->attrib.ulValueLen+att2->attrib.ulValueLen; |
- if (keySize == 0) keySize = tmpKeySize; |
- if (keySize > tmpKeySize) { |
- sftk_FreeObject(newKey); |
- sftk_FreeAttribute(att2); |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- break; |
- } |
- buf = (unsigned char*)PORT_Alloc(tmpKeySize); |
- if (buf == NULL) { |
- sftk_FreeAttribute(att2); |
- sftk_FreeObject(newKey); |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- |
- PORT_Memcpy(buf,att->attrib.pValue,att->attrib.ulValueLen); |
- PORT_Memcpy(buf+att->attrib.ulValueLen, |
- att2->attrib.pValue,att2->attrib.ulValueLen); |
- |
- crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize); |
- PORT_ZFree(buf,tmpKeySize); |
- sftk_FreeAttribute(att2); |
- sftk_FreeObject(newKey); |
- break; |
- } |
- |
- case CKM_CONCATENATE_BASE_AND_DATA: |
- crv = sftk_DeriveSensitiveCheck(sourceKey,key); |
- if (crv != CKR_OK) break; |
- |
- stringPtr = (CK_KEY_DERIVATION_STRING_DATA *) pMechanism->pParameter; |
- tmpKeySize = att->attrib.ulValueLen+stringPtr->ulLen; |
- if (keySize == 0) keySize = tmpKeySize; |
- if (keySize > tmpKeySize) { |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- break; |
- } |
- buf = (unsigned char*)PORT_Alloc(tmpKeySize); |
- if (buf == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- |
- PORT_Memcpy(buf,att->attrib.pValue,att->attrib.ulValueLen); |
- PORT_Memcpy(buf+att->attrib.ulValueLen,stringPtr->pData, |
- stringPtr->ulLen); |
- |
- crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize); |
- PORT_ZFree(buf,tmpKeySize); |
- break; |
- case CKM_CONCATENATE_DATA_AND_BASE: |
- crv = sftk_DeriveSensitiveCheck(sourceKey,key); |
- if (crv != CKR_OK) break; |
- |
- stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter; |
- tmpKeySize = att->attrib.ulValueLen+stringPtr->ulLen; |
- if (keySize == 0) keySize = tmpKeySize; |
- if (keySize > tmpKeySize) { |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- break; |
- } |
- buf = (unsigned char*)PORT_Alloc(tmpKeySize); |
- if (buf == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- |
- PORT_Memcpy(buf,stringPtr->pData,stringPtr->ulLen); |
- PORT_Memcpy(buf+stringPtr->ulLen,att->attrib.pValue, |
- att->attrib.ulValueLen); |
- |
- crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize); |
- PORT_ZFree(buf,tmpKeySize); |
- break; |
- case CKM_XOR_BASE_AND_DATA: |
- crv = sftk_DeriveSensitiveCheck(sourceKey,key); |
- if (crv != CKR_OK) break; |
- |
- stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter; |
- tmpKeySize = PR_MIN(att->attrib.ulValueLen,stringPtr->ulLen); |
- if (keySize == 0) keySize = tmpKeySize; |
- if (keySize > tmpKeySize) { |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- break; |
- } |
- buf = (unsigned char*)PORT_Alloc(keySize); |
- if (buf == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- |
- |
- PORT_Memcpy(buf,att->attrib.pValue,keySize); |
- for (i=0; i < (int)keySize; i++) { |
- buf[i] ^= stringPtr->pData[i]; |
- } |
- |
- crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize); |
- PORT_ZFree(buf,keySize); |
- break; |
- |
- case CKM_EXTRACT_KEY_FROM_KEY: |
- { |
- /* the following assumes 8 bits per byte */ |
- CK_ULONG extract = *(CK_EXTRACT_PARAMS *)pMechanism->pParameter; |
- CK_ULONG shift = extract & 0x7; /* extract mod 8 the fast way */ |
- CK_ULONG offset = extract >> 3; /* extract div 8 the fast way */ |
- |
- crv = sftk_DeriveSensitiveCheck(sourceKey,key); |
- if (crv != CKR_OK) break; |
- |
- if (keySize == 0) { |
- crv = CKR_TEMPLATE_INCOMPLETE; |
- break; |
- } |
- /* make sure we have enough bits in the original key */ |
- if (att->attrib.ulValueLen < |
- (offset + keySize + ((shift != 0)? 1 :0)) ) { |
- crv = CKR_MECHANISM_PARAM_INVALID; |
- break; |
- } |
- buf = (unsigned char*)PORT_Alloc(keySize); |
- if (buf == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- |
- /* copy the bits we need into the new key */ |
- for (i=0; i < (int)keySize; i++) { |
- unsigned char *value = |
- ((unsigned char *)att->attrib.pValue)+offset+i; |
- if (shift) { |
- buf[i] = (value[0] << (shift)) | (value[1] >> (8 - shift)); |
- } else { |
- buf[i] = value[0]; |
- } |
- } |
- |
- crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize); |
- PORT_ZFree(buf,keySize); |
- break; |
- } |
- case CKM_MD2_KEY_DERIVATION: |
- if (keySize == 0) keySize = MD2_LENGTH; |
- if (keySize > MD2_LENGTH) { |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- break; |
- } |
- /* now allocate the hash contexts */ |
- md2 = MD2_NewContext(); |
- if (md2 == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- MD2_Begin(md2); |
- MD2_Update(md2,(const unsigned char*)att->attrib.pValue, |
- att->attrib.ulValueLen); |
- MD2_End(md2,key_block,&outLen,MD2_LENGTH); |
- MD2_DestroyContext(md2, PR_TRUE); |
- |
- crv = sftk_forceAttribute (key,CKA_VALUE,key_block,keySize); |
- break; |
- case CKM_MD5_KEY_DERIVATION: |
- if (keySize == 0) keySize = MD5_LENGTH; |
- if (keySize > MD5_LENGTH) { |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- break; |
- } |
- MD5_HashBuf(key_block,(const unsigned char*)att->attrib.pValue, |
- att->attrib.ulValueLen); |
- |
- crv = sftk_forceAttribute (key,CKA_VALUE,key_block,keySize); |
- break; |
- case CKM_SHA1_KEY_DERIVATION: |
- if (keySize == 0) keySize = SHA1_LENGTH; |
- if (keySize > SHA1_LENGTH) { |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- break; |
- } |
- SHA1_HashBuf(key_block,(const unsigned char*)att->attrib.pValue, |
- att->attrib.ulValueLen); |
- |
- crv = sftk_forceAttribute(key,CKA_VALUE,key_block,keySize); |
- break; |
- |
- case CKM_SHA224_KEY_DERIVATION: |
- if (keySize == 0) keySize = SHA224_LENGTH; |
- if (keySize > SHA224_LENGTH) { |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- break; |
- } |
- SHA224_HashBuf(key_block,(const unsigned char*)att->attrib.pValue, |
- att->attrib.ulValueLen); |
- |
- crv = sftk_forceAttribute(key,CKA_VALUE,key_block,keySize); |
- break; |
- |
- case CKM_SHA256_KEY_DERIVATION: |
- if (keySize == 0) keySize = SHA256_LENGTH; |
- if (keySize > SHA256_LENGTH) { |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- break; |
- } |
- SHA256_HashBuf(key_block,(const unsigned char*)att->attrib.pValue, |
- att->attrib.ulValueLen); |
- |
- crv = sftk_forceAttribute(key,CKA_VALUE,key_block,keySize); |
- break; |
- |
- case CKM_SHA384_KEY_DERIVATION: |
- if (keySize == 0) keySize = SHA384_LENGTH; |
- if (keySize > SHA384_LENGTH) { |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- break; |
- } |
- SHA384_HashBuf(key_block,(const unsigned char*)att->attrib.pValue, |
- att->attrib.ulValueLen); |
- |
- crv = sftk_forceAttribute(key,CKA_VALUE,key_block,keySize); |
- break; |
- |
- case CKM_SHA512_KEY_DERIVATION: |
- if (keySize == 0) keySize = SHA512_LENGTH; |
- if (keySize > SHA512_LENGTH) { |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- break; |
- } |
- SHA512_HashBuf(key_block,(const unsigned char*)att->attrib.pValue, |
- att->attrib.ulValueLen); |
- |
- crv = sftk_forceAttribute(key,CKA_VALUE,key_block,keySize); |
- break; |
- |
- case CKM_DH_PKCS_DERIVE: |
- { |
- SECItem derived, dhPublic; |
- SECItem dhPrime, dhValue; |
- /* sourceKey - values for the local existing low key */ |
- /* get prime and value attributes */ |
- crv = sftk_Attribute2SecItem(NULL, &dhPrime, sourceKey, CKA_PRIME); |
- if (crv != SECSuccess) break; |
- crv = sftk_Attribute2SecItem(NULL, &dhValue, sourceKey, CKA_VALUE); |
- if (crv != SECSuccess) { |
- PORT_Free(dhPrime.data); |
- break; |
- } |
- |
- dhPublic.data = pMechanism->pParameter; |
- dhPublic.len = pMechanism->ulParameterLen; |
- |
- /* calculate private value - oct */ |
- rv = DH_Derive(&dhPublic, &dhPrime, &dhValue, &derived, keySize); |
- |
- PORT_Free(dhPrime.data); |
- PORT_Free(dhValue.data); |
- |
- if (rv == SECSuccess) { |
- sftk_forceAttribute(key, CKA_VALUE, derived.data, derived.len); |
- PORT_ZFree(derived.data, derived.len); |
- } else |
- crv = CKR_HOST_MEMORY; |
- |
- break; |
- } |
- |
-#ifdef NSS_ENABLE_ECC |
- case CKM_ECDH1_DERIVE: |
- case CKM_ECDH1_COFACTOR_DERIVE: |
- { |
- SECItem ecScalar, ecPoint; |
- SECItem tmp; |
- PRBool withCofactor = PR_FALSE; |
- unsigned char *secret; |
- unsigned char *keyData = NULL; |
- int secretlen, curveLen, pubKeyLen; |
- CK_ECDH1_DERIVE_PARAMS *mechParams; |
- NSSLOWKEYPrivateKey *privKey; |
- PLArenaPool *arena = NULL; |
- |
- /* Check mechanism parameters */ |
- mechParams = (CK_ECDH1_DERIVE_PARAMS *) pMechanism->pParameter; |
- if ((pMechanism->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS)) || |
- ((mechParams->kdf == CKD_NULL) && |
- ((mechParams->ulSharedDataLen != 0) || |
- (mechParams->pSharedData != NULL)))) { |
- crv = CKR_MECHANISM_PARAM_INVALID; |
- break; |
- } |
- |
- privKey = sftk_GetPrivKey(sourceKey, CKK_EC, &crv); |
- if (privKey == NULL) { |
- break; |
- } |
- |
- /* Now we are working with a non-NULL private key */ |
- SECITEM_CopyItem(NULL, &ecScalar, &privKey->u.ec.privateValue); |
- |
- ecPoint.data = mechParams->pPublicData; |
- ecPoint.len = mechParams->ulPublicDataLen; |
- |
- curveLen = (privKey->u.ec.ecParams.fieldID.size +7)/8; |
- pubKeyLen = (2*curveLen) + 1; |
- |
- /* if the len is too small, can't be a valid point */ |
- if (ecPoint.len < pubKeyLen) { |
- goto ec_loser; |
- } |
- /* if the len is too large, must be an encoded point (length is |
- * equal case just falls through */ |
- if (ecPoint.len > pubKeyLen) { |
- SECItem newPoint; |
- |
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
- if (arena == NULL) { |
- goto ec_loser; |
- } |
- |
- rv = SEC_QuickDERDecodeItem(arena, &newPoint, |
- SEC_ASN1_GET(SEC_OctetStringTemplate), |
- &ecPoint); |
- if (rv != SECSuccess) { |
- goto ec_loser; |
- } |
- ecPoint = newPoint; |
- } |
- |
- if (pMechanism->mechanism == CKM_ECDH1_COFACTOR_DERIVE) { |
- withCofactor = PR_TRUE; |
- } else { |
- /* When not using cofactor derivation, one should |
- * validate the public key to avoid small subgroup |
- * attacks. |
- */ |
- if (EC_ValidatePublicKey(&privKey->u.ec.ecParams, &ecPoint) |
- != SECSuccess) { |
- goto ec_loser; |
- } |
- } |
- |
- rv = ECDH_Derive(&ecPoint, &privKey->u.ec.ecParams, &ecScalar, |
- withCofactor, &tmp); |
- PORT_Free(ecScalar.data); |
- ecScalar.data = NULL; |
- if (privKey != sourceKey->objectInfo) { |
- nsslowkey_DestroyPrivateKey(privKey); |
- privKey=NULL; |
- } |
- if (arena) { |
- PORT_FreeArena(arena,PR_FALSE); |
- arena=NULL; |
- } |
- |
- if (rv != SECSuccess) { |
- crv = sftk_MapCryptError(PORT_GetError()); |
- break; |
- } |
- |
- |
- /* |
- * apply the kdf function. |
- */ |
- if (mechParams->kdf == CKD_NULL) { |
- /* |
- * tmp is the raw data created by ECDH_Derive, |
- * secret and secretlen are the values we will |
- * eventually pass as our generated key. |
- */ |
- secret = tmp.data; |
- secretlen = tmp.len; |
- } else { |
- secretlen = keySize; |
- rv = sftk_ANSI_X9_63_kdf(&secret, keySize, |
- &tmp, mechParams->pSharedData, |
- mechParams->ulSharedDataLen, mechParams->kdf); |
- PORT_ZFree(tmp.data, tmp.len); |
- if (rv != SECSuccess) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- tmp.data = secret; |
- tmp.len = secretlen; |
- } |
- |
- /* |
- * if keySize is supplied, then we are generating a key of a specific |
- * length. This is done by taking the least significant 'keySize' |
- * bytes from the unsigned value calculated by ECDH. Note: this may |
- * mean padding temp with extra leading zeros from what ECDH_Derive |
- * already returned (which itself may contain leading zeros). |
- */ |
- if (keySize) { |
- if (secretlen < keySize) { |
- keyData = PORT_ZAlloc(keySize); |
- if (!keyData) { |
- PORT_ZFree(tmp.data, tmp.len); |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- PORT_Memcpy(&keyData[keySize-secretlen],secret,secretlen); |
- secret = keyData; |
- } else { |
- secret += (secretlen - keySize); |
- } |
- secretlen = keySize; |
- } |
- |
- sftk_forceAttribute(key, CKA_VALUE, secret, secretlen); |
- PORT_ZFree(tmp.data, tmp.len); |
- if (keyData) { |
- PORT_ZFree(keyData, keySize); |
- } |
- break; |
- |
-ec_loser: |
- crv = CKR_ARGUMENTS_BAD; |
- PORT_Free(ecScalar.data); |
- if (privKey != sourceKey->objectInfo) |
- nsslowkey_DestroyPrivateKey(privKey); |
- if (arena) { |
- PORT_FreeArena(arena, PR_FALSE); |
- } |
- break; |
- |
- } |
-#endif /* NSS_ENABLE_ECC */ |
- |
- /* See RFC 5869 and CK_NSS_HKDFParams for documentation. */ |
- case CKM_NSS_HKDF_SHA1: hashType = HASH_AlgSHA1; goto hkdf; |
- case CKM_NSS_HKDF_SHA256: hashType = HASH_AlgSHA256; goto hkdf; |
- case CKM_NSS_HKDF_SHA384: hashType = HASH_AlgSHA384; goto hkdf; |
- case CKM_NSS_HKDF_SHA512: hashType = HASH_AlgSHA512; goto hkdf; |
-hkdf: { |
- const CK_NSS_HKDFParams * params = |
- (const CK_NSS_HKDFParams *) pMechanism->pParameter; |
- const SECHashObject * rawHash; |
- unsigned hashLen; |
- CK_BYTE buf[HASH_LENGTH_MAX]; |
- CK_BYTE * prk; /* psuedo-random key */ |
- CK_ULONG prkLen; |
- CK_BYTE * okm; /* output keying material */ |
- |
- rawHash = HASH_GetRawHashObject(hashType); |
- if (rawHash == NULL || rawHash->length > sizeof buf) { |
- crv = CKR_FUNCTION_FAILED; |
- break; |
- } |
- hashLen = rawHash->length; |
- |
- if (pMechanism->ulParameterLen != sizeof(CK_NSS_HKDFParams) || |
- !params || (!params->bExpand && !params->bExtract) || |
- (params->bExtract && params->ulSaltLen > 0 && !params->pSalt) || |
- (params->bExpand && params->ulInfoLen > 0 && !params->pInfo)) { |
- crv = CKR_MECHANISM_PARAM_INVALID; |
- break; |
- } |
- if (keySize == 0 || keySize > sizeof key_block || |
- (!params->bExpand && keySize > hashLen) || |
- (params->bExpand && keySize > 255 * hashLen)) { |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- break; |
- } |
- crv = sftk_DeriveSensitiveCheck(sourceKey, key); |
- if (crv != CKR_OK) |
- break; |
- |
- /* HKDF-Extract(salt, base key value) */ |
- if (params->bExtract) { |
- CK_BYTE * salt; |
- CK_ULONG saltLen; |
- HMACContext * hmac; |
- unsigned int bufLen; |
- |
- salt = params->pSalt; |
- saltLen = params->ulSaltLen; |
- if (salt == NULL) { |
- saltLen = hashLen; |
- salt = buf; |
- memset(salt, 0, saltLen); |
- } |
- hmac = HMAC_Create(rawHash, salt, saltLen, isFIPS); |
- if (!hmac) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- HMAC_Begin(hmac); |
- HMAC_Update(hmac, (const unsigned char*) att->attrib.pValue, |
- att->attrib.ulValueLen); |
- HMAC_Finish(hmac, buf, &bufLen, sizeof(buf)); |
- HMAC_Destroy(hmac, PR_TRUE); |
- PORT_Assert(bufLen == rawHash->length); |
- prk = buf; |
- prkLen = bufLen; |
- } else { |
- /* PRK = base key value */ |
- prk = (CK_BYTE*) att->attrib.pValue; |
- prkLen = att->attrib.ulValueLen; |
- } |
- |
- /* HKDF-Expand */ |
- if (!params->bExpand) { |
- okm = prk; |
- } else { |
- /* T(1) = HMAC-Hash(prk, "" | info | 0x01) |
- * T(n) = HMAC-Hash(prk, T(n-1) | info | n |
- * key material = T(1) | ... | T(n) |
- */ |
- HMACContext * hmac; |
- CK_BYTE i; |
- unsigned iterations = PR_ROUNDUP(keySize, hashLen) / hashLen; |
- hmac = HMAC_Create(rawHash, prk, prkLen, isFIPS); |
- if (hmac == NULL) { |
- crv = CKR_HOST_MEMORY; |
- break; |
- } |
- for (i = 1; i <= iterations; ++i) { |
- unsigned len; |
- HMAC_Begin(hmac); |
- if (i > 1) { |
- HMAC_Update(hmac, key_block + ((i-2) * hashLen), hashLen); |
- } |
- if (params->ulInfoLen != 0) { |
- HMAC_Update(hmac, params->pInfo, params->ulInfoLen); |
- } |
- HMAC_Update(hmac, &i, 1); |
- HMAC_Finish(hmac, key_block + ((i-1) * hashLen), &len, |
- hashLen); |
- PORT_Assert(len == hashLen); |
- } |
- HMAC_Destroy(hmac, PR_TRUE); |
- okm = key_block; |
- } |
- /* key material = prk */ |
- crv = sftk_forceAttribute(key, CKA_VALUE, okm, keySize); |
- break; |
- } /* end of CKM_NSS_HKDF_* */ |
- |
- case CKM_NSS_JPAKE_ROUND2_SHA1: hashType = HASH_AlgSHA1; goto jpake2; |
- case CKM_NSS_JPAKE_ROUND2_SHA256: hashType = HASH_AlgSHA256; goto jpake2; |
- case CKM_NSS_JPAKE_ROUND2_SHA384: hashType = HASH_AlgSHA384; goto jpake2; |
- case CKM_NSS_JPAKE_ROUND2_SHA512: hashType = HASH_AlgSHA512; goto jpake2; |
-jpake2: |
- if (pMechanism->pParameter == NULL || |
- pMechanism->ulParameterLen != sizeof(CK_NSS_JPAKERound2Params)) |
- crv = CKR_MECHANISM_PARAM_INVALID; |
- if (crv == CKR_OK && sftk_isTrue(key, CKA_TOKEN)) |
- crv = CKR_TEMPLATE_INCONSISTENT; |
- if (crv == CKR_OK) |
- crv = sftk_DeriveSensitiveCheck(sourceKey, key); |
- if (crv == CKR_OK) |
- crv = jpake_Round2(hashType, |
- (CK_NSS_JPAKERound2Params *) pMechanism->pParameter, |
- sourceKey, key); |
- break; |
- |
- case CKM_NSS_JPAKE_FINAL_SHA1: hashType = HASH_AlgSHA1; goto jpakeFinal; |
- case CKM_NSS_JPAKE_FINAL_SHA256: hashType = HASH_AlgSHA256; goto jpakeFinal; |
- case CKM_NSS_JPAKE_FINAL_SHA384: hashType = HASH_AlgSHA384; goto jpakeFinal; |
- case CKM_NSS_JPAKE_FINAL_SHA512: hashType = HASH_AlgSHA512; goto jpakeFinal; |
-jpakeFinal: |
- if (pMechanism->pParameter == NULL || |
- pMechanism->ulParameterLen != sizeof(CK_NSS_JPAKEFinalParams)) |
- crv = CKR_MECHANISM_PARAM_INVALID; |
- /* We purposely do not do the derive sensitivity check; we want to be |
- able to derive non-sensitive keys while allowing the ROUND1 and |
- ROUND2 keys to be sensitive (which they always are, since they are |
- in the CKO_PRIVATE_KEY class). The caller must include CKA_SENSITIVE |
- in the template in order for the resultant keyblock key to be |
- sensitive. |
- */ |
- if (crv == CKR_OK) |
- crv = jpake_Final(hashType, |
- (CK_NSS_JPAKEFinalParams *) pMechanism->pParameter, |
- sourceKey, key); |
- break; |
- |
- default: |
- crv = CKR_MECHANISM_INVALID; |
- } |
- if (att) { |
- sftk_FreeAttribute(att); |
- } |
- sftk_FreeObject(sourceKey); |
- if (crv != CKR_OK) { |
- if (key) sftk_FreeObject(key); |
- return crv; |
- } |
- |
- /* link the key object into the list */ |
- if (key) { |
- SFTKSessionObject *sessKey = sftk_narrowToSessionObject(key); |
- PORT_Assert(sessKey); |
- /* get the session */ |
- sessKey->wasDerived = PR_TRUE; |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) { |
- sftk_FreeObject(key); |
- return CKR_HOST_MEMORY; |
- } |
- |
- crv = sftk_handleObject(key,session); |
- sftk_FreeSession(session); |
- *phKey = key->handle; |
- sftk_FreeObject(key); |
- } |
- return crv; |
-} |
- |
- |
-/* NSC_GetFunctionStatus obtains an updated status of a function running |
- * in parallel with an application. */ |
-CK_RV NSC_GetFunctionStatus(CK_SESSION_HANDLE hSession) |
-{ |
- CHECK_FORK(); |
- |
- return CKR_FUNCTION_NOT_PARALLEL; |
-} |
- |
-/* NSC_CancelFunction cancels a function running in parallel */ |
-CK_RV NSC_CancelFunction(CK_SESSION_HANDLE hSession) |
-{ |
- CHECK_FORK(); |
- |
- return CKR_FUNCTION_NOT_PARALLEL; |
-} |
- |
-/* NSC_GetOperationState saves the state of the cryptographic |
- *operation in a session. |
- * NOTE: This code only works for digest functions for now. eventually need |
- * to add full flatten/resurect to our state stuff so that all types of state |
- * can be saved */ |
-CK_RV NSC_GetOperationState(CK_SESSION_HANDLE hSession, |
- CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen) |
-{ |
- SFTKSessionContext *context; |
- SFTKSession *session; |
- CK_RV crv; |
- CK_ULONG pOSLen = *pulOperationStateLen; |
- |
- CHECK_FORK(); |
- |
- /* make sure we're legal */ |
- crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, &session); |
- if (crv != CKR_OK) return crv; |
- |
- *pulOperationStateLen = context->cipherInfoLen + sizeof(CK_MECHANISM_TYPE) |
- + sizeof(SFTKContextType); |
- if (pOperationState == NULL) { |
- sftk_FreeSession(session); |
- return CKR_OK; |
- } else { |
- if (pOSLen < *pulOperationStateLen) { |
- return CKR_BUFFER_TOO_SMALL; |
- } |
- } |
- PORT_Memcpy(pOperationState,&context->type,sizeof(SFTKContextType)); |
- pOperationState += sizeof(SFTKContextType); |
- PORT_Memcpy(pOperationState,&context->currentMech, |
- sizeof(CK_MECHANISM_TYPE)); |
- pOperationState += sizeof(CK_MECHANISM_TYPE); |
- PORT_Memcpy(pOperationState,context->cipherInfo,context->cipherInfoLen); |
- sftk_FreeSession(session); |
- return CKR_OK; |
-} |
- |
- |
-#define sftk_Decrement(stateSize,len) \ |
- stateSize = ((stateSize) > (CK_ULONG)(len)) ? \ |
- ((stateSize) - (CK_ULONG)(len)) : 0; |
- |
-/* NSC_SetOperationState restores the state of the cryptographic |
- * operation in a session. This is coded like it can restore lots of |
- * states, but it only works for truly flat cipher structures. */ |
-CK_RV NSC_SetOperationState(CK_SESSION_HANDLE hSession, |
- CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, |
- CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey) |
-{ |
- SFTKSessionContext *context; |
- SFTKSession *session; |
- SFTKContextType type; |
- CK_MECHANISM mech; |
- CK_RV crv = CKR_OK; |
- |
- CHECK_FORK(); |
- |
- while (ulOperationStateLen != 0) { |
- /* get what type of state we're dealing with... */ |
- PORT_Memcpy(&type,pOperationState, sizeof(SFTKContextType)); |
- |
- /* fix up session contexts based on type */ |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) return CKR_SESSION_HANDLE_INVALID; |
- context = sftk_ReturnContextByType(session, type); |
- sftk_SetContextByType(session, type, NULL); |
- if (context) { |
- sftk_FreeContext(context); |
- } |
- pOperationState += sizeof(SFTKContextType); |
- sftk_Decrement(ulOperationStateLen,sizeof(SFTKContextType)); |
- |
- |
- /* get the mechanism structure */ |
- PORT_Memcpy(&mech.mechanism,pOperationState,sizeof(CK_MECHANISM_TYPE)); |
- pOperationState += sizeof(CK_MECHANISM_TYPE); |
- sftk_Decrement(ulOperationStateLen, sizeof(CK_MECHANISM_TYPE)); |
- /* should be filled in... but not necessary for hash */ |
- mech.pParameter = NULL; |
- mech.ulParameterLen = 0; |
- switch (type) { |
- case SFTK_HASH: |
- crv = NSC_DigestInit(hSession,&mech); |
- if (crv != CKR_OK) break; |
- crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, |
- NULL); |
- if (crv != CKR_OK) break; |
- PORT_Memcpy(context->cipherInfo,pOperationState, |
- context->cipherInfoLen); |
- pOperationState += context->cipherInfoLen; |
- sftk_Decrement(ulOperationStateLen,context->cipherInfoLen); |
- break; |
- default: |
- /* do sign/encrypt/decrypt later */ |
- crv = CKR_SAVED_STATE_INVALID; |
- } |
- sftk_FreeSession(session); |
- if (crv != CKR_OK) break; |
- } |
- return crv; |
-} |
- |
-/* Dual-function cryptographic operations */ |
- |
-/* NSC_DigestEncryptUpdate continues a multiple-part digesting and encryption |
- * operation. */ |
-CK_RV NSC_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, |
- CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, |
- CK_ULONG_PTR pulEncryptedPartLen) |
-{ |
- CK_RV crv; |
- |
- CHECK_FORK(); |
- |
- crv = NSC_EncryptUpdate(hSession,pPart,ulPartLen, pEncryptedPart, |
- pulEncryptedPartLen); |
- if (crv != CKR_OK) return crv; |
- crv = NSC_DigestUpdate(hSession,pPart,ulPartLen); |
- |
- return crv; |
-} |
- |
- |
-/* NSC_DecryptDigestUpdate continues a multiple-part decryption and |
- * digesting operation. */ |
-CK_RV NSC_DecryptDigestUpdate(CK_SESSION_HANDLE hSession, |
- CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, |
- CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) |
-{ |
- CK_RV crv; |
- |
- CHECK_FORK(); |
- |
- crv = NSC_DecryptUpdate(hSession,pEncryptedPart, ulEncryptedPartLen, |
- pPart, pulPartLen); |
- if (crv != CKR_OK) return crv; |
- crv = NSC_DigestUpdate(hSession,pPart,*pulPartLen); |
- |
- return crv; |
-} |
- |
- |
-/* NSC_SignEncryptUpdate continues a multiple-part signing and |
- * encryption operation. */ |
-CK_RV NSC_SignEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, |
- CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, |
- CK_ULONG_PTR pulEncryptedPartLen) |
-{ |
- CK_RV crv; |
- |
- CHECK_FORK(); |
- |
- crv = NSC_EncryptUpdate(hSession,pPart,ulPartLen, pEncryptedPart, |
- pulEncryptedPartLen); |
- if (crv != CKR_OK) return crv; |
- crv = NSC_SignUpdate(hSession,pPart,ulPartLen); |
- |
- return crv; |
-} |
- |
- |
-/* NSC_DecryptVerifyUpdate continues a multiple-part decryption |
- * and verify operation. */ |
-CK_RV NSC_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, |
- CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, |
- CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) |
-{ |
- CK_RV crv; |
- |
- CHECK_FORK(); |
- |
- crv = NSC_DecryptUpdate(hSession,pEncryptedData, ulEncryptedDataLen, |
- pData, pulDataLen); |
- if (crv != CKR_OK) return crv; |
- crv = NSC_VerifyUpdate(hSession, pData, *pulDataLen); |
- |
- return crv; |
-} |
- |
-/* NSC_DigestKey continues a multi-part message-digesting operation, |
- * by digesting the value of a secret key as part of the data already digested. |
- */ |
-CK_RV NSC_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) |
-{ |
- SFTKSession *session = NULL; |
- SFTKObject *key = NULL; |
- SFTKAttribute *att; |
- CK_RV crv; |
- |
- CHECK_FORK(); |
- |
- session = sftk_SessionFromHandle(hSession); |
- if (session == NULL) return CKR_SESSION_HANDLE_INVALID; |
- |
- key = sftk_ObjectFromHandle(hKey,session); |
- sftk_FreeSession(session); |
- if (key == NULL) return CKR_KEY_HANDLE_INVALID; |
- |
- /* PUT ANY DIGEST KEY RESTRICTION CHECKS HERE */ |
- |
- /* make sure it's a valid key for this operation */ |
- if (key->objclass != CKO_SECRET_KEY) { |
- sftk_FreeObject(key); |
- return CKR_KEY_TYPE_INCONSISTENT; |
- } |
- /* get the key value */ |
- att = sftk_FindAttribute(key,CKA_VALUE); |
- sftk_FreeObject(key); |
- if (!att) { |
- return CKR_KEY_HANDLE_INVALID; |
- } |
- crv = NSC_DigestUpdate(hSession,(CK_BYTE_PTR)att->attrib.pValue, |
- att->attrib.ulValueLen); |
- sftk_FreeAttribute(att); |
- return crv; |
-} |