security/nss/lib/softoken/pkcs11c.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial