pkcs11c.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:155k
- /*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
- /*
- * 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 "keylow.h"
- #include "cert.h"
- #include "sechash.h"
- #include "secder.h"
- #include "secdig.h"
- #include "secpkcs5.h" /* We do PBE below */
- #include "pkcs11t.h"
- #include "secoid.h"
- #include "alghmac.h"
- #include "softoken.h"
- #include "secasn1.h"
- #include "secmodi.h"
- #include "certdb.h"
- #include "ssl3prot.h" /* for SSL3_RANDOM_LENGTH */
- #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"
- /* forward static declaration. */
- static SECStatus pk11_PRF(const SECItem *secret, const char *label,
- SECItem *seed, SECItem *result);
- #define PK11_OFFSETOF(str, memb) ((PRPtrdiff)(&(((str *)0)->memb)))
- static void pk11_Null(void *data, PRBool freeit)
- {
- return;
- }
- /*
- * free routines.... Free local type allocated data, and convert
- * other free routines to the destroy signature.
- */
- static void
- pk11_FreePrivKey(SECKEYLowPrivateKey *key, PRBool freeit)
- {
- SECKEY_LowDestroyPrivateKey(key);
- }
- static void
- pk11_HMAC_Destroy(HMACContext *context, PRBool freeit)
- {
- HMAC_Destroy(context);
- }
- static void
- pk11_Space(void *data, PRBool freeit)
- {
- PORT_Free(data);
- }
- static void pk11_FreeSignInfo(PK11HashSignInfo *data, PRBool freeit)
- {
- SECKEY_LowDestroyPrivateKey(data->key);
- PORT_Free(data);
- }
- static DSAPublicKey *
- DSA_CreateVerifyContext(SECKEYLowPublicKey *pubKey)
- {
- PLArenaPool * arena;
- DSAPublicKey * dsaKey;
- SECStatus rv;
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (!arena) goto loser;
- dsaKey = (DSAPublicKey *)PORT_ArenaZAlloc(arena, sizeof (DSAPublicKey));
- if (!dsaKey) goto loser;
- dsaKey->params.arena = arena;
- #define COPY_DSA_ITEM(item)
- rv = SECITEM_CopyItem(arena, &dsaKey->item, &pubKey->u.dsa.item);
- if (rv != SECSuccess) goto loser;
- COPY_DSA_ITEM(params.prime);
- COPY_DSA_ITEM(params.subPrime);
- COPY_DSA_ITEM(params.base);
- COPY_DSA_ITEM(publicValue);
- return dsaKey;
- loser:
- if (arena)
- PORT_FreeArena(arena, PR_TRUE);
- return NULL;
- #undef COPY_DSA_ITEM
- }
- static void
- DSA_DestroyVerifyContext(DSAPublicKey * key)
- {
- if (key && key->params.arena)
- PORT_FreeArena(key->params.arena, PR_TRUE);
- }
- static DSAPrivateKey *
- DSA_CreateSignContext(SECKEYLowPrivateKey *privKey)
- {
- PLArenaPool * arena;
- DSAPrivateKey * dsaKey;
- SECStatus rv;
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (!arena) goto loser;
- dsaKey = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof (DSAPrivateKey));
- if (!dsaKey) goto loser;
- dsaKey->params.arena = arena;
- #define COPY_DSA_ITEM(item)
- rv = SECITEM_CopyItem(arena, &dsaKey->item, &privKey->u.dsa.item);
- if (rv != SECSuccess) goto loser;
- COPY_DSA_ITEM(params.prime);
- COPY_DSA_ITEM(params.subPrime);
- COPY_DSA_ITEM(params.base);
- COPY_DSA_ITEM(publicValue);
- COPY_DSA_ITEM(privateValue);
- return dsaKey;
- loser:
- if (arena)
- PORT_FreeArena(arena, PR_TRUE);
- return NULL;
- #undef COPY_DSA_ITEM
- }
- static void
- DSA_DestroySignContext(DSAPrivateKey * key)
- {
- if (key && key->params.arena)
- PORT_FreeArena(key->params.arena, PR_TRUE);
- }
- /*
- * 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
- pk11_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 CKR_DEVICE_ERROR;
- /* xor source with des, zero the parity bits and depricate 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 CKR_DEVICE_ERROR;
- /* set the corret parity on our new des key */
- pk11_FormatDESKey(deskey, 8);
- return CKR_OK;
- }
- static CK_RV
- pk11_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
- CK_OBJECT_HANDLE hKey, CK_ATTRIBUTE_TYPE etype,
- PK11ContextType contextType);
- /*
- * Calculate a Lynx checksum for CKM_LYNX_WRAP mechanism.
- */
- static CK_RV
- pk11_calcLynxChecksum(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hWrapKey,
- unsigned char *checksum, unsigned char *key, CK_ULONG len)
- {
- CK_BYTE E[10];
- CK_ULONG Elen = sizeof (E);
- CK_BYTE C[8];
- CK_ULONG Clen = sizeof (C);
- unsigned short sum1 = 0, sum2 = 0;
- CK_MECHANISM mech = { CKM_DES_ECB, NULL, 0 };
- int i;
- CK_RV crv;
- if (len != 8) return CKR_WRAPPED_KEY_LEN_RANGE;
-
- /* zero the parity bits */
- for (i=0; i < 8; i++) {
- sum1 = sum1 + key[i];
- sum2 = sum2 + sum1;
- }
- /* encrypt with key 1 */
- crv = pk11_EncryptInit(hSession,&mech,hWrapKey,CKA_WRAP, PK11_ENCRYPT);
- if (crv != CKR_OK) return crv;
- crv = NSC_Encrypt(hSession,key,len,E,&Elen);
- if (crv != CKR_OK) return crv;
- E[8] = (sum2 >> 8) & 0xff;
- E[9] = sum2 & 0xff;
- crv = pk11_EncryptInit(hSession,&mech,hWrapKey,CKA_WRAP, PK11_ENCRYPT);
- if (crv != CKR_OK) return crv;
- crv = NSC_Encrypt(hSession,&E[2],len,C,&Clen);
- if (crv != CKR_OK) return crv;
- checksum[0] = C[6];
- checksum[1] = C[7];
-
- return CKR_OK;
- }
- /* NSC_DestroyObject destroys an object. */
- CK_RV
- NSC_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
- {
- PK11Slot *slot = pk11_SlotFromSessionHandle(hSession);
- PK11Session *session;
- PK11Object *object;
- PK11FreeStatus status;
- /*
- * This whole block just makes sure we really can destroy the
- * requested object.
- */
- session = pk11_SessionFromHandle(hSession);
- if (session == NULL) {
- return CKR_SESSION_HANDLE_INVALID;
- }
- object = pk11_ObjectFromHandle(hObject,session);
- if (object == NULL) {
- pk11_FreeSession(session);
- return CKR_OBJECT_HANDLE_INVALID;
- }
- /* don't destroy a private object if we aren't logged in */
- if ((!slot->isLoggedIn) && (slot->needLogin) &&
- (pk11_isTrue(object,CKA_PRIVATE))) {
- pk11_FreeSession(session);
- pk11_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) &&
- (pk11_isTrue(object,CKA_TOKEN))) {
- pk11_FreeSession(session);
- pk11_FreeObject(object);
- return CKR_SESSION_READ_ONLY;
- }
- pk11_DeleteObject(session,object);
- pk11_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 = pk11_FreeObject(object);
- return (status != PK11_DestroyFailure) ? CKR_OK : CKR_DEVICE_ERROR;
- }
- /*
- ************** Crypto Functions: Utilities ************************
- */
- /*
- * return a context based on the PK11Context type.
- */
- PK11SessionContext *
- pk11_ReturnContextByType(PK11Session *session, PK11ContextType type)
- {
- switch (type) {
- case PK11_ENCRYPT:
- case PK11_DECRYPT:
- return session->enc_context;
- case PK11_HASH:
- return session->hash_context;
- case PK11_SIGN:
- case PK11_SIGN_RECOVER:
- case PK11_VERIFY:
- case PK11_VERIFY_RECOVER:
- return session->hash_context;
- }
- return NULL;
- }
- /*
- * change a context based on the PK11Context type.
- */
- void
- pk11_SetContextByType(PK11Session *session, PK11ContextType type,
- PK11SessionContext *context)
- {
- switch (type) {
- case PK11_ENCRYPT:
- case PK11_DECRYPT:
- session->enc_context = context;
- break;
- case PK11_HASH:
- session->hash_context = context;
- break;
- case PK11_SIGN:
- case PK11_SIGN_RECOVER:
- case PK11_VERIFY:
- case PK11_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
- pk11_GetContext(CK_SESSION_HANDLE handle,PK11SessionContext **contextPtr,
- PK11ContextType type, PRBool needMulti, PK11Session **sessionPtr)
- {
- PK11Session *session;
- PK11SessionContext *context;
- session = pk11_SessionFromHandle(handle);
- if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
- context = pk11_ReturnContextByType(session,type);
- /* make sure the context is valid */
- if((context==NULL)||(context->type!=type)||(needMulti&&!(context->multi))){
- pk11_FreeSession(session);
- return CKR_OPERATION_NOT_INITIALIZED;
- }
- *contextPtr = context;
- if (sessionPtr != NULL) {
- *sessionPtr = session;
- } else {
- pk11_FreeSession(session);
- }
- return CKR_OK;
- }
- /*
- ************** 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
- pk11_InitGeneric(PK11Session *session,PK11SessionContext **contextPtr,
- PK11ContextType ctype,PK11Object **keyPtr,
- CK_OBJECT_HANDLE hKey, CK_KEY_TYPE *keyTypePtr,
- CK_OBJECT_CLASS pubKeyType, CK_ATTRIBUTE_TYPE operation)
- {
- PK11Object *key = NULL;
- PK11Attribute *att;
- PK11SessionContext *context;
- /* We can only init if there is not current context active */
- if (pk11_ReturnContextByType(session,ctype) != NULL) {
- return CKR_OPERATION_ACTIVE;
- }
- /* find the key */
- if (keyPtr) {
- key = pk11_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))
- || !pk11_isTrue(key,operation)) {
- pk11_FreeObject(key);
- return CKR_KEY_TYPE_INCONSISTENT;
- }
- /* get the key type */
- att = pk11_FindAttribute(key,CKA_KEY_TYPE);
- PORT_Assert(att != NULL);
- *keyTypePtr = *(CK_KEY_TYPE *)att->attrib.pValue;
- pk11_FreeAttribute(att);
- *keyPtr = key;
- }
- /* allocate the context structure */
- context = (PK11SessionContext *)PORT_Alloc(sizeof(PK11SessionContext));
- if (context == NULL) {
- if (key) pk11_FreeObject(key);
- return CKR_HOST_MEMORY;
- }
- context->type = ctype;
- context->multi = PR_TRUE;
- context->cipherInfo = NULL;
- context->hashInfo = NULL;
- context->doPad = PR_FALSE;
- context->padDataLength = 0;
- *contextPtr = context;
- return CKR_OK;
- }
- /* NSC_EncryptInit initializes an encryption operation. */
- /* This function is used by NSC_EncryptInit and NSC_WrapKey. The only difference
- * in their uses if whether or not etype is CKA_ENCRYPT or CKA_WRAP */
- static CK_RV
- pk11_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
- CK_OBJECT_HANDLE hKey, CK_ATTRIBUTE_TYPE etype,
- PK11ContextType contextType)
- {
- PK11Session *session;
- PK11Object *key;
- PK11SessionContext *context;
- PK11Attribute *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;
- SECKEYLowPublicKey *pubKey;
- unsigned effectiveKeyLength;
- unsigned char newdeskey[8];
- PRBool useNewKey=PR_FALSE;
- int t;
- session = pk11_SessionFromHandle(hSession);
- if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
- crv = pk11_InitGeneric(session,&context,contextType,&key,hKey,&key_type,
- CKO_PUBLIC_KEY, etype);
-
- if (crv != CKR_OK) {
- pk11_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;
- pubKey = pk11_GetPubKey(key,CKK_RSA);
- if (pubKey == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- context->cipherInfo = pubKey;
- context->update = (PK11Cipher) (pMechanism->mechanism == CKM_RSA_X_509
- ? RSA_EncryptRaw : RSA_EncryptBlock);
- context->destroy = pk11_Null;
- break;
- case CKM_RC2_CBC_PAD:
- context->doPad = PR_TRUE;
- context->blockSize = 8;
- /* fall thru */
- case CKM_RC2_ECB:
- case CKM_RC2_CBC:
- if (key_type != CKK_RC2) {
- crv = CKR_KEY_TYPE_INCONSISTENT;
- break;
- }
- att = pk11_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);
- pk11_FreeAttribute(att);
- if (context->cipherInfo == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- context->update = (PK11Cipher) RC2_Encrypt;
- context->destroy = (PK11Destroy) 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 = pk11_FindAttribute(key,CKA_VALUE);
- if (att == NULL) {
- crv = CKR_KEY_HANDLE_INVALID;
- break;
- }
- rc5_param = (CK_RC5_CBC_PARAMS *)pMechanism->pParameter;
- if (context->doPad) {
- 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);
- pk11_FreeAttribute(att);
- if (context->cipherInfo == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- context->update = (PK11Cipher) RC5_Encrypt;
- context->destroy = (PK11Destroy) RC5_DestroyContext;
- break;
- #endif
- case CKM_RC4:
- if (key_type != CKK_RC4) {
- crv = CKR_KEY_TYPE_INCONSISTENT;
- break;
- }
- att = pk11_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);
- pk11_FreeAttribute(att);
- if (context->cipherInfo == NULL) {
- crv = CKR_HOST_MEMORY; /* WRONG !!! */
- break;
- }
- context->update = (PK11Cipher) RC4_Encrypt;
- context->destroy = (PK11Destroy) RC4_DestroyContext;
- break;
- case CKM_CDMF_CBC_PAD:
- context->doPad = PR_TRUE;
- context->blockSize = 8;
- /* 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;
- useNewKey=PR_TRUE;
- 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;
- context->blockSize = 8;
- /* 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;
- context->blockSize = 8;
- /* 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:
- att = pk11_FindAttribute(key,CKA_VALUE);
- if (att == NULL) {
- crv = CKR_KEY_HANDLE_INVALID;
- break;
- }
- if (useNewKey) {
- crv = pk11_cdmf2des((unsigned char*)att->attrib.pValue,newdeskey);
- if (crv != CKR_OK) {
- pk11_FreeAttribute(att);
- break;
- }
- }
- context->cipherInfo = DES_CreateContext(
- useNewKey ? newdeskey : (unsigned char*)att->attrib.pValue,
- (unsigned char*)pMechanism->pParameter,t, PR_TRUE);
- pk11_FreeAttribute(att);
- if (context->cipherInfo == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- context->update = (PK11Cipher) DES_Encrypt;
- context->destroy = (PK11Destroy) DES_DestroyContext;
- break;
- default:
- crv = CKR_MECHANISM_INVALID;
- break;
- }
- pk11_FreeObject(key);
- if (crv != CKR_OK) {
- pk11_FreeContext(context);
- pk11_FreeSession(session);
- return crv;
- }
- pk11_SetContextByType(session, contextType, context);
- pk11_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)
- {
- return pk11_EncryptInit(hSession, pMechanism, hKey, CKA_ENCRYPT,
- PK11_ENCRYPT);
- }
- /* 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)
- {
- PK11SessionContext *context;
- unsigned int outlen,i;
- unsigned int padoutlen = 0;
- unsigned int maxout = *pulEncryptedPartLen;
- CK_RV crv;
- SECStatus rv;
- /* make sure we're legal */
- crv = pk11_GetContext(hSession,&context,PK11_ENCRYPT,PR_TRUE,NULL);
- if (crv != CKR_OK) return crv;
- /* 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,
- &outlen,context->blockSize,context->padBuf,context->blockSize);
- if (rv != SECSuccess) return CKR_DEVICE_ERROR;
- 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 : CKR_DEVICE_ERROR;
- }
- /* NSC_EncryptFinal finishes a multiple-part encryption operation. */
- CK_RV NSC_EncryptFinal(CK_SESSION_HANDLE hSession,
- CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen)
- {
- PK11Session *session;
- PK11SessionContext *context;
- unsigned int outlen,i;
- unsigned int maxout = *pulLastEncryptedPartLen;
- CK_RV crv;
- SECStatus rv = SECSuccess;
- /* make sure we're legal */
- crv = pk11_GetContext(hSession,&context,PK11_ENCRYPT,PR_TRUE,&session);
- if (crv != CKR_OK) return crv;
- *pulLastEncryptedPartLen = 0;
- /* 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;
- }
- /* do it */
- pk11_SetContextByType(session, PK11_ENCRYPT, NULL);
- pk11_FreeContext(context);
- pk11_FreeSession(session);
- return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
- }
- /* 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)
- {
- PK11Session *session;
- PK11SessionContext *context;
- unsigned int outlen;
- unsigned int maxoutlen = *pulEncryptedDataLen;
- CK_RV crv;
- CK_RV crv2;
- SECStatus rv;
- /* make sure we're legal */
- crv = pk11_GetContext(hSession,&context,PK11_ENCRYPT,PR_FALSE,&session);
- if (crv != CKR_OK) return crv;
- if (context->doPad) {
- CK_ULONG finalLen;
- /* padding is fairly complicated, have the update and final
- * code deal with it */
- pk11_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;
- }
-
- /* do it: NOTE: this assumes buf size is big enough. */
- rv = (*context->update)(context->cipherInfo, pEncryptedData,
- &outlen, maxoutlen, pData, ulDataLen);
- *pulEncryptedDataLen = (CK_ULONG) outlen;
- pk11_FreeContext(context);
- pk11_SetContextByType(session, PK11_ENCRYPT, NULL);
- pk11_FreeSession(session);
- return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
- }
- /*
- ************** Crypto Functions: Decrypt ************************
- */
- /* NSC_DecryptInit initializes a decryption operation. */
- static CK_RV pk11_DecryptInit( CK_SESSION_HANDLE hSession,
- CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, CK_ATTRIBUTE_TYPE dtype,
- PK11ContextType contextType)
- {
- PK11Session *session;
- PK11Object *key;
- PK11Attribute *att;
- PK11SessionContext *context;
- 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;
- SECKEYLowPrivateKey *privKey;
- unsigned char newdeskey[8];
- PRBool useNewKey=PR_FALSE;
- int t;
- session = pk11_SessionFromHandle(hSession);
- if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
- crv = pk11_InitGeneric(session,&context,contextType,&key,hKey,&key_type,
- CKO_PRIVATE_KEY,dtype);
- if (crv != CKR_OK) {
- pk11_FreeSession(session);
- return crv;
- }
- /*
- * now handle each mechanism
- */
- 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;
- privKey = pk11_GetPrivKey(key,CKK_RSA);
- if (privKey == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- context->cipherInfo = privKey;
- context->update = (PK11Cipher) (pMechanism->mechanism == CKM_RSA_X_509
- ? RSA_DecryptRaw : RSA_DecryptBlock);
- context->destroy = (context->cipherInfo == key->objectInfo) ?
- (PK11Destroy) pk11_Null : (PK11Destroy) pk11_FreePrivKey;
- break;
- case CKM_RC2_CBC_PAD:
- context->doPad = PR_TRUE;
- context->blockSize = 8;
- /* fall thru */
- case CKM_RC2_ECB:
- case CKM_RC2_CBC:
- if (key_type != CKK_RC2) {
- crv = CKR_KEY_TYPE_INCONSISTENT;
- break;
- }
- att = pk11_FindAttribute(key,CKA_VALUE);
- 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);
- pk11_FreeAttribute(att);
- if (context->cipherInfo == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- context->update = (PK11Cipher) RC2_Decrypt;
- context->destroy = (PK11Destroy) 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 = pk11_FindAttribute(key,CKA_VALUE);
- if (att == NULL) {
- crv = CKR_KEY_HANDLE_INVALID;
- break;
- }
- rc5_param = (CK_RC5_CBC_PARAMS *)pMechanism->pParameter;
- if (context->doPad) {
- 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);
- pk11_FreeAttribute(att);
- if (context->cipherInfo == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- context->update = (PK11Cipher) RC5_Decrypt;
- context->destroy = (PK11Destroy) RC5_DestroyContext;
- break;
- #endif
- case CKM_RC4:
- if (key_type != CKK_RC4) {
- crv = CKR_KEY_TYPE_INCONSISTENT;
- break;
- }
- att = pk11_FindAttribute(key,CKA_VALUE);
- context->cipherInfo =
- RC4_CreateContext((unsigned char*)att->attrib.pValue,
- att->attrib.ulValueLen);
- pk11_FreeAttribute(att);
- if (context->cipherInfo == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- context->update = (PK11Cipher) RC4_Decrypt;
- context->destroy = (PK11Destroy) RC4_DestroyContext;
- break;
- case CKM_CDMF_CBC_PAD:
- context->doPad = PR_TRUE;
- context->blockSize = 8;
- /* 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;
- useNewKey = PR_TRUE;
- 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;
- context->blockSize = 8;
- /* 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;
- context->blockSize = 8;
- /* 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:
- att = pk11_FindAttribute(key,CKA_VALUE);
- if (att == NULL) {
- crv = CKR_KEY_HANDLE_INVALID;
- break;
- }
- if (useNewKey) {
- crv = pk11_cdmf2des((unsigned char*)att->attrib.pValue,newdeskey);
- if (crv != CKR_OK) {
- pk11_FreeAttribute(att);
- break;
- }
- }
- context->cipherInfo = DES_CreateContext(
- useNewKey ? newdeskey : (unsigned char*)att->attrib.pValue,
- (unsigned char*)pMechanism->pParameter,t, PR_FALSE);
- pk11_FreeAttribute(att);
- if (context->cipherInfo == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- context->update = (PK11Cipher) DES_Decrypt;
- context->destroy = (PK11Destroy) DES_DestroyContext;
- break;
- default:
- crv = CKR_MECHANISM_INVALID;
- break;
- }
- pk11_FreeObject(key);
- if (crv != CKR_OK) {
- pk11_FreeContext(context);
- pk11_FreeSession(session);
- return crv;
- }
- pk11_SetContextByType(session, contextType, context);
- pk11_FreeSession(session);
- return CKR_OK;
- }
- /* NSC_DecryptInit initializes a decryption operation. */
- CK_RV NSC_DecryptInit( CK_SESSION_HANDLE hSession,
- CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
- {
- return pk11_DecryptInit(hSession,pMechanism,hKey,CKA_DECRYPT,PK11_DECRYPT);
- }
- /* 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)
- {
- PK11SessionContext *context;
- unsigned int padoutlen = 0;
- unsigned int outlen;
- unsigned int maxout = *pulPartLen;
- CK_RV crv;
- SECStatus rv;
- /* make sure we're legal */
- crv = pk11_GetContext(hSession,&context,PK11_DECRYPT,PR_TRUE,NULL);
- if (crv != CKR_OK) return crv;
- 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 CKR_DEVICE_ERROR;
- 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 : CKR_DEVICE_ERROR;
- }
- /* NSC_DecryptFinal finishes a multiple-part decryption operation. */
- CK_RV NSC_DecryptFinal(CK_SESSION_HANDLE hSession,
- CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen)
- {
- PK11Session *session;
- PK11SessionContext *context;
- unsigned int outlen;
- unsigned int maxout = *pulLastPartLen;
- CK_RV crv;
- SECStatus rv = SECSuccess;
- /* make sure we're legal */
- crv = pk11_GetContext(hSession,&context,PK11_DECRYPT,PR_TRUE,&session);
- if (crv != CKR_OK) return crv;
- *pulLastPartLen = 0;
- 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) {
- unsigned int padSize =
- (unsigned int) pLastPart[context->blockSize-1];
- *pulLastPartLen = outlen - padSize;
- }
- }
- }
- /* do it */
- pk11_SetContextByType(session, PK11_DECRYPT, NULL);
- pk11_FreeContext(context);
- pk11_FreeSession(session);
- return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
- }
- /* 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)
- {
- PK11Session *session;
- PK11SessionContext *context;
- unsigned int outlen;
- unsigned int maxoutlen = *pulDataLen;
- CK_RV crv;
- CK_RV crv2;
- SECStatus rv;
- /* make sure we're legal */
- crv = pk11_GetContext(hSession,&context,PK11_DECRYPT,PR_FALSE,&session);
- if (crv != CKR_OK) return crv;
- if (context->doPad) {
- CK_ULONG finalLen;
- /* padding is fairly complicated, have the update and final
- * code deal with it */
- pk11_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);
- *pulDataLen = (CK_ULONG) outlen;
- pk11_FreeContext(context);
- pk11_SetContextByType(session, PK11_DECRYPT, NULL);
- pk11_FreeSession(session);
- return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
- }
- /*
- ************** Crypto Functions: Digest (HASH) ************************
- */
- /* NSC_DigestInit initializes a message-digesting operation. */
- CK_RV NSC_DigestInit(CK_SESSION_HANDLE hSession,
- CK_MECHANISM_PTR pMechanism)
- {
- PK11Session *session;
- PK11SessionContext *context;
- MD2Context *md2_context;
- MD5Context *md5_context;
- SHA1Context *sha1_context;
- CK_RV crv = CKR_OK;
- session = pk11_SessionFromHandle(hSession);
- if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
- crv = pk11_InitGeneric(session,&context,PK11_HASH,NULL,0,NULL, 0, 0);
- if (crv != CKR_OK) {
- pk11_FreeSession(session);
- return crv;
- }
- switch(pMechanism->mechanism) {
- case CKM_MD2:
- md2_context = MD2_NewContext();
- context->cipherInfo = (void *)md2_context;
- context->cipherInfoLen = MD2_FlattenSize(md2_context);
- context->currentMech = CKM_MD2;
- if (context->cipherInfo == NULL) {
- crv= CKR_HOST_MEMORY;
-
- }
- context->hashUpdate = (PK11Hash) MD2_Update;
- context->end = (PK11End) MD2_End;
- context->destroy = (PK11Destroy) MD2_DestroyContext;
- MD2_Begin(md2_context);
- break;
- case CKM_MD5:
- md5_context = MD5_NewContext();
- context->cipherInfo = (void *)md5_context;
- context->cipherInfoLen = MD5_FlattenSize(md5_context);
- context->currentMech = CKM_MD5;
- if (context->cipherInfo == NULL) {
- crv= CKR_HOST_MEMORY;
-
- }
- context->hashUpdate = (PK11Hash) MD5_Update;
- context->end = (PK11End) MD5_End;
- context->destroy = (PK11Destroy) MD5_DestroyContext;
- MD5_Begin(md5_context);
- break;
- case CKM_SHA_1:
- sha1_context = SHA1_NewContext();
- context->cipherInfo = (void *)sha1_context;
- context->cipherInfoLen = SHA1_FlattenSize(sha1_context);
- context->currentMech = CKM_SHA_1;
- if (context->cipherInfo == NULL) {
- crv= CKR_HOST_MEMORY;
- break;
- }
- context->hashUpdate = (PK11Hash) SHA1_Update;
- context->end = (PK11End) SHA1_End;
- context->destroy = (PK11Destroy) SHA1_DestroyContext;
- SHA1_Begin(sha1_context);
- break;
- default:
- crv = CKR_MECHANISM_INVALID;
- break;
- }
- if (crv != CKR_OK) {
- pk11_FreeContext(context);
- pk11_FreeSession(session);
- return crv;
- }
- pk11_SetContextByType(session, PK11_HASH, context);
- pk11_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)
- {
- PK11Session *session;
- PK11SessionContext *context;
- unsigned int digestLen;
- unsigned int maxout = *pulDigestLen;
- CK_RV crv;
- /* make sure we're legal */
- crv = pk11_GetContext(hSession,&context,PK11_HASH,PR_FALSE,&session);
- if (crv != CKR_OK) return crv;
- /* 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;
- pk11_SetContextByType(session, PK11_HASH, NULL);
- pk11_FreeContext(context);
- pk11_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)
- {
- PK11SessionContext *context;
- CK_RV crv;
- /* make sure we're legal */
- crv = pk11_GetContext(hSession,&context,PK11_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)
- {
- PK11Session *session;
- PK11SessionContext *context;
- unsigned int maxout = *pulDigestLen;
- unsigned int digestLen;
- CK_RV crv;
- /* make sure we're legal */
- crv = pk11_GetContext(hSession, &context, PK11_HASH, PR_TRUE, &session);
- if (crv != CKR_OK) return crv;
- if (pDigest != NULL) {
- (*context->end)(context->cipherInfo, pDigest, &digestLen, maxout);
- *pulDigestLen = digestLen;
- } else {
- *pulDigestLen = 0;
- }
- pk11_SetContextByType(session, PK11_HASH, NULL);
- pk11_FreeContext(context);
- pk11_FreeSession(session);
- return CKR_OK;
- }
- /*
- * this helper functions are used by Generic Macing and Signing functions
- * that use hashes as part of their operations.
- */
- static CK_RV
- pk11_doSubMD2(PK11SessionContext *context) {
- MD2Context *md2_context = MD2_NewContext();
- context->hashInfo = (void *)md2_context;
- if (context->hashInfo == NULL) {
- return CKR_HOST_MEMORY;
- }
- context->hashUpdate = (PK11Hash) MD2_Update;
- context->end = (PK11End) MD2_End;
- context->hashdestroy = (PK11Destroy) MD2_DestroyContext;
- MD2_Begin(md2_context);
- return CKR_OK;
- }
- static CK_RV
- pk11_doSubMD5(PK11SessionContext *context) {
- MD5Context *md5_context = MD5_NewContext();
- context->hashInfo = (void *)md5_context;
- if (context->hashInfo == NULL) {
- return CKR_HOST_MEMORY;
- }
- context->hashUpdate = (PK11Hash) MD5_Update;
- context->end = (PK11End) MD5_End;
- context->hashdestroy = (PK11Destroy) MD5_DestroyContext;
- MD5_Begin(md5_context);
- return CKR_OK;
- }
- static CK_RV
- pk11_doSubSHA1(PK11SessionContext *context) {
- SHA1Context *sha1_context = SHA1_NewContext();
- context->hashInfo = (void *)sha1_context;
- if (context->hashInfo == NULL) {
- return CKR_HOST_MEMORY;
- }
- context->hashUpdate = (PK11Hash) SHA1_Update;
- context->end = (PK11End) SHA1_End;
- context->hashdestroy = (PK11Destroy) SHA1_DestroyContext;
- SHA1_Begin(sha1_context);
- return CKR_OK;
- }
- /*
- * HMAC General copies only a portion of the result. This update routine likes
- * the final HMAC output with the signature.
- */
- static SECStatus
- pk11_HMACCopy(CK_ULONG *copyLen,unsigned char *sig,unsigned int *sigLen,
- unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
- {
- if (maxLen < *copyLen) return SECFailure;
- PORT_Memcpy(sig,hash,*copyLen);
- *sigLen = *copyLen;
- return SECSuccess;
- }
- /* Verify is just a compare for HMAC */
- static SECStatus
- pk11_HMACCmp(CK_ULONG *copyLen,unsigned char *sig,unsigned int sigLen,
- unsigned char *hash, unsigned int hashLen)
- {
- return PORT_Memcmp(sig,hash,*copyLen) ? SECSuccess : SECFailure ;
- }
- /*
- * common HMAC initalization routine
- */
- static CK_RV
- pk11_doHMACInit(PK11SessionContext *context,SECOidTag oid,
- PK11Object *key, CK_ULONG mac_size)
- {
- PK11Attribute *keyval;
- HMACContext *HMACcontext;
- CK_ULONG *intpointer;
- keyval = pk11_FindAttribute(key,CKA_VALUE);
- if (keyval == NULL) return CKR_KEY_SIZE_RANGE;
- HMACcontext = HMAC_Create(oid, (const unsigned char*)keyval->attrib.pValue,
- keyval->attrib.ulValueLen);
- context->hashInfo = HMACcontext;
- context->multi = PR_TRUE;
- pk11_FreeAttribute(keyval);
- if (context->hashInfo == NULL) {
- return CKR_HOST_MEMORY;
- }
- context->hashUpdate = (PK11Hash) HMAC_Update;
- context->end = (PK11End) HMAC_Finish;
- context->hashdestroy = (PK11Destroy) pk11_HMAC_Destroy;
- intpointer = (CK_ULONG *) PORT_Alloc(sizeof(CK_ULONG));
- if (intpointer == NULL) {
- return CKR_HOST_MEMORY;
- }
- *intpointer = mac_size;
- context->cipherInfo = (void *) intpointer;
- context->destroy = (PK11Destroy) pk11_Space;
- context->update = (PK11Cipher) pk11_HMACCopy;
- context->verify = (PK11Verify) pk11_HMACCmp;
- 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
- pk11_SSLMACSign(PK11SSLMACInfo *info,unsigned char *sig,unsigned int *sigLen,
- unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
- {
- unsigned char tmpBuf[PK11_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,PK11_MAX_MAC_LENGTH);
- PORT_Memcpy(sig,tmpBuf,info->macSize);
- *sigLen = info->macSize;
- return SECSuccess;
- }
- static SECStatus
- pk11_SSLMACVerify(PK11SSLMACInfo *info,unsigned char *sig,unsigned int sigLen,
- unsigned char *hash, unsigned int hashLen)
- {
- unsigned char tmpBuf[PK11_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,PK11_MAX_MAC_LENGTH);
- return (PORT_Memcmp(sig,tmpBuf,info->macSize) == 0) ?
- SECSuccess : SECFailure;
- }
- /*
- * common HMAC initalization routine
- */
- static CK_RV
- pk11_doSSLMACInit(PK11SessionContext *context,SECOidTag oid,
- PK11Object *key, CK_ULONG mac_size)
- {
- PK11Attribute *keyval;
- PK11Begin begin;
- int padSize;
- PK11SSLMACInfo *sslmacinfo;
- CK_RV crv = CKR_MECHANISM_INVALID;
- if (oid == SEC_OID_SHA1) {
- crv = pk11_doSubSHA1(context);
- begin = (PK11Begin) SHA1_Begin;
- if (crv != CKR_OK) return crv;
- padSize = 40;
- } else {
- crv = pk11_doSubMD5(context);
- if (crv != CKR_OK) return crv;
- begin = (PK11Begin) MD5_Begin;
- padSize = 48;
- }
- context->multi = PR_TRUE;
- keyval = pk11_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 = (PK11SSLMACInfo *) PORT_Alloc(sizeof(PK11SSLMACInfo));
- if (sslmacinfo == NULL) {
- pk11_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;
- pk11_FreeAttribute(keyval);
- context->cipherInfo = (void *) sslmacinfo;
- context->destroy = (PK11Destroy) pk11_Space;
- context->update = (PK11Cipher) pk11_SSLMACSign;
- context->verify = (PK11Verify) pk11_SSLMACVerify;
- return CKR_OK;
- }
- typedef struct {
- PRUint32 cxSize; /* size of allocated block, in bytes. */
- PRUint32 cxKeyLen; /* number of bytes of cxBuf containing key. */
- PRUint32 cxDataLen; /* number of bytes of cxBuf containing data. */
- SECStatus cxRv; /* records failure of void functions. */
- unsigned char cxBuf[512]; /* actual size may be larger than 512. */
- } TLSPRFContext;
- static void
- pk11_TLSPRFHashUpdate(TLSPRFContext *cx, const unsigned char *data,
- unsigned int data_len)
- {
- PRUint32 bytesUsed = PK11_OFFSETOF(TLSPRFContext, cxBuf) +
- cx->cxKeyLen + cx->cxDataLen;
- if (cx->cxRv != SECSuccess) /* function has previously failed. */
- return;
- if (bytesUsed + data_len > cx->cxSize) {
- /* We don't use realloc here because
- ** (a) realloc doesn't zero out the old block, and
- ** (b) if realloc fails, we lose the old block.
- */
- PRUint32 blockSize = bytesUsed + data_len + 512;
- TLSPRFContext *new_cx = (TLSPRFContext *)PORT_Alloc(blockSize);
- if (!new_cx) {
- cx->cxRv = SECFailure;
- return;
- }
- PORT_Memcpy(new_cx, cx, cx->cxSize);
- new_cx->cxSize = blockSize;
- PORT_ZFree(cx, cx->cxSize);
- cx = new_cx;
- }
- PORT_Memcpy(cx->cxBuf + cx->cxKeyLen + cx->cxDataLen, data, data_len);
- cx->cxDataLen += data_len;
- }
- static void
- pk11_TLSPRFEnd(TLSPRFContext *ctx, unsigned char *hashout,
- unsigned int *pDigestLen, unsigned int maxDigestLen)
- {
- *pDigestLen = 0; /* tells Verify that no data has been input yet. */
- }
- /* Compute the PRF values from the data previously input. */
- static SECStatus
- pk11_TLSPRFUpdate(TLSPRFContext *cx,
- unsigned char *sig, /* output goes here. */
- unsigned int * sigLen, /* how much output. */
- unsigned int maxLen, /* output buffer size */
- unsigned char *hash, /* unused. */
- unsigned int hashLen) /* unused. */
- {
- SECStatus rv;
- SECItem sigItem;
- SECItem seedItem;
- SECItem secretItem;
- if (cx->cxRv != SECSuccess)
- return cx->cxRv;
- secretItem.data = cx->cxBuf;
- secretItem.len = cx->cxKeyLen;
- seedItem.data = cx->cxBuf + cx->cxKeyLen;
- seedItem.len = cx->cxDataLen;
- sigItem.data = sig;
- sigItem.len = maxLen;
- rv = pk11_PRF(&secretItem, NULL, &seedItem, &sigItem);
- if (rv == SECSuccess && sigLen != NULL)
- *sigLen = sigItem.len;
- return rv;
- }
- static SECStatus
- pk11_TLSPRFVerify(TLSPRFContext *cx,
- unsigned char *sig, /* input, for comparison. */
- unsigned int sigLen, /* length of sig. */
- unsigned char *hash, /* data to be verified. */
- unsigned int hashLen) /* size of hash data. */
- {
- unsigned char * tmp = (unsigned char *)PORT_Alloc(sigLen);
- unsigned int tmpLen = sigLen;
- SECStatus rv;
- if (!tmp)
- return SECFailure;
- if (hashLen) {
- /* hashLen is non-zero when the user does a one-step verify.
- ** In this case, none of the data has been input yet.
- */
- pk11_TLSPRFHashUpdate(cx, hash, hashLen);
- }
- rv = pk11_TLSPRFUpdate(cx, tmp, &tmpLen, sigLen, NULL, 0);
- if (rv == SECSuccess) {
- rv = (SECStatus)(1 - !PORT_Memcmp(tmp, sig, sigLen));
- }
- PORT_ZFree(tmp, sigLen);
- return rv;
- }
- static void
- pk11_TLSPRFHashDestroy(TLSPRFContext *cx, PRBool freeit)
- {
- if (freeit)
- PORT_ZFree(cx, cx->cxSize);
- }
- static CK_RV
- pk11_TLSPRFInit(PK11SessionContext *context,
- PK11Object * key,
- CK_KEY_TYPE key_type)
- {
- PK11Attribute * keyVal;
- TLSPRFContext * prf_cx;
- CK_RV crv = CKR_HOST_MEMORY;
- PRUint32 keySize;
- PRUint32 blockSize;
- if (key_type != CKK_GENERIC_SECRET)
- return CKR_KEY_TYPE_INCONSISTENT; /* CKR_KEY_FUNCTION_NOT_PERMITTED */
- context->multi = PR_TRUE;
- keyVal = pk11_FindAttribute(key, CKA_VALUE);
- keySize = (!keyVal) ? 0 : keyVal->attrib.ulValueLen;
- blockSize = keySize + sizeof(TLSPRFContext);
- prf_cx = (TLSPRFContext *)PORT_Alloc(blockSize);
- if (!prf_cx)
- goto done;
- prf_cx->cxSize = blockSize;
- prf_cx->cxKeyLen = keySize;
- prf_cx->cxDataLen = 0;
- prf_cx->cxRv = SECSuccess;
- if (keySize)
- PORT_Memcpy(prf_cx->cxBuf, keyVal->attrib.pValue, keySize);
- context->hashInfo = (void *) prf_cx;
- context->cipherInfo = (void *) prf_cx;
- context->hashUpdate = (PK11Hash) pk11_TLSPRFHashUpdate;
- context->end = (PK11End) pk11_TLSPRFEnd;
- context->update = (PK11Cipher) pk11_TLSPRFUpdate;
- context->verify = (PK11Verify) pk11_TLSPRFVerify;
- context->destroy = (PK11Destroy) pk11_Null;
- context->hashdestroy = (PK11Destroy) pk11_TLSPRFHashDestroy;
- crv = CKR_OK;
- done:
- if (keyVal)
- pk11_FreeAttribute(keyVal);
- return crv;
- }
- /*
- ************** Crypto Functions: Sign ************************
- */
- /*
- * Check if We're using CBCMacing and initialize the session context if we are.
- */
- static CK_RV
- pk11_InitCBCMac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
- CK_OBJECT_HANDLE hKey, CK_ATTRIBUTE_TYPE keyUsage,
- PK11ContextType contextType)
-
- {
- CK_MECHANISM cbc_mechanism;
- CK_ULONG mac_bytes = PK11_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[PK11_MAX_BLOCK_SIZE];
- PK11SessionContext *context;
- CK_RV crv;
- 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;
- blockSize = rc5_mac->ulWordsize*2;
- 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;
- default:
- return CKR_FUNCTION_NOT_SUPPORTED;
- }
- crv = pk11_EncryptInit(hSession, &cbc_mechanism, hKey, keyUsage,
- contextType);
- if (crv != CKR_OK) return crv;
- crv = pk11_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;
- if (mac_bytes == PK11_INVALID_MAC_SIZE) mac_bytes = blockSize/2;
- context->macSize = mac_bytes;
- return CKR_OK;
- }
- /*
- * encode RSA PKCS #1 Signature data before signing...
- */
- static SECStatus
- pk11_HashSign(PK11HashSignInfo *info,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(info->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(info->key,sig,sigLen,maxLen,digder.data,digder.len);
- loser:
- SGN_DestroyDigestInfo(di);
- if (arena != NULL) {
- PORT_FreeArena(arena, PR_FALSE);
- }
- return rv;
- }
- static SECStatus
- nsc_DSA_Verify_Stub(void *ctx, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen,
- CK_BYTE_PTR pData, CK_ULONG ulDataLen)
- {
- SECItem signature, digest;
- signature.data = pSignature;
- signature.len = ulSignatureLen;
- digest.data = pData;
- digest.len = ulDataLen;
- return DSA_VerifyDigest((DSAPublicKey *)ctx, &signature, &digest);
- }
- static SECStatus
- nsc_DSA_Sign_Stub(void *ctx, CK_BYTE_PTR pSignature,
- CK_ULONG_PTR ulSignatureLen, CK_ULONG maxulSignatureLen,
- CK_BYTE_PTR pData, CK_ULONG ulDataLen)
- {
- SECItem signature = { 0 }, digest;
- SECStatus rv;
- (void)SECITEM_AllocItem(NULL, &signature, maxulSignatureLen);
- digest.data = pData;
- digest.len = ulDataLen;
- rv = DSA_SignDigest((DSAPrivateKey *)ctx, &signature, &digest);
- *ulSignatureLen = signature.len;
- PORT_Memcpy(pSignature, signature.data, signature.len);
- SECITEM_FreeItem(&signature, PR_FALSE);
- return rv;
- }
- /* 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)
- {
- PK11Session *session;
- PK11Object *key;
- PK11SessionContext *context;
- CK_KEY_TYPE key_type;
- CK_RV crv = CKR_OK;
- SECKEYLowPrivateKey *privKey;
- PK11HashSignInfo *info = NULL;
- /* Block Cipher MACing Algorithms use a different Context init method..*/
- crv = pk11_InitCBCMac(hSession, pMechanism, hKey, CKA_SIGN, PK11_SIGN);
- if (crv != CKR_FUNCTION_NOT_SUPPORTED) return crv;
- /* we're not using a block cipher mac */
- session = pk11_SessionFromHandle(hSession);
- if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
- crv = pk11_InitGeneric(session,&context,PK11_SIGN,&key,hKey,&key_type,
- CKO_PRIVATE_KEY,CKA_SIGN);
- if (crv != CKR_OK) {
- pk11_FreeSession(session);
- return crv;
- }
- context->multi = PR_FALSE;
- switch(pMechanism->mechanism) {
- case CKM_MD5_RSA_PKCS:
- context->multi = PR_TRUE;
- crv = pk11_doSubMD2(context);
- if (crv != CKR_OK) break;
- context->update = (PK11Cipher) pk11_HashSign;
- info = (PK11HashSignInfo *)PORT_Alloc(sizeof(PK11HashSignInfo));
- if (info == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- info->hashOid = SEC_OID_MD5;
- goto finish_rsa;
- case CKM_MD2_RSA_PKCS:
- context->multi = PR_TRUE;
- crv = pk11_doSubMD2(context);
- if (crv != CKR_OK) break;
- context->update = (PK11Cipher) pk11_HashSign;
- info = (PK11HashSignInfo *)PORT_Alloc(sizeof(PK11HashSignInfo));
- if (info == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- info->hashOid = SEC_OID_MD2;
- goto finish_rsa;
- case CKM_SHA1_RSA_PKCS:
- context->multi = PR_TRUE;
- crv = pk11_doSubSHA1(context);
- if (crv != CKR_OK) break;
- context->update = (PK11Cipher) pk11_HashSign;
- info = (PK11HashSignInfo *)PORT_Alloc(sizeof(PK11HashSignInfo));
- if (info == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- info->hashOid = SEC_OID_SHA1;
- goto finish_rsa;
- case CKM_RSA_PKCS:
- context->update = (PK11Cipher) RSA_Sign;
- goto finish_rsa;
- case CKM_RSA_X_509:
- context->update = (PK11Cipher) RSA_SignRaw;
- finish_rsa:
- if (key_type != CKK_RSA) {
- if (info) PORT_Free(info);
- crv = CKR_KEY_TYPE_INCONSISTENT;
- break;
- }
- context->multi = PR_FALSE;
- privKey = pk11_GetPrivKey(key,CKK_RSA);
- if (privKey == NULL) {
- if (info) PORT_Free(info);
- crv = CKR_HOST_MEMORY;
- 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.
- * Second, what's special about privKey == key->objectInfo?
- * Well we don't 'cache' token versions
- * of private keys because (1) it's sensitive data, and (2) it never
- * gets destroyed. Instead we grab the key out of the database as
- * necessary, but now the key is our context, and we need to free
- * it when we are done. Non-token private keys will get freed when
- * the user destroys the session object (or the session the session
- * object lives in) */
- if (info) {
- info->key = privKey;
- context->cipherInfo = info;
- context->destroy = (privKey == key->objectInfo) ?
- (PK11Destroy)pk11_Space:(PK11Destroy)pk11_FreeSignInfo;
- } else {
- context->cipherInfo = privKey;
- context->destroy = (privKey == key->objectInfo) ?
- (PK11Destroy)pk11_Null:(PK11Destroy)pk11_FreePrivKey;
- }
- break;
- case CKM_DSA_SHA1:
- context->multi = PR_TRUE;
- crv = pk11_doSubSHA1(context);
- if (crv != CKR_OK) break;
- /* fall through */
- case CKM_DSA:
- if (key_type != CKK_DSA) {
- crv = CKR_KEY_TYPE_INCONSISTENT;
- break;
- }
- privKey = pk11_GetPrivKey(key,CKK_DSA);
- if (privKey == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- context->cipherInfo = &(privKey->u.dsa);
- context->update = (PK11Cipher) nsc_DSA_Sign_Stub;
- context->destroy = pk11_Null;
- if (key->objectInfo != privKey) SECKEY_LowDestroyPrivateKey(privKey);
- break;
- case CKM_MD2_HMAC_GENERAL:
- crv = pk11_doHMACInit(context,SEC_OID_MD2,key,
- *(CK_ULONG *)pMechanism->pParameter);
- break;
- case CKM_MD2_HMAC:
- crv = pk11_doHMACInit(context,SEC_OID_MD2,key,MD2_LENGTH);
- break;
- case CKM_MD5_HMAC_GENERAL:
- crv = pk11_doHMACInit(context,SEC_OID_MD5,key,
- *(CK_ULONG *)pMechanism->pParameter);
- break;
- case CKM_MD5_HMAC:
- crv = pk11_doHMACInit(context,SEC_OID_MD5,key,MD5_LENGTH);
- break;
- case CKM_SHA_1_HMAC_GENERAL:
- crv = pk11_doHMACInit(context,SEC_OID_SHA1,key,
- *(CK_ULONG *)pMechanism->pParameter);
- break;
- case CKM_SHA_1_HMAC:
- crv = pk11_doHMACInit(context,SEC_OID_SHA1,key,SHA1_LENGTH);
- break;
- case CKM_SSL3_MD5_MAC:
- crv = pk11_doSSLMACInit(context,SEC_OID_MD5,key,
- *(CK_ULONG *)pMechanism->pParameter);
- break;
- case CKM_SSL3_SHA1_MAC:
- crv = pk11_doSSLMACInit(context,SEC_OID_SHA1,key,
- *(CK_ULONG *)pMechanism->pParameter);
- break;
- case CKM_TLS_PRF_GENERAL:
- crv = pk11_TLSPRFInit(context, key, key_type);
- break;
- default:
- crv = CKR_MECHANISM_INVALID;
- break;
- }
- pk11_FreeObject(key);
- if (crv != CKR_OK) {
- PORT_Free(context);
- pk11_FreeSession(session);
- return crv;
- }
- pk11_SetContextByType(session, PK11_SIGN, context);
- pk11_FreeSession(session);
- return CKR_OK;
- }
- /* MACUpdate is the common implementation for SignUpdate and VerifyUpdate.
- * (sign and verify only very in their setup and final operations) */
- static CK_RV
- pk11_MACUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
- CK_ULONG ulPartLen,PK11ContextType type)
- {
- unsigned int outlen;
- PK11SessionContext *context;
- CK_RV crv;
- SECStatus rv;
- /* make sure we're legal */
- crv = pk11_GetContext(hSession,&context,type,PR_FALSE,NULL);
- if (crv != CKR_OK) return crv;
- if (context->hashInfo) {
- (*context->hashUpdate)(context->hashInfo, pPart, ulPartLen);
- return CKR_OK;
- }
- /* must be block cipher macing */
- /* deal with previous buffered data */
- if (context->padDataLength != 0) {
- int i;
- /* fill in the padded to a full block size */
- for (i=context->padDataLength; (ulPartLen != 0) &&
- i < (int)context->blockSize; i++) {
- context->padBuf[i] = *pPart++;
- ulPartLen--;
- context->padDataLength++;
- }
- /* not enough data to encrypt yet? then return */
- if (context->padDataLength != context->blockSize) return CKR_OK;
- /* encrypt the current padded data */
- rv = (*context->update)(context->cipherInfo,context->macBuf,&outlen,
- PK11_MAX_BLOCK_SIZE,context->padBuf,context->blockSize);
- if (rv != SECSuccess) return CKR_DEVICE_ERROR;
- }
- /* 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) { return CKR_OK; }
- /* run the data through out encrypter */
- while (ulPartLen) {
- rv = (*context->update)(context->cipherInfo, context->padBuf, &outlen,
- PK11_MAX_BLOCK_SIZE, pPart, context->blockSize);
- if (rv != SECSuccess) return CKR_DEVICE_ERROR;
- /* paranoia.. make sure we exit the loop */
- PORT_Assert(ulPartLen >= context->blockSize);
- if (ulPartLen < context->blockSize) break;
- ulPartLen -= context->blockSize;
- }
- return CKR_OK;
-
- }
- /* 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 */
- CK_RV NSC_SignUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
- CK_ULONG ulPartLen)
- {
- return pk11_MACUpdate(hSession, pPart, ulPartLen, PK11_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)
- {
- PK11Session *session;
- PK11SessionContext *context;
- unsigned int outlen;
- unsigned int digestLen;
- unsigned int maxoutlen = *pulSignatureLen;
- unsigned char tmpbuf[PK11_MAX_MAC_LENGTH];
- CK_RV crv;
- SECStatus rv = SECSuccess;
- /* make sure we're legal */
- *pulSignatureLen = 0;
- crv = pk11_GetContext(hSession,&context,PK11_SIGN,PR_TRUE,&session);
- if (crv != CKR_OK) return crv;
- if (context->hashInfo) {
- (*context->end)(context->hashInfo, tmpbuf, &digestLen, sizeof(tmpbuf));
- rv = (*context->update)(context->cipherInfo, pSignature,
- &outlen, maxoutlen, tmpbuf, digestLen);
- *pulSignatureLen = (CK_ULONG) outlen;
- } else {
- /* deal with the last block if any residual */
- if (context->padDataLength) {
- /* fill out rest of pad buffer with pad magic*/
- int i;
- for (i=context->padDataLength; i < (int)context->blockSize; i++) {
- context->padBuf[i] = 0;
- }
- rv = (*context->update)(context->cipherInfo,context->macBuf,
- &outlen,PK11_MAX_BLOCK_SIZE,context->padBuf,context->blockSize);
- }
- if (rv == SECSuccess) {
- PORT_Memcpy(pSignature,context->macBuf,context->macSize);
- *pulSignatureLen = context->macSize;
- }
- }
- pk11_FreeContext(context);
- pk11_SetContextByType(session, PK11_SIGN, NULL);
- pk11_FreeSession(session);
- return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
- }
- /* 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)
- {
- PK11Session *session;
- PK11SessionContext *context;
- unsigned int outlen;
- unsigned int maxoutlen = *pulSignatureLen;
- CK_RV crv,crv2;
- SECStatus rv;
- /* make sure we're legal */
- crv = pk11_GetContext(hSession,&context,PK11_SIGN,PR_FALSE,&session);
- if (crv != CKR_OK) return crv;
- /* multi part Signing are completely implemented by SignUpdate and
- * sign Final */
- if (context->multi) {
- pk11_FreeSession(session);
- crv = NSC_SignUpdate(hSession,pData,ulDataLen);
- if (crv != CKR_OK) *pulSignatureLen = 0;
- crv2 = NSC_SignFinal(hSession, pSignature, pulSignatureLen);
- return crv == CKR_OK ? crv2 :crv;
- }
- rv = (*context->update)(context->cipherInfo, pSignature,
- &outlen, maxoutlen, pData, ulDataLen);
- *pulSignatureLen = (CK_ULONG) outlen;
- pk11_FreeContext(context);
- pk11_SetContextByType(session, PK11_SIGN, NULL);
- pk11_FreeSession(session);
- return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
- }
- /*
- ************** 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)
- {
- 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)
- {
- return NSC_Sign(hSession,pData,ulDataLen,pSignature,pulSignatureLen);
- }
- /*
- ************** Crypto Functions: verify ************************
- */
- /* Handle RSA Signature formating */
- static SECStatus
- pk11_hashCheckSign(PK11HashVerifyInfo *info, unsigned char *sig,
- unsigned int sigLen, unsigned char *digest, unsigned int digestLen)
- {
- SECItem it;
- SGNDigestInfo *di = NULL;
- SECStatus rv = SECSuccess;
-
- it.data = NULL;
- if (info->key == NULL) goto loser;
- it.len = SECKEY_LowPublicModulusLen(info->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(info->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) != info->hashOid) {
- goto loser;
- }
- /* Now check the signature */
- if (PORT_Memcmp(digest, di->digest.data, di->digest.len) == 0) {
- goto done;
- }
- loser:
- rv = SECFailure;
- done:
- if (it.data != NULL) PORT_Free(it.data);
- if (di != NULL) SGN_DestroyDigestInfo(di);
-
- return rv;
- }
- /* 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)
- {
- PK11Session *session;
- PK11Object *key;
- PK11SessionContext *context;
- CK_KEY_TYPE key_type;
- CK_RV crv = CKR_OK;
- SECKEYLowPublicKey *pubKey;
- PK11HashVerifyInfo *info = NULL;
- /* Block Cipher MACing Algorithms use a different Context init method..*/
- crv = pk11_InitCBCMac(hSession, pMechanism, hKey, CKA_VERIFY, PK11_VERIFY);
- if (crv != CKR_FUNCTION_NOT_SUPPORTED) return crv;
- session = pk11_SessionFromHandle(hSession);
- if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
- crv = pk11_InitGeneric(session,&context,PK11_VERIFY,&key,hKey,&key_type,
- CKO_PUBLIC_KEY,CKA_VERIFY);
- if (crv != CKR_OK) {
- pk11_FreeSession(session);
- return crv;
- }
- context->multi = PR_FALSE;
- switch(pMechanism->mechanism) {
- case CKM_MD5_RSA_PKCS:
- context->multi = PR_TRUE;
- crv = pk11_doSubMD5(context);
- if (crv != CKR_OK) break;
- context->verify = (PK11Verify) pk11_hashCheckSign;
- info = (PK11HashVerifyInfo *)PORT_Alloc(sizeof(PK11HashVerifyInfo));
- if (info == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- info->hashOid = SEC_OID_MD5;
- goto finish_rsa;
- case CKM_MD2_RSA_PKCS:
- context->multi = PR_TRUE;
- crv = pk11_doSubMD2(context);
- if (crv != CKR_OK) break;
- context->verify = (PK11Verify) pk11_hashCheckSign;
- info = (PK11HashVerifyInfo *)PORT_Alloc(sizeof(PK11HashVerifyInfo));
- if (info == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- info->hashOid = SEC_OID_MD2;
- goto finish_rsa;
- case CKM_SHA1_RSA_PKCS:
- context->multi = PR_TRUE;
- crv = pk11_doSubSHA1(context);
- if (crv != CKR_OK) break;
- context->verify = (PK11Verify) pk11_hashCheckSign;
- info = (PK11HashVerifyInfo *)PORT_Alloc(sizeof(PK11HashVerifyInfo));
- if (info == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- info->hashOid = SEC_OID_SHA1;
- goto finish_rsa;
- case CKM_RSA_PKCS:
- context->verify = (PK11Verify) RSA_CheckSign;
- goto finish_rsa;
- case CKM_RSA_X_509:
- context->verify = (PK11Verify) RSA_CheckSignRaw;
- finish_rsa:
- if (key_type != CKK_RSA) {
- crv = CKR_KEY_TYPE_INCONSISTENT;
- break;
- }
- pubKey = pk11_GetPubKey(key,CKK_RSA);
- if (pubKey == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- if (info) {
- info->key = pubKey;
- context->cipherInfo = info;
- context->destroy = pk11_Space;
- } else {
- context->cipherInfo = pubKey;
- context->destroy = pk11_Null;
- }
- break;
- case CKM_DSA_SHA1:
- context->multi = PR_TRUE;
- crv = pk11_doSubSHA1(context);
- if (crv != CKR_OK) break;
- /* fall through */
- case CKM_DSA:
- if (key_type != CKK_DSA) {
- crv = CKR_KEY_TYPE_INCONSISTENT;
- break;
- }
- context->multi = PR_FALSE;
- pubKey = pk11_GetPubKey(key,CKK_DSA);
- if (pubKey == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
- }
- context->cipherInfo = &(pubKey->u.dsa);
- context->verify = (PK11Verify) nsc_DSA_Verify_Stub;
- context->destroy = pk11_Null;
- break;
- case CKM_MD2_HMAC_GENERAL:
- crv = pk11_doHMACInit(context,SEC_OID_MD2,key,
- *(CK_ULONG *)pMechanism->pParameter);
- break;
- case CKM_MD2_HMAC:
- crv = pk11_doHMACInit(context,SEC_OID_MD2,key,MD2_LENGTH);
- break;
- case CKM_MD5_HMAC_GENERAL:
- crv = pk11_doHMACInit(context,SEC_OID_MD5,key,
- *(CK_ULONG *)pMechanism->pParameter);
- break;
- case CKM_MD5_HMAC:
- crv = pk11_doHMACInit(context,SEC_OID_MD5,key,MD5_LENGTH);
- break;
- case CKM_SHA_1_HMAC_GENERAL:
- crv = pk11_doHMACInit(context,SEC_OID_SHA1,key,
- *(CK_ULONG *)pMechanism->pParameter);
- break;
- case CKM_SHA_1_HMAC:
- crv = pk11_doHMACInit(context,SEC_OID_SHA1,key,SHA1_LENGTH);
- break;
- case CKM_SSL3_MD5_MAC:
- crv = pk11_doSSLMACInit(context,SEC_OID_MD5,key,
- *(CK_ULONG *)pMechanism->pParameter);
- break;
- case CKM_SSL3_SHA1_MAC:
- crv = pk11_doSSLMACInit(context,SEC_OID_SHA1,key,
- *(CK_ULONG *)pMechanism->pParameter);
- break;
- case CKM_TLS_PRF_GENERAL:
- crv = pk11_TLSPRFInit(context, key, key_type);
- default:
- crv = CKR_MECHANISM_INVALID;
- break;
- }
- pk11_FreeObject(key);
- if (crv != CKR_OK) {
- PORT_Free(context);
- pk11_FreeSession(session);
- return crv;
- }
- pk11_SetContextByType(session, PK11_VERIFY, context);
- pk11_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)
- {
- PK11Session *session;
- PK11SessionContext *context;
- CK_RV crv;
- SECStatus rv;
- /* make sure we're legal */
- crv = pk11_GetContext(hSession,&context,PK11_VERIFY,PR_FALSE,&session);
- if (crv != CKR_OK) return crv;
- rv = (*context->verify)(context->cipherInfo,pSignature, ulSignatureLen,
- pData, ulDataLen);
- pk11_FreeContext(context);
- pk11_SetContextByType(session, PK11_VERIFY, NULL);
- pk11_FreeSession(session);
- return (rv == SECSuccess) ? CKR_OK : CKR_SIGNATURE_INVALID;
- }
- /* 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 */
- CK_RV NSC_VerifyUpdate( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
- CK_ULONG ulPartLen)
- {
- return pk11_MACUpdate(hSession, pPart, ulPartLen, PK11_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)
- {
- PK11Session *session;
- PK11SessionContext *context;
- unsigned int outlen;
- unsigned int digestLen;
- unsigned char tmpbuf[PK11_MAX_MAC_LENGTH];
- CK_RV crv;
- SECStatus rv = SECSuccess;
- /* make sure we're legal */
- crv = pk11_GetContext(hSession,&context,PK11_VERIFY,PR_TRUE,&session);
- if (crv != CKR_OK) return crv;
- if (context->hashInfo) {
- (*context->end)(context->hashInfo, tmpbuf, &digestLen, sizeof(tmpbuf));
- rv = (*context->verify)(context->cipherInfo, pSignature,
- ulSignatureLen, tmpbuf, digestLen);
- } else {
- if (context->padDataLength) {
- /* fill out rest of pad buffer with pad magic*/
- int i;
- for (i=context->padDataLength; i < (int)context->blockSize; i++) {
- context->padBuf[i] = 0;
- }
- rv = (*context->update)(context->cipherInfo,context->macBuf,
- &outlen,PK11_MAX_BLOCK_SIZE,context->padBuf,context->blockSize);
- }
- if (rv == SECSuccess) {
- rv =(PORT_Memcmp(pSignature,context->macBuf,context->macSize) == 0)
- ? SECSuccess : SECFailure;
- }
- }
- pk11_FreeContext(context);
- pk11_SetContextByType(session, PK11_VERIFY, NULL);
- pk11_FreeSession(session);
- return (rv == SECSuccess) ? CKR_OK : CKR_SIGNATURE_INVALID;
- }
- /*
- ************** 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)
- {
- PK11Session *session;
- PK11Object *key;
- PK11SessionContext *context;
- CK_KEY_TYPE key_type;
- CK_RV crv = CKR_OK;
- SECKEYLowPublicKey *pubKey;
- session = pk11_SessionFromHandle(hSession);
- if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
- crv = pk11_InitGeneric(session,&context,PK11_VERIFY_RECOVER,
- &key,hKey,&key_type,CKO_PUBLIC_KEY,CKA_VERIFY_RECOVER);
- if (crv != CKR_OK) {
- pk11_FreeSession(session);
- return crv;
- }