Imported Upstream version 3.13.6
[platform/upstream/nss.git] / mozilla / security / nss / lib / softoken / pkcs11c.c
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is the Netscape security libraries.
15  *
16  * The Initial Developer of the Original Code is
17  * Netscape Communications Corporation.
18  * Portions created by the Initial Developer are Copyright (C) 1994-2000
19  * the Initial Developer. All Rights Reserved.
20  *
21  * Contributor(s):
22  *   Dr Stephen Henson <stephen.henson@gemplus.com>
23  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either the GNU General Public License Version 2 or later (the "GPL"), or
27  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the MPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the MPL, the GPL or the LGPL.
36  *
37  * ***** END LICENSE BLOCK ***** */
38 /*
39  * This file implements PKCS 11 on top of our existing security modules
40  *
41  * For more information about PKCS 11 See PKCS 11 Token Inteface Standard.
42  *   This implementation has two slots:
43  *      slot 1 is our generic crypto support. It does not require login.
44  *   It supports Public Key ops, and all they bulk ciphers and hashes. 
45  *   It can also support Private Key ops for imported Private keys. It does 
46  *   not have any token storage.
47  *      slot 2 is our private key support. It requires a login before use. It
48  *   can store Private Keys and Certs as token objects. Currently only private
49  *   keys and their associated Certificates are saved on the token.
50  *
51  *   In this implementation, session objects are only visible to the session
52  *   that created or generated them.
53  */
54 #include "seccomon.h"
55 #include "secitem.h"
56 #include "secport.h"
57 #include "blapi.h"
58 #include "pkcs11.h"
59 #include "pkcs11i.h"
60 #include "lowkeyi.h"
61 #include "sechash.h"
62 #include "secder.h"
63 #include "secdig.h"
64 #include "lowpbe.h"     /* We do PBE below */
65 #include "pkcs11t.h"
66 #include "secoid.h"
67 #include "alghmac.h"
68 #include "softoken.h"
69 #include "secasn1.h"
70 #include "secerr.h"
71
72 #include "prprf.h"
73
74 #define __PASTE(x,y)    x##y
75
76 /*
77  * we renamed all our internal functions, get the correct
78  * definitions for them...
79  */ 
80 #undef CK_PKCS11_FUNCTION_INFO
81 #undef CK_NEED_ARG_LIST
82
83 #define CK_EXTERN extern
84 #define CK_PKCS11_FUNCTION_INFO(func) \
85                 CK_RV __PASTE(NS,func)
86 #define CK_NEED_ARG_LIST        1
87  
88 #include "pkcs11f.h"
89
90 typedef struct {
91     uint8 client_version[2];
92     uint8 random[46];
93 } SSL3RSAPreMasterSecret;
94
95 static void sftk_Null(void *data, PRBool freeit)
96 {
97     return;
98
99
100 #ifdef NSS_ENABLE_ECC
101 #ifdef EC_DEBUG
102 #define SEC_PRINT(str1, str2, num, sitem) \
103     printf("pkcs11c.c:%s:%s (keytype=%d) [len=%d]\n", \
104             str1, str2, num, sitem->len); \
105     for (i = 0; i < sitem->len; i++) { \
106             printf("%02x:", sitem->data[i]); \
107     } \
108     printf("\n") 
109 #else
110 #define SEC_PRINT(a, b, c, d) 
111 #endif
112 #endif /* NSS_ENABLE_ECC */
113
114 /*
115  * free routines.... Free local type  allocated data, and convert
116  * other free routines to the destroy signature.
117  */
118 static void
119 sftk_FreePrivKey(NSSLOWKEYPrivateKey *key, PRBool freeit)
120 {
121     nsslowkey_DestroyPrivateKey(key);
122 }
123
124 static void
125 sftk_Space(void *data, PRBool freeit)
126 {
127     PORT_Free(data);
128
129
130 /*
131  * map all the SEC_ERROR_xxx error codes that may be returned by freebl
132  * functions to CKR_xxx.  return CKR_DEVICE_ERROR by default for backward
133  * compatibility.
134  */
135 static CK_RV
136 sftk_MapCryptError(int error)
137 {
138     switch (error) {
139         case SEC_ERROR_INVALID_ARGS:
140         case SEC_ERROR_BAD_DATA:  /* MP_RANGE gets mapped to this */
141             return CKR_ARGUMENTS_BAD;
142         case SEC_ERROR_INPUT_LEN:
143             return CKR_DATA_LEN_RANGE;
144         case SEC_ERROR_OUTPUT_LEN:
145             return CKR_BUFFER_TOO_SMALL;
146         case SEC_ERROR_LIBRARY_FAILURE:
147             return CKR_GENERAL_ERROR;
148         case SEC_ERROR_NO_MEMORY:
149             return CKR_HOST_MEMORY;
150         case SEC_ERROR_BAD_SIGNATURE:
151             return CKR_SIGNATURE_INVALID;
152         case SEC_ERROR_INVALID_KEY:
153             return CKR_KEY_SIZE_RANGE;
154         case SEC_ERROR_BAD_KEY:  /* an EC public key that fails validation */
155             return CKR_KEY_SIZE_RANGE;  /* the closest error code */
156         case SEC_ERROR_UNSUPPORTED_EC_POINT_FORM:
157             return CKR_TEMPLATE_INCONSISTENT;
158         /* EC functions set this error if NSS_ENABLE_ECC is not defined */
159         case SEC_ERROR_UNSUPPORTED_KEYALG:
160             return CKR_MECHANISM_INVALID;
161         case SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE:
162             return CKR_DOMAIN_PARAMS_INVALID;
163         /* key pair generation failed after max number of attempts */
164         case SEC_ERROR_NEED_RANDOM:
165             return CKR_FUNCTION_FAILED;
166     }
167     return CKR_DEVICE_ERROR;
168 }
169
170 /* used by Decrypt and UnwrapKey (indirectly) */
171 static CK_RV
172 sftk_MapDecryptError(int error)
173 {
174     switch (error) {
175         case SEC_ERROR_BAD_DATA:
176             return CKR_ENCRYPTED_DATA_INVALID;
177         default:
178             return sftk_MapCryptError(error);
179     }
180 }
181
182 /*
183  * return CKR_SIGNATURE_INVALID instead of CKR_DEVICE_ERROR by default for
184  * backward compatibilty.
185  */
186 static CK_RV
187 sftk_MapVerifyError(int error)
188 {
189     CK_RV crv = sftk_MapCryptError(error);
190     if (crv == CKR_DEVICE_ERROR)
191         crv = CKR_SIGNATURE_INVALID;
192     return crv;
193 }
194
195
196 /*
197  * turn a CDMF key into a des key. CDMF is an old IBM scheme to export DES by
198  * Deprecating a full des key to 40 bit key strenth.
199  */
200 static CK_RV
201 sftk_cdmf2des(unsigned char *cdmfkey, unsigned char *deskey)
202 {
203     unsigned char key1[8] = { 0xc4, 0x08, 0xb0, 0x54, 0x0b, 0xa1, 0xe0, 0xae };
204     unsigned char key2[8] = { 0xef, 0x2c, 0x04, 0x1c, 0xe6, 0x38, 0x2f, 0xe6 };
205     unsigned char enc_src[8];
206     unsigned char enc_dest[8];
207     unsigned int leng,i;
208     DESContext *descx;
209     SECStatus rv;
210     
211     
212     /* zero the parity bits */
213     for (i=0; i < 8; i++) {
214         enc_src[i] = cdmfkey[i] & 0xfe;
215     }
216
217     /* encrypt with key 1 */
218     descx = DES_CreateContext(key1, NULL, NSS_DES, PR_TRUE);
219     if (descx == NULL) return CKR_HOST_MEMORY;
220     rv = DES_Encrypt(descx, enc_dest, &leng, 8, enc_src, 8);
221     DES_DestroyContext(descx,PR_TRUE);
222     if (rv != SECSuccess) return sftk_MapCryptError(PORT_GetError());
223
224     /* xor source with des, zero the parity bits and deprecate the key*/
225     for (i=0; i < 8; i++) {
226         if (i & 1) {
227             enc_src[i] = (enc_src[i] ^ enc_dest[i]) & 0xfe;
228         } else {
229             enc_src[i] = (enc_src[i] ^ enc_dest[i]) & 0x0e;
230         }
231     }
232
233     /* encrypt with key 2 */
234     descx = DES_CreateContext(key2, NULL, NSS_DES, PR_TRUE);
235     if (descx == NULL) return CKR_HOST_MEMORY;
236     rv = DES_Encrypt(descx, deskey, &leng, 8, enc_src, 8);
237     DES_DestroyContext(descx,PR_TRUE);
238     if (rv != SECSuccess) return sftk_MapCryptError(PORT_GetError());
239
240     /* set the corret parity on our new des key */      
241     sftk_FormatDESKey(deskey, 8);
242     return CKR_OK;
243 }
244
245
246 /* NSC_DestroyObject destroys an object. */
247 CK_RV
248 NSC_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
249 {
250     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
251     SFTKSession *session;
252     SFTKObject *object;
253     SFTKFreeStatus status;
254
255     CHECK_FORK();
256
257     if (slot == NULL) {
258         return CKR_SESSION_HANDLE_INVALID;
259     }
260     /*
261      * This whole block just makes sure we really can destroy the
262      * requested object.
263      */
264     session = sftk_SessionFromHandle(hSession);
265     if (session == NULL) {
266         return CKR_SESSION_HANDLE_INVALID;
267     }
268
269     object = sftk_ObjectFromHandle(hObject,session);
270     if (object == NULL) {
271         sftk_FreeSession(session);
272         return CKR_OBJECT_HANDLE_INVALID;
273     }
274
275     /* don't destroy a private object if we aren't logged in */
276     if ((!slot->isLoggedIn) && (slot->needLogin) &&
277                                 (sftk_isTrue(object,CKA_PRIVATE))) {
278         sftk_FreeSession(session);
279         sftk_FreeObject(object);
280         return CKR_USER_NOT_LOGGED_IN;
281     }
282
283     /* don't destroy a token object if we aren't in a rw session */
284
285     if (((session->info.flags & CKF_RW_SESSION) == 0) &&
286                                 (sftk_isTrue(object,CKA_TOKEN))) {
287         sftk_FreeSession(session);
288         sftk_FreeObject(object);
289         return CKR_SESSION_READ_ONLY;
290     }
291
292     sftk_DeleteObject(session,object);
293
294     sftk_FreeSession(session);
295
296     /*
297      * get some indication if the object is destroyed. Note: this is not
298      * 100%. Someone may have an object reference outstanding (though that
299      * should not be the case by here. Also note that the object is "half"
300      * destroyed. Our internal representation is destroyed, but it may still
301      * be in the data base.
302      */
303     status = sftk_FreeObject(object);
304
305     return (status != SFTK_DestroyFailure) ? CKR_OK : CKR_DEVICE_ERROR;
306 }
307
308
309 /*
310  ************** Crypto Functions:     Utilities ************************
311  */
312
313
314 /* 
315  * return a context based on the SFTKContext type.
316  */
317 SFTKSessionContext *
318 sftk_ReturnContextByType(SFTKSession *session, SFTKContextType type)
319 {
320     switch (type) {
321         case SFTK_ENCRYPT:
322         case SFTK_DECRYPT:
323             return session->enc_context;
324         case SFTK_HASH:
325             return session->hash_context;
326         case SFTK_SIGN:
327         case SFTK_SIGN_RECOVER:
328         case SFTK_VERIFY:
329         case SFTK_VERIFY_RECOVER:
330             return session->hash_context;
331     }
332     return NULL;
333 }
334
335 /* 
336  * change a context based on the SFTKContext type.
337  */
338 void
339 sftk_SetContextByType(SFTKSession *session, SFTKContextType type, 
340                                                 SFTKSessionContext *context)
341 {
342     switch (type) {
343         case SFTK_ENCRYPT:
344         case SFTK_DECRYPT:
345             session->enc_context = context;
346             break;
347         case SFTK_HASH:
348             session->hash_context = context;
349             break;
350         case SFTK_SIGN:
351         case SFTK_SIGN_RECOVER:
352         case SFTK_VERIFY:
353         case SFTK_VERIFY_RECOVER:
354             session->hash_context = context;
355             break;
356     }
357     return;
358 }
359
360 /*
361  * code to grab the context. Needed by every C_XXXUpdate, C_XXXFinal,
362  * and C_XXX function. The function takes a session handle, the context type,
363  * and wether or not the session needs to be multipart. It returns the context,
364  * and optionally returns the session pointer (if sessionPtr != NULL) if session
365  * pointer is returned, the caller is responsible for freeing it.
366  */
367 static CK_RV
368 sftk_GetContext(CK_SESSION_HANDLE handle,SFTKSessionContext **contextPtr,
369         SFTKContextType type, PRBool needMulti, SFTKSession **sessionPtr)
370 {
371     SFTKSession *session;
372     SFTKSessionContext *context;
373
374     session = sftk_SessionFromHandle(handle);
375     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
376     context = sftk_ReturnContextByType(session,type);
377     /* make sure the context is valid */
378     if((context==NULL)||(context->type!=type)||(needMulti&&!(context->multi))){
379         sftk_FreeSession(session);
380         return CKR_OPERATION_NOT_INITIALIZED;
381     }
382     *contextPtr = context;
383     if (sessionPtr != NULL) {
384         *sessionPtr = session;
385     } else {
386         sftk_FreeSession(session);
387     }
388     return CKR_OK;
389 }
390
391 /** Terminate operation (in the PKCS#11 spec sense).
392  *  Intuitive name for FreeContext/SetNullContext pair.
393  */
394 static void
395 sftk_TerminateOp( SFTKSession *session, SFTKContextType ctype,
396         SFTKSessionContext *context )
397 {
398     sftk_FreeContext( context );
399     sftk_SetContextByType( session, ctype, NULL );
400 }
401
402 /*
403  ************** Crypto Functions:     Encrypt ************************
404  */
405
406 /*
407  * All the NSC_InitXXX functions have a set of common checks and processing they
408  * all need to do at the beginning. This is done here.
409  */
410 static CK_RV
411 sftk_InitGeneric(SFTKSession *session,SFTKSessionContext **contextPtr,
412                  SFTKContextType ctype,SFTKObject **keyPtr,
413                  CK_OBJECT_HANDLE hKey, CK_KEY_TYPE *keyTypePtr,
414                  CK_OBJECT_CLASS pubKeyType, CK_ATTRIBUTE_TYPE operation)
415 {
416     SFTKObject *key = NULL;
417     SFTKAttribute *att;
418     SFTKSessionContext *context;
419
420     /* We can only init if there is not current context active */
421     if (sftk_ReturnContextByType(session,ctype) != NULL) {
422         return CKR_OPERATION_ACTIVE;
423     }
424
425     /* find the key */
426     if (keyPtr) {
427         key = sftk_ObjectFromHandle(hKey,session);
428         if (key == NULL) {
429             return CKR_KEY_HANDLE_INVALID;
430         }
431
432         /* make sure it's a valid  key for this operation */
433         if (((key->objclass != CKO_SECRET_KEY) && (key->objclass != pubKeyType))
434                                         || !sftk_isTrue(key,operation)) {
435             sftk_FreeObject(key);
436             return CKR_KEY_TYPE_INCONSISTENT;
437         }
438         /* get the key type */
439         att = sftk_FindAttribute(key,CKA_KEY_TYPE);
440         if (att == NULL) {
441             sftk_FreeObject(key);
442             return CKR_KEY_TYPE_INCONSISTENT;
443         }
444         PORT_Assert(att->attrib.ulValueLen == sizeof(CK_KEY_TYPE));
445         if (att->attrib.ulValueLen != sizeof(CK_KEY_TYPE)) {
446             sftk_FreeAttribute(att);
447             sftk_FreeObject(key);
448             return CKR_ATTRIBUTE_VALUE_INVALID;
449         }
450         PORT_Memcpy(keyTypePtr, att->attrib.pValue, sizeof(CK_KEY_TYPE));
451         sftk_FreeAttribute(att);
452         *keyPtr = key;
453     }
454
455     /* allocate the context structure */
456     context = (SFTKSessionContext *)PORT_Alloc(sizeof(SFTKSessionContext));
457     if (context == NULL) {
458         if (key) sftk_FreeObject(key);
459         return CKR_HOST_MEMORY;
460     }
461     context->type = ctype;
462     context->multi = PR_TRUE;
463     context->cipherInfo = NULL;
464     context->hashInfo = NULL;
465     context->doPad = PR_FALSE;
466     context->padDataLength = 0;
467     context->key = key;
468     context->blockSize = 0;
469
470     *contextPtr = context;
471     return CKR_OK;
472 }
473
474 /** NSC_CryptInit initializes an encryption/Decryption operation.
475  *
476  * Always called by NSC_EncryptInit, NSC_DecryptInit, NSC_WrapKey,NSC_UnwrapKey.
477  * Called by NSC_SignInit, NSC_VerifyInit (via sftk_InitCBCMac) only for block
478  *  ciphers MAC'ing.
479  */
480 static CK_RV
481 sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
482      CK_OBJECT_HANDLE hKey,
483      CK_ATTRIBUTE_TYPE mechUsage, CK_ATTRIBUTE_TYPE keyUsage,
484                  SFTKContextType contextType, PRBool isEncrypt)
485 {
486     SFTKSession *session;
487     SFTKObject *key;
488     SFTKSessionContext *context;
489     SFTKAttribute *att;
490     CK_RC2_CBC_PARAMS *rc2_param;
491 #if NSS_SOFTOKEN_DOES_RC5
492     CK_RC5_CBC_PARAMS *rc5_param;
493     SECItem rc5Key;
494 #endif
495     CK_KEY_TYPE key_type;
496     CK_RV crv = CKR_OK;
497     unsigned effectiveKeyLength;
498     unsigned char newdeskey[24];
499     PRBool useNewKey=PR_FALSE;
500     int t;
501
502     crv = sftk_MechAllowsOperation(pMechanism->mechanism, mechUsage );
503     if (crv != CKR_OK) 
504         return crv;
505
506     session = sftk_SessionFromHandle(hSession);
507     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
508
509     crv = sftk_InitGeneric(session,&context,contextType,&key,hKey,&key_type,
510                         isEncrypt ?CKO_PUBLIC_KEY:CKO_PRIVATE_KEY, keyUsage);
511                                                 
512     if (crv != CKR_OK) {
513         sftk_FreeSession(session);
514         return crv;
515     }
516
517     context->doPad = PR_FALSE;
518     switch(pMechanism->mechanism) {
519     case CKM_RSA_PKCS:
520     case CKM_RSA_X_509:
521         if (key_type != CKK_RSA) {
522             crv = CKR_KEY_TYPE_INCONSISTENT;
523             break;
524         }
525         context->multi = PR_FALSE;
526         if (isEncrypt) {
527             NSSLOWKEYPublicKey *pubKey = sftk_GetPubKey(key,CKK_RSA,&crv);
528             if (pubKey == NULL) {
529                 break;
530             }
531             context->maxLen = nsslowkey_PublicModulusLen(pubKey);
532             context->cipherInfo =  (void *)pubKey;
533             context->update = (SFTKCipher) 
534                 (pMechanism->mechanism == CKM_RSA_X_509
535                                         ? RSA_EncryptRaw : RSA_EncryptBlock);
536         } else {
537             NSSLOWKEYPrivateKey *privKey = sftk_GetPrivKey(key,CKK_RSA,&crv);
538             if (privKey == NULL) {
539                 break;
540             }
541             context->maxLen = nsslowkey_PrivateModulusLen(privKey);
542             context->cipherInfo =  (void *)privKey;
543             context->update = (SFTKCipher) 
544                 (pMechanism->mechanism == CKM_RSA_X_509
545                                         ? RSA_DecryptRaw : RSA_DecryptBlock);
546         }
547         context->destroy = sftk_Null;
548         break;
549     case CKM_RC2_CBC_PAD:
550         context->doPad = PR_TRUE;
551         /* fall thru */
552     case CKM_RC2_ECB:
553     case CKM_RC2_CBC:
554         context->blockSize = 8;
555         if (key_type != CKK_RC2) {
556             crv = CKR_KEY_TYPE_INCONSISTENT;
557             break;
558         }
559         att = sftk_FindAttribute(key,CKA_VALUE);
560         if (att == NULL) {
561             crv = CKR_KEY_HANDLE_INVALID;
562             break;
563         }
564         rc2_param = (CK_RC2_CBC_PARAMS *)pMechanism->pParameter;
565         effectiveKeyLength = (rc2_param->ulEffectiveBits+7)/8;
566         context->cipherInfo = 
567             RC2_CreateContext((unsigned char*)att->attrib.pValue,
568                               att->attrib.ulValueLen, rc2_param->iv,
569                               pMechanism->mechanism == CKM_RC2_ECB ? NSS_RC2 :
570                               NSS_RC2_CBC,effectiveKeyLength);
571         sftk_FreeAttribute(att);
572         if (context->cipherInfo == NULL) {
573             crv = CKR_HOST_MEMORY;
574             break;
575         }
576         context->update = (SFTKCipher) (isEncrypt ? RC2_Encrypt : RC2_Decrypt);
577         context->destroy = (SFTKDestroy) RC2_DestroyContext;
578         break;
579 #if NSS_SOFTOKEN_DOES_RC5
580     case CKM_RC5_CBC_PAD:
581         context->doPad = PR_TRUE;
582         /* fall thru */
583     case CKM_RC5_ECB:
584     case CKM_RC5_CBC:
585         if (key_type != CKK_RC5) {
586             crv = CKR_KEY_TYPE_INCONSISTENT;
587             break;
588         }
589         att = sftk_FindAttribute(key,CKA_VALUE);
590         if (att == NULL) {
591             crv = CKR_KEY_HANDLE_INVALID;
592             break;
593         }
594         rc5_param = (CK_RC5_CBC_PARAMS *)pMechanism->pParameter;
595         context->blockSize = rc5_param->ulWordsize*2;
596         rc5Key.data = (unsigned char*)att->attrib.pValue;
597         rc5Key.len = att->attrib.ulValueLen;
598         context->cipherInfo = RC5_CreateContext(&rc5Key,rc5_param->ulRounds,
599            rc5_param->ulWordsize,rc5_param->pIv,
600                  pMechanism->mechanism == CKM_RC5_ECB ? NSS_RC5 : NSS_RC5_CBC);
601         sftk_FreeAttribute(att);
602         if (context->cipherInfo == NULL) {
603             crv = CKR_HOST_MEMORY;
604             break;
605         }
606         context->update = (SFTKCipher) (isEncrypt ? RC5_Encrypt : RC5_Decrypt);
607         context->destroy = (SFTKDestroy) RC5_DestroyContext;
608         break;
609 #endif
610     case CKM_RC4:
611         if (key_type != CKK_RC4) {
612             crv = CKR_KEY_TYPE_INCONSISTENT;
613             break;
614         }
615         att = sftk_FindAttribute(key,CKA_VALUE);
616         if (att == NULL) {
617             crv = CKR_KEY_HANDLE_INVALID;
618             break;
619         }
620         context->cipherInfo = 
621             RC4_CreateContext((unsigned char*)att->attrib.pValue,
622                               att->attrib.ulValueLen);
623         sftk_FreeAttribute(att);
624         if (context->cipherInfo == NULL) {
625             crv = CKR_HOST_MEMORY;  /* WRONG !!! */
626             break;
627         }
628         context->update = (SFTKCipher) (isEncrypt ? RC4_Encrypt : RC4_Decrypt);
629         context->destroy = (SFTKDestroy) RC4_DestroyContext;
630         break;
631     case CKM_CDMF_CBC_PAD:
632         context->doPad = PR_TRUE;
633         /* fall thru */
634     case CKM_CDMF_ECB:
635     case CKM_CDMF_CBC:
636         if (key_type != CKK_CDMF) {
637             crv = CKR_KEY_TYPE_INCONSISTENT;
638             break;
639         }
640         t = (pMechanism->mechanism == CKM_CDMF_ECB) ? NSS_DES : NSS_DES_CBC;
641         if (crv != CKR_OK) break;
642         goto finish_des;
643     case CKM_DES_ECB:
644         if (key_type != CKK_DES) {
645             crv = CKR_KEY_TYPE_INCONSISTENT;
646             break;
647         }
648         t = NSS_DES;
649         goto finish_des;
650     case CKM_DES_CBC_PAD:
651         context->doPad = PR_TRUE;
652         /* fall thru */
653     case CKM_DES_CBC:
654         if (key_type != CKK_DES) {
655             crv = CKR_KEY_TYPE_INCONSISTENT;
656             break;
657         }
658         t = NSS_DES_CBC;
659         goto finish_des;
660     case CKM_DES3_ECB:
661         if ((key_type != CKK_DES2) && (key_type != CKK_DES3)) {
662             crv = CKR_KEY_TYPE_INCONSISTENT;
663             break;
664         }
665         t = NSS_DES_EDE3;
666         goto finish_des;
667     case CKM_DES3_CBC_PAD:
668         context->doPad = PR_TRUE;
669         /* fall thru */
670     case CKM_DES3_CBC:
671         if ((key_type != CKK_DES2) && (key_type != CKK_DES3)) {
672             crv = CKR_KEY_TYPE_INCONSISTENT;
673             break;
674         }
675         t = NSS_DES_EDE3_CBC;
676 finish_des:
677         context->blockSize = 8;
678         att = sftk_FindAttribute(key,CKA_VALUE);
679         if (att == NULL) {
680             crv = CKR_KEY_HANDLE_INVALID;
681             break;
682         }
683         if (key_type == CKK_DES2 && 
684             (t == NSS_DES_EDE3_CBC || t == NSS_DES_EDE3)) {
685             /* extend DES2 key to DES3 key. */
686             memcpy(newdeskey, att->attrib.pValue, 16);
687             memcpy(newdeskey + 16, newdeskey, 8);
688             useNewKey=PR_TRUE;
689         } else if (key_type == CKK_CDMF) {
690             crv = sftk_cdmf2des((unsigned char*)att->attrib.pValue,newdeskey);
691             if (crv != CKR_OK) {
692                 sftk_FreeAttribute(att);
693                 break;
694             }
695             useNewKey=PR_TRUE;
696         }
697         context->cipherInfo = DES_CreateContext(
698                 useNewKey ? newdeskey : (unsigned char*)att->attrib.pValue,
699                 (unsigned char*)pMechanism->pParameter,t, isEncrypt);
700         if (useNewKey) 
701             memset(newdeskey, 0, sizeof newdeskey);
702         sftk_FreeAttribute(att);
703         if (context->cipherInfo == NULL) {
704             crv = CKR_HOST_MEMORY;
705             break;
706         }
707         context->update = (SFTKCipher) (isEncrypt ? DES_Encrypt : DES_Decrypt);
708         context->destroy = (SFTKDestroy) DES_DestroyContext;
709         break;
710     case CKM_SEED_CBC_PAD:
711         context->doPad = PR_TRUE;
712         /* fall thru */
713     case CKM_SEED_CBC:
714         if (!pMechanism->pParameter ||
715              pMechanism->ulParameterLen != 16) {
716             crv = CKR_MECHANISM_PARAM_INVALID;
717             break;
718         }
719         /* fall thru */
720     case CKM_SEED_ECB:
721         context->blockSize = 16;
722         if (key_type != CKK_SEED) {
723             crv = CKR_KEY_TYPE_INCONSISTENT;
724             break;
725         }
726         att = sftk_FindAttribute(key,CKA_VALUE);
727         if (att == NULL) {
728             crv = CKR_KEY_HANDLE_INVALID;
729             break;
730         }
731         context->cipherInfo = SEED_CreateContext(
732             (unsigned char*)att->attrib.pValue,
733             (unsigned char*)pMechanism->pParameter,
734             pMechanism->mechanism == CKM_SEED_ECB ? NSS_SEED : NSS_SEED_CBC,
735             isEncrypt);
736         sftk_FreeAttribute(att);
737         if (context->cipherInfo == NULL) {
738             crv = CKR_HOST_MEMORY;
739             break;
740         }
741         context->update = (SFTKCipher)(isEncrypt ? SEED_Encrypt : SEED_Decrypt);
742         context->destroy = (SFTKDestroy) SEED_DestroyContext;
743         break;
744
745     case CKM_CAMELLIA_CBC_PAD:
746         context->doPad = PR_TRUE;
747         /* fall thru */
748     case CKM_CAMELLIA_CBC:
749         if (!pMechanism->pParameter ||
750                  pMechanism->ulParameterLen != 16) {
751             crv = CKR_MECHANISM_PARAM_INVALID;
752             break;
753         }
754         /* fall thru */
755     case CKM_CAMELLIA_ECB:
756         context->blockSize = 16;
757         if (key_type != CKK_CAMELLIA) {
758             crv = CKR_KEY_TYPE_INCONSISTENT;
759             break;
760         }
761         att = sftk_FindAttribute(key,CKA_VALUE);
762         if (att == NULL) {
763             crv = CKR_KEY_HANDLE_INVALID;
764             break;
765         }
766         context->cipherInfo = Camellia_CreateContext(
767             (unsigned char*)att->attrib.pValue,
768             (unsigned char*)pMechanism->pParameter,
769             pMechanism->mechanism ==
770             CKM_CAMELLIA_ECB ? NSS_CAMELLIA : NSS_CAMELLIA_CBC,
771             isEncrypt, att->attrib.ulValueLen);
772         sftk_FreeAttribute(att);
773         if (context->cipherInfo == NULL) {
774             crv = CKR_HOST_MEMORY;
775             break;
776         }
777         context->update = (SFTKCipher) (isEncrypt ?
778                                         Camellia_Encrypt : Camellia_Decrypt);
779         context->destroy = (SFTKDestroy) Camellia_DestroyContext;
780         break;
781
782     case CKM_AES_CBC_PAD:
783         context->doPad = PR_TRUE;
784         /* fall thru */
785     case CKM_AES_ECB:
786     case CKM_AES_CBC:
787         context->blockSize = 16;
788         if (key_type != CKK_AES) {
789             crv = CKR_KEY_TYPE_INCONSISTENT;
790             break;
791         }
792         att = sftk_FindAttribute(key,CKA_VALUE);
793         if (att == NULL) {
794             crv = CKR_KEY_HANDLE_INVALID;
795             break;
796         }
797         context->cipherInfo = AES_CreateContext(
798             (unsigned char*)att->attrib.pValue,
799             (unsigned char*)pMechanism->pParameter,
800             pMechanism->mechanism == CKM_AES_ECB ? NSS_AES : NSS_AES_CBC,
801             isEncrypt, att->attrib.ulValueLen, 16);
802         sftk_FreeAttribute(att);
803         if (context->cipherInfo == NULL) {
804             crv = CKR_HOST_MEMORY;
805             break;
806         }
807         context->update = (SFTKCipher) (isEncrypt ? AES_Encrypt : AES_Decrypt);
808         context->destroy = (SFTKDestroy) AES_DestroyContext;
809         break;
810
811     case CKM_NETSCAPE_AES_KEY_WRAP_PAD:
812         context->doPad = PR_TRUE;
813         /* fall thru */
814     case CKM_NETSCAPE_AES_KEY_WRAP:
815         context->multi = PR_FALSE;
816         context->blockSize = 8;
817         if (key_type != CKK_AES) {
818             crv = CKR_KEY_TYPE_INCONSISTENT;
819             break;
820         }
821         att = sftk_FindAttribute(key,CKA_VALUE);
822         if (att == NULL) {
823             crv = CKR_KEY_HANDLE_INVALID;
824             break;
825         }
826         context->cipherInfo = AESKeyWrap_CreateContext(
827             (unsigned char*)att->attrib.pValue,
828             (unsigned char*)pMechanism->pParameter,
829             isEncrypt, att->attrib.ulValueLen);
830         sftk_FreeAttribute(att);
831         if (context->cipherInfo == NULL) {
832             crv = CKR_HOST_MEMORY;
833             break;
834         }
835         context->update = (SFTKCipher) (isEncrypt ? AESKeyWrap_Encrypt 
836                                                   : AESKeyWrap_Decrypt);
837         context->destroy = (SFTKDestroy) AESKeyWrap_DestroyContext;
838         break;
839
840     default:
841         crv = CKR_MECHANISM_INVALID;
842         break;
843     }
844
845     if (crv != CKR_OK) {
846         sftk_FreeContext(context);
847         sftk_FreeSession(session);
848         return crv;
849     }
850     sftk_SetContextByType(session, contextType, context);
851     sftk_FreeSession(session);
852     return CKR_OK;
853 }
854
855 /* NSC_EncryptInit initializes an encryption operation. */
856 CK_RV NSC_EncryptInit(CK_SESSION_HANDLE hSession,
857                  CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
858 {
859     CHECK_FORK();
860     return sftk_CryptInit(hSession, pMechanism, hKey, CKA_ENCRYPT, CKA_ENCRYPT,
861                                                 SFTK_ENCRYPT, PR_TRUE);
862 }
863
864 /* NSC_EncryptUpdate continues a multiple-part encryption operation. */
865 CK_RV NSC_EncryptUpdate(CK_SESSION_HANDLE hSession,
866     CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart,  
867                                         CK_ULONG_PTR pulEncryptedPartLen)
868 {
869     SFTKSessionContext *context;
870     unsigned int outlen,i;
871     unsigned int padoutlen = 0;
872     unsigned int maxout = *pulEncryptedPartLen;
873     CK_RV crv;
874     SECStatus rv;
875
876     CHECK_FORK();
877
878     /* make sure we're legal */
879     crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_TRUE,NULL);
880     if (crv != CKR_OK) return crv;
881
882     if (!pEncryptedPart) {
883         if (context->doPad) {
884             CK_ULONG totalDataAvailable = ulPartLen + context->padDataLength;
885             CK_ULONG blocksToSend = totalDataAvailable/context->blockSize;
886
887             *pulEncryptedPartLen = blocksToSend * context->blockSize;
888             return CKR_OK;
889         }
890         *pulEncryptedPartLen = ulPartLen;
891         return CKR_OK;
892     }
893
894     /* do padding */
895     if (context->doPad) {
896         /* deal with previous buffered data */
897         if (context->padDataLength != 0) {
898             /* fill in the padded to a full block size */
899             for (i=context->padDataLength; 
900                         (ulPartLen != 0) && i < context->blockSize; i++) {
901                 context->padBuf[i] = *pPart++;
902                 ulPartLen--;
903                 context->padDataLength++;
904             }
905
906             /* not enough data to encrypt yet? then return */
907             if (context->padDataLength != context->blockSize) {
908                 *pulEncryptedPartLen = 0;
909                 return CKR_OK;
910             }
911             /* encrypt the current padded data */
912             rv = (*context->update)(context->cipherInfo, pEncryptedPart, 
913                 &padoutlen, context->blockSize, context->padBuf,
914                                                         context->blockSize);
915             if (rv != SECSuccess) {
916                 return sftk_MapCryptError(PORT_GetError());
917             }
918             pEncryptedPart += padoutlen;
919             maxout -= padoutlen;
920         }
921         /* save the residual */
922         context->padDataLength = ulPartLen % context->blockSize;
923         if (context->padDataLength) {
924             PORT_Memcpy(context->padBuf,
925                         &pPart[ulPartLen-context->padDataLength],
926                                                         context->padDataLength);
927             ulPartLen -= context->padDataLength;
928         }
929         /* if we've exhausted our new buffer, we're done */
930         if (ulPartLen == 0) {
931             *pulEncryptedPartLen = padoutlen;
932             return CKR_OK;
933         }
934     }
935
936
937     /* do it: NOTE: this assumes buf size in is >= buf size out! */
938     rv = (*context->update)(context->cipherInfo,pEncryptedPart, 
939                                         &outlen, maxout, pPart, ulPartLen);
940     *pulEncryptedPartLen = (CK_ULONG) (outlen + padoutlen);
941     return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
942 }
943
944
945 /* NSC_EncryptFinal finishes a multiple-part encryption operation. */
946 CK_RV NSC_EncryptFinal(CK_SESSION_HANDLE hSession,
947     CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen)
948 {
949     SFTKSession *session;
950     SFTKSessionContext *context;
951     unsigned int outlen,i;
952     unsigned int maxout = *pulLastEncryptedPartLen;
953     CK_RV crv;
954     SECStatus rv = SECSuccess;
955     PRBool contextFinished = PR_TRUE;
956
957     CHECK_FORK();
958
959     /* make sure we're legal */
960     crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_TRUE,&session);
961     if (crv != CKR_OK) return crv;
962
963     *pulLastEncryptedPartLen = 0;
964     if (!pLastEncryptedPart) {
965         /* caller is checking the amount of remaining data */
966         if (context->blockSize > 0 && context->doPad) {
967             *pulLastEncryptedPartLen = context->blockSize;
968             contextFinished = PR_FALSE; /* still have padding to go */
969         }
970         goto finish;
971     }
972
973     /* do padding */
974     if (context->doPad) {
975         unsigned char  padbyte = (unsigned char) 
976                                 (context->blockSize - context->padDataLength); 
977         /* fill out rest of pad buffer with pad magic*/
978         for (i=context->padDataLength; i < context->blockSize; i++) {
979             context->padBuf[i] = padbyte;
980         }
981         rv = (*context->update)(context->cipherInfo,pLastEncryptedPart, 
982                         &outlen, maxout, context->padBuf, context->blockSize);
983         if (rv == SECSuccess) *pulLastEncryptedPartLen = (CK_ULONG) outlen;
984     }
985
986 finish:
987     if (contextFinished)
988         sftk_TerminateOp( session, SFTK_ENCRYPT, context );
989     sftk_FreeSession(session);
990     return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
991 }
992
993 /* NSC_Encrypt encrypts single-part data. */
994 CK_RV NSC_Encrypt (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
995                    CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData,
996                    CK_ULONG_PTR pulEncryptedDataLen)
997 {
998     SFTKSession *session;
999     SFTKSessionContext *context;
1000     unsigned int outlen;
1001     unsigned int maxoutlen = *pulEncryptedDataLen;
1002     CK_RV crv;
1003     CK_RV crv2;
1004     SECStatus rv = SECSuccess;
1005     SECItem   pText;
1006
1007     pText.type = siBuffer;
1008     pText.data = pData;
1009     pText.len  = ulDataLen;
1010
1011     CHECK_FORK();
1012
1013     /* make sure we're legal */
1014     crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_FALSE,&session);
1015     if (crv != CKR_OK) return crv;
1016
1017     if (!pEncryptedData) {
1018         *pulEncryptedDataLen = context->multi ? 
1019                 ulDataLen + 2 * context->blockSize : context->maxLen;
1020         goto finish;
1021     }
1022
1023     if (context->doPad) {
1024         if (context->multi) {
1025             CK_ULONG finalLen;
1026             /* padding is fairly complicated, have the update and final 
1027              * code deal with it */
1028             sftk_FreeSession(session);
1029             crv = NSC_EncryptUpdate(hSession, pData, ulDataLen, pEncryptedData, 
1030                                     pulEncryptedDataLen);
1031             if (crv != CKR_OK) 
1032                 *pulEncryptedDataLen = 0;
1033             maxoutlen      -= *pulEncryptedDataLen;
1034             pEncryptedData += *pulEncryptedDataLen;
1035             finalLen = maxoutlen;
1036             crv2 = NSC_EncryptFinal(hSession, pEncryptedData, &finalLen);
1037             if (crv2 == CKR_OK) 
1038                 *pulEncryptedDataLen += finalLen;
1039             return crv == CKR_OK ? crv2 : crv;
1040         }
1041         /* doPad without multi means that padding must be done on the first
1042         ** and only update.  There will be no final.
1043         */
1044         PORT_Assert(context->blockSize > 1);
1045         if (context->blockSize > 1) {
1046             CK_ULONG remainder = ulDataLen % context->blockSize;
1047             CK_ULONG padding   = context->blockSize - remainder;
1048             pText.len += padding;
1049             pText.data = PORT_ZAlloc(pText.len);
1050             if (pText.data) {
1051                 memcpy(pText.data, pData, ulDataLen);
1052                 memset(pText.data + ulDataLen, padding, padding);
1053             } else {
1054                 crv = CKR_HOST_MEMORY;
1055                 goto fail;
1056             }
1057         }
1058     }
1059
1060     /* do it: NOTE: this assumes buf size is big enough. */
1061     rv = (*context->update)(context->cipherInfo, pEncryptedData, 
1062                             &outlen, maxoutlen, pText.data, pText.len);
1063     crv = (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
1064     *pulEncryptedDataLen = (CK_ULONG) outlen;
1065     if (pText.data != pData)
1066         PORT_ZFree(pText.data, pText.len);
1067 fail:
1068     sftk_TerminateOp( session, SFTK_ENCRYPT, context );
1069 finish:
1070     sftk_FreeSession(session);
1071
1072     return crv;
1073 }
1074
1075
1076 /*
1077  ************** Crypto Functions:     Decrypt ************************
1078  */
1079
1080 /* NSC_DecryptInit initializes a decryption operation. */
1081 CK_RV NSC_DecryptInit( CK_SESSION_HANDLE hSession,
1082                          CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
1083 {
1084     CHECK_FORK();
1085     return sftk_CryptInit(hSession, pMechanism, hKey, CKA_DECRYPT, CKA_DECRYPT,
1086                                                 SFTK_DECRYPT, PR_FALSE);
1087 }
1088
1089 /* NSC_DecryptUpdate continues a multiple-part decryption operation. */
1090 CK_RV NSC_DecryptUpdate(CK_SESSION_HANDLE hSession,
1091     CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen,
1092                                 CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen)
1093 {
1094     SFTKSessionContext *context;
1095     unsigned int padoutlen = 0;
1096     unsigned int outlen;
1097     unsigned int maxout = *pulPartLen;
1098     CK_RV crv;
1099     SECStatus rv;
1100
1101     CHECK_FORK();
1102
1103     /* make sure we're legal */
1104     crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_TRUE,NULL);
1105     if (crv != CKR_OK) return crv;
1106
1107     /* this can only happen on an NSS programming error */
1108     PORT_Assert((context->padDataLength == 0) 
1109                 || context->padDataLength == context->blockSize);
1110
1111
1112     if (!pPart) {
1113         if (context->doPad) {
1114             /* we can check the data length here because if we are padding,
1115              * then we must be using a block cipher. In the non-padding case
1116              * the error will be returned by the underlying decryption
1117              * function when do do the actual decrypt. We need to do the
1118              * check here to avoid returning a negative length to the caller.
1119              */
1120             if ((ulEncryptedPartLen == 0) ||
1121                 (ulEncryptedPartLen % context->blockSize) != 0) {
1122                 return CKR_ENCRYPTED_DATA_LEN_RANGE;
1123             }
1124             *pulPartLen = 
1125                 ulEncryptedPartLen + context->padDataLength - context->blockSize;
1126             return CKR_OK;
1127         }
1128         /* for stream ciphers there is are no constraints on ulEncryptedPartLen.
1129          * for block ciphers, it must be a multiple of blockSize. The error is
1130          * detected when this function is called again do decrypt the output.
1131          */
1132         *pulPartLen = ulEncryptedPartLen;
1133         return CKR_OK;
1134     }
1135
1136     if (context->doPad) {
1137         /* first decrypt our saved buffer */
1138         if (context->padDataLength != 0) {
1139             rv = (*context->update)(context->cipherInfo, pPart, &padoutlen,
1140                  maxout, context->padBuf, context->blockSize);
1141             if (rv != SECSuccess) return sftk_MapDecryptError(PORT_GetError());
1142             pPart += padoutlen;
1143             maxout -= padoutlen;
1144         }
1145         /* now save the final block for the next decrypt or the final */
1146         PORT_Memcpy(context->padBuf,&pEncryptedPart[ulEncryptedPartLen -
1147                                 context->blockSize], context->blockSize);
1148         context->padDataLength = context->blockSize;
1149         ulEncryptedPartLen -= context->padDataLength;
1150     }
1151
1152     /* do it: NOTE: this assumes buf size in is >= buf size out! */
1153     rv = (*context->update)(context->cipherInfo,pPart, &outlen,
1154                  maxout, pEncryptedPart, ulEncryptedPartLen);
1155     *pulPartLen = (CK_ULONG) (outlen + padoutlen);
1156     return (rv == SECSuccess)  ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
1157 }
1158
1159
1160 /* NSC_DecryptFinal finishes a multiple-part decryption operation. */
1161 CK_RV NSC_DecryptFinal(CK_SESSION_HANDLE hSession,
1162     CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen)
1163 {
1164     SFTKSession *session;
1165     SFTKSessionContext *context;
1166     unsigned int outlen;
1167     unsigned int maxout = *pulLastPartLen;
1168     CK_RV crv;
1169     SECStatus rv = SECSuccess;
1170
1171     CHECK_FORK();
1172
1173     /* make sure we're legal */
1174     crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_TRUE,&session);
1175     if (crv != CKR_OK) return crv;
1176
1177     *pulLastPartLen = 0;
1178     if (!pLastPart) {
1179         /* caller is checking the amount of remaining data */
1180         if (context->padDataLength > 0) {
1181             *pulLastPartLen = context->padDataLength;
1182         }
1183         rv = SECSuccess;
1184         goto finish;
1185     }
1186
1187     if (context->doPad) {
1188         /* decrypt our saved buffer */
1189         if (context->padDataLength != 0) {
1190             /* this assumes that pLastPart is big enough to hold the *whole*
1191              * buffer!!! */
1192             rv = (*context->update)(context->cipherInfo, pLastPart, &outlen,
1193                  maxout, context->padBuf, context->blockSize);
1194             if (rv == SECSuccess) {
1195                 unsigned int padSize = 
1196                             (unsigned int) pLastPart[context->blockSize-1];
1197                 if ((padSize > context->blockSize) || (padSize == 0)) {
1198                     rv = SECFailure;
1199                 } else {
1200                     *pulLastPartLen = outlen - padSize;
1201                 }
1202             }
1203         }
1204     }
1205
1206     sftk_TerminateOp( session, SFTK_DECRYPT, context );
1207 finish:
1208     sftk_FreeSession(session);
1209     return (rv == SECSuccess) ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
1210 }
1211
1212 /* NSC_Decrypt decrypts encrypted data in a single part. */
1213 CK_RV NSC_Decrypt(CK_SESSION_HANDLE hSession,
1214     CK_BYTE_PTR pEncryptedData,CK_ULONG ulEncryptedDataLen,CK_BYTE_PTR pData,
1215                                                 CK_ULONG_PTR pulDataLen)
1216 {
1217     SFTKSession *session;
1218     SFTKSessionContext *context;
1219     unsigned int outlen;
1220     unsigned int maxoutlen = *pulDataLen;
1221     CK_RV crv;
1222     CK_RV crv2;
1223     SECStatus rv = SECSuccess;
1224
1225     CHECK_FORK();
1226
1227     /* make sure we're legal */
1228     crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_FALSE,&session);
1229     if (crv != CKR_OK) return crv;
1230
1231     if (!pData) {
1232         *pulDataLen = ulEncryptedDataLen + context->blockSize;
1233         goto finish;
1234     }
1235
1236     if (context->doPad && context->multi) {
1237         CK_ULONG finalLen;
1238         /* padding is fairly complicated, have the update and final 
1239          * code deal with it */
1240         sftk_FreeSession(session);
1241         crv = NSC_DecryptUpdate(hSession,pEncryptedData,ulEncryptedDataLen,
1242                                                         pData, pulDataLen);
1243         if (crv != CKR_OK) 
1244             *pulDataLen = 0;
1245         maxoutlen -= *pulDataLen;
1246         pData     += *pulDataLen;
1247         finalLen = maxoutlen;
1248         crv2 = NSC_DecryptFinal(hSession, pData, &finalLen);
1249         if (crv2 == CKR_OK) 
1250             *pulDataLen += finalLen;
1251         return crv == CKR_OK ? crv2 : crv;
1252     }
1253
1254     rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen, 
1255                                         pEncryptedData, ulEncryptedDataLen);
1256     /* XXX need to do MUCH better error mapping than this. */
1257     crv = (rv == SECSuccess) ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
1258     if (rv == SECSuccess && context->doPad) {
1259         CK_ULONG padding = pData[outlen - 1];
1260         if (padding > context->blockSize || !padding) {
1261             crv = CKR_ENCRYPTED_DATA_INVALID;
1262         } else
1263             outlen -= padding;
1264     }
1265     *pulDataLen = (CK_ULONG) outlen;
1266     sftk_TerminateOp( session, SFTK_DECRYPT, context );
1267 finish:
1268     sftk_FreeSession(session);
1269     return crv;
1270 }
1271
1272
1273
1274 /*
1275  ************** Crypto Functions:     Digest (HASH)  ************************
1276  */
1277
1278 /* NSC_DigestInit initializes a message-digesting operation. */
1279 CK_RV NSC_DigestInit(CK_SESSION_HANDLE hSession,
1280                                         CK_MECHANISM_PTR pMechanism)
1281 {
1282     SFTKSession *session;
1283     SFTKSessionContext *context;
1284     CK_RV crv = CKR_OK;
1285
1286     CHECK_FORK();
1287
1288     session = sftk_SessionFromHandle(hSession);
1289     if (session == NULL) 
1290         return CKR_SESSION_HANDLE_INVALID;
1291     crv = sftk_InitGeneric(session,&context,SFTK_HASH,NULL,0,NULL, 0, 0);
1292     if (crv != CKR_OK) {
1293         sftk_FreeSession(session);
1294         return crv;
1295     }
1296
1297
1298 #define INIT_MECH(mech,mmm) \
1299     case mech: { \
1300         mmm ## Context * mmm ## _ctx = mmm ## _NewContext(); \
1301         context->cipherInfo    = (void *)mmm ## _ctx; \
1302         context->cipherInfoLen = mmm ## _FlattenSize(mmm ## _ctx); \
1303         context->currentMech   = mech; \
1304         context->hashUpdate    = (SFTKHash)    mmm ## _Update; \
1305         context->end           = (SFTKEnd)     mmm ## _End; \
1306         context->destroy       = (SFTKDestroy) mmm ## _DestroyContext; \
1307         context->maxLen        = mmm ## _LENGTH; \
1308         if (mmm ## _ctx) \
1309             mmm ## _Begin(mmm ## _ctx); \
1310         else  \
1311             crv = CKR_HOST_MEMORY; \
1312         break; \
1313     }
1314
1315     switch(pMechanism->mechanism) {
1316     INIT_MECH(CKM_MD2,    MD2)
1317     INIT_MECH(CKM_MD5,    MD5)
1318     INIT_MECH(CKM_SHA_1,  SHA1)
1319     INIT_MECH(CKM_SHA224, SHA224)
1320     INIT_MECH(CKM_SHA256, SHA256)
1321     INIT_MECH(CKM_SHA384, SHA384)
1322     INIT_MECH(CKM_SHA512, SHA512)
1323
1324     default:
1325         crv = CKR_MECHANISM_INVALID;
1326         break;
1327     }
1328
1329     if (crv != CKR_OK) {
1330         sftk_FreeContext(context);
1331         sftk_FreeSession(session);
1332         return crv;
1333     }
1334     sftk_SetContextByType(session, SFTK_HASH, context);
1335     sftk_FreeSession(session);
1336     return CKR_OK;
1337 }
1338
1339
1340 /* NSC_Digest digests data in a single part. */
1341 CK_RV NSC_Digest(CK_SESSION_HANDLE hSession,
1342     CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest,
1343                                                 CK_ULONG_PTR pulDigestLen)
1344 {
1345     SFTKSession *session;
1346     SFTKSessionContext *context;
1347     unsigned int digestLen;
1348     unsigned int maxout = *pulDigestLen;
1349     CK_RV crv;
1350
1351     CHECK_FORK();
1352
1353     /* make sure we're legal */
1354     crv = sftk_GetContext(hSession,&context,SFTK_HASH,PR_FALSE,&session);
1355     if (crv != CKR_OK) return crv;
1356
1357     if (pDigest == NULL) {
1358         *pulDigestLen = context->maxLen;
1359         goto finish;
1360     }
1361
1362     /* do it: */
1363     (*context->hashUpdate)(context->cipherInfo, pData, ulDataLen);
1364     /*  NOTE: this assumes buf size is bigenough for the algorithm */
1365     (*context->end)(context->cipherInfo, pDigest, &digestLen,maxout);
1366     *pulDigestLen = digestLen;
1367
1368     sftk_TerminateOp( session, SFTK_HASH, context );
1369 finish:
1370     sftk_FreeSession(session);
1371     return CKR_OK;
1372 }
1373
1374
1375 /* NSC_DigestUpdate continues a multiple-part message-digesting operation. */
1376 CK_RV NSC_DigestUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
1377                                             CK_ULONG ulPartLen)
1378 {
1379     SFTKSessionContext *context;
1380     CK_RV crv;
1381
1382     CHECK_FORK();
1383
1384     /* make sure we're legal */
1385     crv = sftk_GetContext(hSession,&context,SFTK_HASH,PR_TRUE,NULL);
1386     if (crv != CKR_OK) return crv;
1387     /* do it: */
1388     (*context->hashUpdate)(context->cipherInfo, pPart, ulPartLen);
1389     return CKR_OK;
1390 }
1391
1392
1393 /* NSC_DigestFinal finishes a multiple-part message-digesting operation. */
1394 CK_RV NSC_DigestFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pDigest,
1395                                                 CK_ULONG_PTR pulDigestLen)
1396 {
1397     SFTKSession *session;
1398     SFTKSessionContext *context;
1399     unsigned int maxout = *pulDigestLen;
1400     unsigned int digestLen;
1401     CK_RV crv;
1402
1403     CHECK_FORK();
1404
1405     /* make sure we're legal */
1406     crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, &session);
1407     if (crv != CKR_OK) return crv;
1408
1409     if (pDigest != NULL) {
1410         (*context->end)(context->cipherInfo, pDigest, &digestLen, maxout);
1411         *pulDigestLen = digestLen;
1412         sftk_TerminateOp( session, SFTK_HASH, context );
1413     } else {
1414         *pulDigestLen = context->maxLen;
1415     }
1416
1417     sftk_FreeSession(session);
1418     return CKR_OK;
1419 }
1420
1421 /*
1422  * these helper functions are used by Generic Macing and Signing functions
1423  * that use hashes as part of their operations. 
1424  */
1425 #define DOSUB(mmm) \
1426 static CK_RV \
1427 sftk_doSub ## mmm(SFTKSessionContext *context) { \
1428     mmm ## Context * mmm ## _ctx = mmm ## _NewContext(); \
1429     context->hashInfo    = (void *)      mmm ## _ctx; \
1430     context->hashUpdate  = (SFTKHash)    mmm ## _Update; \
1431     context->end         = (SFTKEnd)     mmm ## _End; \
1432     context->hashdestroy = (SFTKDestroy) mmm ## _DestroyContext; \
1433     if (!context->hashInfo) { \
1434         return CKR_HOST_MEMORY; \
1435     } \
1436     mmm ## _Begin( mmm ## _ctx ); \
1437     return CKR_OK; \
1438 }
1439
1440 DOSUB(MD2)
1441 DOSUB(MD5)
1442 DOSUB(SHA1)
1443 DOSUB(SHA224)
1444 DOSUB(SHA256)
1445 DOSUB(SHA384)
1446 DOSUB(SHA512)
1447
1448 /*
1449  * HMAC General copies only a portion of the result. This update routine likes
1450  * the final HMAC output with the signature.
1451  */
1452 static SECStatus
1453 sftk_HMACCopy(CK_ULONG *copyLen,unsigned char *sig,unsigned int *sigLen,
1454                 unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
1455 {
1456     if (maxLen < *copyLen) return SECFailure;
1457     PORT_Memcpy(sig,hash,*copyLen);
1458     *sigLen = *copyLen;
1459     return SECSuccess;
1460 }
1461
1462 /* Verify is just a compare for HMAC */
1463 static SECStatus
1464 sftk_HMACCmp(CK_ULONG *copyLen,unsigned char *sig,unsigned int sigLen,
1465                                 unsigned char *hash, unsigned int hashLen)
1466 {
1467     return (PORT_Memcmp(sig,hash,*copyLen) == 0) ? SECSuccess : SECFailure ; 
1468 }
1469
1470 /*
1471  * common HMAC initalization routine
1472  */
1473 static CK_RV
1474 sftk_doHMACInit(SFTKSessionContext *context,HASH_HashType hash,
1475                                         SFTKObject *key, CK_ULONG mac_size)
1476 {
1477     SFTKAttribute *keyval;
1478     HMACContext *HMACcontext;
1479     CK_ULONG *intpointer;
1480     const SECHashObject *hashObj = HASH_GetRawHashObject(hash);
1481     PRBool isFIPS = (key->slot->slotID == FIPS_SLOT_ID);
1482
1483     /* required by FIPS 198 Section 4 */
1484     if (isFIPS && (mac_size < 4 || mac_size < hashObj->length/2)) {
1485         return CKR_BUFFER_TOO_SMALL;
1486     }
1487
1488     keyval = sftk_FindAttribute(key,CKA_VALUE);
1489     if (keyval == NULL) return CKR_KEY_SIZE_RANGE;
1490
1491     HMACcontext = HMAC_Create(hashObj, 
1492                 (const unsigned char*)keyval->attrib.pValue,
1493                 keyval->attrib.ulValueLen, isFIPS);
1494     context->hashInfo = HMACcontext;
1495     context->multi = PR_TRUE;
1496     sftk_FreeAttribute(keyval);
1497     if (context->hashInfo == NULL) {
1498         if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) {
1499             return CKR_KEY_SIZE_RANGE;
1500         }
1501         return CKR_HOST_MEMORY;
1502     }
1503     context->hashUpdate = (SFTKHash) HMAC_Update;
1504     context->end = (SFTKEnd) HMAC_Finish;
1505
1506     context->hashdestroy = (SFTKDestroy) HMAC_Destroy;
1507     intpointer = (CK_ULONG *) PORT_Alloc(sizeof(CK_ULONG));
1508     if (intpointer == NULL) {
1509         return CKR_HOST_MEMORY;
1510     }
1511     *intpointer = mac_size;
1512     context->cipherInfo = (void *) intpointer;
1513     context->destroy = (SFTKDestroy) sftk_Space;
1514     context->update = (SFTKCipher) sftk_HMACCopy;
1515     context->verify = (SFTKVerify) sftk_HMACCmp;
1516     context->maxLen = hashObj->length;
1517     HMAC_Begin(HMACcontext);
1518     return CKR_OK;
1519 }
1520
1521 /*
1522  *  SSL Macing support. SSL Macs are inited, then update with the base
1523  * hashing algorithm, then finalized in sign and verify
1524  */
1525
1526 /*
1527  * FROM SSL:
1528  * 60 bytes is 3 times the maximum length MAC size that is supported.
1529  * We probably should have one copy of this table. We still need this table
1530  * in ssl to 'sign' the handshake hashes.
1531  */
1532 static unsigned char ssl_pad_1 [60] = {
1533     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
1534     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
1535     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
1536     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
1537     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
1538     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
1539     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
1540     0x36, 0x36, 0x36, 0x36
1541 };
1542 static unsigned char ssl_pad_2 [60] = {
1543     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
1544     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
1545     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
1546     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
1547     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
1548     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
1549     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
1550     0x5c, 0x5c, 0x5c, 0x5c
1551 };
1552
1553 static SECStatus
1554 sftk_SSLMACSign(SFTKSSLMACInfo *info,unsigned char *sig,unsigned int *sigLen,
1555                 unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
1556 {
1557     unsigned char tmpBuf[SFTK_MAX_MAC_LENGTH];
1558     unsigned int out;
1559
1560     info->begin(info->hashContext);
1561     info->update(info->hashContext,info->key,info->keySize);
1562     info->update(info->hashContext,ssl_pad_2,info->padSize);
1563     info->update(info->hashContext,hash,hashLen);
1564     info->end(info->hashContext,tmpBuf,&out,SFTK_MAX_MAC_LENGTH);
1565     PORT_Memcpy(sig,tmpBuf,info->macSize);
1566     *sigLen = info->macSize;
1567     return SECSuccess;
1568 }
1569
1570 static SECStatus
1571 sftk_SSLMACVerify(SFTKSSLMACInfo *info,unsigned char *sig,unsigned int sigLen,
1572                 unsigned char *hash, unsigned int hashLen)
1573 {
1574     unsigned char tmpBuf[SFTK_MAX_MAC_LENGTH];
1575     unsigned int out;
1576
1577     info->begin(info->hashContext);
1578     info->update(info->hashContext,info->key,info->keySize);
1579     info->update(info->hashContext,ssl_pad_2,info->padSize);
1580     info->update(info->hashContext,hash,hashLen);
1581     info->end(info->hashContext,tmpBuf,&out,SFTK_MAX_MAC_LENGTH);
1582     return (PORT_Memcmp(sig,tmpBuf,info->macSize) == 0) ? 
1583                                                 SECSuccess : SECFailure;
1584 }
1585
1586 /*
1587  * common HMAC initalization routine
1588  */
1589 static CK_RV
1590 sftk_doSSLMACInit(SFTKSessionContext *context,SECOidTag oid,
1591                                         SFTKObject *key, CK_ULONG mac_size)
1592 {
1593     SFTKAttribute *keyval;
1594     SFTKBegin begin;
1595     int padSize;
1596     SFTKSSLMACInfo *sslmacinfo;
1597     CK_RV crv = CKR_MECHANISM_INVALID;
1598
1599     if (oid == SEC_OID_SHA1) {
1600         crv = sftk_doSubSHA1(context);
1601         if (crv != CKR_OK) return crv;
1602         begin = (SFTKBegin) SHA1_Begin;
1603         padSize = 40;
1604     } else {
1605         crv = sftk_doSubMD5(context);
1606         if (crv != CKR_OK) return crv;
1607         begin = (SFTKBegin) MD5_Begin;
1608         padSize = 48;
1609     }
1610     context->multi = PR_TRUE;
1611
1612     keyval = sftk_FindAttribute(key,CKA_VALUE);
1613     if (keyval == NULL) return CKR_KEY_SIZE_RANGE;
1614
1615     context->hashUpdate(context->hashInfo,keyval->attrib.pValue,
1616                                                  keyval->attrib.ulValueLen);
1617     context->hashUpdate(context->hashInfo,ssl_pad_1,padSize);
1618     sslmacinfo = (SFTKSSLMACInfo *) PORT_Alloc(sizeof(SFTKSSLMACInfo));
1619     if (sslmacinfo == NULL) {
1620         sftk_FreeAttribute(keyval);
1621         return CKR_HOST_MEMORY;
1622     }
1623     sslmacinfo->macSize = mac_size;
1624     sslmacinfo->hashContext = context->hashInfo;
1625     PORT_Memcpy(sslmacinfo->key,keyval->attrib.pValue,
1626                                         keyval->attrib.ulValueLen);
1627     sslmacinfo->keySize = keyval->attrib.ulValueLen;
1628     sslmacinfo->begin = begin;
1629     sslmacinfo->end = context->end;
1630     sslmacinfo->update = context->hashUpdate;
1631     sslmacinfo->padSize = padSize;
1632     sftk_FreeAttribute(keyval);
1633     context->cipherInfo = (void *) sslmacinfo;
1634     context->destroy = (SFTKDestroy) sftk_Space;
1635     context->update = (SFTKCipher) sftk_SSLMACSign;
1636     context->verify = (SFTKVerify) sftk_SSLMACVerify;
1637     context->maxLen = mac_size;
1638     return CKR_OK;
1639 }
1640
1641 /*
1642  ************** Crypto Functions:     Sign  ************************
1643  */
1644
1645 /** 
1646  * Check if We're using CBCMacing and initialize the session context if we are.
1647  *  @param contextType SFTK_SIGN or SFTK_VERIFY
1648  *  @param keyUsage    check whether key allows this usage
1649  */
1650 static CK_RV
1651 sftk_InitCBCMac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
1652         CK_OBJECT_HANDLE hKey, CK_ATTRIBUTE_TYPE keyUsage,
1653                                                  SFTKContextType contextType)
1654         
1655 {
1656     CK_MECHANISM cbc_mechanism;
1657     CK_ULONG mac_bytes = SFTK_INVALID_MAC_SIZE;
1658     CK_RC2_CBC_PARAMS rc2_params;
1659 #if NSS_SOFTOKEN_DOES_RC5
1660     CK_RC5_CBC_PARAMS rc5_params;
1661     CK_RC5_MAC_GENERAL_PARAMS *rc5_mac;
1662 #endif
1663     unsigned char ivBlock[SFTK_MAX_BLOCK_SIZE];
1664     SFTKSessionContext *context;
1665     CK_RV crv;
1666     unsigned int blockSize;
1667
1668     switch (pMechanism->mechanism) {
1669     case CKM_RC2_MAC_GENERAL:
1670         mac_bytes = 
1671             ((CK_RC2_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength;
1672         /* fall through */
1673     case CKM_RC2_MAC:
1674         /* this works because ulEffectiveBits is in the same place in both the
1675          * CK_RC2_MAC_GENERAL_PARAMS and CK_RC2_CBC_PARAMS */
1676         rc2_params.ulEffectiveBits = ((CK_RC2_MAC_GENERAL_PARAMS *)
1677                                 pMechanism->pParameter)->ulEffectiveBits;
1678         PORT_Memset(rc2_params.iv,0,sizeof(rc2_params.iv));
1679         cbc_mechanism.mechanism = CKM_RC2_CBC;
1680         cbc_mechanism.pParameter = &rc2_params;
1681         cbc_mechanism.ulParameterLen = sizeof(rc2_params);
1682         blockSize = 8;
1683         break;
1684 #if NSS_SOFTOKEN_DOES_RC5
1685     case CKM_RC5_MAC_GENERAL:
1686         mac_bytes = 
1687             ((CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength;
1688         /* fall through */
1689     case CKM_RC5_MAC:
1690         /* this works because ulEffectiveBits is in the same place in both the
1691          * CK_RC5_MAC_GENERAL_PARAMS and CK_RC5_CBC_PARAMS */
1692         rc5_mac = (CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter;
1693         rc5_params.ulWordsize = rc5_mac->ulWordsize;
1694         rc5_params.ulRounds = rc5_mac->ulRounds;
1695         rc5_params.pIv = ivBlock;
1696         if( (blockSize = rc5_mac->ulWordsize*2) > SFTK_MAX_BLOCK_SIZE )
1697             return CKR_MECHANISM_PARAM_INVALID;
1698         rc5_params.ulIvLen = blockSize;
1699         PORT_Memset(ivBlock,0,blockSize);
1700         cbc_mechanism.mechanism = CKM_RC5_CBC;
1701         cbc_mechanism.pParameter = &rc5_params;
1702         cbc_mechanism.ulParameterLen = sizeof(rc5_params);
1703         break;
1704 #endif
1705     /* add cast and idea later */
1706     case CKM_DES_MAC_GENERAL:
1707         mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
1708         /* fall through */
1709     case CKM_DES_MAC:
1710         blockSize = 8;
1711         PORT_Memset(ivBlock,0,blockSize);
1712         cbc_mechanism.mechanism = CKM_DES_CBC;
1713         cbc_mechanism.pParameter = &ivBlock;
1714         cbc_mechanism.ulParameterLen = blockSize;
1715         break;
1716     case CKM_DES3_MAC_GENERAL:
1717         mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
1718         /* fall through */
1719     case CKM_DES3_MAC:
1720         blockSize = 8;
1721         PORT_Memset(ivBlock,0,blockSize);
1722         cbc_mechanism.mechanism = CKM_DES3_CBC;
1723         cbc_mechanism.pParameter = &ivBlock;
1724         cbc_mechanism.ulParameterLen = blockSize;
1725         break;
1726     case CKM_CDMF_MAC_GENERAL:
1727         mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
1728         /* fall through */
1729     case CKM_CDMF_MAC:
1730         blockSize = 8;
1731         PORT_Memset(ivBlock,0,blockSize);
1732         cbc_mechanism.mechanism = CKM_CDMF_CBC;
1733         cbc_mechanism.pParameter = &ivBlock;
1734         cbc_mechanism.ulParameterLen = blockSize;
1735         break;
1736     case CKM_SEED_MAC_GENERAL:
1737         mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
1738         /* fall through */
1739     case CKM_SEED_MAC:
1740         blockSize = 16;
1741         PORT_Memset(ivBlock,0,blockSize);
1742         cbc_mechanism.mechanism = CKM_SEED_CBC;
1743         cbc_mechanism.pParameter = &ivBlock;
1744         cbc_mechanism.ulParameterLen = blockSize;
1745         break;
1746     case CKM_CAMELLIA_MAC_GENERAL:
1747         mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
1748         /* fall through */
1749     case CKM_CAMELLIA_MAC:
1750         blockSize = 16;
1751         PORT_Memset(ivBlock,0,blockSize);
1752         cbc_mechanism.mechanism = CKM_CAMELLIA_CBC;
1753         cbc_mechanism.pParameter = &ivBlock;
1754         cbc_mechanism.ulParameterLen = blockSize;
1755         break;
1756     case CKM_AES_MAC_GENERAL:
1757         mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
1758         /* fall through */
1759     case CKM_AES_MAC:
1760         blockSize = 16;
1761         PORT_Memset(ivBlock,0,blockSize);
1762         cbc_mechanism.mechanism = CKM_AES_CBC;
1763         cbc_mechanism.pParameter = &ivBlock;
1764         cbc_mechanism.ulParameterLen = blockSize;
1765         break;
1766     default:
1767         return CKR_FUNCTION_NOT_SUPPORTED;
1768     }
1769
1770     /* if MAC size is externally supplied, it should be checked.
1771      */
1772     if (mac_bytes == SFTK_INVALID_MAC_SIZE)
1773         mac_bytes = blockSize >> 1;
1774     else {
1775         if( mac_bytes > blockSize )
1776             return CKR_MECHANISM_PARAM_INVALID;
1777     }
1778
1779     crv = sftk_CryptInit(hSession, &cbc_mechanism, hKey,
1780             CKA_ENCRYPT, /* CBC mech is able to ENCRYPT, not SIGN/VERIFY */
1781             keyUsage, contextType, PR_TRUE );
1782     if (crv != CKR_OK) return crv;
1783     crv = sftk_GetContext(hSession,&context,contextType,PR_TRUE,NULL);
1784
1785     /* this shouldn't happen! */
1786     PORT_Assert(crv == CKR_OK);
1787     if (crv != CKR_OK) return crv;
1788     context->blockSize = blockSize;
1789     context->macSize = mac_bytes;
1790     return CKR_OK;
1791 }
1792
1793 /*
1794  * encode RSA PKCS #1 Signature data before signing... 
1795  */
1796 static SECStatus
1797 sftk_HashSign(SFTKHashSignInfo *info,unsigned char *sig,unsigned int *sigLen,
1798                 unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
1799 {
1800     return RSA_HashSign(info->hashOid,info->key,sig,sigLen,maxLen,
1801                                                         hash,hashLen);
1802 }
1803
1804 /* XXX Old template; want to expunge it eventually. */
1805 static DERTemplate SECAlgorithmIDTemplate[] = {
1806     { DER_SEQUENCE,
1807           0, NULL, sizeof(SECAlgorithmID) },
1808     { DER_OBJECT_ID,
1809           offsetof(SECAlgorithmID,algorithm), },
1810     { DER_OPTIONAL | DER_ANY,
1811           offsetof(SECAlgorithmID,parameters), },
1812     { 0, }
1813 };
1814
1815 /*
1816  * XXX OLD Template.  Once all uses have been switched over to new one,
1817  * remove this.
1818  */
1819 static DERTemplate SGNDigestInfoTemplate[] = {
1820     { DER_SEQUENCE,
1821           0, NULL, sizeof(SGNDigestInfo) },
1822     { DER_INLINE,
1823           offsetof(SGNDigestInfo,digestAlgorithm),
1824           SECAlgorithmIDTemplate, },
1825     { DER_OCTET_STRING,
1826           offsetof(SGNDigestInfo,digest), },
1827     { 0, }
1828 };
1829
1830 SECStatus
1831 RSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key,
1832                 unsigned char *sig, unsigned int *sigLen, unsigned int maxLen,
1833                 unsigned char *hash, unsigned int hashLen)
1834 {
1835     
1836     SECStatus rv = SECFailure;
1837     SECItem digder;
1838     PLArenaPool *arena = NULL;
1839     SGNDigestInfo *di = NULL;
1840
1841     digder.data = NULL;
1842
1843     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1844     if ( !arena ) { goto loser; }
1845     
1846     /* Construct digest info */
1847     di = SGN_CreateDigestInfo(hashOid, hash, hashLen);
1848     if (!di) { goto loser; }
1849
1850     /* Der encode the digest as a DigestInfo */
1851     rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di);
1852     if (rv != SECSuccess) {
1853         goto loser;
1854     }
1855
1856     /*
1857     ** Encrypt signature after constructing appropriate PKCS#1 signature
1858     ** block
1859     */
1860     rv = RSA_Sign(key,sig,sigLen,maxLen,digder.data,digder.len);
1861
1862   loser:
1863     SGN_DestroyDigestInfo(di);
1864     if (arena != NULL) {
1865         PORT_FreeArena(arena, PR_FALSE);
1866     }
1867     return rv;
1868 }
1869
1870 static SECStatus
1871 sftk_SignPSS(SFTKHashSignInfo *info,unsigned char *sig,unsigned int *sigLen,
1872                 unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
1873 {
1874     return RSA_SignPSS(info->params,info->key,sig,sigLen,maxLen,
1875                                                         hash,hashLen);
1876 }
1877
1878 static SECStatus
1879 nsc_DSA_Verify_Stub(void *ctx, void *sigBuf, unsigned int sigLen,
1880                                void *dataBuf, unsigned int dataLen)
1881 {
1882     SECItem signature, digest;
1883     NSSLOWKEYPublicKey *key = (NSSLOWKEYPublicKey *)ctx;
1884
1885     signature.data = (unsigned char *)sigBuf;
1886     signature.len = sigLen;
1887     digest.data = (unsigned char *)dataBuf;
1888     digest.len = dataLen;
1889     return DSA_VerifyDigest(&(key->u.dsa), &signature, &digest);
1890 }
1891
1892 static SECStatus
1893 nsc_DSA_Sign_Stub(void *ctx, void *sigBuf,
1894                   unsigned int *sigLen, unsigned int maxSigLen,
1895                   void *dataBuf, unsigned int dataLen)
1896 {
1897     SECItem signature, digest;
1898     SECStatus rv;
1899     NSSLOWKEYPrivateKey *key = (NSSLOWKEYPrivateKey *)ctx;
1900
1901     signature.data = (unsigned char *)sigBuf;
1902     signature.len = maxSigLen;
1903     digest.data = (unsigned char *)dataBuf;
1904     digest.len = dataLen;
1905     rv = DSA_SignDigest(&(key->u.dsa), &signature, &digest);
1906     if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
1907         sftk_fatalError = PR_TRUE;
1908     }
1909     *sigLen = signature.len;
1910     return rv;
1911 }
1912
1913 #ifdef NSS_ENABLE_ECC
1914 static SECStatus
1915 nsc_ECDSAVerifyStub(void *ctx, void *sigBuf, unsigned int sigLen,
1916                     void *dataBuf, unsigned int dataLen)
1917 {
1918     SECItem signature, digest;
1919     NSSLOWKEYPublicKey *key = (NSSLOWKEYPublicKey *)ctx;
1920
1921     signature.data = (unsigned char *)sigBuf;
1922     signature.len = sigLen;
1923     digest.data = (unsigned char *)dataBuf;
1924     digest.len = dataLen;
1925     return ECDSA_VerifyDigest(&(key->u.ec), &signature, &digest);
1926 }
1927
1928 static SECStatus
1929 nsc_ECDSASignStub(void *ctx, void *sigBuf,
1930                   unsigned int *sigLen, unsigned int maxSigLen,
1931                   void *dataBuf, unsigned int dataLen)
1932 {
1933     SECItem signature, digest;
1934     SECStatus rv;
1935     NSSLOWKEYPrivateKey *key = (NSSLOWKEYPrivateKey *)ctx;
1936
1937     signature.data = (unsigned char *)sigBuf;
1938     signature.len = maxSigLen;
1939     digest.data = (unsigned char *)dataBuf;
1940     digest.len = dataLen;
1941     rv = ECDSA_SignDigest(&(key->u.ec), &signature, &digest);
1942     if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
1943         sftk_fatalError = PR_TRUE;
1944     }
1945     *sigLen = signature.len;
1946     return rv;
1947 }
1948 #endif /* NSS_ENABLE_ECC */
1949
1950 /* NSC_SignInit setups up the signing operations. There are three basic
1951  * types of signing:
1952  *      (1) the tradition single part, where "Raw RSA" or "Raw DSA" is applied
1953  *  to data in a single Sign operation (which often looks a lot like an
1954  *  encrypt, with data coming in and data going out).
1955  *      (2) Hash based signing, where we continually hash the data, then apply
1956  *  some sort of signature to the end.
1957  *      (3) Block Encryption CBC MAC's, where the Data is encrypted with a key,
1958  *  and only the final block is part of the mac.
1959  *
1960  *  For case number 3, we initialize a context much like the Encryption Context
1961  *  (in fact we share code). We detect case 3 in C_SignUpdate, C_Sign, and 
1962  *  C_Final by the following method... if it's not multi-part, and it's doesn't
1963  *  have a hash context, it must be a block Encryption CBC MAC.
1964  *
1965  *  For case number 2, we initialize a hash structure, as well as make it 
1966  *  multi-part. Updates are simple calls to the hash update function. Final
1967  *  calls the hashend, then passes the result to the 'update' function (which
1968  *  operates as a final signature function). In some hash based MAC'ing (as
1969  *  opposed to hash base signatures), the update function is can be simply a 
1970  *  copy (as is the case with HMAC).
1971  */
1972 CK_RV NSC_SignInit(CK_SESSION_HANDLE hSession,
1973                  CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
1974 {
1975     SFTKSession *session;
1976     SFTKObject *key;
1977     SFTKSessionContext *context;
1978     CK_KEY_TYPE key_type;
1979     CK_RV crv = CKR_OK;
1980     NSSLOWKEYPrivateKey *privKey;
1981     SFTKHashSignInfo *info = NULL;
1982
1983     CHECK_FORK();
1984
1985     /* Block Cipher MACing Algorithms use a different Context init method..*/
1986     crv = sftk_InitCBCMac(hSession, pMechanism, hKey, CKA_SIGN, SFTK_SIGN);
1987     if (crv != CKR_FUNCTION_NOT_SUPPORTED) return crv;
1988
1989     /* we're not using a block cipher mac */
1990     session = sftk_SessionFromHandle(hSession);
1991     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
1992     crv = sftk_InitGeneric(session,&context,SFTK_SIGN,&key,hKey,&key_type,
1993                                                 CKO_PRIVATE_KEY,CKA_SIGN);
1994     if (crv != CKR_OK) {
1995         sftk_FreeSession(session);
1996         return crv;
1997     }
1998
1999     context->multi = PR_FALSE;
2000
2001 #define INIT_RSA_SIGN_MECH(mmm) \
2002     case CKM_ ## mmm ## _RSA_PKCS: \
2003         context->multi = PR_TRUE; \
2004         crv = sftk_doSub ## mmm (context); \
2005         if (crv != CKR_OK) break; \
2006         context->update = (SFTKCipher) sftk_HashSign; \
2007         info = PORT_New(SFTKHashSignInfo); \
2008         if (info == NULL) { crv = CKR_HOST_MEMORY; break; } \
2009         info->hashOid = SEC_OID_ ## mmm ; \
2010         goto finish_rsa; 
2011
2012     switch(pMechanism->mechanism) {
2013     INIT_RSA_SIGN_MECH(MD5)
2014     INIT_RSA_SIGN_MECH(MD2)
2015     INIT_RSA_SIGN_MECH(SHA1)
2016     INIT_RSA_SIGN_MECH(SHA224)
2017     INIT_RSA_SIGN_MECH(SHA256)
2018     INIT_RSA_SIGN_MECH(SHA384)
2019     INIT_RSA_SIGN_MECH(SHA512)
2020
2021     case CKM_RSA_PKCS:
2022         context->update = (SFTKCipher) RSA_Sign;
2023         goto finish_rsa;
2024     case CKM_RSA_X_509:
2025         context->update = (SFTKCipher)  RSA_SignRaw;
2026 finish_rsa:
2027         if (key_type != CKK_RSA) {
2028             crv = CKR_KEY_TYPE_INCONSISTENT;
2029             break;
2030         }
2031         privKey = sftk_GetPrivKey(key,CKK_RSA,&crv);
2032         if (privKey == NULL) {
2033             crv = CKR_KEY_TYPE_INCONSISTENT;
2034             break;
2035         }
2036         /* OK, info is allocated only if we're doing hash and sign mechanism.
2037          * It's necessary to be able to set the correct OID in the final 
2038          * signature.
2039          */
2040         if (info) {
2041             info->key = privKey;
2042             context->cipherInfo = info;
2043             context->destroy = (SFTKDestroy)sftk_Space;
2044         } else {
2045             context->cipherInfo = privKey;
2046             context->destroy = (SFTKDestroy)sftk_Null;
2047         }
2048         context->maxLen = nsslowkey_PrivateModulusLen(privKey);
2049         break;
2050     case CKM_RSA_PKCS_PSS:
2051         if (key_type != CKK_RSA) {
2052             crv = CKR_KEY_TYPE_INCONSISTENT;
2053             break;
2054         } 
2055         if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) {
2056             crv = CKR_MECHANISM_PARAM_INVALID;
2057             break;
2058         }
2059         info = PORT_New(SFTKHashSignInfo);
2060         if (info == NULL) {
2061             crv = CKR_HOST_MEMORY;
2062             break;
2063         }
2064         info->params = pMechanism->pParameter;
2065         info->key = sftk_GetPrivKey(key,CKK_RSA,&crv);
2066         if (info->key == NULL) {
2067             PORT_Free(info);
2068             break;
2069         }
2070         context->cipherInfo = info;
2071         context->destroy = (SFTKDestroy) sftk_Space;
2072         context->update = (SFTKCipher) sftk_SignPSS;
2073         context->maxLen = nsslowkey_PrivateModulusLen(info->key);
2074         break;  
2075
2076     case CKM_DSA_SHA1:
2077         context->multi = PR_TRUE;
2078         crv = sftk_doSubSHA1(context);
2079         if (crv != CKR_OK) break;
2080         /* fall through */
2081     case CKM_DSA:
2082         if (key_type != CKK_DSA) {
2083             crv = CKR_KEY_TYPE_INCONSISTENT;
2084             break;
2085         }
2086         privKey = sftk_GetPrivKey(key,CKK_DSA,&crv);
2087         if (privKey == NULL) {
2088             break;
2089         }
2090         context->cipherInfo = privKey;
2091         context->update     = (SFTKCipher) nsc_DSA_Sign_Stub;
2092         context->destroy    = (privKey == key->objectInfo) ?
2093                 (SFTKDestroy) sftk_Null:(SFTKDestroy)sftk_FreePrivKey;
2094         context->maxLen     = DSA_SIGNATURE_LEN;
2095
2096         break;
2097
2098 #ifdef NSS_ENABLE_ECC
2099     case CKM_ECDSA_SHA1:
2100         context->multi = PR_TRUE;
2101         crv = sftk_doSubSHA1(context);
2102         if (crv != CKR_OK) break;
2103         /* fall through */
2104     case CKM_ECDSA:
2105         if (key_type != CKK_EC) {
2106             crv = CKR_KEY_TYPE_INCONSISTENT;
2107             break;
2108         }
2109         privKey = sftk_GetPrivKey(key,CKK_EC,&crv);
2110         if (privKey == NULL) {
2111             crv = CKR_HOST_MEMORY;
2112             break;
2113         }
2114         context->cipherInfo = privKey;
2115         context->update     = (SFTKCipher) nsc_ECDSASignStub;
2116         context->destroy    = (privKey == key->objectInfo) ?
2117                 (SFTKDestroy) sftk_Null:(SFTKDestroy)sftk_FreePrivKey;
2118         context->maxLen     = MAX_ECKEY_LEN * 2;
2119
2120         break;
2121 #endif /* NSS_ENABLE_ECC */
2122
2123 #define INIT_HMAC_MECH(mmm) \
2124     case CKM_ ## mmm ## _HMAC_GENERAL: \
2125         crv = sftk_doHMACInit(context, HASH_Alg ## mmm ,key, \
2126                                 *(CK_ULONG *)pMechanism->pParameter); \
2127         break; \
2128     case CKM_ ## mmm ## _HMAC: \
2129         crv = sftk_doHMACInit(context, HASH_Alg ## mmm ,key, mmm ## _LENGTH); \
2130         break; 
2131
2132     INIT_HMAC_MECH(MD2)
2133     INIT_HMAC_MECH(MD5)
2134     INIT_HMAC_MECH(SHA224)
2135     INIT_HMAC_MECH(SHA256)
2136     INIT_HMAC_MECH(SHA384)
2137     INIT_HMAC_MECH(SHA512)
2138
2139     case CKM_SHA_1_HMAC_GENERAL:
2140         crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,
2141                                 *(CK_ULONG *)pMechanism->pParameter);
2142         break;
2143     case CKM_SHA_1_HMAC:
2144         crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,SHA1_LENGTH);
2145         break;
2146
2147     case CKM_SSL3_MD5_MAC:
2148         crv = sftk_doSSLMACInit(context,SEC_OID_MD5,key,
2149                                         *(CK_ULONG *)pMechanism->pParameter);
2150         break;
2151     case CKM_SSL3_SHA1_MAC:
2152         crv = sftk_doSSLMACInit(context,SEC_OID_SHA1,key,
2153                                         *(CK_ULONG *)pMechanism->pParameter);
2154         break;
2155     case CKM_TLS_PRF_GENERAL:
2156         crv = sftk_TLSPRFInit(context, key, key_type);
2157         break;
2158     default:
2159         crv = CKR_MECHANISM_INVALID;
2160         break;
2161     }
2162
2163     if (crv != CKR_OK) {
2164         if (info) PORT_Free(info);
2165         sftk_FreeContext(context);
2166         sftk_FreeSession(session);
2167         return crv;
2168     }
2169     sftk_SetContextByType(session, SFTK_SIGN, context);
2170     sftk_FreeSession(session);
2171     return CKR_OK;
2172 }
2173
2174 /** MAC one block of data by block cipher
2175  */
2176 static CK_RV
2177 sftk_MACBlock( SFTKSessionContext *ctx, void *blk )
2178 {
2179     unsigned int outlen;
2180     return ( SECSuccess == (ctx->update)( ctx->cipherInfo, ctx->macBuf, &outlen,
2181                 SFTK_MAX_BLOCK_SIZE, blk, ctx->blockSize ))
2182             ? CKR_OK : sftk_MapCryptError(PORT_GetError());
2183 }
2184
2185 /** MAC last (incomplete) block of data by block cipher
2186  *
2187  *  Call once, then terminate MACing operation.
2188  */
2189 static CK_RV
2190 sftk_MACFinal( SFTKSessionContext *ctx )
2191 {
2192     unsigned int padLen = ctx->padDataLength;
2193     /* pad and proceed the residual */
2194     if( padLen ) {
2195         /* shd clr ctx->padLen to make sftk_MACFinal idempotent */
2196         PORT_Memset( ctx->padBuf + padLen, 0, ctx->blockSize - padLen );
2197         return sftk_MACBlock( ctx, ctx->padBuf );
2198     } else
2199         return CKR_OK;
2200 }
2201
2202 /** The common implementation for {Sign,Verify}Update. (S/V only vary in their
2203  * setup and final operations).
2204  * 
2205  * A call which results in an error terminates the operation [PKCS#11,v2.11]
2206  */
2207 static CK_RV
2208 sftk_MACUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
2209                                         CK_ULONG ulPartLen,SFTKContextType type)
2210 {
2211     SFTKSession *session;
2212     SFTKSessionContext *context;
2213     CK_RV crv;
2214
2215     /* make sure we're legal */
2216     crv = sftk_GetContext(hSession,&context,type, PR_TRUE, &session );
2217     if (crv != CKR_OK) return crv;
2218
2219     if (context->hashInfo) {
2220         (*context->hashUpdate)(context->hashInfo, pPart, ulPartLen);
2221     } else {   
2222         /* must be block cipher MACing */
2223
2224         unsigned int  blkSize   = context->blockSize;
2225         unsigned char *residual = /* free room in context->padBuf */
2226                                 context->padBuf + context->padDataLength;
2227         unsigned int  minInput  = /* min input for MACing at least one block */
2228                                 blkSize - context->padDataLength;
2229
2230         /* not enough data even for one block */
2231         if( ulPartLen < minInput ) {
2232             PORT_Memcpy( residual, pPart, ulPartLen );
2233             context->padDataLength += ulPartLen;
2234             goto cleanup;
2235         }
2236         /* MACing residual */
2237         if( context->padDataLength ) {
2238             PORT_Memcpy( residual, pPart, minInput );
2239             ulPartLen -= minInput;
2240             pPart     += minInput;
2241             if( CKR_OK != (crv = sftk_MACBlock( context, context->padBuf )) )
2242                 goto terminate;
2243         }
2244         /* MACing full blocks */
2245         while( ulPartLen >= blkSize )
2246         {
2247             if( CKR_OK != (crv = sftk_MACBlock( context, pPart )) )
2248                 goto terminate;
2249             ulPartLen -= blkSize;
2250             pPart     += blkSize;
2251         }
2252         /* save the residual */
2253         if( (context->padDataLength = ulPartLen) )
2254             PORT_Memcpy( context->padBuf, pPart, ulPartLen );
2255     } /* blk cipher MACing */
2256
2257     goto  cleanup;
2258
2259 terminate:
2260     sftk_TerminateOp( session, type, context );
2261 cleanup:
2262     sftk_FreeSession(session);
2263     return crv;
2264 }
2265
2266 /* NSC_SignUpdate continues a multiple-part signature operation,
2267  * where the signature is (will be) an appendix to the data, 
2268  * and plaintext cannot be recovered from the signature 
2269  *
2270  * A call which results in an error terminates the operation [PKCS#11,v2.11]
2271  */
2272 CK_RV NSC_SignUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
2273                                                         CK_ULONG ulPartLen)
2274 {
2275     CHECK_FORK();
2276     return sftk_MACUpdate(hSession, pPart, ulPartLen, SFTK_SIGN);
2277 }
2278
2279
2280 /* NSC_SignFinal finishes a multiple-part signature operation, 
2281  * returning the signature. */
2282 CK_RV NSC_SignFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pSignature,
2283                                             CK_ULONG_PTR pulSignatureLen)
2284 {
2285     SFTKSession *session;
2286     SFTKSessionContext *context;
2287     unsigned int outlen;
2288     unsigned int maxoutlen = *pulSignatureLen;
2289     CK_RV crv;
2290
2291     CHECK_FORK();
2292
2293     /* make sure we're legal */
2294     crv = sftk_GetContext(hSession,&context,SFTK_SIGN,PR_TRUE,&session);
2295     if (crv != CKR_OK) return crv;
2296
2297     if (context->hashInfo) {
2298         unsigned int digestLen;
2299         unsigned char tmpbuf[SFTK_MAX_MAC_LENGTH];
2300
2301         if( !pSignature ) {
2302             outlen = context->maxLen; goto finish;
2303         }
2304         (*context->end)(context->hashInfo, tmpbuf, &digestLen, sizeof(tmpbuf));
2305         if( SECSuccess != (context->update)(context->cipherInfo, pSignature,
2306                     &outlen, maxoutlen, tmpbuf, digestLen))
2307             crv = sftk_MapCryptError(PORT_GetError());
2308         /* CKR_BUFFER_TOO_SMALL here isn't continuable, let operation terminate.
2309          * Keeping "too small" CK_RV intact is a standard violation, but allows
2310          * application read EXACT signature length */
2311     } else {
2312         /* must be block cipher MACing */
2313         outlen = context->macSize;
2314         /* null or "too small" buf doesn't terminate operation [PKCS#11,v2.11]*/
2315         if( !pSignature  ||  maxoutlen < outlen ) {
2316             if( pSignature ) crv = CKR_BUFFER_TOO_SMALL;
2317             goto finish;
2318         }
2319         if( CKR_OK == (crv = sftk_MACFinal( context )) )
2320             PORT_Memcpy(pSignature, context->macBuf, outlen );
2321     }
2322
2323     sftk_TerminateOp( session, SFTK_SIGN, context );
2324 finish:
2325     *pulSignatureLen = outlen;
2326     sftk_FreeSession(session);
2327     return crv;
2328 }
2329
2330 /* NSC_Sign signs (encrypts with private key) data in a single part,
2331  * where the signature is (will be) an appendix to the data, 
2332  * and plaintext cannot be recovered from the signature */
2333 CK_RV NSC_Sign(CK_SESSION_HANDLE hSession,
2334     CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSignature,
2335                                         CK_ULONG_PTR pulSignatureLen)
2336 {
2337     SFTKSession *session;
2338     SFTKSessionContext *context;
2339     CK_RV crv;
2340
2341     CHECK_FORK();
2342
2343     /* make sure we're legal */
2344     crv = sftk_GetContext(hSession,&context,SFTK_SIGN,PR_FALSE,&session);
2345     if (crv != CKR_OK) return crv;
2346
2347     if (!pSignature) {
2348         /* see also how C_SignUpdate implements this */
2349         *pulSignatureLen = (!context->multi || context->hashInfo)
2350             ? context->maxLen
2351             : context->macSize; /* must be block cipher MACing */
2352         goto finish;
2353     }
2354
2355     /* multi part Signing are completely implemented by SignUpdate and
2356      * sign Final */
2357     if (context->multi) {
2358         /* SignFinal can't follow failed SignUpdate */
2359         if( CKR_OK == (crv = NSC_SignUpdate(hSession,pData,ulDataLen) ))
2360             crv = NSC_SignFinal(hSession, pSignature, pulSignatureLen);
2361     } else {   
2362         /* single-part PKC signature (e.g. CKM_ECDSA) */
2363         unsigned int outlen;
2364         unsigned int maxoutlen = *pulSignatureLen;
2365         if( SECSuccess != (*context->update)(context->cipherInfo, pSignature,
2366                     &outlen, maxoutlen, pData, ulDataLen))
2367             crv = sftk_MapCryptError(PORT_GetError());
2368         *pulSignatureLen = (CK_ULONG) outlen;
2369         /*  "too small" here is certainly continuable */
2370         if( crv != CKR_BUFFER_TOO_SMALL )
2371             sftk_TerminateOp(session, SFTK_SIGN, context);
2372     } /* single-part */
2373
2374 finish:
2375     sftk_FreeSession(session);
2376     return crv;
2377 }
2378
2379
2380 /*
2381  ************** Crypto Functions:     Sign Recover  ************************
2382  */
2383 /* NSC_SignRecoverInit initializes a signature operation,
2384  * where the (digest) data can be recovered from the signature. 
2385  * E.g. encryption with the user's private key */
2386 CK_RV NSC_SignRecoverInit(CK_SESSION_HANDLE hSession,
2387                          CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey)
2388 {
2389     CHECK_FORK();
2390
2391     switch (pMechanism->mechanism) {
2392     case CKM_RSA_PKCS:
2393     case CKM_RSA_X_509:
2394         return NSC_SignInit(hSession,pMechanism,hKey);
2395     default:
2396         break;
2397     }
2398     return CKR_MECHANISM_INVALID;
2399 }
2400
2401
2402 /* NSC_SignRecover signs data in a single operation
2403  * where the (digest) data can be recovered from the signature. 
2404  * E.g. encryption with the user's private key */
2405 CK_RV NSC_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
2406   CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
2407 {
2408     CHECK_FORK();
2409
2410     return NSC_Sign(hSession,pData,ulDataLen,pSignature,pulSignatureLen);
2411 }
2412
2413 /*
2414  ************** Crypto Functions:     verify  ************************
2415  */
2416
2417 /* Handle RSA Signature formatting */
2418 static SECStatus
2419 sftk_hashCheckSign(SFTKHashVerifyInfo *info, unsigned char *sig, 
2420         unsigned int sigLen, unsigned char *digest, unsigned int digestLen)
2421 {
2422     return RSA_HashCheckSign(info->hashOid, info->key, sig, sigLen,
2423                                                 digest, digestLen);
2424 }
2425
2426 SECStatus
2427 RSA_HashCheckSign(SECOidTag hashOid, NSSLOWKEYPublicKey *key,
2428         unsigned char *sig, unsigned int sigLen,
2429         unsigned char *digest, unsigned int digestLen)
2430 {
2431
2432     SECItem it;
2433     SGNDigestInfo *di = NULL;
2434     SECStatus rv = SECSuccess;
2435     
2436     it.data = NULL;
2437
2438     if (key == NULL) goto loser;
2439
2440     it.len = nsslowkey_PublicModulusLen(key); 
2441     if (!it.len) goto loser;
2442
2443     it.data = (unsigned char *) PORT_Alloc(it.len);
2444     if (it.data == NULL) goto loser;
2445
2446     /* decrypt the block */
2447     rv = RSA_CheckSignRecover(key, it.data, &it.len, it.len, sig, sigLen);
2448     if (rv != SECSuccess) goto loser;
2449
2450     di = SGN_DecodeDigestInfo(&it);
2451     if (di == NULL) goto loser;
2452     if (di->digest.len != digestLen)  goto loser; 
2453
2454     /* make sure the tag is OK */
2455     if (SECOID_GetAlgorithmTag(&di->digestAlgorithm) != hashOid) {
2456         goto loser;
2457     }
2458     /* make sure the "parameters" are not too bogus. */
2459     if (di->digestAlgorithm.parameters.len > 2) {
2460         goto loser;
2461     }
2462     /* Now check the signature */
2463     if (PORT_Memcmp(digest, di->digest.data, di->digest.len) == 0) {
2464         goto done;
2465     }
2466
2467   loser:
2468     PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
2469     rv = SECFailure;
2470
2471   done:
2472     if (it.data != NULL) PORT_Free(it.data);
2473     if (di != NULL) SGN_DestroyDigestInfo(di);
2474     
2475     return rv;
2476 }
2477
2478 static SECStatus
2479 sftk_CheckSignPSS(SFTKHashVerifyInfo *info, unsigned char *sig,
2480         unsigned int sigLen, unsigned char *digest, unsigned int digestLen)
2481 {
2482     return RSA_CheckSignPSS(info->params, info->key, sig, sigLen,
2483                                                 digest, digestLen);
2484 }
2485
2486 /* NSC_VerifyInit initializes a verification operation, 
2487  * where the signature is an appendix to the data, 
2488  * and plaintext cannot be recovered from the signature (e.g. DSA) */
2489 CK_RV NSC_VerifyInit(CK_SESSION_HANDLE hSession,
2490                            CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey) 
2491 {
2492     SFTKSession *session;
2493     SFTKObject *key;
2494     SFTKSessionContext *context;
2495     CK_KEY_TYPE key_type;
2496     CK_RV crv = CKR_OK;
2497     NSSLOWKEYPublicKey *pubKey;
2498     SFTKHashVerifyInfo *info = NULL;
2499
2500     CHECK_FORK();
2501
2502     /* Block Cipher MACing Algorithms use a different Context init method..*/
2503     crv = sftk_InitCBCMac(hSession, pMechanism, hKey, CKA_VERIFY, SFTK_VERIFY);
2504     if (crv != CKR_FUNCTION_NOT_SUPPORTED) return crv;
2505
2506     session = sftk_SessionFromHandle(hSession);
2507     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
2508     crv = sftk_InitGeneric(session,&context,SFTK_VERIFY,&key,hKey,&key_type,
2509                                                 CKO_PUBLIC_KEY,CKA_VERIFY);
2510     if (crv != CKR_OK) {
2511         sftk_FreeSession(session);
2512         return crv;
2513     }
2514
2515     context->multi = PR_FALSE;
2516
2517 #define INIT_RSA_VFY_MECH(mmm) \
2518     case CKM_ ## mmm ## _RSA_PKCS: \
2519         context->multi = PR_TRUE; \
2520         crv = sftk_doSub ## mmm (context); \
2521         if (crv != CKR_OK) break; \
2522         context->verify = (SFTKVerify) sftk_hashCheckSign; \
2523         info = PORT_New(SFTKHashVerifyInfo); \
2524         if (info == NULL) { crv = CKR_HOST_MEMORY; break; } \
2525         info->hashOid = SEC_OID_ ## mmm ; \
2526         goto finish_rsa; 
2527
2528     switch(pMechanism->mechanism) {
2529     INIT_RSA_VFY_MECH(MD5) 
2530     INIT_RSA_VFY_MECH(MD2) 
2531     INIT_RSA_VFY_MECH(SHA1) 
2532     INIT_RSA_VFY_MECH(SHA224)
2533     INIT_RSA_VFY_MECH(SHA256) 
2534     INIT_RSA_VFY_MECH(SHA384) 
2535     INIT_RSA_VFY_MECH(SHA512) 
2536
2537     case CKM_RSA_PKCS:
2538         context->verify = (SFTKVerify) RSA_CheckSign;
2539         goto finish_rsa;
2540     case CKM_RSA_X_509:
2541         context->verify = (SFTKVerify) RSA_CheckSignRaw;
2542 finish_rsa:
2543         if (key_type != CKK_RSA) {
2544             if (info) PORT_Free(info);
2545             crv = CKR_KEY_TYPE_INCONSISTENT;
2546             break;
2547         }
2548         pubKey = sftk_GetPubKey(key,CKK_RSA,&crv);
2549         if (pubKey == NULL) {
2550             if (info) PORT_Free(info);
2551             crv = CKR_KEY_TYPE_INCONSISTENT;
2552             break;
2553         }
2554         if (info) {
2555             info->key = pubKey;
2556             context->cipherInfo = info;
2557             context->destroy = sftk_Space;
2558         } else {
2559             context->cipherInfo = pubKey;
2560             context->destroy = sftk_Null;
2561         }
2562         break;
2563     case CKM_RSA_PKCS_PSS:
2564         if (key_type != CKK_RSA) {
2565             crv = CKR_KEY_TYPE_INCONSISTENT;
2566             break;
2567         } 
2568         if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) {
2569             crv = CKR_MECHANISM_PARAM_INVALID;
2570             break;
2571         }
2572         info = PORT_New(SFTKHashVerifyInfo);
2573         if (info == NULL) {
2574             crv = CKR_HOST_MEMORY;
2575             break;
2576         }
2577         info->params = pMechanism->pParameter;
2578         info->key = sftk_GetPubKey(key,CKK_RSA,&crv);
2579         if (info->key == NULL) {
2580             PORT_Free(info);
2581             break;
2582         }
2583         context->cipherInfo = info;
2584         context->destroy = (SFTKDestroy) sftk_Space;
2585         context->verify = (SFTKVerify) sftk_CheckSignPSS;
2586         break;
2587     case CKM_DSA_SHA1:
2588         context->multi = PR_TRUE;
2589         crv = sftk_doSubSHA1(context);
2590         if (crv != CKR_OK) break;
2591         /* fall through */
2592     case CKM_DSA:
2593         if (key_type != CKK_DSA) {
2594             crv = CKR_KEY_TYPE_INCONSISTENT;
2595             break;
2596         }
2597         pubKey = sftk_GetPubKey(key,CKK_DSA,&crv);
2598         if (pubKey == NULL) {
2599             break;
2600         }
2601         context->cipherInfo = pubKey;
2602         context->verify     = (SFTKVerify) nsc_DSA_Verify_Stub;
2603         context->destroy    = sftk_Null;
2604         break;
2605 #ifdef NSS_ENABLE_ECC
2606     case CKM_ECDSA_SHA1:
2607         context->multi = PR_TRUE;
2608         crv = sftk_doSubSHA1(context);
2609         if (crv != CKR_OK) break;
2610         /* fall through */
2611     case CKM_ECDSA:
2612         if (key_type != CKK_EC) {
2613             crv = CKR_KEY_TYPE_INCONSISTENT;
2614             break;
2615         }
2616         pubKey = sftk_GetPubKey(key,CKK_EC,&crv);
2617         if (pubKey == NULL) {
2618             crv = CKR_HOST_MEMORY;
2619             break;
2620         }
2621         context->cipherInfo = pubKey;
2622         context->verify     = (SFTKVerify) nsc_ECDSAVerifyStub;
2623         context->destroy    = sftk_Null;
2624         break;
2625 #endif /* NSS_ENABLE_ECC */
2626
2627     INIT_HMAC_MECH(MD2)
2628     INIT_HMAC_MECH(MD5)
2629     INIT_HMAC_MECH(SHA224)
2630     INIT_HMAC_MECH(SHA256)
2631     INIT_HMAC_MECH(SHA384)
2632     INIT_HMAC_MECH(SHA512)
2633
2634     case CKM_SHA_1_HMAC_GENERAL:
2635         crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,
2636                                 *(CK_ULONG *)pMechanism->pParameter);
2637         break;
2638     case CKM_SHA_1_HMAC:
2639         crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,SHA1_LENGTH);
2640         break;
2641
2642     case CKM_SSL3_MD5_MAC:
2643         crv = sftk_doSSLMACInit(context,SEC_OID_MD5,key,
2644                                         *(CK_ULONG *)pMechanism->pParameter);
2645         break;
2646     case CKM_SSL3_SHA1_MAC:
2647         crv = sftk_doSSLMACInit(context,SEC_OID_SHA1,key,
2648                                         *(CK_ULONG *)pMechanism->pParameter);
2649         break;
2650     case CKM_TLS_PRF_GENERAL:
2651         crv = sftk_TLSPRFInit(context, key, key_type);
2652         break;
2653
2654     default:
2655         crv = CKR_MECHANISM_INVALID;
2656         break;
2657     }
2658
2659     if (crv != CKR_OK) {
2660         if (info) PORT_Free(info);
2661         sftk_FreeContext(context);
2662         sftk_FreeSession(session);
2663         return crv;
2664     }
2665     sftk_SetContextByType(session, SFTK_VERIFY, context);
2666     sftk_FreeSession(session);
2667     return CKR_OK;
2668 }
2669
2670 /* NSC_Verify verifies a signature in a single-part operation, 
2671  * where the signature is an appendix to the data, 
2672  * and plaintext cannot be recovered from the signature */
2673 CK_RV NSC_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
2674     CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
2675 {
2676     SFTKSession *session;
2677     SFTKSessionContext *context;
2678     CK_RV crv;
2679
2680     CHECK_FORK();
2681
2682     /* make sure we're legal */
2683     crv = sftk_GetContext(hSession,&context,SFTK_VERIFY,PR_FALSE,&session);
2684     if (crv != CKR_OK) return crv;
2685
2686     /* multi part Verifying are completely implemented by VerifyUpdate and
2687      * VerifyFinal */
2688     if (context->multi) {
2689         /* VerifyFinal can't follow failed VerifyUpdate */
2690         if( CKR_OK == (crv = NSC_VerifyUpdate(hSession, pData, ulDataLen)))
2691             crv = NSC_VerifyFinal(hSession, pSignature, ulSignatureLen);
2692     } else {
2693         if (SECSuccess != (*context->verify)(context->cipherInfo,pSignature,
2694                                              ulSignatureLen, pData, ulDataLen))
2695             crv = sftk_MapCryptError(PORT_GetError());
2696
2697         sftk_TerminateOp( session, SFTK_VERIFY, context );
2698     }
2699     sftk_FreeSession(session);
2700     return crv;
2701 }
2702
2703
2704 /* NSC_VerifyUpdate continues a multiple-part verification operation, 
2705  * where the signature is an appendix to the data, 
2706  * and plaintext cannot be recovered from the signature
2707  *
2708  * A call which results in an error terminates the operation [PKCS#11,v2.11]
2709  */
2710 CK_RV NSC_VerifyUpdate( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
2711                                                 CK_ULONG ulPartLen)
2712 {
2713     CHECK_FORK();
2714     return sftk_MACUpdate(hSession, pPart, ulPartLen, SFTK_VERIFY);
2715 }
2716
2717
2718 /* NSC_VerifyFinal finishes a multiple-part verification operation, 
2719  * checking the signature. */
2720 CK_RV NSC_VerifyFinal(CK_SESSION_HANDLE hSession,
2721                         CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen)
2722 {
2723     SFTKSession *session;
2724     SFTKSessionContext *context;
2725     CK_RV crv;
2726
2727     CHECK_FORK();
2728
2729     if (!pSignature) 
2730         return CKR_ARGUMENTS_BAD;
2731
2732     /* make sure we're legal */
2733     crv = sftk_GetContext(hSession,&context,SFTK_VERIFY,PR_TRUE,&session);
2734     if (crv != CKR_OK) 
2735         return crv;
2736     
2737     if (context->hashInfo) {
2738         unsigned int digestLen;
2739         unsigned char tmpbuf[SFTK_MAX_MAC_LENGTH];
2740         
2741         (*context->end)(context->hashInfo, tmpbuf, &digestLen, sizeof(tmpbuf));
2742         if( SECSuccess != (context->verify)(context->cipherInfo, pSignature,
2743                                             ulSignatureLen, tmpbuf, digestLen))
2744             crv = sftk_MapCryptError(PORT_GetError());
2745     } else if (ulSignatureLen != context->macSize) {
2746         /* must be block cipher MACing */
2747         crv = CKR_SIGNATURE_LEN_RANGE;
2748     } else if (CKR_OK == (crv = sftk_MACFinal(context))) {
2749         if (PORT_Memcmp(pSignature, context->macBuf, ulSignatureLen))
2750             crv = CKR_SIGNATURE_INVALID;
2751     }
2752
2753     sftk_TerminateOp( session, SFTK_VERIFY, context );
2754     sftk_FreeSession(session);
2755     return crv;
2756
2757 }
2758
2759 /*
2760  ************** Crypto Functions:     Verify  Recover ************************
2761  */
2762
2763 /* NSC_VerifyRecoverInit initializes a signature verification operation, 
2764  * where the data is recovered from the signature. 
2765  * E.g. Decryption with the user's public key */
2766 CK_RV NSC_VerifyRecoverInit(CK_SESSION_HANDLE hSession,
2767                         CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey)
2768 {
2769     SFTKSession *session;
2770     SFTKObject *key;
2771     SFTKSessionContext *context;
2772     CK_KEY_TYPE key_type;
2773     CK_RV crv = CKR_OK;
2774     NSSLOWKEYPublicKey *pubKey;
2775
2776     CHECK_FORK();
2777
2778     session = sftk_SessionFromHandle(hSession);
2779     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
2780     crv = sftk_InitGeneric(session,&context,SFTK_VERIFY_RECOVER,
2781                         &key,hKey,&key_type,CKO_PUBLIC_KEY,CKA_VERIFY_RECOVER);
2782     if (crv != CKR_OK) {
2783         sftk_FreeSession(session);
2784         return crv;
2785     }
2786
2787     context->multi = PR_TRUE;
2788
2789     switch(pMechanism->mechanism) {
2790     case CKM_RSA_PKCS:
2791     case CKM_RSA_X_509:
2792         if (key_type != CKK_RSA) {
2793             crv = CKR_KEY_TYPE_INCONSISTENT;
2794             break;
2795         }
2796         context->multi = PR_FALSE;
2797         pubKey = sftk_GetPubKey(key,CKK_RSA,&crv);
2798         if (pubKey == NULL) {
2799             break;
2800         }
2801         context->cipherInfo = pubKey;
2802         context->update = (SFTKCipher) (pMechanism->mechanism == CKM_RSA_X_509
2803                         ? RSA_CheckSignRecoverRaw : RSA_CheckSignRecover);
2804         context->destroy = sftk_Null;
2805         break;
2806     default:
2807         crv = CKR_MECHANISM_INVALID;
2808         break;
2809     }
2810
2811     if (crv != CKR_OK) {
2812         PORT_Free(context);
2813         sftk_FreeSession(session);
2814         return crv;
2815     }
2816     sftk_SetContextByType(session, SFTK_VERIFY_RECOVER, context);
2817     sftk_FreeSession(session);
2818     return CKR_OK;
2819 }
2820
2821
2822 /* NSC_VerifyRecover verifies a signature in a single-part operation, 
2823  * where the data is recovered from the signature. 
2824  * E.g. Decryption with the user's public key */
2825 CK_RV NSC_VerifyRecover(CK_SESSION_HANDLE hSession,
2826                  CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen,
2827                                 CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen)
2828 {
2829     SFTKSession *session;
2830     SFTKSessionContext *context;
2831     unsigned int outlen;
2832     unsigned int maxoutlen = *pulDataLen;
2833     CK_RV crv;
2834     SECStatus rv;
2835
2836     CHECK_FORK();
2837
2838     /* make sure we're legal */
2839     crv = sftk_GetContext(hSession,&context,SFTK_VERIFY_RECOVER,
2840                                                         PR_FALSE,&session);
2841     if (crv != CKR_OK) return crv;
2842     if (pData == NULL) {
2843         /* to return the actual size, we need  to do the decrypt, just return
2844          * the max size, which is the size of the input signature. */
2845         *pulDataLen = ulSignatureLen;
2846         rv = SECSuccess;
2847         goto finish;
2848     }
2849
2850     rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen, 
2851                                                 pSignature, ulSignatureLen);
2852     *pulDataLen = (CK_ULONG) outlen;
2853
2854     sftk_TerminateOp(session, SFTK_VERIFY_RECOVER, context);
2855 finish:
2856     sftk_FreeSession(session);
2857     return (rv == SECSuccess)  ? CKR_OK : sftk_MapVerifyError(PORT_GetError());
2858 }
2859
2860 /*
2861  **************************** Random Functions:  ************************
2862  */
2863
2864 /* NSC_SeedRandom mixes additional seed material into the token's random number 
2865  * generator. */
2866 CK_RV NSC_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed,
2867     CK_ULONG ulSeedLen) 
2868 {
2869     SECStatus rv;
2870
2871     CHECK_FORK();
2872
2873     rv = RNG_RandomUpdate(pSeed, ulSeedLen);
2874     return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
2875 }
2876
2877 /* NSC_GenerateRandom generates random data. */
2878 CK_RV NSC_GenerateRandom(CK_SESSION_HANDLE hSession,
2879     CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen)
2880 {
2881     SECStatus rv;
2882
2883     CHECK_FORK();
2884
2885     rv = RNG_GenerateGlobalRandomBytes(pRandomData, ulRandomLen);
2886     /*
2887      * This may fail with SEC_ERROR_NEED_RANDOM, which means the RNG isn't
2888      * seeded with enough entropy.
2889      */
2890     return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
2891 }
2892
2893 /*
2894  **************************** Key Functions:  ************************
2895  */
2896
2897
2898 /*
2899  * generate a password based encryption key. This code uses
2900  * PKCS5 to do the work.
2901  */
2902 static CK_RV
2903 nsc_pbe_key_gen(NSSPKCS5PBEParameter *pkcs5_pbe, CK_MECHANISM_PTR pMechanism,
2904                         void *buf, CK_ULONG *key_length, PRBool faulty3DES)
2905 {
2906     SECItem *pbe_key = NULL, iv, pwitem;
2907     CK_PBE_PARAMS *pbe_params = NULL;
2908     CK_PKCS5_PBKD2_PARAMS *pbkd2_params = NULL;
2909
2910     *key_length = 0;
2911     iv.data = NULL; iv.len = 0;
2912
2913     if (pMechanism->mechanism == CKM_PKCS5_PBKD2) {
2914         pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter;
2915         pwitem.data = (unsigned char *)pbkd2_params->pPassword;
2916         /* was this a typo in the PKCS #11 spec? */
2917         pwitem.len = *pbkd2_params->ulPasswordLen;
2918     } else {
2919         pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
2920         pwitem.data = (unsigned char *)pbe_params->pPassword;
2921         pwitem.len = pbe_params->ulPasswordLen;
2922     }
2923     pbe_key = nsspkcs5_ComputeKeyAndIV(pkcs5_pbe, &pwitem, &iv, faulty3DES);
2924     if (pbe_key == NULL) {
2925         return CKR_HOST_MEMORY;
2926     }
2927
2928     PORT_Memcpy(buf, pbe_key->data, pbe_key->len);
2929     *key_length = pbe_key->len;
2930     SECITEM_ZfreeItem(pbe_key, PR_TRUE);
2931     pbe_key = NULL;
2932
2933     if (iv.data) {
2934         if (pbe_params && pbe_params->pInitVector != NULL) {
2935             PORT_Memcpy(pbe_params->pInitVector, iv.data, iv.len);
2936         }
2937         PORT_Free(iv.data);
2938     }
2939
2940     return CKR_OK;
2941 }
2942 static CK_RV
2943 nsc_parameter_gen(CK_KEY_TYPE key_type, SFTKObject *key)
2944 {
2945     SFTKAttribute *attribute;
2946     CK_ULONG counter;
2947     unsigned int seedBits = 0;
2948     unsigned int primeBits;
2949     unsigned int j;
2950     CK_RV crv = CKR_OK;
2951     PQGParams *params = NULL;
2952     PQGVerify *vfy = NULL;
2953     SECStatus rv;
2954
2955     attribute = sftk_FindAttribute(key, CKA_PRIME_BITS);
2956     if (attribute == NULL) {
2957         return CKR_TEMPLATE_INCOMPLETE;
2958     }
2959     primeBits = (unsigned int) *(CK_ULONG *)attribute->attrib.pValue;
2960     sftk_FreeAttribute(attribute);
2961     j = PQG_PBITS_TO_INDEX(primeBits);
2962     if (j == (unsigned int)-1) {
2963         return CKR_ATTRIBUTE_VALUE_INVALID;
2964     }
2965
2966     attribute = sftk_FindAttribute(key, CKA_NETSCAPE_PQG_SEED_BITS);
2967     if (attribute != NULL) {
2968         seedBits = (unsigned int) *(CK_ULONG *)attribute->attrib.pValue;
2969         sftk_FreeAttribute(attribute);
2970     }
2971
2972     sftk_DeleteAttributeType(key,CKA_PRIME_BITS);
2973     sftk_DeleteAttributeType(key,CKA_NETSCAPE_PQG_SEED_BITS);
2974
2975     if (seedBits == 0) {
2976         rv = PQG_ParamGen(j, &params, &vfy);
2977     } else {
2978         rv = PQG_ParamGenSeedLen(j,seedBits/8, &params, &vfy);
2979     }
2980
2981     if (rv != SECSuccess) {
2982         if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
2983             sftk_fatalError = PR_TRUE;
2984         }
2985         return sftk_MapCryptError(PORT_GetError());
2986     }
2987     crv = sftk_AddAttributeType(key,CKA_PRIME,
2988                                  params->prime.data, params->prime.len);
2989     if (crv != CKR_OK) goto loser;
2990     crv = sftk_AddAttributeType(key,CKA_SUBPRIME,
2991                                  params->subPrime.data, params->subPrime.len);
2992     if (crv != CKR_OK) goto loser;
2993     crv = sftk_AddAttributeType(key,CKA_BASE,
2994                                  params->base.data, params->base.len);
2995     if (crv != CKR_OK) goto loser;
2996     counter = vfy->counter;
2997     crv = sftk_AddAttributeType(key,CKA_NETSCAPE_PQG_COUNTER,
2998                                  &counter, sizeof(counter));
2999     crv = sftk_AddAttributeType(key,CKA_NETSCAPE_PQG_SEED,
3000                                  vfy->seed.data, vfy->seed.len);
3001     if (crv != CKR_OK) goto loser;
3002     crv = sftk_AddAttributeType(key,CKA_NETSCAPE_PQG_H,
3003                                  vfy->h.data, vfy->h.len);
3004     if (crv != CKR_OK) goto loser;
3005
3006 loser:
3007     PQG_DestroyParams(params);
3008
3009     if (vfy) {
3010         PQG_DestroyVerify(vfy);
3011     }
3012     return crv;
3013 }
3014
3015
3016 static CK_RV
3017 nsc_SetupBulkKeyGen(CK_MECHANISM_TYPE mechanism, CK_KEY_TYPE *key_type,
3018                                                         CK_ULONG *key_length)
3019 {
3020     CK_RV crv = CKR_OK;
3021
3022     switch (mechanism) {
3023     case CKM_RC2_KEY_GEN:
3024         *key_type = CKK_RC2;
3025         if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
3026         break;
3027 #if NSS_SOFTOKEN_DOES_RC5
3028     case CKM_RC5_KEY_GEN:
3029         *key_type = CKK_RC5;
3030         if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
3031         break;
3032 #endif
3033     case CKM_RC4_KEY_GEN:
3034         *key_type = CKK_RC4;
3035         if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
3036         break;
3037     case CKM_GENERIC_SECRET_KEY_GEN:
3038         *key_type = CKK_GENERIC_SECRET;
3039         if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
3040         break;
3041     case CKM_CDMF_KEY_GEN:
3042         *key_type = CKK_CDMF;
3043         *key_length = 8;
3044         break;
3045     case CKM_DES_KEY_GEN:
3046         *key_type = CKK_DES;
3047         *key_length = 8;
3048         break;
3049     case CKM_DES2_KEY_GEN:
3050         *key_type = CKK_DES2;
3051         *key_length = 16;
3052         break;
3053     case CKM_DES3_KEY_GEN:
3054         *key_type = CKK_DES3;
3055         *key_length = 24;
3056         break;
3057     case CKM_SEED_KEY_GEN:
3058         *key_type = CKK_SEED;
3059         *key_length = 16;
3060         break;
3061     case CKM_CAMELLIA_KEY_GEN:
3062         *key_type = CKK_CAMELLIA;
3063         if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
3064         break;
3065     case CKM_AES_KEY_GEN:
3066         *key_type = CKK_AES;
3067         if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
3068         break;
3069     default:
3070         PORT_Assert(0);
3071         crv = CKR_MECHANISM_INVALID;
3072         break;
3073     }
3074
3075     return crv;
3076 }
3077
3078 CK_RV
3079 nsc_SetupHMACKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe)
3080 {
3081     SECItem  salt;
3082     CK_PBE_PARAMS *pbe_params = NULL;
3083     NSSPKCS5PBEParameter *params;
3084     PRArenaPool *arena = NULL;
3085     SECStatus rv;
3086
3087     *pbe = NULL;
3088
3089     arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
3090     if (arena == NULL) {
3091         return CKR_HOST_MEMORY;
3092     }
3093
3094     params = (NSSPKCS5PBEParameter *) PORT_ArenaZAlloc(arena,
3095                                 sizeof(NSSPKCS5PBEParameter));
3096     if (params == NULL) {
3097         PORT_FreeArena(arena,PR_TRUE);
3098         return CKR_HOST_MEMORY;
3099     }
3100
3101     params->poolp = arena;
3102     params->ivLen = 0;
3103     params->pbeType = NSSPKCS5_PKCS12_V2;
3104     params->hashType = HASH_AlgSHA1;
3105     params->encAlg = SEC_OID_SHA1; /* any invalid value */
3106     params->is2KeyDES = PR_FALSE;
3107     params->keyID = pbeBitGenIntegrityKey;
3108     pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
3109     params->iter = pbe_params->ulIteration;
3110
3111     salt.data = (unsigned char *)pbe_params->pSalt;
3112     salt.len = (unsigned int)pbe_params->ulSaltLen;
3113     rv = SECITEM_CopyItem(arena,&params->salt,&salt);
3114     if (rv != SECSuccess) {
3115         PORT_FreeArena(arena,PR_TRUE);
3116         return CKR_HOST_MEMORY;
3117     }
3118     switch (pMechanism->mechanism) {
3119     case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN:
3120     case CKM_PBA_SHA1_WITH_SHA1_HMAC:
3121         params->hashType = HASH_AlgSHA1; 
3122         params->keyLen = 20;
3123         break;
3124     case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN:
3125         params->hashType = HASH_AlgMD5; 
3126         params->keyLen = 16;
3127         break;
3128     case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN:
3129         params->hashType = HASH_AlgMD2; 
3130         params->keyLen = 16;
3131         break;
3132     default:
3133         PORT_FreeArena(arena,PR_TRUE);
3134         return CKR_MECHANISM_INVALID;
3135     }
3136     *pbe = params;
3137     return CKR_OK;
3138 }
3139
3140 /* maybe this should be table driven? */
3141 static CK_RV
3142 nsc_SetupPBEKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter  **pbe,
3143                                 CK_KEY_TYPE *key_type, CK_ULONG *key_length)
3144 {
3145     CK_RV crv = CKR_OK;
3146     SECOidData *oid;
3147     CK_PBE_PARAMS *pbe_params = NULL;
3148     NSSPKCS5PBEParameter *params = NULL;
3149     CK_PKCS5_PBKD2_PARAMS *pbkd2_params = NULL;
3150     SECItem salt;
3151     CK_ULONG iteration = 0;
3152
3153     *pbe = NULL;
3154
3155     oid = SECOID_FindOIDByMechanism(pMechanism->mechanism);
3156     if (oid == NULL) {
3157         return CKR_MECHANISM_INVALID;
3158     }
3159
3160     if (pMechanism->mechanism == CKM_PKCS5_PBKD2) {
3161         pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter;
3162         if (pbkd2_params->saltSource != CKZ_SALT_SPECIFIED) {
3163             return CKR_MECHANISM_PARAM_INVALID;
3164         }
3165         salt.data = (unsigned char *)pbkd2_params->pSaltSourceData;
3166         salt.len = (unsigned int)pbkd2_params->ulSaltSourceDataLen;
3167         iteration = pbkd2_params->iterations;
3168     } else {
3169         pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
3170         salt.data = (unsigned char *)pbe_params->pSalt;
3171         salt.len = (unsigned int)pbe_params->ulSaltLen;
3172         iteration = pbe_params->ulIteration;
3173     }
3174     params=nsspkcs5_NewParam(oid->offset, &salt, iteration);
3175     if (params == NULL) {
3176         return CKR_MECHANISM_INVALID;
3177     }
3178
3179     switch (params->encAlg) {
3180     case SEC_OID_DES_CBC:
3181         *key_type = CKK_DES;
3182         *key_length = params->keyLen;
3183         break;
3184     case SEC_OID_DES_EDE3_CBC:
3185         *key_type = params->is2KeyDES ? CKK_DES2 : CKK_DES3;
3186         *key_length = params->keyLen;
3187         break;
3188     case SEC_OID_RC2_CBC:
3189         *key_type = CKK_RC2;
3190         *key_length = params->keyLen;
3191         break;
3192     case SEC_OID_RC4:
3193         *key_type = CKK_RC4;
3194         *key_length = params->keyLen;
3195         break;
3196     case SEC_OID_PKCS5_PBKDF2:
3197         /* sigh, PKCS #11 currently only defines SHA1 for the KDF hash type. 
3198          * we do the check here because this where we would handle multiple
3199          * hash types in the future */
3200         if (pbkd2_params == NULL || 
3201                 pbkd2_params->prf != CKP_PKCS5_PBKD2_HMAC_SHA1) {
3202             crv = CKR_MECHANISM_PARAM_INVALID;
3203             break;
3204         }
3205         /* key type must already be set */
3206         if (*key_type == CKK_INVALID_KEY_TYPE) {
3207             crv = CKR_TEMPLATE_INCOMPLETE;
3208             break;
3209         }
3210         /* PBKDF2 needs to calculate the key length from the other parameters
3211          */
3212         if (*key_length == 0) {
3213             *key_length = sftk_MapKeySize(*key_type);
3214         }
3215         if (*key_length == 0) {
3216             crv = CKR_TEMPLATE_INCOMPLETE;
3217             break;
3218         }
3219         params->keyLen = *key_length;
3220         break;
3221     default:
3222         crv = CKR_MECHANISM_INVALID;
3223         nsspkcs5_DestroyPBEParameter(params);
3224         break;
3225     }
3226     if (crv == CKR_OK) {
3227         *pbe = params;
3228     }
3229     return crv;
3230 }
3231
3232 /* NSC_GenerateKey generates a secret key, creating a new key object. */
3233 CK_RV NSC_GenerateKey(CK_SESSION_HANDLE hSession,
3234     CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,
3235                                                 CK_OBJECT_HANDLE_PTR phKey)
3236 {
3237     SFTKObject *key;
3238     SFTKSession *session;
3239     PRBool checkWeak = PR_FALSE;
3240     CK_ULONG key_length = 0;
3241     CK_KEY_TYPE key_type = CKK_INVALID_KEY_TYPE;
3242     CK_OBJECT_CLASS objclass = CKO_SECRET_KEY;
3243     CK_RV crv = CKR_OK;
3244     CK_BBOOL cktrue = CK_TRUE;
3245     int i;
3246     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
3247     unsigned char buf[MAX_KEY_LEN];
3248     enum {nsc_pbe, nsc_ssl, nsc_bulk, nsc_param, nsc_jpake} key_gen_type;
3249     NSSPKCS5PBEParameter *pbe_param;
3250     SSL3RSAPreMasterSecret *rsa_pms;
3251     CK_VERSION *version;
3252     /* in very old versions of NSS, there were implementation errors with key 
3253      * generation methods.  We want to beable to read these, but not 
3254      * produce them any more.  The affected algorithm was 3DES.
3255      */
3256     PRBool faultyPBE3DES = PR_FALSE;
3257     HASH_HashType hashType;
3258
3259     CHECK_FORK();
3260
3261     if (!slot) {
3262         return CKR_SESSION_HANDLE_INVALID;
3263     }
3264     /*
3265      * now lets create an object to hang the attributes off of
3266      */
3267     key = sftk_NewObject(slot); /* fill in the handle later */
3268     if (key == NULL) {
3269         return CKR_HOST_MEMORY;
3270     }
3271
3272     /*
3273      * load the template values into the object
3274      */
3275     for (i=0; i < (int) ulCount; i++) {
3276         if (pTemplate[i].type == CKA_VALUE_LEN) {
3277             key_length = *(CK_ULONG *)pTemplate[i].pValue;
3278             continue;
3279         }
3280         /* some algorithms need keytype specified */
3281         if (pTemplate[i].type == CKA_KEY_TYPE) {
3282             key_type = *(CK_ULONG *)pTemplate[i].pValue;
3283             continue;
3284         }
3285
3286         crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i]));
3287         if (crv != CKR_OK) break;
3288     }
3289     if (crv != CKR_OK) {
3290         sftk_FreeObject(key);
3291         return crv;
3292     }
3293
3294     /* make sure we don't have any class, key_type, or value fields */
3295     sftk_DeleteAttributeType(key,CKA_CLASS);
3296     sftk_DeleteAttributeType(key,CKA_KEY_TYPE);
3297     sftk_DeleteAttributeType(key,CKA_VALUE);
3298
3299     /* Now Set up the parameters to generate the key (based on mechanism) */
3300     key_gen_type = nsc_bulk; /* bulk key by default */
3301     switch (pMechanism->mechanism) {
3302     case CKM_CDMF_KEY_GEN:
3303     case CKM_DES_KEY_GEN:
3304     case CKM_DES2_KEY_GEN:
3305     case CKM_DES3_KEY_GEN:
3306         checkWeak = PR_TRUE;
3307     case CKM_RC2_KEY_GEN:
3308     case CKM_RC4_KEY_GEN:
3309     case CKM_GENERIC_SECRET_KEY_GEN:
3310     case CKM_SEED_KEY_GEN:
3311     case CKM_CAMELLIA_KEY_GEN:
3312     case CKM_AES_KEY_GEN:
3313 #if NSS_SOFTOKEN_DOES_RC5
3314     case CKM_RC5_KEY_GEN:
3315 #endif
3316         crv = nsc_SetupBulkKeyGen(pMechanism->mechanism,&key_type,&key_length);
3317         break;
3318     case CKM_SSL3_PRE_MASTER_KEY_GEN:
3319         key_type = CKK_GENERIC_SECRET;
3320         key_length = 48;
3321         key_gen_type = nsc_ssl;
3322         break;
3323     case CKM_PBA_SHA1_WITH_SHA1_HMAC:
3324     case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN:
3325     case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN:
3326     case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN:
3327         key_gen_type = nsc_pbe;
3328         key_type = CKK_GENERIC_SECRET;
3329         crv = nsc_SetupHMACKeyGen(pMechanism, &pbe_param);
3330         break;
3331     case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC:
3332         faultyPBE3DES = PR_TRUE;
3333     case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC:
3334     case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC:
3335     case CKM_NETSCAPE_PBE_SHA1_DES_CBC:
3336     case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC:
3337     case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4:
3338     case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4:
3339     case CKM_PBE_SHA1_DES3_EDE_CBC:
3340     case CKM_PBE_SHA1_DES2_EDE_CBC:
3341     case CKM_PBE_SHA1_RC2_128_CBC:
3342     case CKM_PBE_SHA1_RC2_40_CBC:
3343     case CKM_PBE_SHA1_RC4_128:
3344     case CKM_PBE_SHA1_RC4_40:
3345     case CKM_PBE_MD5_DES_CBC:
3346     case CKM_PBE_MD2_DES_CBC:
3347     case CKM_PKCS5_PBKD2:
3348         key_gen_type = nsc_pbe;
3349         crv = nsc_SetupPBEKeyGen(pMechanism,&pbe_param, &key_type, &key_length);
3350         break;
3351     case CKM_DSA_PARAMETER_GEN:
3352         key_gen_type = nsc_param;
3353         key_type = CKK_DSA;
3354         objclass = CKO_KG_PARAMETERS;
3355         crv = CKR_OK;
3356         break;
3357     case CKM_NSS_JPAKE_ROUND1_SHA1:   hashType = HASH_AlgSHA1;   goto jpake1;
3358     case CKM_NSS_JPAKE_ROUND1_SHA256: hashType = HASH_AlgSHA256; goto jpake1;
3359     case CKM_NSS_JPAKE_ROUND1_SHA384: hashType = HASH_AlgSHA384; goto jpake1;
3360     case CKM_NSS_JPAKE_ROUND1_SHA512: hashType = HASH_AlgSHA512; goto jpake1;
3361 jpake1:
3362         key_gen_type = nsc_jpake;
3363         key_type = CKK_NSS_JPAKE_ROUND1;
3364         objclass = CKO_PRIVATE_KEY;
3365         if (pMechanism->pParameter == NULL ||
3366             pMechanism->ulParameterLen != sizeof(CK_NSS_JPAKERound1Params)) {
3367             crv = CKR_MECHANISM_PARAM_INVALID;
3368             break;
3369         }
3370         if (sftk_isTrue(key, CKA_TOKEN)) {
3371             crv = CKR_TEMPLATE_INCONSISTENT;
3372         }
3373         crv = CKR_OK;
3374         break;
3375     default:
3376         crv = CKR_MECHANISM_INVALID;
3377         break;
3378     }
3379
3380     /* make sure we aren't going to overflow the buffer */
3381     if (sizeof(buf) < key_length) {
3382         /* someone is getting pretty optimistic about how big their key can
3383          * be... */
3384         crv = CKR_TEMPLATE_INCONSISTENT;
3385     }
3386
3387     if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
3388
3389     /* if there was no error,
3390      * key_type *MUST* be set in the switch statement above */
3391     PORT_Assert( key_type != CKK_INVALID_KEY_TYPE );
3392
3393     /*
3394      * now to the actual key gen.
3395      */
3396     switch (key_gen_type) {
3397     case nsc_pbe:
3398         crv = nsc_pbe_key_gen(pbe_param, pMechanism, buf, &key_length,
3399                                faultyPBE3DES);
3400         nsspkcs5_DestroyPBEParameter(pbe_param);
3401         break;
3402     case nsc_ssl:
3403         rsa_pms = (SSL3RSAPreMasterSecret *)buf;
3404         version = (CK_VERSION *)pMechanism->pParameter;
3405         rsa_pms->client_version[0] = version->major;
3406         rsa_pms->client_version[1] = version->minor;
3407         crv = 
3408             NSC_GenerateRandom(0,&rsa_pms->random[0], sizeof(rsa_pms->random));
3409         break;
3410     case nsc_bulk:
3411         /* get the key, check for weak keys and repeat if found */
3412         do {
3413             crv = NSC_GenerateRandom(0, buf, key_length);
3414         } while (crv == CKR_OK && checkWeak && sftk_IsWeakKey(buf,key_type));
3415         break;
3416     case nsc_param:
3417         /* generate parameters */
3418         *buf = 0;
3419         crv = nsc_parameter_gen(key_type,key);
3420         break;
3421     case nsc_jpake:
3422         crv = jpake_Round1(hashType,
3423                            (CK_NSS_JPAKERound1Params *) pMechanism->pParameter,
3424                            key);
3425         break;
3426     }
3427
3428     if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
3429
3430     /* Add the class, key_type, and value */
3431     crv = sftk_AddAttributeType(key,CKA_CLASS,&objclass,sizeof(CK_OBJECT_CLASS));
3432     if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
3433     crv = sftk_AddAttributeType(key,CKA_KEY_TYPE,&key_type,sizeof(CK_KEY_TYPE));
3434     if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
3435     if (key_length != 0) {
3436         crv = sftk_AddAttributeType(key,CKA_VALUE,buf,key_length);
3437         if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
3438     }
3439
3440     /* get the session */
3441     session = sftk_SessionFromHandle(hSession);
3442     if (session == NULL) {
3443         sftk_FreeObject(key);
3444         return CKR_SESSION_HANDLE_INVALID;
3445     }
3446
3447     /*
3448      * handle the base object stuff
3449      */
3450     crv = sftk_handleObject(key,session);
3451     sftk_FreeSession(session);
3452     if (sftk_isTrue(key,CKA_SENSITIVE)) {
3453         sftk_forceAttribute(key,CKA_ALWAYS_SENSITIVE,&cktrue,sizeof(CK_BBOOL));
3454     }
3455     if (!sftk_isTrue(key,CKA_EXTRACTABLE)) {
3456         sftk_forceAttribute(key,CKA_NEVER_EXTRACTABLE,&cktrue,sizeof(CK_BBOOL));
3457     }
3458
3459     *phKey = key->handle;
3460     sftk_FreeObject(key);
3461     return crv;
3462 }
3463
3464 #define PAIRWISE_DIGEST_LENGTH                  SHA1_LENGTH /* 160-bits */
3465 #define PAIRWISE_MESSAGE_LENGTH                 20          /* 160-bits */
3466
3467 /*
3468  * FIPS 140-2 pairwise consistency check utilized to validate key pair.
3469  *
3470  * This function returns
3471  *   CKR_OK               if pairwise consistency check passed
3472  *   CKR_GENERAL_ERROR    if pairwise consistency check failed
3473  *   other error codes    if paiswise consistency check could not be
3474  *                        performed, for example, CKR_HOST_MEMORY.
3475  */
3476 static CK_RV
3477 sftk_PairwiseConsistencyCheck(CK_SESSION_HANDLE hSession,
3478     SFTKObject *publicKey, SFTKObject *privateKey, CK_KEY_TYPE keyType)
3479 {
3480     /*
3481      *                      Key type    Mechanism type
3482      *                      --------------------------------
3483      * For encrypt/decrypt: CKK_RSA  => CKM_RSA_PKCS
3484      *                      others   => CKM_INVALID_MECHANISM
3485      *
3486      * For sign/verify:     CKK_RSA  => CKM_RSA_PKCS
3487      *                      CKK_DSA  => CKM_DSA
3488      *                      CKK_EC   => CKM_ECDSA
3489      *                      others   => CKM_INVALID_MECHANISM
3490      *
3491      * None of these mechanisms has a parameter.
3492      */
3493     CK_MECHANISM mech = {0, NULL, 0};
3494
3495     CK_ULONG modulusLen;
3496     PRBool isEncryptable = PR_FALSE;
3497     PRBool canSignVerify = PR_FALSE;
3498     PRBool isDerivable = PR_FALSE;
3499     CK_RV crv;
3500
3501     /* Variables used for Encrypt/Decrypt functions. */
3502     unsigned char *known_message = (unsigned char *)"Known Crypto Message";
3503     unsigned char plaintext[PAIRWISE_MESSAGE_LENGTH];
3504     CK_ULONG bytes_decrypted;
3505     unsigned char *ciphertext;
3506     unsigned char *text_compared;
3507     CK_ULONG bytes_encrypted;
3508     CK_ULONG bytes_compared;
3509
3510     /* Variables used for Signature/Verification functions. */
3511     /* always uses SHA-1 digest */
3512     unsigned char *known_digest = (unsigned char *)"Mozilla Rules World!";
3513     unsigned char *signature;
3514     CK_ULONG signature_length;
3515
3516     if (keyType == CKK_RSA) {
3517         SFTKAttribute *attribute;
3518
3519         /* Get modulus length of private key. */
3520         attribute = sftk_FindAttribute(privateKey, CKA_MODULUS);
3521         if (attribute == NULL) {
3522             return CKR_DEVICE_ERROR;
3523         }
3524         modulusLen = attribute->attrib.ulValueLen;
3525         if (*(unsigned char *)attribute->attrib.pValue == 0) {
3526             modulusLen--;
3527         }
3528         sftk_FreeAttribute(attribute);
3529     }
3530
3531     /**************************************************/
3532     /* Pairwise Consistency Check of Encrypt/Decrypt. */
3533     /**************************************************/
3534
3535     isEncryptable = sftk_isTrue(privateKey, CKA_DECRYPT); 
3536
3537     /*
3538      * If the decryption attribute is set, attempt to encrypt
3539      * with the public key and decrypt with the private key.
3540      */
3541     if (isEncryptable) {
3542         if (keyType != CKK_RSA) {
3543             return CKR_DEVICE_ERROR;
3544         }
3545         bytes_encrypted = modulusLen;
3546         mech.mechanism = CKM_RSA_PKCS;
3547
3548         /* Allocate space for ciphertext. */
3549         ciphertext = (unsigned char *) PORT_ZAlloc(bytes_encrypted);
3550         if (ciphertext == NULL) {
3551             return CKR_HOST_MEMORY;
3552         }
3553
3554         /* Prepare for encryption using the public key. */
3555         crv = NSC_EncryptInit(hSession, &mech, publicKey->handle);
3556         if (crv != CKR_OK) {
3557             PORT_Free(ciphertext);
3558             return crv;
3559         }
3560
3561         /* Encrypt using the public key. */
3562         crv = NSC_Encrypt(hSession,
3563                           known_message,
3564                           PAIRWISE_MESSAGE_LENGTH,
3565                           ciphertext,
3566                           &bytes_encrypted);
3567         if (crv != CKR_OK) {
3568             PORT_Free(ciphertext);
3569             return crv;
3570         }
3571
3572         /* Always use the smaller of these two values . . . */
3573         bytes_compared = PR_MIN(bytes_encrypted, PAIRWISE_MESSAGE_LENGTH);
3574
3575         /*
3576          * If there was a failure, the plaintext
3577          * goes at the end, therefore . . .
3578          */
3579         text_compared = ciphertext + bytes_encrypted - bytes_compared;
3580
3581         /*
3582          * Check to ensure that ciphertext does
3583          * NOT EQUAL known input message text
3584          * per FIPS PUB 140-2 directive.
3585          */
3586         if (PORT_Memcmp(text_compared, known_message,
3587                         bytes_compared) == 0) {
3588             /* Set error to Invalid PRIVATE Key. */
3589             PORT_SetError(SEC_ERROR_INVALID_KEY);
3590             PORT_Free(ciphertext);
3591             return CKR_GENERAL_ERROR;
3592         }
3593
3594         /* Prepare for decryption using the private key. */
3595         crv = NSC_DecryptInit(hSession, &mech, privateKey->handle);
3596         if (crv != CKR_OK) {
3597             PORT_Free(ciphertext);
3598             return crv;
3599         }
3600
3601         memset(plaintext, 0, PAIRWISE_MESSAGE_LENGTH);
3602
3603         /*
3604          * Initialize bytes decrypted to be the
3605          * expected PAIRWISE_MESSAGE_LENGTH.
3606          */
3607         bytes_decrypted = PAIRWISE_MESSAGE_LENGTH;
3608
3609         /*
3610          * Decrypt using the private key.
3611          * NOTE:  No need to reset the
3612          *        value of bytes_encrypted.
3613          */
3614         crv = NSC_Decrypt(hSession,
3615                           ciphertext,
3616                           bytes_encrypted,
3617                           plaintext,
3618                           &bytes_decrypted);
3619
3620         /* Finished with ciphertext; free it. */
3621         PORT_Free(ciphertext);
3622
3623         if (crv != CKR_OK) {
3624             return crv;
3625         }
3626
3627         /*
3628          * Check to ensure that the output plaintext
3629          * does EQUAL known input message text.
3630          */
3631         if ((bytes_decrypted != PAIRWISE_MESSAGE_LENGTH) ||
3632             (PORT_Memcmp(plaintext, known_message,
3633                          PAIRWISE_MESSAGE_LENGTH) != 0)) {
3634             /* Set error to Bad PUBLIC Key. */
3635             PORT_SetError(SEC_ERROR_BAD_KEY);
3636             return CKR_GENERAL_ERROR;
3637         }
3638     }
3639
3640     /**********************************************/
3641     /* Pairwise Consistency Check of Sign/Verify. */
3642     /**********************************************/
3643
3644     canSignVerify = sftk_isTrue(privateKey, CKA_SIGN);
3645     
3646     if (canSignVerify) {
3647         /* Determine length of signature. */
3648         switch (keyType) {
3649         case CKK_RSA:
3650             signature_length = modulusLen;
3651             mech.mechanism = CKM_RSA_PKCS;
3652             break;
3653         case CKK_DSA:
3654             signature_length = DSA_SIGNATURE_LEN;
3655             mech.mechanism = CKM_DSA;
3656             break;
3657 #ifdef NSS_ENABLE_ECC
3658         case CKK_EC:
3659             signature_length = MAX_ECKEY_LEN * 2;
3660             mech.mechanism = CKM_ECDSA;
3661             break;
3662 #endif
3663         default:
3664             return CKR_DEVICE_ERROR;
3665         }
3666         
3667         /* Allocate space for signature data. */
3668         signature = (unsigned char *) PORT_ZAlloc(signature_length);
3669         if (signature == NULL) {
3670             return CKR_HOST_MEMORY;
3671         }
3672         
3673         /* Sign the known hash using the private key. */
3674         crv = NSC_SignInit(hSession, &mech, privateKey->handle);
3675         if (crv != CKR_OK) {
3676             PORT_Free(signature);
3677             return crv;
3678         }
3679
3680         crv = NSC_Sign(hSession,
3681                        known_digest,
3682                        PAIRWISE_DIGEST_LENGTH,
3683                        signature,
3684                        &signature_length);
3685         if (crv != CKR_OK) {
3686             PORT_Free(signature);
3687             return crv;
3688         }
3689         
3690         /* Verify the known hash using the public key. */
3691         crv = NSC_VerifyInit(hSession, &mech, publicKey->handle);
3692         if (crv != CKR_OK) {
3693             PORT_Free(signature);
3694             return crv;
3695         }
3696
3697         crv = NSC_Verify(hSession,
3698                          known_digest,
3699                          PAIRWISE_DIGEST_LENGTH,
3700                          signature,
3701                          signature_length);
3702
3703         /* Free signature data. */
3704         PORT_Free(signature);
3705
3706         if ((crv == CKR_SIGNATURE_LEN_RANGE) ||
3707                 (crv == CKR_SIGNATURE_INVALID)) {
3708             return CKR_GENERAL_ERROR;
3709         }
3710         if (crv != CKR_OK) {
3711             return crv;
3712         }
3713     }
3714
3715     /**********************************************/
3716     /* Pairwise Consistency Check for Derivation  */
3717     /**********************************************/
3718
3719     isDerivable = sftk_isTrue(privateKey, CKA_DERIVE);
3720     
3721     if (isDerivable) {
3722         /* 
3723          * We are not doing consistency check for Diffie-Hellman Key - 
3724          * otherwise it would be here
3725          * This is also true for Elliptic Curve Diffie-Hellman keys
3726          * NOTE: EC keys are currently subjected to pairwise
3727          * consistency check for signing/verification.
3728          */
3729         /*
3730          * FIPS 140-2 had the following pairwise consistency test for
3731          * public and private keys used for key agreement:
3732          *   If the keys are used to perform key agreement, then the
3733          *   cryptographic module shall create a second, compatible
3734          *   key pair.  The cryptographic module shall perform both
3735          *   sides of the key agreement algorithm and shall compare
3736          *   the resulting shared values.  If the shared values are
3737          *   not equal, the test shall fail.
3738          * This test was removed in Change Notice 3.
3739          */
3740
3741     }
3742
3743     return CKR_OK;
3744 }
3745
3746 /* NSC_GenerateKeyPair generates a public-key/private-key pair, 
3747  * creating new key objects. */
3748 CK_RV NSC_GenerateKeyPair (CK_SESSION_HANDLE hSession,
3749     CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate,
3750     CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
3751     CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey,
3752                                         CK_OBJECT_HANDLE_PTR phPrivateKey)
3753 {
3754     SFTKObject *        publicKey,*privateKey;
3755     SFTKSession *       session;
3756     CK_KEY_TYPE         key_type;
3757     CK_RV               crv     = CKR_OK;
3758     CK_BBOOL            cktrue  = CK_TRUE;
3759     SECStatus           rv;
3760     CK_OBJECT_CLASS     pubClass = CKO_PUBLIC_KEY;
3761     CK_OBJECT_CLASS     privClass = CKO_PRIVATE_KEY;
3762     int                 i;
3763     SFTKSlot *          slot    = sftk_SlotFromSessionHandle(hSession);
3764     unsigned int bitSize;
3765
3766     /* RSA */
3767     int                 public_modulus_bits = 0;
3768     SECItem             pubExp;
3769     RSAPrivateKey *     rsaPriv;
3770
3771     /* DSA */
3772     PQGParams           pqgParam;
3773     DHParams            dhParam;
3774     DSAPrivateKey *     dsaPriv;
3775
3776     /* Diffie Hellman */
3777     int                 private_value_bits = 0;
3778     DHPrivateKey *      dhPriv;
3779
3780 #ifdef NSS_ENABLE_ECC
3781     /* Elliptic Curve Cryptography */
3782     SECItem             ecEncodedParams;  /* DER Encoded parameters */
3783     ECPrivateKey *      ecPriv;
3784     ECParams *          ecParams;
3785 #endif /* NSS_ENABLE_ECC */
3786
3787     CHECK_FORK();
3788
3789     if (!slot) {
3790         return CKR_SESSION_HANDLE_INVALID;
3791     }
3792     /*
3793      * now lets create an object to hang the attributes off of
3794      */
3795     publicKey = sftk_NewObject(slot); /* fill in the handle later */
3796     if (publicKey == NULL) {
3797         return CKR_HOST_MEMORY;
3798     }
3799
3800     /*
3801      * load the template values into the publicKey
3802      */
3803     for (i=0; i < (int) ulPublicKeyAttributeCount; i++) {
3804         if (pPublicKeyTemplate[i].type == CKA_MODULUS_BITS) {
3805             public_modulus_bits = *(CK_ULONG *)pPublicKeyTemplate[i].pValue;
3806             continue;
3807         }
3808
3809         crv = sftk_AddAttributeType(publicKey,
3810                                     sftk_attr_expand(&pPublicKeyTemplate[i]));
3811         if (crv != CKR_OK) break;
3812     }
3813
3814     if (crv != CKR_OK) {
3815         sftk_FreeObject(publicKey);
3816         return CKR_HOST_MEMORY;
3817     }
3818
3819     privateKey = sftk_NewObject(slot); /* fill in the handle later */
3820     if (privateKey == NULL) {
3821         sftk_FreeObject(publicKey);
3822         return CKR_HOST_MEMORY;
3823     }
3824     /*
3825      * now load the private key template
3826      */
3827     for (i=0; i < (int) ulPrivateKeyAttributeCount; i++) {
3828         if (pPrivateKeyTemplate[i].type == CKA_VALUE_BITS) {
3829             private_value_bits = *(CK_ULONG *)pPrivateKeyTemplate[i].pValue;
3830             continue;
3831         }
3832
3833         crv = sftk_AddAttributeType(privateKey,
3834                                     sftk_attr_expand(&pPrivateKeyTemplate[i]));
3835         if (crv != CKR_OK) break;
3836     }
3837
3838     if (crv != CKR_OK) {
3839         sftk_FreeObject(publicKey);
3840         sftk_FreeObject(privateKey);
3841         return CKR_HOST_MEMORY;
3842     }
3843     sftk_DeleteAttributeType(privateKey,CKA_CLASS);
3844     sftk_DeleteAttributeType(privateKey,CKA_KEY_TYPE);
3845     sftk_DeleteAttributeType(privateKey,CKA_VALUE);
3846     sftk_DeleteAttributeType(publicKey,CKA_CLASS);
3847     sftk_DeleteAttributeType(publicKey,CKA_KEY_TYPE);
3848     sftk_DeleteAttributeType(publicKey,CKA_VALUE);
3849
3850     /* Now Set up the parameters to generate the key (based on mechanism) */
3851     switch (pMechanism->mechanism) {
3852     case CKM_RSA_PKCS_KEY_PAIR_GEN:
3853         /* format the keys */
3854         sftk_DeleteAttributeType(publicKey,CKA_MODULUS);
3855         sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
3856         sftk_DeleteAttributeType(privateKey,CKA_MODULUS);
3857         sftk_DeleteAttributeType(privateKey,CKA_PRIVATE_EXPONENT);
3858         sftk_DeleteAttributeType(privateKey,CKA_PUBLIC_EXPONENT);
3859         sftk_DeleteAttributeType(privateKey,CKA_PRIME_1);
3860         sftk_DeleteAttributeType(privateKey,CKA_PRIME_2);
3861         sftk_DeleteAttributeType(privateKey,CKA_EXPONENT_1);
3862         sftk_DeleteAttributeType(privateKey,CKA_EXPONENT_2);
3863         sftk_DeleteAttributeType(privateKey,CKA_COEFFICIENT);
3864         key_type = CKK_RSA;
3865         if (public_modulus_bits == 0) {
3866             crv = CKR_TEMPLATE_INCOMPLETE;
3867             break;
3868         }
3869         if (public_modulus_bits < RSA_MIN_MODULUS_BITS) {
3870             crv = CKR_ATTRIBUTE_VALUE_INVALID;
3871             break;
3872         }
3873         if (public_modulus_bits % 2 != 0) {
3874             crv = CKR_ATTRIBUTE_VALUE_INVALID;
3875             break;
3876         }
3877
3878         /* extract the exponent */
3879         crv=sftk_Attribute2SSecItem(NULL,&pubExp,publicKey,CKA_PUBLIC_EXPONENT);
3880         if (crv != CKR_OK) break;
3881         bitSize = sftk_GetLengthInBits(pubExp.data, pubExp.len);
3882         if (bitSize < 2) {
3883             crv = CKR_ATTRIBUTE_VALUE_INVALID;
3884             break;
3885         }
3886         crv = sftk_AddAttributeType(privateKey,CKA_PUBLIC_EXPONENT,
3887                                                     sftk_item_expand(&pubExp));
3888         if (crv != CKR_OK) {
3889             PORT_Free(pubExp.data);
3890             break;
3891         }
3892
3893         rsaPriv = RSA_NewKey(public_modulus_bits, &pubExp);
3894         PORT_Free(pubExp.data);
3895         if (rsaPriv == NULL) {
3896             if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
3897                 sftk_fatalError = PR_TRUE;
3898             }
3899             crv = sftk_MapCryptError(PORT_GetError());
3900             break;
3901         }
3902         /* now fill in the RSA dependent paramenters in the public key */
3903         crv = sftk_AddAttributeType(publicKey,CKA_MODULUS,
3904                            sftk_item_expand(&rsaPriv->modulus));
3905         if (crv != CKR_OK) goto kpg_done;
3906         /* now fill in the RSA dependent paramenters in the private key */
3907         crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
3908                            sftk_item_expand(&rsaPriv->modulus));
3909         if (crv != CKR_OK) goto kpg_done;
3910         crv = sftk_AddAttributeType(privateKey,CKA_MODULUS,
3911                            sftk_item_expand(&rsaPriv->modulus));
3912         if (crv != CKR_OK) goto kpg_done;
3913         crv = sftk_AddAttributeType(privateKey,CKA_PRIVATE_EXPONENT,
3914                            sftk_item_expand(&rsaPriv->privateExponent));
3915         if (crv != CKR_OK) goto kpg_done;
3916         crv = sftk_AddAttributeType(privateKey,CKA_PRIME_1,
3917                            sftk_item_expand(&rsaPriv->prime1));
3918         if (crv != CKR_OK) goto kpg_done;
3919         crv = sftk_AddAttributeType(privateKey,CKA_PRIME_2,
3920                            sftk_item_expand(&rsaPriv->prime2));
3921         if (crv != CKR_OK) goto kpg_done;
3922         crv = sftk_AddAttributeType(privateKey,CKA_EXPONENT_1,
3923                            sftk_item_expand(&rsaPriv->exponent1));
3924         if (crv != CKR_OK) goto kpg_done;
3925         crv = sftk_AddAttributeType(privateKey,CKA_EXPONENT_2,
3926                            sftk_item_expand(&rsaPriv->exponent2));
3927         if (crv != CKR_OK) goto kpg_done;
3928         crv = sftk_AddAttributeType(privateKey,CKA_COEFFICIENT,
3929                            sftk_item_expand(&rsaPriv->coefficient));
3930 kpg_done:
3931         /* Should zeroize the contents first, since this func doesn't. */
3932         PORT_FreeArena(rsaPriv->arena, PR_TRUE);
3933         break;
3934     case CKM_DSA_KEY_PAIR_GEN:
3935         sftk_DeleteAttributeType(publicKey,CKA_VALUE);
3936         sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
3937         sftk_DeleteAttributeType(privateKey,CKA_PRIME);
3938         sftk_DeleteAttributeType(privateKey,CKA_SUBPRIME);
3939         sftk_DeleteAttributeType(privateKey,CKA_BASE);
3940         key_type = CKK_DSA;
3941
3942         /* extract the necessary parameters and copy them to the private key */
3943         crv=sftk_Attribute2SSecItem(NULL,&pqgParam.prime,publicKey,CKA_PRIME);
3944         if (crv != CKR_OK) break;
3945         crv=sftk_Attribute2SSecItem(NULL,&pqgParam.subPrime,publicKey,
3946                                     CKA_SUBPRIME);
3947         if (crv != CKR_OK) {
3948             PORT_Free(pqgParam.prime.data);
3949             break;
3950         }
3951         crv=sftk_Attribute2SSecItem(NULL,&pqgParam.base,publicKey,CKA_BASE);
3952         if (crv != CKR_OK) {
3953             PORT_Free(pqgParam.prime.data);
3954             PORT_Free(pqgParam.subPrime.data);
3955             break;
3956         }
3957         crv = sftk_AddAttributeType(privateKey,CKA_PRIME,
3958                                     sftk_item_expand(&pqgParam.prime));
3959         if (crv != CKR_OK) {
3960             PORT_Free(pqgParam.prime.data);
3961             PORT_Free(pqgParam.subPrime.data);
3962             PORT_Free(pqgParam.base.data);
3963             break;
3964         }
3965         crv = sftk_AddAttributeType(privateKey,CKA_SUBPRIME,
3966                                     sftk_item_expand(&pqgParam.subPrime));
3967         if (crv != CKR_OK) {
3968             PORT_Free(pqgParam.prime.data);
3969             PORT_Free(pqgParam.subPrime.data);
3970             PORT_Free(pqgParam.base.data);
3971             break;
3972         }
3973         crv = sftk_AddAttributeType(privateKey,CKA_BASE,
3974                                     sftk_item_expand(&pqgParam.base));
3975         if (crv != CKR_OK) {
3976             PORT_Free(pqgParam.prime.data);
3977             PORT_Free(pqgParam.subPrime.data);
3978             PORT_Free(pqgParam.base.data);
3979             break;
3980         }
3981
3982         bitSize = sftk_GetLengthInBits(pqgParam.subPrime.data, 
3983                                                         pqgParam.subPrime.len);
3984         if (bitSize != DSA_Q_BITS)  {
3985             crv = CKR_TEMPLATE_INCOMPLETE;
3986             PORT_Free(pqgParam.prime.data);
3987             PORT_Free(pqgParam.subPrime.data);
3988             PORT_Free(pqgParam.base.data);
3989             break;
3990         }
3991         bitSize = sftk_GetLengthInBits(pqgParam.prime.data,pqgParam.prime.len);
3992         if ((bitSize <  DSA_MIN_P_BITS) || (bitSize > DSA_MAX_P_BITS)) {
3993             crv = CKR_TEMPLATE_INCOMPLETE;
3994             PORT_Free(pqgParam.prime.data);
3995             PORT_Free(pqgParam.subPrime.data);
3996             PORT_Free(pqgParam.base.data);
3997             break;
3998         }
3999         bitSize = sftk_GetLengthInBits(pqgParam.base.data,pqgParam.base.len);
4000         if ((bitSize <  1) || (bitSize > DSA_MAX_P_BITS)) {
4001             crv = CKR_TEMPLATE_INCOMPLETE;
4002             PORT_Free(pqgParam.prime.data);
4003             PORT_Free(pqgParam.subPrime.data);
4004             PORT_Free(pqgParam.base.data);
4005             break;
4006         }
4007             
4008         /* Generate the key */
4009         rv = DSA_NewKey(&pqgParam, &dsaPriv);
4010
4011         PORT_Free(pqgParam.prime.data);
4012         PORT_Free(pqgParam.subPrime.data);
4013         PORT_Free(pqgParam.base.data);
4014
4015         if (rv != SECSuccess) {
4016             if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
4017                 sftk_fatalError = PR_TRUE;
4018             }
4019             crv = sftk_MapCryptError(PORT_GetError());
4020             break;
4021         }
4022
4023         /* store the generated key into the attributes */
4024         crv = sftk_AddAttributeType(publicKey,CKA_VALUE,
4025                            sftk_item_expand(&dsaPriv->publicValue));
4026         if (crv != CKR_OK) goto dsagn_done;
4027
4028         /* now fill in the RSA dependent paramenters in the private key */
4029         crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
4030                            sftk_item_expand(&dsaPriv->publicValue));
4031         if (crv != CKR_OK) goto dsagn_done;
4032         crv = sftk_AddAttributeType(privateKey,CKA_VALUE,
4033                            sftk_item_expand(&dsaPriv->privateValue));
4034
4035 dsagn_done:
4036         /* should zeroize, since this function doesn't. */
4037         PORT_FreeArena(dsaPriv->params.arena, PR_TRUE);
4038         break;
4039
4040     case CKM_DH_PKCS_KEY_PAIR_GEN:
4041         sftk_DeleteAttributeType(privateKey,CKA_PRIME);
4042         sftk_DeleteAttributeType(privateKey,CKA_BASE);
4043         sftk_DeleteAttributeType(privateKey,CKA_VALUE);
4044         sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
4045         key_type = CKK_DH;
4046
4047         /* extract the necessary parameters and copy them to private keys */
4048         crv = sftk_Attribute2SSecItem(NULL, &dhParam.prime, publicKey, 
4049                                       CKA_PRIME);
4050         if (crv != CKR_OK) break;
4051         crv = sftk_Attribute2SSecItem(NULL, &dhParam.base, publicKey, CKA_BASE);
4052         if (crv != CKR_OK) {
4053             PORT_Free(dhParam.prime.data);
4054             break;
4055         }
4056         crv = sftk_AddAttributeType(privateKey, CKA_PRIME, 
4057                                     sftk_item_expand(&dhParam.prime));
4058         if (crv != CKR_OK) {
4059             PORT_Free(dhParam.prime.data);
4060             PORT_Free(dhParam.base.data);
4061             break;
4062         }
4063         crv = sftk_AddAttributeType(privateKey, CKA_BASE, 
4064                                     sftk_item_expand(&dhParam.base));
4065         if (crv != CKR_OK) {
4066             PORT_Free(dhParam.prime.data);
4067             PORT_Free(dhParam.base.data);
4068             break;
4069         }
4070         bitSize = sftk_GetLengthInBits(dhParam.prime.data,dhParam.prime.len);
4071         if ((bitSize <  DH_MIN_P_BITS) || (bitSize > DH_MAX_P_BITS)) {
4072             crv = CKR_TEMPLATE_INCOMPLETE;
4073             PORT_Free(dhParam.prime.data);
4074             PORT_Free(dhParam.base.data);
4075             break;
4076         }
4077         bitSize = sftk_GetLengthInBits(dhParam.base.data,dhParam.base.len);
4078         if ((bitSize <  1) || (bitSize > DH_MAX_P_BITS)) {
4079             crv = CKR_TEMPLATE_INCOMPLETE;
4080             PORT_Free(dhParam.prime.data);
4081             PORT_Free(dhParam.base.data);
4082             break;
4083         }
4084
4085         rv = DH_NewKey(&dhParam, &dhPriv);
4086         PORT_Free(dhParam.prime.data);
4087         PORT_Free(dhParam.base.data);
4088         if (rv != SECSuccess) { 
4089             if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
4090                 sftk_fatalError = PR_TRUE;
4091             }
4092             crv = sftk_MapCryptError(PORT_GetError());
4093             break;
4094         }
4095
4096         crv=sftk_AddAttributeType(publicKey, CKA_VALUE, 
4097                                 sftk_item_expand(&dhPriv->publicValue));
4098         if (crv != CKR_OK) goto dhgn_done;
4099
4100         crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
4101                            sftk_item_expand(&dhPriv->publicValue));
4102         if (crv != CKR_OK) goto dhgn_done;
4103
4104         crv=sftk_AddAttributeType(privateKey, CKA_VALUE, 
4105                               sftk_item_expand(&dhPriv->privateValue));
4106
4107 dhgn_done:
4108         /* should zeroize, since this function doesn't. */
4109         PORT_FreeArena(dhPriv->arena, PR_TRUE);
4110         break;
4111
4112 #ifdef NSS_ENABLE_ECC
4113     case CKM_EC_KEY_PAIR_GEN:
4114         sftk_DeleteAttributeType(privateKey,CKA_EC_PARAMS);
4115         sftk_DeleteAttributeType(privateKey,CKA_VALUE);
4116         sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
4117         key_type = CKK_EC;
4118
4119         /* extract the necessary parameters and copy them to private keys */
4120         crv = sftk_Attribute2SSecItem(NULL, &ecEncodedParams, publicKey, 
4121                                       CKA_EC_PARAMS);
4122         if (crv != CKR_OK) break;
4123
4124         crv = sftk_AddAttributeType(privateKey, CKA_EC_PARAMS, 
4125                                     sftk_item_expand(&ecEncodedParams));
4126         if (crv != CKR_OK) {
4127           PORT_Free(ecEncodedParams.data);
4128           break;
4129         }
4130
4131         /* Decode ec params before calling EC_NewKey */
4132         rv = EC_DecodeParams(&ecEncodedParams, &ecParams);
4133         PORT_Free(ecEncodedParams.data);
4134         if (rv != SECSuccess) {
4135             crv = sftk_MapCryptError(PORT_GetError());
4136             break;
4137         }
4138         rv = EC_NewKey(ecParams, &ecPriv);
4139         PORT_FreeArena(ecParams->arena, PR_TRUE);
4140         if (rv != SECSuccess) { 
4141             if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
4142                 sftk_fatalError = PR_TRUE;
4143             }
4144             crv = sftk_MapCryptError(PORT_GetError());
4145             break;
4146         }
4147
4148         if (getenv("NSS_USE_DECODED_CKA_EC_POINT")) {
4149             crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT, 
4150                                 sftk_item_expand(&ecPriv->publicValue));
4151         } else {
4152             SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL, 
4153                                         &ecPriv->publicValue, 
4154                                         SEC_ASN1_GET(SEC_OctetStringTemplate));
4155             if (!pubValue) {
4156                 crv = CKR_ARGUMENTS_BAD;
4157                 goto ecgn_done;
4158             }
4159             crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT, 
4160                                 sftk_item_expand(pubValue));
4161             SECITEM_FreeItem(pubValue, PR_TRUE);
4162         }
4163         if (crv != CKR_OK) goto ecgn_done;
4164
4165         crv = sftk_AddAttributeType(privateKey, CKA_VALUE, 
4166                               sftk_item_expand(&ecPriv->privateValue));
4167         if (crv != CKR_OK) goto ecgn_done;
4168
4169         crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
4170                            sftk_item_expand(&ecPriv->publicValue));
4171 ecgn_done:
4172         /* should zeroize, since this function doesn't. */
4173         PORT_FreeArena(ecPriv->ecParams.arena, PR_TRUE);
4174         break;
4175 #endif /* NSS_ENABLE_ECC */
4176
4177     default:
4178         crv = CKR_MECHANISM_INVALID;
4179     }
4180
4181     if (crv != CKR_OK) {
4182         sftk_FreeObject(privateKey);
4183         sftk_FreeObject(publicKey);
4184         return crv;
4185     }
4186
4187
4188     /* Add the class, key_type The loop lets us check errors blow out
4189      *  on errors and clean up at the bottom */
4190     session = NULL; /* make pedtantic happy... session cannot leave the*/
4191                     /* loop below NULL unless an error is set... */
4192     do {
4193         crv = sftk_AddAttributeType(privateKey,CKA_CLASS,&privClass,
4194                                                 sizeof(CK_OBJECT_CLASS));
4195         if (crv != CKR_OK) break;
4196         crv = sftk_AddAttributeType(publicKey,CKA_CLASS,&pubClass,
4197                                                 sizeof(CK_OBJECT_CLASS));
4198         if (crv != CKR_OK) break;
4199         crv = sftk_AddAttributeType(privateKey,CKA_KEY_TYPE,&key_type,
4200                                                 sizeof(CK_KEY_TYPE));
4201         if (crv != CKR_OK) break;
4202         crv = sftk_AddAttributeType(publicKey,CKA_KEY_TYPE,&key_type,
4203                                                 sizeof(CK_KEY_TYPE));
4204         if (crv != CKR_OK) break;
4205         session = sftk_SessionFromHandle(hSession);
4206         if (session == NULL) crv = CKR_SESSION_HANDLE_INVALID;
4207     } while (0);
4208
4209     if (crv != CKR_OK) {
4210          sftk_FreeObject(privateKey);
4211          sftk_FreeObject(publicKey);
4212          return crv;
4213     }
4214
4215     /*
4216      * handle the base object cleanup for the public Key
4217      */
4218     crv = sftk_handleObject(privateKey,session);
4219     if (crv != CKR_OK) {
4220         sftk_FreeSession(session);
4221         sftk_FreeObject(privateKey);
4222         sftk_FreeObject(publicKey);
4223         return crv;
4224     }
4225
4226     /*
4227      * handle the base object cleanup for the private Key
4228      * If we have any problems, we destroy the public Key we've
4229      * created and linked.
4230      */
4231     crv = sftk_handleObject(publicKey,session);
4232     sftk_FreeSession(session);
4233     if (crv != CKR_OK) {
4234         sftk_FreeObject(publicKey);
4235         NSC_DestroyObject(hSession,privateKey->handle);
4236         sftk_FreeObject(privateKey);
4237         return crv;
4238     }
4239     if (sftk_isTrue(privateKey,CKA_SENSITIVE)) {
4240         sftk_forceAttribute(privateKey,CKA_ALWAYS_SENSITIVE,
4241                                                 &cktrue,sizeof(CK_BBOOL));
4242     }
4243     if (sftk_isTrue(publicKey,CKA_SENSITIVE)) {
4244         sftk_forceAttribute(publicKey,CKA_ALWAYS_SENSITIVE,
4245                                                 &cktrue,sizeof(CK_BBOOL));
4246     }
4247     if (!sftk_isTrue(privateKey,CKA_EXTRACTABLE)) {
4248         sftk_forceAttribute(privateKey,CKA_NEVER_EXTRACTABLE,
4249                                                 &cktrue,sizeof(CK_BBOOL));
4250     }
4251     if (!sftk_isTrue(publicKey,CKA_EXTRACTABLE)) {
4252         sftk_forceAttribute(publicKey,CKA_NEVER_EXTRACTABLE,
4253                                                 &cktrue,sizeof(CK_BBOOL));
4254     }
4255
4256     /* Perform FIPS 140-2 pairwise consistency check. */
4257     crv = sftk_PairwiseConsistencyCheck(hSession,
4258                                         publicKey, privateKey, key_type);
4259     if (crv != CKR_OK) {
4260         NSC_DestroyObject(hSession,publicKey->handle);
4261         sftk_FreeObject(publicKey);
4262         NSC_DestroyObject(hSession,privateKey->handle);
4263         sftk_FreeObject(privateKey);
4264         if (sftk_audit_enabled) {
4265             char msg[128];
4266             PR_snprintf(msg,sizeof msg,
4267                         "C_GenerateKeyPair(hSession=0x%08lX, "
4268                         "pMechanism->mechanism=0x%08lX)=0x%08lX "
4269                         "self-test: pair-wise consistency test failed",
4270                         (PRUint32)hSession,(PRUint32)pMechanism->mechanism,
4271                         (PRUint32)crv);
4272             sftk_LogAuditMessage(NSS_AUDIT_ERROR, NSS_AUDIT_SELF_TEST, msg);
4273         }
4274         return crv;
4275     }
4276
4277     *phPrivateKey = privateKey->handle;
4278     *phPublicKey = publicKey->handle;
4279     sftk_FreeObject(publicKey);
4280     sftk_FreeObject(privateKey);
4281
4282     return CKR_OK;
4283 }
4284
4285 static SECItem *sftk_PackagePrivateKey(SFTKObject *key, CK_RV *crvp)
4286 {
4287     NSSLOWKEYPrivateKey *lk = NULL;
4288     NSSLOWKEYPrivateKeyInfo *pki = NULL;
4289     SFTKAttribute *attribute = NULL;
4290     PLArenaPool *arena = NULL;
4291     SECOidTag algorithm = SEC_OID_UNKNOWN;
4292     void *dummy, *param = NULL;
4293     SECStatus rv = SECSuccess;
4294     SECItem *encodedKey = NULL;
4295 #ifdef NSS_ENABLE_ECC
4296     SECItem *fordebug;
4297     int savelen;
4298 #endif
4299
4300     if(!key) {
4301         *crvp = CKR_KEY_HANDLE_INVALID; /* really can't happen */
4302         return NULL;
4303     }
4304
4305     attribute = sftk_FindAttribute(key, CKA_KEY_TYPE);
4306     if(!attribute) {
4307         *crvp = CKR_KEY_TYPE_INCONSISTENT;
4308         return NULL;
4309     }
4310
4311     lk = sftk_GetPrivKey(key, *(CK_KEY_TYPE *)attribute->attrib.pValue, crvp);
4312     sftk_FreeAttribute(attribute);
4313     if(!lk) {
4314         return NULL;
4315     }
4316
4317     arena = PORT_NewArena(2048);        /* XXX different size? */
4318     if(!arena) {
4319         *crvp = CKR_HOST_MEMORY;
4320         rv = SECFailure;
4321         goto loser;
4322     }
4323
4324     pki = (NSSLOWKEYPrivateKeyInfo*)PORT_ArenaZAlloc(arena, 
4325                                         sizeof(NSSLOWKEYPrivateKeyInfo));
4326     if(!pki) {
4327         *crvp = CKR_HOST_MEMORY;
4328         rv = SECFailure;
4329         goto loser;
4330     }
4331     pki->arena = arena;
4332
4333     param = NULL;
4334     switch(lk->keyType) {
4335         case NSSLOWKEYRSAKey:
4336             prepare_low_rsa_priv_key_for_asn1(lk);
4337             dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
4338                                        nsslowkey_RSAPrivateKeyTemplate);
4339             algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION;
4340             break;
4341         case NSSLOWKEYDSAKey:
4342             prepare_low_dsa_priv_key_export_for_asn1(lk);
4343             dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
4344                                        nsslowkey_DSAPrivateKeyExportTemplate);
4345             prepare_low_pqg_params_for_asn1(&lk->u.dsa.params);
4346             param = SEC_ASN1EncodeItem(NULL, NULL, &(lk->u.dsa.params),
4347                                        nsslowkey_PQGParamsTemplate);
4348             algorithm = SEC_OID_ANSIX9_DSA_SIGNATURE;
4349             break;
4350 #ifdef NSS_ENABLE_ECC       
4351         case NSSLOWKEYECKey:
4352             prepare_low_ec_priv_key_for_asn1(lk);
4353             /* Public value is encoded as a bit string so adjust length
4354              * to be in bits before ASN encoding and readjust 
4355              * immediately after.
4356              *
4357              * Since the SECG specification recommends not including the
4358              * parameters as part of ECPrivateKey, we zero out the curveOID
4359              * length before encoding and restore it later.
4360              */
4361             lk->u.ec.publicValue.len <<= 3;
4362             savelen = lk->u.ec.ecParams.curveOID.len;
4363             lk->u.ec.ecParams.curveOID.len = 0;
4364             dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
4365                                        nsslowkey_ECPrivateKeyTemplate);
4366             lk->u.ec.ecParams.curveOID.len = savelen;
4367             lk->u.ec.publicValue.len >>= 3;
4368
4369             fordebug = &pki->privateKey;
4370             SEC_PRINT("sftk_PackagePrivateKey()", "PrivateKey", lk->keyType,
4371                       fordebug);
4372
4373             param = SECITEM_DupItem(&lk->u.ec.ecParams.DEREncoding);
4374
4375             algorithm = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
4376             break;
4377 #endif /* NSS_ENABLE_ECC */
4378         case NSSLOWKEYDHKey:
4379         default:
4380             dummy = NULL;
4381             break;
4382     }
4383  
4384     if(!dummy || ((lk->keyType == NSSLOWKEYDSAKey) && !param)) {
4385         *crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */
4386         rv = SECFailure;
4387         goto loser;
4388     }
4389     
4390     rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, algorithm, 
4391                                (SECItem*)param);
4392     if(rv != SECSuccess) {
4393         *crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */
4394         rv = SECFailure;
4395         goto loser;
4396     }
4397
4398     dummy = SEC_ASN1EncodeInteger(arena, &pki->version,
4399                                   NSSLOWKEY_PRIVATE_KEY_INFO_VERSION);
4400     if(!dummy) {
4401         *crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */
4402         rv = SECFailure;
4403         goto loser;
4404     }
4405
4406     encodedKey = SEC_ASN1EncodeItem(NULL, NULL, pki, 
4407                                     nsslowkey_PrivateKeyInfoTemplate);
4408     *crvp = encodedKey ? CKR_OK : CKR_DEVICE_ERROR;
4409
4410 #ifdef NSS_ENABLE_ECC
4411     fordebug = encodedKey;
4412     SEC_PRINT("sftk_PackagePrivateKey()", "PrivateKeyInfo", lk->keyType,
4413               fordebug);
4414 #endif
4415 loser:
4416     if(arena) {
4417         PORT_FreeArena(arena, PR_TRUE);
4418     }
4419
4420     if(lk && (lk != key->objectInfo)) {
4421         nsslowkey_DestroyPrivateKey(lk);
4422     }
4423  
4424     if(param) {
4425         SECITEM_ZfreeItem((SECItem*)param, PR_TRUE);
4426     }
4427
4428     if(rv != SECSuccess) {
4429         return NULL;
4430     }
4431
4432     return encodedKey;
4433 }
4434     
4435 /* it doesn't matter yet, since we colapse error conditions in the
4436  * level above, but we really should map those few key error differences */
4437 static CK_RV 
4438 sftk_mapWrap(CK_RV crv) 
4439
4440     switch (crv) {
4441     case CKR_ENCRYPTED_DATA_INVALID:  crv = CKR_WRAPPED_KEY_INVALID; break;
4442     }
4443     return crv; 
4444 }
4445
4446 /* NSC_WrapKey wraps (i.e., encrypts) a key. */
4447 CK_RV NSC_WrapKey(CK_SESSION_HANDLE hSession,
4448     CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey,
4449     CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey,
4450                                          CK_ULONG_PTR pulWrappedKeyLen)
4451 {
4452     SFTKSession *session;
4453     SFTKAttribute *attribute;
4454     SFTKObject *key;
4455     CK_RV crv;
4456
4457     CHECK_FORK();
4458
4459     session = sftk_SessionFromHandle(hSession);
4460     if (session == NULL) {
4461         return CKR_SESSION_HANDLE_INVALID;
4462     }
4463
4464     key = sftk_ObjectFromHandle(hKey,session);
4465     sftk_FreeSession(session);
4466     if (key == NULL) {
4467         return CKR_KEY_HANDLE_INVALID;
4468     }
4469
4470     switch(key->objclass) {
4471         case CKO_SECRET_KEY:
4472           {
4473             SFTKSessionContext *context = NULL;
4474             SECItem pText;
4475
4476             attribute = sftk_FindAttribute(key,CKA_VALUE);
4477
4478             if (attribute == NULL) {
4479                 crv = CKR_KEY_TYPE_INCONSISTENT;
4480                 break;
4481             }
4482             crv = sftk_CryptInit(hSession, pMechanism, hWrappingKey, 
4483                                 CKA_WRAP, CKA_WRAP, SFTK_ENCRYPT, PR_TRUE);
4484             if (crv != CKR_OK) {
4485                 sftk_FreeAttribute(attribute);
4486                 break;
4487             }
4488
4489             pText.type = siBuffer;
4490             pText.data = (unsigned char *)attribute->attrib.pValue;
4491             pText.len  = attribute->attrib.ulValueLen;
4492
4493             /* Find out if this is a block cipher. */
4494             crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_FALSE,NULL);
4495             if (crv != CKR_OK || !context) 
4496                 break;
4497             if (context->blockSize > 1) {
4498                 unsigned int remainder = pText.len % context->blockSize;
4499                 if (!context->doPad && remainder) {
4500                     /* When wrapping secret keys with unpadded block ciphers, 
4501                     ** the keys are zero padded, if necessary, to fill out 
4502                     ** a full block.
4503                     */
4504                     pText.len += context->blockSize - remainder;
4505                     pText.data = PORT_ZAlloc(pText.len);
4506                     if (pText.data)
4507                         memcpy(pText.data, attribute->attrib.pValue,
4508                                            attribute->attrib.ulValueLen);
4509                     else {
4510                         crv = CKR_HOST_MEMORY;
4511                         break;
4512                     }
4513                 }
4514             }
4515
4516             crv = NSC_Encrypt(hSession, (CK_BYTE_PTR)pText.data, 
4517                               pText.len, pWrappedKey, pulWrappedKeyLen);
4518             /* always force a finalize, both on errors and when
4519              * we are just getting the size */
4520             if (crv != CKR_OK || pWrappedKey == NULL) {
4521                 CK_RV lcrv ;
4522                 lcrv = sftk_GetContext(hSession,&context,
4523                                        SFTK_ENCRYPT,PR_FALSE,NULL);
4524                 sftk_SetContextByType(session, SFTK_ENCRYPT, NULL);
4525                 if (lcrv == CKR_OK && context) {
4526                     sftk_FreeContext(context);
4527                 }
4528             }
4529
4530             if (pText.data != (unsigned char *)attribute->attrib.pValue) 
4531                 PORT_ZFree(pText.data, pText.len);
4532             sftk_FreeAttribute(attribute);
4533             break;
4534           }
4535
4536         case CKO_PRIVATE_KEY:
4537             {
4538                 SECItem *bpki = sftk_PackagePrivateKey(key, &crv);
4539                 SFTKSessionContext *context = NULL;
4540
4541                 if(!bpki) {
4542                     break;
4543                 }
4544
4545                 crv = sftk_CryptInit(hSession, pMechanism, hWrappingKey,
4546                                 CKA_WRAP, CKA_WRAP, SFTK_ENCRYPT, PR_TRUE);
4547                 if(crv != CKR_OK) {
4548                     SECITEM_ZfreeItem(bpki, PR_TRUE);
4549                     crv = CKR_KEY_TYPE_INCONSISTENT;
4550                     break;
4551                 }
4552
4553                 crv = NSC_Encrypt(hSession, bpki->data, bpki->len,
4554                                         pWrappedKey, pulWrappedKeyLen);
4555                 /* always force a finalize */
4556                 if (crv != CKR_OK || pWrappedKey == NULL) {
4557                     CK_RV lcrv ;
4558                     lcrv = sftk_GetContext(hSession,&context,
4559                                            SFTK_ENCRYPT,PR_FALSE,NULL);
4560                     sftk_SetContextByType(session, SFTK_ENCRYPT, NULL);
4561                     if (lcrv == CKR_OK && context)  {
4562                         sftk_FreeContext(context);
4563                     }
4564                 }
4565                 SECITEM_ZfreeItem(bpki, PR_TRUE);
4566                 break;
4567             }
4568
4569         default:
4570             crv = CKR_KEY_TYPE_INCONSISTENT;
4571             break;
4572     }
4573     sftk_FreeObject(key);
4574
4575     return sftk_mapWrap(crv);
4576 }
4577
4578 /*
4579  * import a pprivate key info into the desired slot
4580  */
4581 static SECStatus
4582 sftk_unwrapPrivateKey(SFTKObject *key, SECItem *bpki)
4583 {
4584     CK_BBOOL cktrue = CK_TRUE; 
4585     CK_KEY_TYPE keyType = CKK_RSA;
4586     SECStatus rv = SECFailure;
4587     const SEC_ASN1Template *keyTemplate, *paramTemplate;
4588     void *paramDest = NULL;
4589     PLArenaPool *arena;
4590     NSSLOWKEYPrivateKey *lpk = NULL;
4591     NSSLOWKEYPrivateKeyInfo *pki = NULL;
4592     CK_RV crv = CKR_KEY_TYPE_INCONSISTENT;
4593
4594     arena = PORT_NewArena(2048);
4595     if(!arena) {
4596         return SECFailure;
4597     }
4598
4599     pki = (NSSLOWKEYPrivateKeyInfo*)PORT_ArenaZAlloc(arena, 
4600                                         sizeof(NSSLOWKEYPrivateKeyInfo));
4601     if(!pki) {
4602         PORT_FreeArena(arena, PR_FALSE);
4603         return SECFailure;
4604     }
4605
4606     if(SEC_ASN1DecodeItem(arena, pki, nsslowkey_PrivateKeyInfoTemplate, bpki) 
4607                                 != SECSuccess) {
4608         PORT_FreeArena(arena, PR_TRUE);
4609         return SECFailure;
4610     }
4611
4612     lpk = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(arena,
4613                                                   sizeof(NSSLOWKEYPrivateKey));
4614     if(lpk == NULL) {
4615         goto loser;
4616     }
4617     lpk->arena = arena;
4618
4619     switch(SECOID_GetAlgorithmTag(&pki->algorithm)) {
4620         case SEC_OID_PKCS1_RSA_ENCRYPTION:
4621             keyTemplate = nsslowkey_RSAPrivateKeyTemplate;
4622             paramTemplate = NULL;
4623             paramDest = NULL;
4624             lpk->keyType = NSSLOWKEYRSAKey;
4625             prepare_low_rsa_priv_key_for_asn1(lpk);
4626             break;
4627         case SEC_OID_ANSIX9_DSA_SIGNATURE:
4628             keyTemplate = nsslowkey_DSAPrivateKeyExportTemplate;
4629             paramTemplate = nsslowkey_PQGParamsTemplate;
4630             paramDest = &(lpk->u.dsa.params);
4631             lpk->keyType = NSSLOWKEYDSAKey;
4632             prepare_low_dsa_priv_key_export_for_asn1(lpk);
4633             prepare_low_pqg_params_for_asn1(&lpk->u.dsa.params);
4634             break;
4635         /* case NSSLOWKEYDHKey: */
4636 #ifdef NSS_ENABLE_ECC
4637         case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
4638             keyTemplate = nsslowkey_ECPrivateKeyTemplate;
4639             paramTemplate = NULL;
4640             paramDest = &(lpk->u.ec.ecParams.DEREncoding);
4641             lpk->keyType = NSSLOWKEYECKey;
4642             prepare_low_ec_priv_key_for_asn1(lpk);
4643             prepare_low_ecparams_for_asn1(&lpk->u.ec.ecParams);
4644             break;
4645 #endif /* NSS_ENABLE_ECC */
4646         default:
4647             keyTemplate = NULL;
4648             paramTemplate = NULL;
4649             paramDest = NULL;
4650             break;
4651     }
4652
4653     if(!keyTemplate) {
4654         goto loser;
4655     }
4656
4657     /* decode the private key and any algorithm parameters */
4658     rv = SEC_QuickDERDecodeItem(arena, lpk, keyTemplate, &pki->privateKey);
4659
4660 #ifdef NSS_ENABLE_ECC
4661     if (lpk->keyType == NSSLOWKEYECKey) {
4662         /* convert length in bits to length in bytes */
4663         lpk->u.ec.publicValue.len >>= 3;
4664         rv = SECITEM_CopyItem(arena, 
4665                               &(lpk->u.ec.ecParams.DEREncoding),
4666                               &(pki->algorithm.parameters));
4667         if(rv != SECSuccess) {
4668             goto loser;
4669         }
4670     }
4671 #endif /* NSS_ENABLE_ECC */
4672
4673     if(rv != SECSuccess) {
4674         goto loser;
4675     }
4676     if(paramDest && paramTemplate) {
4677         rv = SEC_QuickDERDecodeItem(arena, paramDest, paramTemplate, 
4678                                  &(pki->algorithm.parameters));
4679         if(rv != SECSuccess) {
4680             goto loser;
4681         }
4682     }
4683
4684     rv = SECFailure;
4685
4686     switch (lpk->keyType) {
4687         case NSSLOWKEYRSAKey:
4688             keyType = CKK_RSA;
4689             if(sftk_hasAttribute(key, CKA_NETSCAPE_DB)) {
4690                 sftk_DeleteAttributeType(key, CKA_NETSCAPE_DB);
4691             }
4692             crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, 
4693                                         sizeof(keyType));
4694             if(crv != CKR_OK) break;
4695             crv = sftk_AddAttributeType(key, CKA_UNWRAP, &cktrue, 
4696                                         sizeof(CK_BBOOL));
4697             if(crv != CKR_OK) break;
4698             crv = sftk_AddAttributeType(key, CKA_DECRYPT, &cktrue, 
4699                                         sizeof(CK_BBOOL));
4700             if(crv != CKR_OK) break;
4701             crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, 
4702                                         sizeof(CK_BBOOL));
4703             if(crv != CKR_OK) break;
4704             crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue, 
4705                                     sizeof(CK_BBOOL));
4706             if(crv != CKR_OK) break;
4707             crv = sftk_AddAttributeType(key, CKA_MODULUS, 
4708                                 sftk_item_expand(&lpk->u.rsa.modulus));
4709             if(crv != CKR_OK) break;
4710             crv = sftk_AddAttributeType(key, CKA_PUBLIC_EXPONENT, 
4711                                 sftk_item_expand(&lpk->u.rsa.publicExponent));
4712             if(crv != CKR_OK) break;
4713             crv = sftk_AddAttributeType(key, CKA_PRIVATE_EXPONENT, 
4714                                 sftk_item_expand(&lpk->u.rsa.privateExponent));
4715             if(crv != CKR_OK) break;
4716             crv = sftk_AddAttributeType(key, CKA_PRIME_1, 
4717                                 sftk_item_expand(&lpk->u.rsa.prime1));
4718             if(crv != CKR_OK) break;
4719             crv = sftk_AddAttributeType(key, CKA_PRIME_2, 
4720                                 sftk_item_expand(&lpk->u.rsa.prime2));
4721             if(crv != CKR_OK) break;
4722             crv = sftk_AddAttributeType(key, CKA_EXPONENT_1, 
4723                                 sftk_item_expand(&lpk->u.rsa.exponent1));
4724             if(crv != CKR_OK) break;
4725             crv = sftk_AddAttributeType(key, CKA_EXPONENT_2, 
4726                                 sftk_item_expand(&lpk->u.rsa.exponent2));
4727             if(crv != CKR_OK) break;
4728             crv = sftk_AddAttributeType(key, CKA_COEFFICIENT, 
4729                                 sftk_item_expand(&lpk->u.rsa.coefficient));
4730             break;
4731         case NSSLOWKEYDSAKey:
4732             keyType = CKK_DSA;
4733             crv = (sftk_hasAttribute(key, CKA_NETSCAPE_DB)) ? CKR_OK :
4734                                                 CKR_KEY_TYPE_INCONSISTENT;
4735             if(crv != CKR_OK) break;
4736             crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, 
4737                                                 sizeof(keyType));
4738             if(crv != CKR_OK) break;
4739             crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, 
4740                                                 sizeof(CK_BBOOL));
4741             if(crv != CKR_OK) break;
4742             crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue, 
4743                                                 sizeof(CK_BBOOL)); 
4744             if(crv != CKR_OK) break;
4745             crv = sftk_AddAttributeType(key, CKA_PRIME,    
4746                                     sftk_item_expand(&lpk->u.dsa.params.prime));
4747             if(crv != CKR_OK) break;
4748             crv = sftk_AddAttributeType(key, CKA_SUBPRIME,
4749                                  sftk_item_expand(&lpk->u.dsa.params.subPrime));
4750             if(crv != CKR_OK) break;
4751             crv = sftk_AddAttributeType(key, CKA_BASE,  
4752                                     sftk_item_expand(&lpk->u.dsa.params.base));
4753             if(crv != CKR_OK) break;
4754             crv = sftk_AddAttributeType(key, CKA_VALUE, 
4755                         sftk_item_expand(&lpk->u.dsa.privateValue));
4756             if(crv != CKR_OK) break;
4757             break;
4758 #ifdef notdef
4759         case NSSLOWKEYDHKey:
4760             template = dhTemplate;
4761             templateCount = sizeof(dhTemplate)/sizeof(CK_ATTRIBUTE);
4762             keyType = CKK_DH;
4763             break;
4764 #endif
4765         /* what about fortezza??? */
4766 #ifdef NSS_ENABLE_ECC
4767         case NSSLOWKEYECKey:
4768             keyType = CKK_EC;
4769             crv = (sftk_hasAttribute(key, CKA_NETSCAPE_DB)) ? CKR_OK :
4770                                                 CKR_KEY_TYPE_INCONSISTENT;
4771             if(crv != CKR_OK) break;
4772             crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, 
4773                                                 sizeof(keyType));
4774             if(crv != CKR_OK) break;
4775             crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, 
4776                                                 sizeof(CK_BBOOL));
4777             if(crv != CKR_OK) break;
4778             crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue, 
4779                                                 sizeof(CK_BBOOL)); 
4780             if(crv != CKR_OK) break;
4781             crv = sftk_AddAttributeType(key, CKA_DERIVE, &cktrue, 
4782                                                 sizeof(CK_BBOOL)); 
4783             if(crv != CKR_OK) break;
4784             crv = sftk_AddAttributeType(key, CKA_EC_PARAMS,
4785                                  sftk_item_expand(&lpk->u.ec.ecParams.DEREncoding));
4786             if(crv != CKR_OK) break;
4787             crv = sftk_AddAttributeType(key, CKA_VALUE, 
4788                         sftk_item_expand(&lpk->u.ec.privateValue));
4789             if(crv != CKR_OK) break;
4790             /* XXX Do we need to decode the EC Params here ?? */
4791             break;
4792 #endif /* NSS_ENABLE_ECC */
4793         default:
4794             crv = CKR_KEY_TYPE_INCONSISTENT;
4795             break;
4796     }
4797
4798 loser:
4799     if(lpk) {
4800         nsslowkey_DestroyPrivateKey(lpk);
4801     }
4802
4803     if(crv != CKR_OK) {
4804         return SECFailure;
4805     }
4806
4807     return SECSuccess;
4808 }
4809
4810
4811 /* NSC_UnwrapKey unwraps (decrypts) a wrapped key, creating a new key object. */
4812 CK_RV NSC_UnwrapKey(CK_SESSION_HANDLE hSession,
4813     CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey,
4814     CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen,
4815     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
4816                                                  CK_OBJECT_HANDLE_PTR phKey)
4817 {
4818     SFTKObject *key = NULL;
4819     SFTKSession *session;
4820     CK_ULONG key_length = 0;
4821     unsigned char * buf = NULL;
4822     CK_RV crv = CKR_OK;
4823     int i;
4824     CK_ULONG bsize = ulWrappedKeyLen;
4825     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
4826     SECItem bpki;
4827     CK_OBJECT_CLASS target_type = CKO_SECRET_KEY;
4828
4829     CHECK_FORK();
4830
4831     if (!slot) {
4832         return CKR_SESSION_HANDLE_INVALID;
4833     }
4834     /*
4835      * now lets create an object to hang the attributes off of
4836      */
4837     key = sftk_NewObject(slot); /* fill in the handle later */
4838     if (key == NULL) {
4839         return CKR_HOST_MEMORY;
4840     }
4841
4842     /*
4843      * load the template values into the object
4844      */
4845     for (i=0; i < (int) ulAttributeCount; i++) {
4846         if (pTemplate[i].type == CKA_VALUE_LEN) {
4847             key_length = *(CK_ULONG *)pTemplate[i].pValue;
4848             continue;
4849         }
4850         if (pTemplate[i].type == CKA_CLASS) {
4851             target_type = *(CK_OBJECT_CLASS *)pTemplate[i].pValue;
4852         }
4853         crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i]));
4854         if (crv != CKR_OK) break;
4855     }
4856     if (crv != CKR_OK) {
4857         sftk_FreeObject(key);
4858         return crv;
4859     }
4860
4861     crv = sftk_CryptInit(hSession,pMechanism,hUnwrappingKey,CKA_UNWRAP,
4862                                         CKA_UNWRAP, SFTK_DECRYPT, PR_FALSE);
4863     if (crv != CKR_OK) {
4864         sftk_FreeObject(key);
4865         return sftk_mapWrap(crv);
4866     }
4867
4868     /* allocate the buffer to decrypt into 
4869      * this assumes the unwrapped key is never larger than the
4870      * wrapped key. For all the mechanisms we support this is true */
4871     buf = (unsigned char *)PORT_Alloc( ulWrappedKeyLen);
4872     bsize = ulWrappedKeyLen;
4873
4874     crv = NSC_Decrypt(hSession, pWrappedKey, ulWrappedKeyLen, buf, &bsize);
4875     if (crv != CKR_OK) {
4876         sftk_FreeObject(key);
4877         PORT_Free(buf);
4878         return sftk_mapWrap(crv);
4879     }
4880
4881     switch(target_type) {
4882         case CKO_SECRET_KEY:
4883             if (!sftk_hasAttribute(key,CKA_KEY_TYPE)) {
4884                 crv = CKR_TEMPLATE_INCOMPLETE;
4885                 break;
4886             }
4887
4888             if (key_length == 0 || key_length > bsize) {
4889                 key_length = bsize;
4890             }
4891             if (key_length > MAX_KEY_LEN) {
4892                 crv = CKR_TEMPLATE_INCONSISTENT;
4893                 break;
4894             }
4895     
4896             /* add the value */
4897             crv = sftk_AddAttributeType(key,CKA_VALUE,buf,key_length);
4898             break;
4899         case CKO_PRIVATE_KEY:
4900             bpki.data = (unsigned char *)buf;
4901             bpki.len = bsize;
4902             crv = CKR_OK;
4903             if(sftk_unwrapPrivateKey(key, &bpki) != SECSuccess) {
4904                 crv = CKR_TEMPLATE_INCOMPLETE;
4905             }
4906             break;
4907         default:
4908             crv = CKR_TEMPLATE_INCONSISTENT;
4909             break;
4910     }
4911
4912     PORT_ZFree(buf, bsize);
4913     if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
4914
4915     /* get the session */
4916     session = sftk_SessionFromHandle(hSession);
4917     if (session == NULL) {
4918         sftk_FreeObject(key);
4919         return CKR_SESSION_HANDLE_INVALID;
4920     }
4921
4922     /*
4923      * handle the base object stuff
4924      */
4925     crv = sftk_handleObject(key,session);
4926     *phKey = key->handle;
4927     sftk_FreeSession(session);
4928     sftk_FreeObject(key);
4929
4930     return crv;
4931
4932 }
4933
4934 /*
4935  * The SSL key gen mechanism create's lots of keys. This function handles the
4936  * details of each of these key creation.
4937  */
4938 static CK_RV
4939 sftk_buildSSLKey(CK_SESSION_HANDLE hSession, SFTKObject *baseKey, 
4940     PRBool isMacKey, unsigned char *keyBlock, unsigned int keySize,
4941                                                  CK_OBJECT_HANDLE *keyHandle)
4942 {
4943     SFTKObject *key;
4944     SFTKSession *session;
4945     CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
4946     CK_BBOOL cktrue = CK_TRUE;
4947     CK_BBOOL ckfalse = CK_FALSE;
4948     CK_RV crv = CKR_HOST_MEMORY;
4949
4950     /*
4951      * now lets create an object to hang the attributes off of
4952      */
4953     *keyHandle = CK_INVALID_HANDLE;
4954     key = sftk_NewObject(baseKey->slot); 
4955     if (key == NULL) return CKR_HOST_MEMORY;
4956     sftk_narrowToSessionObject(key)->wasDerived = PR_TRUE;
4957
4958     crv = sftk_CopyObject(key,baseKey);
4959     if (crv != CKR_OK) goto loser;
4960     if (isMacKey) {
4961         crv = sftk_forceAttribute(key,CKA_KEY_TYPE,&keyType,sizeof(keyType));
4962         if (crv != CKR_OK) goto loser;
4963         crv = sftk_forceAttribute(key,CKA_DERIVE,&cktrue,sizeof(CK_BBOOL));
4964         if (crv != CKR_OK) goto loser;
4965         crv = sftk_forceAttribute(key,CKA_ENCRYPT,&ckfalse,sizeof(CK_BBOOL));
4966         if (crv != CKR_OK) goto loser;
4967         crv = sftk_forceAttribute(key,CKA_DECRYPT,&ckfalse,sizeof(CK_BBOOL));
4968         if (crv != CKR_OK) goto loser;
4969         crv = sftk_forceAttribute(key,CKA_SIGN,&cktrue,sizeof(CK_BBOOL));
4970         if (crv != CKR_OK) goto loser;
4971         crv = sftk_forceAttribute(key,CKA_VERIFY,&cktrue,sizeof(CK_BBOOL));
4972         if (crv != CKR_OK) goto loser;
4973         crv = sftk_forceAttribute(key,CKA_WRAP,&ckfalse,sizeof(CK_BBOOL));
4974         if (crv != CKR_OK) goto loser;
4975         crv = sftk_forceAttribute(key,CKA_UNWRAP,&ckfalse,sizeof(CK_BBOOL));
4976         if (crv != CKR_OK) goto loser;
4977     }
4978     crv = sftk_forceAttribute(key,CKA_VALUE,keyBlock,keySize);
4979     if (crv != CKR_OK) goto loser;
4980
4981     /* get the session */
4982     crv = CKR_HOST_MEMORY;
4983     session = sftk_SessionFromHandle(hSession);
4984     if (session == NULL) { goto loser; }
4985
4986     crv = sftk_handleObject(key,session);
4987     sftk_FreeSession(session);
4988     *keyHandle = key->handle;
4989 loser:
4990     if (key) sftk_FreeObject(key);
4991     return crv;
4992 }
4993
4994 /*
4995  * if there is an error, we need to free the keys we already created in SSL
4996  * This is the routine that will do it..
4997  */
4998 static void
4999 sftk_freeSSLKeys(CK_SESSION_HANDLE session,
5000                                 CK_SSL3_KEY_MAT_OUT *returnedMaterial ) 
5001 {
5002         if (returnedMaterial->hClientMacSecret != CK_INVALID_HANDLE) {
5003            NSC_DestroyObject(session,returnedMaterial->hClientMacSecret);
5004         }
5005         if (returnedMaterial->hServerMacSecret != CK_INVALID_HANDLE) {
5006            NSC_DestroyObject(session, returnedMaterial->hServerMacSecret);
5007         }
5008         if (returnedMaterial->hClientKey != CK_INVALID_HANDLE) {
5009            NSC_DestroyObject(session, returnedMaterial->hClientKey);
5010         }
5011         if (returnedMaterial->hServerKey != CK_INVALID_HANDLE) {
5012            NSC_DestroyObject(session, returnedMaterial->hServerKey);
5013         }
5014 }
5015
5016 /*
5017  * when deriving from sensitive and extractable keys, we need to preserve some
5018  * of the semantics in the derived key. This helper routine maintains these
5019  * semantics.
5020  */
5021 static CK_RV
5022 sftk_DeriveSensitiveCheck(SFTKObject *baseKey,SFTKObject *destKey) 
5023 {
5024     PRBool hasSensitive;
5025     PRBool sensitive = PR_FALSE;
5026     PRBool hasExtractable;
5027     PRBool extractable = PR_TRUE;
5028     CK_RV crv = CKR_OK;
5029     SFTKAttribute *att;
5030
5031     hasSensitive = PR_FALSE;
5032     att = sftk_FindAttribute(destKey,CKA_SENSITIVE);
5033     if (att) {
5034         hasSensitive = PR_TRUE;
5035         sensitive = (PRBool) *(CK_BBOOL *)att->attrib.pValue;
5036         sftk_FreeAttribute(att);
5037     }
5038
5039     hasExtractable = PR_FALSE;
5040     att = sftk_FindAttribute(destKey,CKA_EXTRACTABLE);
5041     if (att) {
5042         hasExtractable = PR_TRUE;
5043         extractable = (PRBool) *(CK_BBOOL *)att->attrib.pValue;
5044         sftk_FreeAttribute(att);
5045     }
5046
5047
5048     /* don't make a key more accessible */
5049     if (sftk_isTrue(baseKey,CKA_SENSITIVE) && hasSensitive && 
5050                                                 (sensitive == PR_FALSE)) {
5051         return CKR_KEY_FUNCTION_NOT_PERMITTED;
5052     }
5053     if (!sftk_isTrue(baseKey,CKA_EXTRACTABLE) && hasExtractable && 
5054                                                 (extractable == PR_TRUE)) {
5055         return CKR_KEY_FUNCTION_NOT_PERMITTED;
5056     }
5057
5058     /* inherit parent's sensitivity */
5059     if (!hasSensitive) {
5060         att = sftk_FindAttribute(baseKey,CKA_SENSITIVE);
5061         if (att == NULL) return CKR_KEY_TYPE_INCONSISTENT;
5062         crv = sftk_defaultAttribute(destKey,sftk_attr_expand(&att->attrib));
5063         sftk_FreeAttribute(att);
5064         if (crv != CKR_OK) return crv;
5065     }
5066     if (!hasExtractable) {
5067         att = sftk_FindAttribute(baseKey,CKA_EXTRACTABLE);
5068         if (att == NULL) return CKR_KEY_TYPE_INCONSISTENT;
5069         crv = sftk_defaultAttribute(destKey,sftk_attr_expand(&att->attrib));
5070         sftk_FreeAttribute(att);
5071         if (crv != CKR_OK) return crv;
5072     }
5073
5074     /* we should inherit the parent's always extractable/ never sensitive info,
5075      * but handleObject always forces this attributes, so we would need to do
5076      * something special. */
5077     return CKR_OK;
5078 }
5079
5080 /*
5081  * make known fixed PKCS #11 key types to their sizes in bytes
5082  */     
5083 unsigned long
5084 sftk_MapKeySize(CK_KEY_TYPE keyType) 
5085 {
5086     switch (keyType) {
5087     case CKK_CDMF:
5088         return 8;
5089     case CKK_DES:
5090         return 8;
5091     case CKK_DES2:
5092         return 16;
5093     case CKK_DES3:
5094         return 24;
5095     /* IDEA and CAST need to be added */
5096     default:
5097         break;
5098     }
5099     return 0;
5100 }
5101
5102 /*
5103  * SSL Key generation given pre master secret
5104  */
5105 #define NUM_MIXERS 9
5106 static const char * const mixers[NUM_MIXERS] = { 
5107     "A", 
5108     "BB", 
5109     "CCC", 
5110     "DDDD", 
5111     "EEEEE", 
5112     "FFFFFF", 
5113     "GGGGGGG",
5114     "HHHHHHHH",
5115     "IIIIIIIII" };
5116 #define SSL3_PMS_LENGTH 48
5117 #define SSL3_MASTER_SECRET_LENGTH 48
5118 #define SSL3_RANDOM_LENGTH 32
5119
5120
5121 /* NSC_DeriveKey derives a key from a base key, creating a new key object. */
5122 CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession,
5123          CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey,
5124          CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, 
5125                                                 CK_OBJECT_HANDLE_PTR phKey)
5126 {
5127     SFTKSession *   session;
5128     SFTKSlot    *   slot        = sftk_SlotFromSessionHandle(hSession);
5129     SFTKObject  *   key;
5130     SFTKObject  *   sourceKey;
5131     SFTKAttribute * att = NULL;
5132     SFTKAttribute * att2 = NULL;
5133     unsigned char * buf;
5134     SHA1Context *   sha;
5135     MD5Context *    md5;
5136     MD2Context *    md2;
5137     CK_ULONG        macSize;
5138     CK_ULONG        tmpKeySize;
5139     CK_ULONG        IVSize;
5140     CK_ULONG        keySize     = 0;
5141     CK_RV           crv         = CKR_OK;
5142     CK_BBOOL        cktrue      = CK_TRUE;
5143     CK_KEY_TYPE     keyType     = CKK_GENERIC_SECRET;
5144     CK_OBJECT_CLASS classType   = CKO_SECRET_KEY;
5145     CK_KEY_DERIVATION_STRING_DATA *stringPtr;
5146     PRBool          isTLS = PR_FALSE;
5147     PRBool          isDH = PR_FALSE;
5148     SECStatus       rv;
5149     int             i;
5150     unsigned int    outLen;
5151     unsigned char   sha_out[SHA1_LENGTH];
5152     unsigned char   key_block[NUM_MIXERS * MD5_LENGTH];
5153     unsigned char   key_block2[MD5_LENGTH];
5154     PRBool          isFIPS;             
5155     HASH_HashType   hashType;
5156     PRBool          extractValue = PR_TRUE;
5157
5158     CHECK_FORK();
5159
5160     if (!slot) {
5161         return CKR_SESSION_HANDLE_INVALID;
5162     }
5163     /*
5164      * now lets create an object to hang the attributes off of
5165      */
5166     if (phKey) *phKey = CK_INVALID_HANDLE;
5167
5168     key = sftk_NewObject(slot); /* fill in the handle later */
5169     if (key == NULL) {
5170         return CKR_HOST_MEMORY;
5171     }
5172     isFIPS = (slot->slotID == FIPS_SLOT_ID);
5173
5174     /*
5175      * load the template values into the object
5176      */
5177     for (i=0; i < (int) ulAttributeCount; i++) {
5178         crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i]));
5179         if (crv != CKR_OK) break;
5180
5181         if (pTemplate[i].type == CKA_KEY_TYPE) {
5182             keyType = *(CK_KEY_TYPE *)pTemplate[i].pValue;
5183         }
5184         if (pTemplate[i].type == CKA_VALUE_LEN) {
5185             keySize = *(CK_ULONG *)pTemplate[i].pValue;
5186         }
5187     }
5188     if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
5189
5190     if (keySize == 0) {
5191         keySize = sftk_MapKeySize(keyType);
5192     }
5193
5194     switch (pMechanism->mechanism) {
5195       case CKM_NSS_JPAKE_ROUND2_SHA1:   /* fall through */
5196       case CKM_NSS_JPAKE_ROUND2_SHA256: /* fall through */
5197       case CKM_NSS_JPAKE_ROUND2_SHA384: /* fall through */
5198       case CKM_NSS_JPAKE_ROUND2_SHA512:
5199           extractValue = PR_FALSE;
5200           classType = CKO_PRIVATE_KEY;
5201           break;
5202       case CKM_NSS_JPAKE_FINAL_SHA1:   /* fall through */
5203       case CKM_NSS_JPAKE_FINAL_SHA256: /* fall through */
5204       case CKM_NSS_JPAKE_FINAL_SHA384: /* fall through */
5205       case CKM_NSS_JPAKE_FINAL_SHA512:
5206           extractValue = PR_FALSE;
5207           /* fall through */
5208       default:
5209           classType = CKO_SECRET_KEY;
5210     }
5211     
5212     crv = sftk_forceAttribute (key,CKA_CLASS,&classType,sizeof(classType));
5213     if (crv != CKR_OK) {
5214         sftk_FreeObject(key);
5215         return crv;
5216     }
5217
5218     /* look up the base key we're deriving with */ 
5219     session = sftk_SessionFromHandle(hSession);
5220     if (session == NULL) {
5221         sftk_FreeObject(key);
5222         return CKR_SESSION_HANDLE_INVALID;
5223     }
5224
5225     sourceKey = sftk_ObjectFromHandle(hBaseKey,session);
5226     sftk_FreeSession(session);
5227     if (sourceKey == NULL) {
5228         sftk_FreeObject(key);
5229         return CKR_KEY_HANDLE_INVALID;
5230     }
5231
5232     if (extractValue) {
5233         /* get the value of the base key */
5234         att = sftk_FindAttribute(sourceKey,CKA_VALUE);
5235         if (att == NULL) {
5236             sftk_FreeObject(key);
5237             sftk_FreeObject(sourceKey);
5238             return CKR_KEY_HANDLE_INVALID;
5239         }
5240     }
5241
5242     switch (pMechanism->mechanism) {
5243     /*
5244      * generate the master secret 
5245      */
5246     case CKM_TLS_MASTER_KEY_DERIVE:
5247     case CKM_TLS_MASTER_KEY_DERIVE_DH:
5248         isTLS = PR_TRUE;
5249         /* fall thru */
5250     case CKM_SSL3_MASTER_KEY_DERIVE:
5251     case CKM_SSL3_MASTER_KEY_DERIVE_DH:
5252       {
5253         CK_SSL3_MASTER_KEY_DERIVE_PARAMS *ssl3_master;
5254         SSL3RSAPreMasterSecret *          rsa_pms;
5255         unsigned char                     crsrdata[SSL3_RANDOM_LENGTH * 2];
5256
5257         if ((pMechanism->mechanism == CKM_SSL3_MASTER_KEY_DERIVE_DH) ||
5258             (pMechanism->mechanism == CKM_TLS_MASTER_KEY_DERIVE_DH))
5259                 isDH = PR_TRUE;
5260
5261         /* first do the consistancy checks */
5262         if (!isDH && (att->attrib.ulValueLen != SSL3_PMS_LENGTH)) {
5263             crv = CKR_KEY_TYPE_INCONSISTENT;
5264             break;
5265         }
5266         att2 = sftk_FindAttribute(sourceKey,CKA_KEY_TYPE);
5267         if ((att2 == NULL) || (*(CK_KEY_TYPE *)att2->attrib.pValue !=
5268                                         CKK_GENERIC_SECRET)) {
5269             if (att2) sftk_FreeAttribute(att2);
5270             crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
5271             break;
5272         }
5273         sftk_FreeAttribute(att2);
5274         if (keyType != CKK_GENERIC_SECRET) {
5275             crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
5276             break;
5277         }
5278         if ((keySize != 0) && (keySize != SSL3_MASTER_SECRET_LENGTH)) {
5279             crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
5280             break;
5281         }
5282
5283         /* finally do the key gen */
5284         ssl3_master = (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *)
5285                                         pMechanism->pParameter;
5286
5287         PORT_Memcpy(crsrdata, 
5288                     ssl3_master->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH);
5289         PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, 
5290                     ssl3_master->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
5291
5292         if (ssl3_master->pVersion) {
5293             SFTKSessionObject *sessKey = sftk_narrowToSessionObject(key);
5294             rsa_pms = (SSL3RSAPreMasterSecret *) att->attrib.pValue;
5295             /* don't leak more key material then necessary for SSL to work */
5296             if ((sessKey == NULL) || sessKey->wasDerived) {
5297                 ssl3_master->pVersion->major = 0xff;
5298                 ssl3_master->pVersion->minor = 0xff;
5299             } else {
5300                 ssl3_master->pVersion->major = rsa_pms->client_version[0];
5301                 ssl3_master->pVersion->minor = rsa_pms->client_version[1];
5302             }
5303         }
5304         if (ssl3_master->RandomInfo.ulClientRandomLen != SSL3_RANDOM_LENGTH) {
5305            crv = CKR_MECHANISM_PARAM_INVALID;
5306            break;
5307         }
5308         if (ssl3_master->RandomInfo.ulServerRandomLen != SSL3_RANDOM_LENGTH) {
5309            crv = CKR_MECHANISM_PARAM_INVALID;
5310            break;
5311         }
5312
5313         if (isTLS) {
5314             SECStatus status;
5315             SECItem crsr   = { siBuffer, NULL, 0 };
5316             SECItem master = { siBuffer, NULL, 0 };
5317             SECItem pms    = { siBuffer, NULL, 0 };
5318
5319             crsr.data   = crsrdata;
5320             crsr.len    = sizeof crsrdata;
5321             master.data = key_block;
5322             master.len  = SSL3_MASTER_SECRET_LENGTH;
5323             pms.data    = (unsigned char*)att->attrib.pValue;
5324             pms.len     =                 att->attrib.ulValueLen;
5325
5326             status = TLS_PRF(&pms, "master secret", &crsr, &master, isFIPS);
5327             if (status != SECSuccess) {
5328                 crv = CKR_FUNCTION_FAILED;
5329                 break;
5330             }
5331         } else {
5332             /* now allocate the hash contexts */
5333             md5 = MD5_NewContext();
5334             if (md5 == NULL) { 
5335                 crv = CKR_HOST_MEMORY;
5336                 break;
5337             }
5338             sha = SHA1_NewContext();
5339             if (sha == NULL) { 
5340                 PORT_Free(md5);
5341                 crv = CKR_HOST_MEMORY;
5342                 break;
5343             }
5344             for (i = 0; i < 3; i++) {
5345               SHA1_Begin(sha);
5346               SHA1_Update(sha, (unsigned char*) mixers[i], strlen(mixers[i]));
5347               SHA1_Update(sha, (const unsigned char*)att->attrib.pValue, 
5348                           att->attrib.ulValueLen);
5349               SHA1_Update(sha, crsrdata, sizeof crsrdata);
5350               SHA1_End(sha, sha_out, &outLen, SHA1_LENGTH);
5351               PORT_Assert(outLen == SHA1_LENGTH);
5352
5353               MD5_Begin(md5);
5354               MD5_Update(md5, (const unsigned char*)att->attrib.pValue, 
5355                          att->attrib.ulValueLen);
5356               MD5_Update(md5, sha_out, outLen);
5357               MD5_End(md5, &key_block[i*MD5_LENGTH], &outLen, MD5_LENGTH);
5358               PORT_Assert(outLen == MD5_LENGTH);
5359             }
5360             PORT_Free(md5);
5361             PORT_Free(sha);
5362         }
5363
5364         /* store the results */
5365         crv = sftk_forceAttribute
5366                         (key,CKA_VALUE,key_block,SSL3_MASTER_SECRET_LENGTH);
5367         if (crv != CKR_OK) break;
5368         keyType = CKK_GENERIC_SECRET;
5369         crv = sftk_forceAttribute (key,CKA_KEY_TYPE,&keyType,sizeof(keyType));
5370         if (isTLS) {
5371             /* TLS's master secret is used to "sign" finished msgs with PRF. */
5372             /* XXX This seems like a hack.   But SFTK_Derive only accepts 
5373              * one "operation" argument. */
5374             crv = sftk_forceAttribute(key,CKA_SIGN,  &cktrue,sizeof(CK_BBOOL));
5375             if (crv != CKR_OK) break;
5376             crv = sftk_forceAttribute(key,CKA_VERIFY,&cktrue,sizeof(CK_BBOOL));
5377             if (crv != CKR_OK) break;
5378             /* While we're here, we might as well force this, too. */
5379             crv = sftk_forceAttribute(key,CKA_DERIVE,&cktrue,sizeof(CK_BBOOL));
5380             if (crv != CKR_OK) break;
5381         }
5382         break;
5383       }
5384
5385     case CKM_TLS_KEY_AND_MAC_DERIVE:
5386         isTLS = PR_TRUE;
5387         /* fall thru */
5388     case CKM_SSL3_KEY_AND_MAC_DERIVE:
5389       {
5390         CK_SSL3_KEY_MAT_PARAMS *ssl3_keys;
5391         CK_SSL3_KEY_MAT_OUT *   ssl3_keys_out;
5392         CK_ULONG                effKeySize;
5393         unsigned int            block_needed;
5394         unsigned char           srcrdata[SSL3_RANDOM_LENGTH * 2];
5395         unsigned char           crsrdata[SSL3_RANDOM_LENGTH * 2];
5396
5397         crv = sftk_DeriveSensitiveCheck(sourceKey,key);
5398         if (crv != CKR_OK) break;
5399
5400         if (att->attrib.ulValueLen != SSL3_MASTER_SECRET_LENGTH) {
5401             crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
5402             break;
5403         }
5404         att2 = sftk_FindAttribute(sourceKey,CKA_KEY_TYPE);
5405         if ((att2 == NULL) || (*(CK_KEY_TYPE *)att2->attrib.pValue !=
5406                                         CKK_GENERIC_SECRET)) {
5407             if (att2) sftk_FreeAttribute(att2);
5408             crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
5409             break;
5410         }
5411         sftk_FreeAttribute(att2);
5412         md5 = MD5_NewContext();
5413         if (md5 == NULL) { 
5414             crv = CKR_HOST_MEMORY;
5415             break;
5416         }
5417         sha = SHA1_NewContext();
5418         if (sha == NULL) { 
5419             PORT_Free(md5);
5420             crv = CKR_HOST_MEMORY;
5421             break;
5422         }
5423         ssl3_keys = (CK_SSL3_KEY_MAT_PARAMS *) pMechanism->pParameter;
5424
5425         PORT_Memcpy(srcrdata, 
5426                     ssl3_keys->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
5427         PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, 
5428                     ssl3_keys->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH);
5429
5430         PORT_Memcpy(crsrdata, 
5431                     ssl3_keys->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH);
5432         PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, 
5433                     ssl3_keys->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
5434
5435         /*
5436          * clear out our returned keys so we can recover on failure
5437          */
5438         ssl3_keys_out = ssl3_keys->pReturnedKeyMaterial;
5439         ssl3_keys_out->hClientMacSecret = CK_INVALID_HANDLE;
5440         ssl3_keys_out->hServerMacSecret = CK_INVALID_HANDLE;
5441         ssl3_keys_out->hClientKey       = CK_INVALID_HANDLE;
5442         ssl3_keys_out->hServerKey       = CK_INVALID_HANDLE;
5443
5444         /*
5445          * How much key material do we need?
5446          */
5447         macSize    = ssl3_keys->ulMacSizeInBits/8;
5448         effKeySize = ssl3_keys->ulKeySizeInBits/8;
5449         IVSize     = ssl3_keys->ulIVSizeInBits/8;
5450         if (keySize == 0) {
5451             effKeySize = keySize;
5452         }
5453         block_needed = 2 * (macSize + effKeySize + 
5454                             ((!ssl3_keys->bIsExport) * IVSize));
5455         PORT_Assert(block_needed <= sizeof key_block);
5456         if (block_needed > sizeof key_block)
5457             block_needed = sizeof key_block;
5458
5459         /*
5460          * generate the key material: This looks amazingly similar to the
5461          * PMS code, and is clearly crying out for a function to provide it.
5462          */
5463         if (isTLS) {
5464             SECStatus     status;
5465             SECItem       srcr   = { siBuffer, NULL, 0 };
5466             SECItem       keyblk = { siBuffer, NULL, 0 };
5467             SECItem       master = { siBuffer, NULL, 0 }; 
5468
5469             srcr.data   = srcrdata;
5470             srcr.len    = sizeof srcrdata;
5471             keyblk.data = key_block;
5472             keyblk.len  = block_needed;
5473             master.data = (unsigned char*)att->attrib.pValue;
5474             master.len  =                 att->attrib.ulValueLen;
5475
5476             status = TLS_PRF(&master, "key expansion", &srcr, &keyblk,
5477                               isFIPS);
5478             if (status != SECSuccess) {
5479                 goto key_and_mac_derive_fail;
5480             }
5481         } else {
5482             unsigned int block_bytes = 0;
5483             /* key_block = 
5484              *     MD5(master_secret + SHA('A' + master_secret + 
5485              *                      ServerHello.random + ClientHello.random)) +
5486              *     MD5(master_secret + SHA('BB' + master_secret + 
5487              *                      ServerHello.random + ClientHello.random)) +
5488              *     MD5(master_secret + SHA('CCC' + master_secret + 
5489              *                      ServerHello.random + ClientHello.random)) +
5490              *     [...];
5491              */
5492             for (i = 0; i < NUM_MIXERS && block_bytes < block_needed; i++) {
5493               SHA1_Begin(sha);
5494               SHA1_Update(sha, (unsigned char*) mixers[i], strlen(mixers[i]));
5495               SHA1_Update(sha, (const unsigned char*)att->attrib.pValue, 
5496                           att->attrib.ulValueLen);
5497               SHA1_Update(sha, srcrdata, sizeof srcrdata);
5498               SHA1_End(sha, sha_out, &outLen, SHA1_LENGTH);
5499               PORT_Assert(outLen == SHA1_LENGTH);
5500               MD5_Begin(md5);
5501               MD5_Update(md5, (const unsigned char*)att->attrib.pValue,
5502                          att->attrib.ulValueLen);
5503               MD5_Update(md5, sha_out, outLen);
5504               MD5_End(md5, &key_block[i*MD5_LENGTH], &outLen, MD5_LENGTH);
5505               PORT_Assert(outLen == MD5_LENGTH);
5506               block_bytes += outLen;
5507             }
5508         }
5509
5510         /*
5511          * Put the key material where it goes.
5512          */
5513         i = 0;                  /* now shows how much consumed */
5514
5515         /* 
5516          * The key_block is partitioned as follows:
5517          * client_write_MAC_secret[CipherSpec.hash_size]
5518          */
5519         crv = sftk_buildSSLKey(hSession,key,PR_TRUE,&key_block[i],macSize,
5520                                          &ssl3_keys_out->hClientMacSecret);
5521         if (crv != CKR_OK)
5522             goto key_and_mac_derive_fail;
5523
5524         i += macSize;
5525
5526         /* 
5527          * server_write_MAC_secret[CipherSpec.hash_size]
5528          */
5529         crv = sftk_buildSSLKey(hSession,key,PR_TRUE,&key_block[i],macSize,
5530                                             &ssl3_keys_out->hServerMacSecret);
5531         if (crv != CKR_OK) {
5532             goto key_and_mac_derive_fail;
5533         }
5534         i += macSize;
5535
5536         if (keySize) {
5537             if (!ssl3_keys->bIsExport) {
5538                 /* 
5539                 ** Generate Domestic write keys and IVs.
5540                 ** client_write_key[CipherSpec.key_material]
5541                 */
5542                 crv = sftk_buildSSLKey(hSession,key,PR_FALSE,&key_block[i],
5543                                         keySize, &ssl3_keys_out->hClientKey);
5544                 if (crv != CKR_OK) {
5545                     goto key_and_mac_derive_fail;
5546                 }
5547                 i += keySize;
5548
5549                 /* 
5550                 ** server_write_key[CipherSpec.key_material]
5551                 */
5552                 crv = sftk_buildSSLKey(hSession,key,PR_FALSE,&key_block[i],
5553                                         keySize, &ssl3_keys_out->hServerKey);
5554                 if (crv != CKR_OK) {
5555                     goto key_and_mac_derive_fail;
5556                 }
5557                 i += keySize;
5558
5559                 /* 
5560                 ** client_write_IV[CipherSpec.IV_size]
5561                 */
5562                 if (IVSize > 0) {
5563                     PORT_Memcpy(ssl3_keys_out->pIVClient, 
5564                                 &key_block[i], IVSize);
5565                     i += IVSize;
5566                 }
5567
5568                 /* 
5569                 ** server_write_IV[CipherSpec.IV_size]
5570                 */
5571                 if (IVSize > 0) {
5572                     PORT_Memcpy(ssl3_keys_out->pIVServer, 
5573                                 &key_block[i], IVSize);
5574                     i += IVSize;
5575                 }
5576                 PORT_Assert(i <= sizeof key_block);
5577
5578             } else if (!isTLS) {
5579
5580                 /*
5581                 ** Generate SSL3 Export write keys and IVs.
5582                 ** client_write_key[CipherSpec.key_material]
5583                 ** final_client_write_key = MD5(client_write_key +
5584                 **                   ClientHello.random + ServerHello.random);
5585                 */
5586                 MD5_Begin(md5);
5587                 MD5_Update(md5, &key_block[i], effKeySize);
5588                 MD5_Update(md5, crsrdata, sizeof crsrdata);
5589                 MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
5590                 i += effKeySize;
5591                 crv = sftk_buildSSLKey(hSession,key,PR_FALSE,key_block2,
5592                                         keySize,&ssl3_keys_out->hClientKey);
5593                 if (crv != CKR_OK) {
5594                     goto key_and_mac_derive_fail;
5595                 }
5596
5597                 /*
5598                 ** server_write_key[CipherSpec.key_material]
5599                 ** final_server_write_key = MD5(server_write_key +
5600                 **                    ServerHello.random + ClientHello.random);
5601                 */
5602                 MD5_Begin(md5);
5603                 MD5_Update(md5, &key_block[i], effKeySize);
5604                 MD5_Update(md5, srcrdata, sizeof srcrdata);
5605                 MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
5606                 i += effKeySize;
5607                 crv = sftk_buildSSLKey(hSession,key,PR_FALSE,key_block2,
5608                                          keySize,&ssl3_keys_out->hServerKey);
5609                 if (crv != CKR_OK) {
5610                     goto key_and_mac_derive_fail;
5611                 }
5612
5613                 /*
5614                 ** client_write_IV = 
5615                 **      MD5(ClientHello.random + ServerHello.random);
5616                 */
5617                 MD5_Begin(md5);
5618                 MD5_Update(md5, crsrdata, sizeof crsrdata);
5619                 MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
5620                 PORT_Memcpy(ssl3_keys_out->pIVClient, key_block2, IVSize);
5621
5622                 /*
5623                 ** server_write_IV = 
5624                 **      MD5(ServerHello.random + ClientHello.random);
5625                 */
5626                 MD5_Begin(md5);
5627                 MD5_Update(md5, srcrdata, sizeof srcrdata);
5628                 MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
5629                 PORT_Memcpy(ssl3_keys_out->pIVServer, key_block2, IVSize);
5630
5631             } else {
5632
5633                 /*
5634                 ** Generate TLS Export write keys and IVs.
5635                 */
5636                 SECStatus     status;
5637                 SECItem       secret = { siBuffer, NULL, 0 };
5638                 SECItem       crsr   = { siBuffer, NULL, 0 };
5639                 SECItem       keyblk = { siBuffer, NULL, 0 };
5640
5641                 /*
5642                 ** client_write_key[CipherSpec.key_material]
5643                 ** final_client_write_key = PRF(client_write_key, 
5644                 **                              "client write key",
5645                 **                              client_random + server_random);
5646                 */
5647                 secret.data = &key_block[i];
5648                 secret.len  = effKeySize;
5649                 i          += effKeySize;
5650                 crsr.data   = crsrdata;
5651                 crsr.len    = sizeof crsrdata;
5652                 keyblk.data = key_block2;
5653                 keyblk.len  = sizeof key_block2;
5654                 status = TLS_PRF(&secret, "client write key", &crsr, &keyblk,
5655                                   isFIPS);
5656                 if (status != SECSuccess) {
5657                     goto key_and_mac_derive_fail;
5658                 }
5659                 crv = sftk_buildSSLKey(hSession, key, PR_FALSE, key_block2, 
5660                                        keySize, &ssl3_keys_out->hClientKey);
5661                 if (crv != CKR_OK) {
5662                     goto key_and_mac_derive_fail;
5663                 }
5664
5665                 /*
5666                 ** server_write_key[CipherSpec.key_material]
5667                 ** final_server_write_key = PRF(server_write_key,
5668                 **                              "server write key",
5669                 **                              client_random + server_random);
5670                 */
5671                 secret.data = &key_block[i];
5672                 secret.len  = effKeySize;
5673                 i          += effKeySize;
5674                 keyblk.data = key_block2;
5675                 keyblk.len  = sizeof key_block2;
5676                 status = TLS_PRF(&secret, "server write key", &crsr, &keyblk,
5677                                   isFIPS);
5678                 if (status != SECSuccess) {
5679                     goto key_and_mac_derive_fail;
5680                 }
5681                 crv = sftk_buildSSLKey(hSession, key, PR_FALSE, key_block2, 
5682                                        keySize, &ssl3_keys_out->hServerKey);
5683                 if (crv != CKR_OK) {
5684                     goto key_and_mac_derive_fail;
5685                 }
5686
5687                 /*
5688                 ** iv_block = PRF("", "IV block", 
5689                 **                    client_random + server_random);
5690                 ** client_write_IV[SecurityParameters.IV_size]
5691                 ** server_write_IV[SecurityParameters.IV_size]
5692                 */
5693                 if (IVSize) {
5694                     secret.data = NULL;
5695                     secret.len  = 0;
5696                     keyblk.data = &key_block[i];
5697                     keyblk.len  = 2 * IVSize;
5698                     status = TLS_PRF(&secret, "IV block", &crsr, &keyblk,
5699                                       isFIPS);
5700                     if (status != SECSuccess) {
5701                         goto key_and_mac_derive_fail;
5702                     }
5703                     PORT_Memcpy(ssl3_keys_out->pIVClient, keyblk.data, IVSize);
5704                     PORT_Memcpy(ssl3_keys_out->pIVServer, keyblk.data + IVSize,
5705                                 IVSize);
5706                 }
5707             }
5708         }
5709
5710         crv = CKR_OK;
5711
5712         if (0) {
5713 key_and_mac_derive_fail:
5714             if (crv == CKR_OK)
5715                 crv = CKR_FUNCTION_FAILED;
5716             sftk_freeSSLKeys(hSession, ssl3_keys_out);
5717         }
5718         MD5_DestroyContext(md5, PR_TRUE);
5719         SHA1_DestroyContext(sha, PR_TRUE);
5720         sftk_FreeObject(key);
5721         key = NULL;
5722         break;
5723       }
5724
5725     case CKM_CONCATENATE_BASE_AND_KEY:
5726       {
5727         SFTKObject *newKey;
5728
5729         crv = sftk_DeriveSensitiveCheck(sourceKey,key);
5730         if (crv != CKR_OK) break;
5731
5732         session = sftk_SessionFromHandle(hSession);
5733         if (session == NULL) {
5734             crv = CKR_SESSION_HANDLE_INVALID;
5735             break;
5736         }
5737
5738         newKey = sftk_ObjectFromHandle(*(CK_OBJECT_HANDLE *)
5739                                         pMechanism->pParameter,session);
5740         sftk_FreeSession(session);
5741         if ( newKey == NULL) {
5742             crv = CKR_KEY_HANDLE_INVALID;
5743             break;
5744         }
5745
5746         if (sftk_isTrue(newKey,CKA_SENSITIVE)) {
5747             crv = sftk_forceAttribute(newKey,CKA_SENSITIVE,&cktrue,
5748                                                         sizeof(CK_BBOOL));
5749             if (crv != CKR_OK) {
5750                 sftk_FreeObject(newKey);
5751                 break;
5752             }
5753         }
5754
5755         att2 = sftk_FindAttribute(newKey,CKA_VALUE);
5756         if (att2 == NULL) {
5757             sftk_FreeObject(newKey);
5758             crv = CKR_KEY_HANDLE_INVALID;
5759             break;
5760         }
5761         tmpKeySize = att->attrib.ulValueLen+att2->attrib.ulValueLen;
5762         if (keySize == 0) keySize = tmpKeySize;
5763         if (keySize > tmpKeySize) {
5764             sftk_FreeObject(newKey);
5765             sftk_FreeAttribute(att2);
5766             crv = CKR_TEMPLATE_INCONSISTENT;
5767             break;
5768         }
5769         buf = (unsigned char*)PORT_Alloc(tmpKeySize);
5770         if (buf == NULL) {
5771             sftk_FreeAttribute(att2);
5772             sftk_FreeObject(newKey);
5773             crv = CKR_HOST_MEMORY;      
5774             break;
5775         }
5776
5777         PORT_Memcpy(buf,att->attrib.pValue,att->attrib.ulValueLen);
5778         PORT_Memcpy(buf+att->attrib.ulValueLen,
5779                                 att2->attrib.pValue,att2->attrib.ulValueLen);
5780
5781         crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
5782         PORT_ZFree(buf,tmpKeySize);
5783         sftk_FreeAttribute(att2);
5784         sftk_FreeObject(newKey);
5785         break;
5786       }
5787
5788     case CKM_CONCATENATE_BASE_AND_DATA:
5789         crv = sftk_DeriveSensitiveCheck(sourceKey,key);
5790         if (crv != CKR_OK) break;
5791
5792         stringPtr = (CK_KEY_DERIVATION_STRING_DATA *) pMechanism->pParameter;
5793         tmpKeySize = att->attrib.ulValueLen+stringPtr->ulLen;
5794         if (keySize == 0) keySize = tmpKeySize;
5795         if (keySize > tmpKeySize) {
5796             crv = CKR_TEMPLATE_INCONSISTENT;
5797             break;
5798         }
5799         buf = (unsigned char*)PORT_Alloc(tmpKeySize);
5800         if (buf == NULL) {
5801             crv = CKR_HOST_MEMORY;
5802             break;
5803         }
5804
5805         PORT_Memcpy(buf,att->attrib.pValue,att->attrib.ulValueLen);
5806         PORT_Memcpy(buf+att->attrib.ulValueLen,stringPtr->pData,
5807                                                         stringPtr->ulLen);
5808
5809         crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
5810         PORT_ZFree(buf,tmpKeySize);
5811         break;
5812     case CKM_CONCATENATE_DATA_AND_BASE:
5813         crv = sftk_DeriveSensitiveCheck(sourceKey,key);
5814         if (crv != CKR_OK) break;
5815
5816         stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
5817         tmpKeySize = att->attrib.ulValueLen+stringPtr->ulLen;
5818         if (keySize == 0) keySize = tmpKeySize;
5819         if (keySize > tmpKeySize) {
5820             crv = CKR_TEMPLATE_INCONSISTENT;
5821             break;
5822         }
5823         buf = (unsigned char*)PORT_Alloc(tmpKeySize);
5824         if (buf == NULL) {
5825             crv = CKR_HOST_MEMORY;
5826             break;
5827         }
5828
5829         PORT_Memcpy(buf,stringPtr->pData,stringPtr->ulLen);
5830         PORT_Memcpy(buf+stringPtr->ulLen,att->attrib.pValue,
5831                                                         att->attrib.ulValueLen);
5832
5833         crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
5834         PORT_ZFree(buf,tmpKeySize);
5835         break;
5836     case CKM_XOR_BASE_AND_DATA:
5837         crv = sftk_DeriveSensitiveCheck(sourceKey,key);
5838         if (crv != CKR_OK) break;
5839
5840         stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
5841         tmpKeySize = PR_MIN(att->attrib.ulValueLen,stringPtr->ulLen);
5842         if (keySize == 0) keySize = tmpKeySize;
5843         if (keySize > tmpKeySize) {
5844             crv = CKR_TEMPLATE_INCONSISTENT;
5845             break;
5846         }
5847         buf = (unsigned char*)PORT_Alloc(keySize);
5848         if (buf == NULL) {
5849             crv = CKR_HOST_MEMORY;
5850             break;
5851         }
5852
5853         
5854         PORT_Memcpy(buf,att->attrib.pValue,keySize);
5855         for (i=0; i < (int)keySize; i++) {
5856             buf[i] ^= stringPtr->pData[i];
5857         }
5858
5859         crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
5860         PORT_ZFree(buf,keySize);
5861         break;
5862
5863     case CKM_EXTRACT_KEY_FROM_KEY:
5864       {
5865         /* the following assumes 8 bits per byte */
5866         CK_ULONG extract = *(CK_EXTRACT_PARAMS *)pMechanism->pParameter;
5867         CK_ULONG shift   = extract & 0x7;      /* extract mod 8 the fast way */
5868         CK_ULONG offset  = extract >> 3;       /* extract div 8 the fast way */
5869
5870         crv = sftk_DeriveSensitiveCheck(sourceKey,key);
5871         if (crv != CKR_OK) break;
5872
5873         if (keySize == 0)  {
5874             crv = CKR_TEMPLATE_INCOMPLETE;
5875             break;
5876         }
5877         /* make sure we have enough bits in the original key */
5878         if (att->attrib.ulValueLen < 
5879                         (offset + keySize + ((shift != 0)? 1 :0)) ) {
5880             crv = CKR_MECHANISM_PARAM_INVALID;
5881             break;
5882         }
5883         buf = (unsigned char*)PORT_Alloc(keySize);
5884         if (buf == NULL) {
5885             crv = CKR_HOST_MEMORY;
5886             break;
5887         }
5888
5889         /* copy the bits we need into the new key */    
5890         for (i=0; i < (int)keySize; i++) {
5891             unsigned char *value =
5892                          ((unsigned char *)att->attrib.pValue)+offset+i;
5893             if (shift) {
5894                 buf[i] = (value[0] << (shift)) | (value[1] >> (8 - shift));
5895             } else {
5896                 buf[i] = value[0];
5897             }
5898         }
5899
5900         crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
5901         PORT_ZFree(buf,keySize);
5902         break;
5903       }
5904     case CKM_MD2_KEY_DERIVATION:
5905         if (keySize == 0) keySize = MD2_LENGTH;
5906         if (keySize > MD2_LENGTH) {
5907             crv = CKR_TEMPLATE_INCONSISTENT;
5908             break;
5909         }
5910         /* now allocate the hash contexts */
5911         md2 = MD2_NewContext();
5912         if (md2 == NULL) { 
5913             crv = CKR_HOST_MEMORY;
5914             break;
5915         }
5916         MD2_Begin(md2);
5917         MD2_Update(md2,(const unsigned char*)att->attrib.pValue,
5918                    att->attrib.ulValueLen);
5919         MD2_End(md2,key_block,&outLen,MD2_LENGTH);
5920         MD2_DestroyContext(md2, PR_TRUE);
5921
5922         crv = sftk_forceAttribute (key,CKA_VALUE,key_block,keySize);
5923         break;
5924     case CKM_MD5_KEY_DERIVATION:
5925         if (keySize == 0) keySize = MD5_LENGTH;
5926         if (keySize > MD5_LENGTH) {
5927             crv = CKR_TEMPLATE_INCONSISTENT;
5928             break;
5929         }
5930         /* now allocate the hash contexts */
5931         md5 = MD5_NewContext();
5932         if (md5 == NULL) { 
5933             crv = CKR_HOST_MEMORY;
5934             break;
5935         }
5936         MD5_Begin(md5);
5937         MD5_Update(md5,(const unsigned char*)att->attrib.pValue,
5938                    att->attrib.ulValueLen);
5939         MD5_End(md5,key_block,&outLen,MD5_LENGTH);
5940         MD5_DestroyContext(md5, PR_TRUE);
5941
5942         crv = sftk_forceAttribute (key,CKA_VALUE,key_block,keySize);
5943         break;
5944      case CKM_SHA1_KEY_DERIVATION:
5945         if (keySize == 0) keySize = SHA1_LENGTH;
5946         if (keySize > SHA1_LENGTH) {
5947             crv = CKR_TEMPLATE_INCONSISTENT;
5948             break;
5949         }
5950         /* now allocate the hash contexts */
5951         sha = SHA1_NewContext();
5952         if (sha == NULL) { 
5953             crv = CKR_HOST_MEMORY;
5954             break;
5955         }
5956         SHA1_Begin(sha);
5957         SHA1_Update(sha,(const unsigned char*)att->attrib.pValue,
5958                     att->attrib.ulValueLen);
5959         SHA1_End(sha,key_block,&outLen,SHA1_LENGTH);
5960         SHA1_DestroyContext(sha, PR_TRUE);
5961
5962         crv = sftk_forceAttribute(key,CKA_VALUE,key_block,keySize);
5963         break;
5964
5965     case CKM_DH_PKCS_DERIVE:
5966       {
5967         SECItem  derived,  dhPublic;
5968         SECItem  dhPrime,  dhValue;
5969         /* sourceKey - values for the local existing low key */
5970         /* get prime and value attributes */
5971         crv = sftk_Attribute2SecItem(NULL, &dhPrime, sourceKey, CKA_PRIME); 
5972         if (crv != SECSuccess) break;
5973         crv = sftk_Attribute2SecItem(NULL, &dhValue, sourceKey, CKA_VALUE); 
5974         if (crv != SECSuccess) {
5975             PORT_Free(dhPrime.data);
5976             break;
5977         }
5978
5979         dhPublic.data = pMechanism->pParameter;
5980         dhPublic.len  = pMechanism->ulParameterLen;
5981
5982         /* calculate private value - oct */
5983         rv = DH_Derive(&dhPublic, &dhPrime, &dhValue, &derived, keySize); 
5984
5985         PORT_Free(dhPrime.data);
5986         PORT_Free(dhValue.data);
5987      
5988         if (rv == SECSuccess) {
5989             sftk_forceAttribute(key, CKA_VALUE, derived.data, derived.len);
5990             PORT_ZFree(derived.data, derived.len);
5991         } else
5992             crv = CKR_HOST_MEMORY;
5993             
5994         break;
5995       }
5996
5997 #ifdef NSS_ENABLE_ECC
5998     case CKM_ECDH1_DERIVE:
5999     case CKM_ECDH1_COFACTOR_DERIVE:
6000       {
6001         SECItem  ecScalar, ecPoint;
6002         SECItem  tmp;
6003         PRBool   withCofactor = PR_FALSE;
6004         unsigned char secret_hash[20];
6005         unsigned char *secret;
6006         unsigned char *keyData = NULL;
6007         int secretlen, curveLen, pubKeyLen;
6008         CK_ECDH1_DERIVE_PARAMS *mechParams;
6009         NSSLOWKEYPrivateKey *privKey;
6010         PLArenaPool *arena = NULL;
6011
6012         /* Check mechanism parameters */
6013         mechParams = (CK_ECDH1_DERIVE_PARAMS *) pMechanism->pParameter;
6014         if ((pMechanism->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS)) ||
6015             ((mechParams->kdf == CKD_NULL) &&
6016                 ((mechParams->ulSharedDataLen != 0) || 
6017                     (mechParams->pSharedData != NULL)))) {
6018             crv = CKR_MECHANISM_PARAM_INVALID;
6019             break;
6020         }
6021
6022         privKey = sftk_GetPrivKey(sourceKey, CKK_EC, &crv);
6023         if (privKey == NULL) {
6024             break;
6025         }
6026
6027         /* Now we are working with a non-NULL private key */
6028         SECITEM_CopyItem(NULL, &ecScalar, &privKey->u.ec.privateValue);
6029
6030         ecPoint.data = mechParams->pPublicData;
6031         ecPoint.len  = mechParams->ulPublicDataLen;
6032
6033         curveLen = (privKey->u.ec.ecParams.fieldID.size +7)/8;
6034         pubKeyLen = (2*curveLen) + 1;
6035
6036         /* if the len is too small, can't be a valid point */
6037         if (ecPoint.len < pubKeyLen) {
6038             goto ec_loser;
6039         }
6040         /* if the len is too large, must be an encoded point (length is
6041          * equal case just falls through */
6042         if (ecPoint.len > pubKeyLen) {
6043             SECItem newPoint;
6044
6045             arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
6046             if (arena == NULL) {
6047                 goto ec_loser;
6048             }
6049
6050             rv = SEC_QuickDERDecodeItem(arena, &newPoint, 
6051                                         SEC_ASN1_GET(SEC_OctetStringTemplate), 
6052                                         &ecPoint);
6053             if (rv != SECSuccess) {
6054                 goto ec_loser;
6055             }
6056             ecPoint = newPoint;
6057         }
6058
6059         if (pMechanism->mechanism == CKM_ECDH1_COFACTOR_DERIVE) {
6060             withCofactor = PR_TRUE;
6061         } else {
6062             /* When not using cofactor derivation, one should
6063              * validate the public key to avoid small subgroup
6064              * attacks.
6065              */
6066             if (EC_ValidatePublicKey(&privKey->u.ec.ecParams, &ecPoint) 
6067                 != SECSuccess) {
6068                 goto ec_loser;
6069             }
6070         }
6071
6072         rv = ECDH_Derive(&ecPoint, &privKey->u.ec.ecParams, &ecScalar,
6073                          withCofactor, &tmp); 
6074         PORT_Free(ecScalar.data);
6075         ecScalar.data = NULL;
6076         if (privKey != sourceKey->objectInfo) {
6077            nsslowkey_DestroyPrivateKey(privKey);
6078            privKey=NULL;
6079         }
6080         if (arena) {
6081             PORT_FreeArena(arena,PR_FALSE);
6082             arena=NULL;
6083         }
6084
6085         if (rv != SECSuccess) {
6086             crv = sftk_MapCryptError(PORT_GetError());
6087             break;
6088         }
6089
6090         /*
6091          * tmp is the raw data created by ECDH_Derive,
6092          * secret and secretlen are the values we will eventually pass as our
6093          * generated key.
6094          */
6095         secret = tmp.data;
6096         secretlen = tmp.len;
6097
6098         /*
6099          * apply the kdf function.
6100          */
6101         if (mechParams->kdf == CKD_SHA1_KDF) {
6102             /* Compute SHA1 hash */
6103             PORT_Memset(secret_hash, 0, 20);
6104             rv = SHA1_HashBuf(secret_hash, tmp.data, tmp.len);
6105             if (rv != SECSuccess) {
6106                 PORT_ZFree(tmp.data, tmp.len);
6107                 crv = CKR_HOST_MEMORY;
6108                 break;
6109             } 
6110             secret = secret_hash;
6111             secretlen = 20;
6112         }
6113
6114         /*
6115          * if keySize is supplied, then we are generating a key of a specific 
6116          * length. This is done by taking the least significant 'keySize' 
6117          * bytes from the unsigned value calculated by ECDH. Note: this may 
6118          * mean padding temp with extra leading zeros from what ECDH_Derive 
6119          * already returned (which itself may contain leading zeros).
6120          */
6121         if (keySize) {
6122             if (secretlen < keySize) {
6123                 keyData = PORT_ZAlloc(keySize);
6124                 if (!keyData) {
6125                     PORT_ZFree(tmp.data, tmp.len);
6126                     crv = CKR_HOST_MEMORY;
6127                     break;
6128                 }
6129                 PORT_Memcpy(&keyData[keySize-secretlen],secret,secretlen);
6130                 secret = keyData;
6131             } else {
6132                 secret += (secretlen - keySize);
6133             }
6134             secretlen = keySize;
6135         }
6136
6137         sftk_forceAttribute(key, CKA_VALUE, secret, secretlen);
6138         PORT_ZFree(tmp.data, tmp.len);
6139         if (keyData) {
6140             PORT_ZFree(keyData, keySize);
6141         }
6142         PORT_Memset(secret_hash, 0, 20);
6143             
6144         break;
6145
6146 ec_loser:
6147         crv = CKR_ARGUMENTS_BAD;
6148         PORT_Free(ecScalar.data);
6149         if (privKey != sourceKey->objectInfo)
6150             nsslowkey_DestroyPrivateKey(privKey);
6151         if (arena) {
6152             PORT_FreeArena(arena, PR_FALSE);
6153         }
6154         break;
6155
6156       }
6157 #endif /* NSS_ENABLE_ECC */
6158
6159     /* See RFC 5869 and CK_NSS_HKDFParams for documentation. */
6160     case CKM_NSS_HKDF_SHA1:   hashType = HASH_AlgSHA1;   goto hkdf;
6161     case CKM_NSS_HKDF_SHA256: hashType = HASH_AlgSHA256; goto hkdf;
6162     case CKM_NSS_HKDF_SHA384: hashType = HASH_AlgSHA384; goto hkdf;
6163     case CKM_NSS_HKDF_SHA512: hashType = HASH_AlgSHA512; goto hkdf;
6164 hkdf: {
6165         const CK_NSS_HKDFParams * params =
6166             (const CK_NSS_HKDFParams *) pMechanism->pParameter;
6167         const SECHashObject * rawHash;
6168         unsigned hashLen;
6169         CK_BYTE buf[HASH_LENGTH_MAX];
6170         /* const */ CK_BYTE * prk;  /* psuedo-random key */
6171         CK_ULONG prkLen;
6172         const CK_BYTE * okm;        /* output keying material */
6173
6174         rawHash = HASH_GetRawHashObject(hashType);
6175         if (rawHash == NULL || rawHash->length > sizeof buf) {
6176             crv = CKR_FUNCTION_FAILED;
6177             break;
6178         }
6179         hashLen = rawHash->length;
6180
6181         if (pMechanism->ulParameterLen != sizeof(CK_NSS_HKDFParams) ||
6182             !params || (!params->bExpand && !params->bExtract) ||
6183             (params->bExtract && params->ulSaltLen > 0 && !params->pSalt) ||
6184             (params->bExpand && params->ulInfoLen > 0 && !params->pInfo)) {
6185             crv = CKR_MECHANISM_PARAM_INVALID;
6186             break;
6187         }
6188         if (keySize == 0 || keySize > sizeof key_block ||
6189             (!params->bExpand && keySize > hashLen) ||
6190             (params->bExpand && keySize > 255 * hashLen)) {
6191             crv = CKR_TEMPLATE_INCONSISTENT;
6192             break;
6193         }
6194         crv = sftk_DeriveSensitiveCheck(sourceKey, key);
6195         if (crv != CKR_OK)
6196             break;
6197
6198         /* HKDF-Extract(salt, base key value) */
6199         if (params->bExtract) {
6200             CK_BYTE * salt;
6201             CK_ULONG saltLen;
6202             HMACContext * hmac;
6203             unsigned int bufLen;
6204
6205             salt = params->pSalt;
6206             saltLen = params->ulSaltLen;
6207             if (salt == NULL) {
6208                 saltLen = hashLen;
6209                 salt = buf;
6210                 memset(salt, 0, saltLen);
6211             }
6212             hmac = HMAC_Create(rawHash, salt, saltLen, isFIPS);
6213             if (!hmac) {
6214                 crv = CKR_HOST_MEMORY;
6215                 break;
6216             }
6217             HMAC_Begin(hmac);
6218             HMAC_Update(hmac, (const unsigned char*) att->attrib.pValue,
6219                         att->attrib.ulValueLen);
6220             HMAC_Finish(hmac, buf, &bufLen, sizeof(buf));
6221             HMAC_Destroy(hmac, PR_TRUE);
6222             PORT_Assert(bufLen == rawHash->length);
6223             prk = buf;
6224             prkLen = bufLen;
6225         } else {
6226             /* PRK = base key value */
6227             prk = (CK_BYTE*) att->attrib.pValue;
6228             prkLen = att->attrib.ulValueLen;
6229         }
6230         
6231         /* HKDF-Expand */
6232         if (!params->bExpand) {
6233             okm = prk;
6234         } else {
6235             /* T(1) = HMAC-Hash(prk, "" | info | 0x01)
6236              * T(n) = HMAC-Hash(prk, T(n-1) | info | n
6237              * key material = T(1) | ... | T(n)
6238              */
6239             HMACContext * hmac;
6240             CK_BYTE i;
6241             unsigned iterations = PR_ROUNDUP(keySize, hashLen) / hashLen;
6242             hmac = HMAC_Create(rawHash, prk, prkLen, isFIPS);
6243             if (hmac == NULL) {
6244                 crv = CKR_HOST_MEMORY;
6245                 break;
6246             }
6247             for (i = 1; i <= iterations; ++i) {
6248                 unsigned len;
6249                 HMAC_Begin(hmac);
6250                 if (i > 1) {
6251                     HMAC_Update(hmac, key_block + ((i-2) * hashLen), hashLen);
6252                 }
6253                 if (params->ulInfoLen != 0) {
6254                     HMAC_Update(hmac, params->pInfo, params->ulInfoLen);
6255                 }
6256                 HMAC_Update(hmac, &i, 1);
6257                 HMAC_Finish(hmac, key_block + ((i-1) * hashLen), &len,
6258                             hashLen);
6259                 PORT_Assert(len == hashLen);
6260             }
6261             HMAC_Destroy(hmac, PR_TRUE);
6262             okm = key_block;
6263         }
6264         /* key material = prk */
6265         crv = sftk_forceAttribute(key, CKA_VALUE, okm, keySize);
6266         break;
6267       } /* end of CKM_NSS_HKDF_* */
6268
6269     case CKM_NSS_JPAKE_ROUND2_SHA1: hashType = HASH_AlgSHA1; goto jpake2;
6270     case CKM_NSS_JPAKE_ROUND2_SHA256: hashType = HASH_AlgSHA256; goto jpake2;
6271     case CKM_NSS_JPAKE_ROUND2_SHA384: hashType = HASH_AlgSHA384; goto jpake2;
6272     case CKM_NSS_JPAKE_ROUND2_SHA512: hashType = HASH_AlgSHA512; goto jpake2;
6273 jpake2:
6274         if (pMechanism->pParameter == NULL ||
6275             pMechanism->ulParameterLen != sizeof(CK_NSS_JPAKERound2Params))
6276             crv = CKR_MECHANISM_PARAM_INVALID;
6277         if (crv == CKR_OK && sftk_isTrue(key, CKA_TOKEN))
6278             crv = CKR_TEMPLATE_INCONSISTENT;
6279         if (crv == CKR_OK)
6280             crv = sftk_DeriveSensitiveCheck(sourceKey, key);
6281         if (crv == CKR_OK)
6282             crv = jpake_Round2(hashType,
6283                         (CK_NSS_JPAKERound2Params *) pMechanism->pParameter,
6284                         sourceKey, key);
6285         break;
6286
6287     case CKM_NSS_JPAKE_FINAL_SHA1: hashType = HASH_AlgSHA1; goto jpakeFinal;
6288     case CKM_NSS_JPAKE_FINAL_SHA256: hashType = HASH_AlgSHA256; goto jpakeFinal;
6289     case CKM_NSS_JPAKE_FINAL_SHA384: hashType = HASH_AlgSHA384; goto jpakeFinal;
6290     case CKM_NSS_JPAKE_FINAL_SHA512: hashType = HASH_AlgSHA512; goto jpakeFinal;
6291 jpakeFinal:
6292         if (pMechanism->pParameter == NULL ||
6293             pMechanism->ulParameterLen != sizeof(CK_NSS_JPAKEFinalParams))
6294             crv = CKR_MECHANISM_PARAM_INVALID;
6295         /* We purposely do not do the derive sensitivity check; we want to be
6296            able to derive non-sensitive keys while allowing the ROUND1 and 
6297            ROUND2 keys to be sensitive (which they always are, since they are
6298            in the CKO_PRIVATE_KEY class). The caller must include CKA_SENSITIVE
6299            in the template in order for the resultant keyblock key to be
6300            sensitive.
6301          */
6302         if (crv == CKR_OK)
6303             crv = jpake_Final(hashType,
6304                         (CK_NSS_JPAKEFinalParams *) pMechanism->pParameter,
6305                         sourceKey, key);
6306         break;
6307
6308     default:
6309         crv = CKR_MECHANISM_INVALID;
6310     }
6311     if (att) {
6312         sftk_FreeAttribute(att);
6313     }
6314     sftk_FreeObject(sourceKey);
6315     if (crv != CKR_OK) { 
6316         if (key) sftk_FreeObject(key);
6317         return crv;
6318     }
6319
6320     /* link the key object into the list */
6321     if (key) {
6322         SFTKSessionObject *sessKey = sftk_narrowToSessionObject(key);
6323         PORT_Assert(sessKey);
6324         /* get the session */
6325         sessKey->wasDerived = PR_TRUE;
6326         session = sftk_SessionFromHandle(hSession);
6327         if (session == NULL) {
6328             sftk_FreeObject(key);
6329             return CKR_HOST_MEMORY;
6330         }
6331
6332         crv = sftk_handleObject(key,session);
6333         sftk_FreeSession(session);
6334         *phKey = key->handle;
6335         sftk_FreeObject(key);
6336     }
6337     return crv;
6338 }
6339
6340
6341 /* NSC_GetFunctionStatus obtains an updated status of a function running 
6342  * in parallel with an application. */
6343 CK_RV NSC_GetFunctionStatus(CK_SESSION_HANDLE hSession)
6344 {
6345     CHECK_FORK();
6346
6347     return CKR_FUNCTION_NOT_PARALLEL;
6348 }
6349
6350 /* NSC_CancelFunction cancels a function running in parallel */
6351 CK_RV NSC_CancelFunction(CK_SESSION_HANDLE hSession)
6352 {
6353     CHECK_FORK();
6354
6355     return CKR_FUNCTION_NOT_PARALLEL;
6356 }
6357
6358 /* NSC_GetOperationState saves the state of the cryptographic 
6359  *operation in a session.
6360  * NOTE: This code only works for digest functions for now. eventually need
6361  * to add full flatten/resurect to our state stuff so that all types of state
6362  * can be saved */
6363 CK_RV NSC_GetOperationState(CK_SESSION_HANDLE hSession, 
6364         CK_BYTE_PTR  pOperationState, CK_ULONG_PTR pulOperationStateLen)
6365 {
6366     SFTKSessionContext *context;
6367     SFTKSession *session;
6368     CK_RV crv;
6369     CK_ULONG pOSLen = *pulOperationStateLen;
6370
6371     CHECK_FORK();
6372
6373     /* make sure we're legal */
6374     crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, &session);
6375     if (crv != CKR_OK) return crv;
6376
6377     *pulOperationStateLen = context->cipherInfoLen + sizeof(CK_MECHANISM_TYPE)
6378                                 + sizeof(SFTKContextType);
6379     if (pOperationState == NULL) {
6380         sftk_FreeSession(session);
6381         return CKR_OK;
6382     } else {
6383         if (pOSLen < *pulOperationStateLen) {
6384             return CKR_BUFFER_TOO_SMALL;
6385         }
6386     }
6387     PORT_Memcpy(pOperationState,&context->type,sizeof(SFTKContextType));
6388     pOperationState += sizeof(SFTKContextType);
6389     PORT_Memcpy(pOperationState,&context->currentMech,
6390                                                 sizeof(CK_MECHANISM_TYPE));
6391     pOperationState += sizeof(CK_MECHANISM_TYPE);
6392     PORT_Memcpy(pOperationState,context->cipherInfo,context->cipherInfoLen);
6393     sftk_FreeSession(session);
6394     return CKR_OK;
6395 }
6396
6397
6398 #define sftk_Decrement(stateSize,len) \
6399         stateSize = ((stateSize) > (CK_ULONG)(len)) ? \
6400                                 ((stateSize) - (CK_ULONG)(len)) : 0;
6401
6402 /* NSC_SetOperationState restores the state of the cryptographic 
6403  * operation in a session. This is coded like it can restore lots of
6404  * states, but it only works for truly flat cipher structures. */
6405 CK_RV NSC_SetOperationState(CK_SESSION_HANDLE hSession, 
6406         CK_BYTE_PTR  pOperationState, CK_ULONG  ulOperationStateLen,
6407         CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey)
6408 {
6409     SFTKSessionContext *context;
6410     SFTKSession *session;
6411     SFTKContextType type;
6412     CK_MECHANISM mech;
6413     CK_RV crv = CKR_OK;
6414
6415     CHECK_FORK();
6416
6417     while (ulOperationStateLen != 0) {
6418         /* get what type of state we're dealing with... */
6419         PORT_Memcpy(&type,pOperationState, sizeof(SFTKContextType));
6420
6421         /* fix up session contexts based on type */
6422         session = sftk_SessionFromHandle(hSession);
6423         if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
6424         context = sftk_ReturnContextByType(session, type);
6425         sftk_SetContextByType(session, type, NULL);
6426         if (context) { 
6427              sftk_FreeContext(context);
6428         }
6429         pOperationState += sizeof(SFTKContextType);
6430         sftk_Decrement(ulOperationStateLen,sizeof(SFTKContextType));
6431
6432
6433         /* get the mechanism structure */
6434         PORT_Memcpy(&mech.mechanism,pOperationState,sizeof(CK_MECHANISM_TYPE));
6435         pOperationState += sizeof(CK_MECHANISM_TYPE);
6436         sftk_Decrement(ulOperationStateLen, sizeof(CK_MECHANISM_TYPE));
6437         /* should be filled in... but not necessary for hash */
6438         mech.pParameter = NULL;
6439         mech.ulParameterLen = 0;
6440         switch (type) {
6441         case SFTK_HASH:
6442             crv = NSC_DigestInit(hSession,&mech);
6443             if (crv != CKR_OK) break;
6444             crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, 
6445                                                                 NULL);
6446             if (crv != CKR_OK) break;
6447             PORT_Memcpy(context->cipherInfo,pOperationState,
6448                                                 context->cipherInfoLen);
6449             pOperationState += context->cipherInfoLen;
6450             sftk_Decrement(ulOperationStateLen,context->cipherInfoLen);
6451             break;
6452         default:
6453             /* do sign/encrypt/decrypt later */
6454             crv = CKR_SAVED_STATE_INVALID;
6455          }
6456          sftk_FreeSession(session);
6457          if (crv != CKR_OK) break;
6458     }
6459     return crv;
6460 }
6461
6462 /* Dual-function cryptographic operations */
6463
6464 /* NSC_DigestEncryptUpdate continues a multiple-part digesting and encryption 
6465  * operation. */
6466 CK_RV NSC_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR  pPart,
6467     CK_ULONG  ulPartLen, CK_BYTE_PTR  pEncryptedPart,
6468                                          CK_ULONG_PTR pulEncryptedPartLen)
6469 {
6470     CK_RV crv;
6471
6472     CHECK_FORK();
6473
6474     crv = NSC_EncryptUpdate(hSession,pPart,ulPartLen, pEncryptedPart,   
6475                                                       pulEncryptedPartLen);
6476     if (crv != CKR_OK) return crv;
6477     crv = NSC_DigestUpdate(hSession,pPart,ulPartLen);
6478
6479     return crv;
6480 }
6481
6482
6483 /* NSC_DecryptDigestUpdate continues a multiple-part decryption and 
6484  * digesting operation. */
6485 CK_RV NSC_DecryptDigestUpdate(CK_SESSION_HANDLE hSession,
6486     CK_BYTE_PTR  pEncryptedPart, CK_ULONG  ulEncryptedPartLen,
6487                                 CK_BYTE_PTR  pPart, CK_ULONG_PTR pulPartLen)
6488 {
6489     CK_RV crv;
6490
6491     CHECK_FORK();
6492
6493     crv = NSC_DecryptUpdate(hSession,pEncryptedPart, ulEncryptedPartLen, 
6494                                                         pPart,  pulPartLen);
6495     if (crv != CKR_OK) return crv;
6496     crv = NSC_DigestUpdate(hSession,pPart,*pulPartLen);
6497
6498     return crv;
6499 }
6500
6501
6502 /* NSC_SignEncryptUpdate continues a multiple-part signing and 
6503  * encryption operation. */
6504 CK_RV NSC_SignEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR  pPart,
6505          CK_ULONG  ulPartLen, CK_BYTE_PTR  pEncryptedPart,
6506                                          CK_ULONG_PTR pulEncryptedPartLen)
6507 {
6508     CK_RV crv;
6509
6510     CHECK_FORK();
6511
6512     crv = NSC_EncryptUpdate(hSession,pPart,ulPartLen, pEncryptedPart,   
6513                                                       pulEncryptedPartLen);
6514     if (crv != CKR_OK) return crv;
6515     crv = NSC_SignUpdate(hSession,pPart,ulPartLen);
6516
6517     return crv;
6518 }
6519
6520
6521 /* NSC_DecryptVerifyUpdate continues a multiple-part decryption 
6522  * and verify operation. */
6523 CK_RV NSC_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, 
6524         CK_BYTE_PTR  pEncryptedData, CK_ULONG  ulEncryptedDataLen, 
6525                                 CK_BYTE_PTR  pData, CK_ULONG_PTR pulDataLen)
6526 {
6527     CK_RV crv;
6528
6529     CHECK_FORK();
6530
6531     crv = NSC_DecryptUpdate(hSession,pEncryptedData, ulEncryptedDataLen, 
6532                                                         pData,  pulDataLen);
6533     if (crv != CKR_OK) return crv;
6534     crv = NSC_VerifyUpdate(hSession, pData, *pulDataLen);
6535
6536     return crv;
6537 }
6538
6539 /* NSC_DigestKey continues a multi-part message-digesting operation,
6540  * by digesting the value of a secret key as part of the data already digested.
6541  */
6542 CK_RV NSC_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) 
6543 {
6544     SFTKSession *session = NULL;
6545     SFTKObject *key = NULL;
6546     SFTKAttribute *att;
6547     CK_RV crv;
6548
6549     CHECK_FORK();
6550
6551     session = sftk_SessionFromHandle(hSession);
6552     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
6553
6554     key = sftk_ObjectFromHandle(hKey,session);
6555     sftk_FreeSession(session);
6556     if (key == NULL)  return CKR_KEY_HANDLE_INVALID;
6557
6558     /* PUT ANY DIGEST KEY RESTRICTION CHECKS HERE */
6559
6560     /* make sure it's a valid  key for this operation */
6561     if (key->objclass != CKO_SECRET_KEY) {
6562         sftk_FreeObject(key);
6563         return CKR_KEY_TYPE_INCONSISTENT;
6564     }
6565     /* get the key value */
6566     att = sftk_FindAttribute(key,CKA_VALUE);
6567     sftk_FreeObject(key);
6568     if (!att) {
6569         return CKR_KEY_HANDLE_INVALID;        
6570     }
6571     crv = NSC_DigestUpdate(hSession,(CK_BYTE_PTR)att->attrib.pValue,
6572                            att->attrib.ulValueLen);
6573     sftk_FreeAttribute(att);
6574     return crv;
6575 }