Wed, 31 Dec 2014 06:09:35 +0100
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, ¶ms, &vfy); |
michael@0 | 3509 | } else { |
michael@0 | 3510 | rv = PQG_ParamGenSeedLen(j,seedBits/8, ¶ms, &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, ¶ms, &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,¶ms->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 | } |