1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/pk11wrap/pk11akey.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2393 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +/* 1.8 + * This file contains functions to manage asymetric keys, (public and 1.9 + * private keys). 1.10 + */ 1.11 +#include "seccomon.h" 1.12 +#include "secmod.h" 1.13 +#include "secmodi.h" 1.14 +#include "secmodti.h" 1.15 +#include "pkcs11.h" 1.16 +#include "pkcs11t.h" 1.17 +#include "pk11func.h" 1.18 +#include "cert.h" 1.19 +#include "key.h" 1.20 +#include "secitem.h" 1.21 +#include "secasn1.h" 1.22 +#include "secoid.h" 1.23 +#include "secerr.h" 1.24 +#include "sslerr.h" 1.25 +#include "sechash.h" 1.26 + 1.27 +#include "secpkcs5.h" 1.28 +#include "blapit.h" 1.29 + 1.30 +static SECItem * 1.31 +pk11_MakeIDFromPublicKey(SECKEYPublicKey *pubKey) 1.32 +{ 1.33 + /* set the ID to the public key so we can find it again */ 1.34 + SECItem *pubKeyIndex = NULL; 1.35 + switch (pubKey->keyType) { 1.36 + case rsaKey: 1.37 + pubKeyIndex = &pubKey->u.rsa.modulus; 1.38 + break; 1.39 + case dsaKey: 1.40 + pubKeyIndex = &pubKey->u.dsa.publicValue; 1.41 + break; 1.42 + case dhKey: 1.43 + pubKeyIndex = &pubKey->u.dh.publicValue; 1.44 + break; 1.45 + case ecKey: 1.46 + pubKeyIndex = &pubKey->u.ec.publicValue; 1.47 + break; 1.48 + default: 1.49 + return NULL; 1.50 + } 1.51 + PORT_Assert(pubKeyIndex != NULL); 1.52 + 1.53 + return PK11_MakeIDFromPubKey(pubKeyIndex); 1.54 +} 1.55 + 1.56 +/* 1.57 + * import a public key into the desired slot 1.58 + * 1.59 + * This function takes a public key structure and creates a public key in a 1.60 + * given slot. If isToken is set, then a persistant public key is created. 1.61 + * 1.62 + * Note: it is possible for this function to return a handle for a key which 1.63 + * is persistant, even if isToken is not set. 1.64 + */ 1.65 +CK_OBJECT_HANDLE 1.66 +PK11_ImportPublicKey(PK11SlotInfo *slot, SECKEYPublicKey *pubKey, 1.67 + PRBool isToken) 1.68 +{ 1.69 + CK_BBOOL cktrue = CK_TRUE; 1.70 + CK_BBOOL ckfalse = CK_FALSE; 1.71 + CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; 1.72 + CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; 1.73 + CK_OBJECT_HANDLE objectID; 1.74 + CK_ATTRIBUTE theTemplate[11]; 1.75 + CK_ATTRIBUTE *signedattr = NULL; 1.76 + CK_ATTRIBUTE *attrs = theTemplate; 1.77 + SECItem *ckaId = NULL; 1.78 + SECItem *pubValue = NULL; 1.79 + int signedcount = 0; 1.80 + int templateCount = 0; 1.81 + SECStatus rv; 1.82 + 1.83 + /* if we already have an object in the desired slot, use it */ 1.84 + if (!isToken && pubKey->pkcs11Slot == slot) { 1.85 + return pubKey->pkcs11ID; 1.86 + } 1.87 + 1.88 + /* free the existing key */ 1.89 + if (pubKey->pkcs11Slot != NULL) { 1.90 + PK11SlotInfo *oSlot = pubKey->pkcs11Slot; 1.91 + if (!PK11_IsPermObject(pubKey->pkcs11Slot,pubKey->pkcs11ID)) { 1.92 + PK11_EnterSlotMonitor(oSlot); 1.93 + (void) PK11_GETTAB(oSlot)->C_DestroyObject(oSlot->session, 1.94 + pubKey->pkcs11ID); 1.95 + PK11_ExitSlotMonitor(oSlot); 1.96 + } 1.97 + PK11_FreeSlot(oSlot); 1.98 + pubKey->pkcs11Slot = NULL; 1.99 + } 1.100 + PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++; 1.101 + PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++; 1.102 + PK11_SETATTRS(attrs, CKA_TOKEN, isToken ? &cktrue : &ckfalse, 1.103 + sizeof(CK_BBOOL) ); attrs++; 1.104 + if (isToken) { 1.105 + ckaId = pk11_MakeIDFromPublicKey(pubKey); 1.106 + if (ckaId == NULL) { 1.107 + PORT_SetError( SEC_ERROR_BAD_KEY ); 1.108 + return CK_INVALID_HANDLE; 1.109 + } 1.110 + PK11_SETATTRS(attrs, CKA_ID, ckaId->data, ckaId->len); attrs++; 1.111 + } 1.112 + 1.113 + /* now import the key */ 1.114 + { 1.115 + switch (pubKey->keyType) { 1.116 + case rsaKey: 1.117 + keyType = CKK_RSA; 1.118 + PK11_SETATTRS(attrs, CKA_WRAP, &cktrue, sizeof(CK_BBOOL) ); attrs++; 1.119 + PK11_SETATTRS(attrs, CKA_ENCRYPT, &cktrue, 1.120 + sizeof(CK_BBOOL) ); attrs++; 1.121 + PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL)); attrs++; 1.122 + signedattr = attrs; 1.123 + PK11_SETATTRS(attrs, CKA_MODULUS, pubKey->u.rsa.modulus.data, 1.124 + pubKey->u.rsa.modulus.len); attrs++; 1.125 + PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, 1.126 + pubKey->u.rsa.publicExponent.data, 1.127 + pubKey->u.rsa.publicExponent.len); attrs++; 1.128 + break; 1.129 + case dsaKey: 1.130 + keyType = CKK_DSA; 1.131 + PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++; 1.132 + signedattr = attrs; 1.133 + PK11_SETATTRS(attrs, CKA_PRIME, pubKey->u.dsa.params.prime.data, 1.134 + pubKey->u.dsa.params.prime.len); attrs++; 1.135 + PK11_SETATTRS(attrs,CKA_SUBPRIME,pubKey->u.dsa.params.subPrime.data, 1.136 + pubKey->u.dsa.params.subPrime.len); attrs++; 1.137 + PK11_SETATTRS(attrs, CKA_BASE, pubKey->u.dsa.params.base.data, 1.138 + pubKey->u.dsa.params.base.len); attrs++; 1.139 + PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.dsa.publicValue.data, 1.140 + pubKey->u.dsa.publicValue.len); attrs++; 1.141 + break; 1.142 + case fortezzaKey: 1.143 + keyType = CKK_DSA; 1.144 + PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++; 1.145 + signedattr = attrs; 1.146 + PK11_SETATTRS(attrs, CKA_PRIME,pubKey->u.fortezza.params.prime.data, 1.147 + pubKey->u.fortezza.params.prime.len); attrs++; 1.148 + PK11_SETATTRS(attrs,CKA_SUBPRIME, 1.149 + pubKey->u.fortezza.params.subPrime.data, 1.150 + pubKey->u.fortezza.params.subPrime.len);attrs++; 1.151 + PK11_SETATTRS(attrs, CKA_BASE, pubKey->u.fortezza.params.base.data, 1.152 + pubKey->u.fortezza.params.base.len); attrs++; 1.153 + PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.fortezza.DSSKey.data, 1.154 + pubKey->u.fortezza.DSSKey.len); attrs++; 1.155 + break; 1.156 + case dhKey: 1.157 + keyType = CKK_DH; 1.158 + PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));attrs++; 1.159 + signedattr = attrs; 1.160 + PK11_SETATTRS(attrs, CKA_PRIME, pubKey->u.dh.prime.data, 1.161 + pubKey->u.dh.prime.len); attrs++; 1.162 + PK11_SETATTRS(attrs, CKA_BASE, pubKey->u.dh.base.data, 1.163 + pubKey->u.dh.base.len); attrs++; 1.164 + PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.dh.publicValue.data, 1.165 + pubKey->u.dh.publicValue.len); attrs++; 1.166 + break; 1.167 + case ecKey: 1.168 + keyType = CKK_EC; 1.169 + PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++; 1.170 + PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));attrs++; 1.171 + signedattr = attrs; 1.172 + PK11_SETATTRS(attrs, CKA_EC_PARAMS, 1.173 + pubKey->u.ec.DEREncodedParams.data, 1.174 + pubKey->u.ec.DEREncodedParams.len); attrs++; 1.175 + if (PR_GetEnv("NSS_USE_DECODED_CKA_EC_POINT")) { 1.176 + PK11_SETATTRS(attrs, CKA_EC_POINT, 1.177 + pubKey->u.ec.publicValue.data, 1.178 + pubKey->u.ec.publicValue.len); attrs++; 1.179 + } else { 1.180 + pubValue = SEC_ASN1EncodeItem(NULL, NULL, 1.181 + &pubKey->u.ec.publicValue, 1.182 + SEC_ASN1_GET(SEC_OctetStringTemplate)); 1.183 + if (pubValue == NULL) { 1.184 + if (ckaId) { 1.185 + SECITEM_FreeItem(ckaId,PR_TRUE); 1.186 + } 1.187 + return CK_INVALID_HANDLE; 1.188 + } 1.189 + PK11_SETATTRS(attrs, CKA_EC_POINT, 1.190 + pubValue->data, pubValue->len); attrs++; 1.191 + } 1.192 + break; 1.193 + default: 1.194 + if (ckaId) { 1.195 + SECITEM_FreeItem(ckaId,PR_TRUE); 1.196 + } 1.197 + PORT_SetError( SEC_ERROR_BAD_KEY ); 1.198 + return CK_INVALID_HANDLE; 1.199 + } 1.200 + 1.201 + templateCount = attrs - theTemplate; 1.202 + signedcount = attrs - signedattr; 1.203 + PORT_Assert(templateCount <= (sizeof(theTemplate)/sizeof(CK_ATTRIBUTE))); 1.204 + for (attrs=signedattr; signedcount; attrs++, signedcount--) { 1.205 + pk11_SignedToUnsigned(attrs); 1.206 + } 1.207 + rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, theTemplate, 1.208 + templateCount, isToken, &objectID); 1.209 + if (ckaId) { 1.210 + SECITEM_FreeItem(ckaId,PR_TRUE); 1.211 + } 1.212 + if (pubValue) { 1.213 + SECITEM_FreeItem(pubValue,PR_TRUE); 1.214 + } 1.215 + if ( rv != SECSuccess) { 1.216 + return CK_INVALID_HANDLE; 1.217 + } 1.218 + } 1.219 + 1.220 + pubKey->pkcs11ID = objectID; 1.221 + pubKey->pkcs11Slot = PK11_ReferenceSlot(slot); 1.222 + 1.223 + return objectID; 1.224 +} 1.225 + 1.226 +/* 1.227 + * take an attribute and copy it into a secitem 1.228 + */ 1.229 +static CK_RV 1.230 +pk11_Attr2SecItem(PLArenaPool *arena, const CK_ATTRIBUTE *attr, SECItem *item) 1.231 +{ 1.232 + item->data = NULL; 1.233 + 1.234 + (void)SECITEM_AllocItem(arena, item, attr->ulValueLen); 1.235 + if (item->data == NULL) { 1.236 + return CKR_HOST_MEMORY; 1.237 + } 1.238 + PORT_Memcpy(item->data, attr->pValue, item->len); 1.239 + return CKR_OK; 1.240 +} 1.241 + 1.242 + 1.243 +/* 1.244 + * get a curve length from a set of ecParams. 1.245 + * 1.246 + * We need this so we can reliably determine if the ecPoint passed to us 1.247 + * was encoded or not. With out this, for many curves, we would incorrectly 1.248 + * identify an unencoded curve as an encoded curve 1 in 65536 times, and for 1.249 + * a few we would make that same mistake 1 in 32768 times. These are bad 1.250 + * numbers since they are rare enough to pass tests, but common enough to 1.251 + * be tripped over in the field. 1.252 + * 1.253 + * This function will only work for curves we recognized as of March 2009. 1.254 + * The assumption is curves in use after March of 2009 would be supplied by 1.255 + * PKCS #11 modules that already pass the correct encoding to us. 1.256 + * 1.257 + * Point length = (Roundup(curveLenInBits/8)*2+1) 1.258 + */ 1.259 +static int 1.260 +pk11_get_EC_PointLenInBytes(PLArenaPool *arena, const SECItem *ecParams) 1.261 +{ 1.262 + SECItem oid; 1.263 + SECOidTag tag; 1.264 + SECStatus rv; 1.265 + 1.266 + /* decode the OID tag */ 1.267 + rv = SEC_QuickDERDecodeItem(arena, &oid, 1.268 + SEC_ASN1_GET(SEC_ObjectIDTemplate), ecParams); 1.269 + if (rv != SECSuccess) { 1.270 + /* could be explict curves, allow them to work if the 1.271 + * PKCS #11 module support them. If we try to parse the 1.272 + * explicit curve value in the future, we may return -1 here 1.273 + * to indicate an invalid parameter if the explicit curve 1.274 + * decode fails. */ 1.275 + return 0; 1.276 + } 1.277 + 1.278 + tag = SECOID_FindOIDTag(&oid); 1.279 + switch (tag) { 1.280 + case SEC_OID_SECG_EC_SECP112R1: 1.281 + case SEC_OID_SECG_EC_SECP112R2: 1.282 + return 29; /* curve len in bytes = 14 bytes */ 1.283 + case SEC_OID_SECG_EC_SECT113R1: 1.284 + case SEC_OID_SECG_EC_SECT113R2: 1.285 + return 31; /* curve len in bytes = 15 bytes */ 1.286 + case SEC_OID_SECG_EC_SECP128R1: 1.287 + case SEC_OID_SECG_EC_SECP128R2: 1.288 + return 33; /* curve len in bytes = 16 bytes */ 1.289 + case SEC_OID_SECG_EC_SECT131R1: 1.290 + case SEC_OID_SECG_EC_SECT131R2: 1.291 + return 35; /* curve len in bytes = 17 bytes */ 1.292 + case SEC_OID_SECG_EC_SECP160K1: 1.293 + case SEC_OID_SECG_EC_SECP160R1: 1.294 + case SEC_OID_SECG_EC_SECP160R2: 1.295 + return 41; /* curve len in bytes = 20 bytes */ 1.296 + case SEC_OID_SECG_EC_SECT163K1: 1.297 + case SEC_OID_SECG_EC_SECT163R1: 1.298 + case SEC_OID_SECG_EC_SECT163R2: 1.299 + case SEC_OID_ANSIX962_EC_C2PNB163V1: 1.300 + case SEC_OID_ANSIX962_EC_C2PNB163V2: 1.301 + case SEC_OID_ANSIX962_EC_C2PNB163V3: 1.302 + return 43; /* curve len in bytes = 21 bytes */ 1.303 + case SEC_OID_ANSIX962_EC_C2PNB176V1: 1.304 + return 45; /* curve len in bytes = 22 bytes */ 1.305 + case SEC_OID_ANSIX962_EC_C2TNB191V1: 1.306 + case SEC_OID_ANSIX962_EC_C2TNB191V2: 1.307 + case SEC_OID_ANSIX962_EC_C2TNB191V3: 1.308 + case SEC_OID_SECG_EC_SECP192K1: 1.309 + case SEC_OID_ANSIX962_EC_PRIME192V1: 1.310 + case SEC_OID_ANSIX962_EC_PRIME192V2: 1.311 + case SEC_OID_ANSIX962_EC_PRIME192V3: 1.312 + return 49; /*curve len in bytes = 24 bytes */ 1.313 + case SEC_OID_SECG_EC_SECT193R1: 1.314 + case SEC_OID_SECG_EC_SECT193R2: 1.315 + return 51; /*curve len in bytes = 25 bytes */ 1.316 + case SEC_OID_ANSIX962_EC_C2PNB208W1: 1.317 + return 53; /*curve len in bytes = 26 bytes */ 1.318 + case SEC_OID_SECG_EC_SECP224K1: 1.319 + case SEC_OID_SECG_EC_SECP224R1: 1.320 + return 57; /*curve len in bytes = 28 bytes */ 1.321 + case SEC_OID_SECG_EC_SECT233K1: 1.322 + case SEC_OID_SECG_EC_SECT233R1: 1.323 + case SEC_OID_SECG_EC_SECT239K1: 1.324 + case SEC_OID_ANSIX962_EC_PRIME239V1: 1.325 + case SEC_OID_ANSIX962_EC_PRIME239V2: 1.326 + case SEC_OID_ANSIX962_EC_PRIME239V3: 1.327 + case SEC_OID_ANSIX962_EC_C2TNB239V1: 1.328 + case SEC_OID_ANSIX962_EC_C2TNB239V2: 1.329 + case SEC_OID_ANSIX962_EC_C2TNB239V3: 1.330 + return 61; /*curve len in bytes = 30 bytes */ 1.331 + case SEC_OID_ANSIX962_EC_PRIME256V1: 1.332 + case SEC_OID_SECG_EC_SECP256K1: 1.333 + return 65; /*curve len in bytes = 32 bytes */ 1.334 + case SEC_OID_ANSIX962_EC_C2PNB272W1: 1.335 + return 69; /*curve len in bytes = 34 bytes */ 1.336 + case SEC_OID_SECG_EC_SECT283K1: 1.337 + case SEC_OID_SECG_EC_SECT283R1: 1.338 + return 73; /*curve len in bytes = 36 bytes */ 1.339 + case SEC_OID_ANSIX962_EC_C2PNB304W1: 1.340 + return 77; /*curve len in bytes = 38 bytes */ 1.341 + case SEC_OID_ANSIX962_EC_C2TNB359V1: 1.342 + return 91; /*curve len in bytes = 45 bytes */ 1.343 + case SEC_OID_ANSIX962_EC_C2PNB368W1: 1.344 + return 93; /*curve len in bytes = 46 bytes */ 1.345 + case SEC_OID_SECG_EC_SECP384R1: 1.346 + return 97; /*curve len in bytes = 48 bytes */ 1.347 + case SEC_OID_SECG_EC_SECT409K1: 1.348 + case SEC_OID_SECG_EC_SECT409R1: 1.349 + return 105; /*curve len in bytes = 52 bytes */ 1.350 + case SEC_OID_ANSIX962_EC_C2TNB431R1: 1.351 + return 109; /*curve len in bytes = 54 bytes */ 1.352 + case SEC_OID_SECG_EC_SECP521R1: 1.353 + return 133; /*curve len in bytes = 66 bytes */ 1.354 + case SEC_OID_SECG_EC_SECT571K1: 1.355 + case SEC_OID_SECG_EC_SECT571R1: 1.356 + return 145; /*curve len in bytes = 72 bytes */ 1.357 + /* unknown or unrecognized OIDs. return unknown length */ 1.358 + default: 1.359 + break; 1.360 + } 1.361 + return 0; 1.362 +} 1.363 + 1.364 +/* 1.365 + * returns the decoded point. In some cases the point may already be decoded. 1.366 + * this function tries to detect those cases and return the point in 1.367 + * publicKeyValue. In other cases it's DER encoded. In those cases the point 1.368 + * is first decoded and returned. Space for the point is allocated out of 1.369 + * the passed in arena. 1.370 + */ 1.371 +static CK_RV 1.372 +pk11_get_Decoded_ECPoint(PLArenaPool *arena, const SECItem *ecParams, 1.373 + const CK_ATTRIBUTE *ecPoint, SECItem *publicKeyValue) 1.374 +{ 1.375 + SECItem encodedPublicValue; 1.376 + SECStatus rv; 1.377 + int keyLen; 1.378 + 1.379 + if (ecPoint->ulValueLen == 0) { 1.380 + return CKR_ATTRIBUTE_VALUE_INVALID; 1.381 + } 1.382 + 1.383 + /* 1.384 + * The PKCS #11 spec requires ecPoints to be encoded as a DER OCTET String. 1.385 + * NSS has mistakenly passed unencoded values, and some PKCS #11 vendors 1.386 + * followed that mistake. Now we need to detect which encoding we were 1.387 + * passed in. The task is made more complicated by the fact the the 1.388 + * DER encoding byte (SEC_ASN_OCTET_STRING) is the same as the 1.389 + * EC_POINT_FORM_UNCOMPRESSED byte (0x04), so we can't use that to 1.390 + * determine which curve we are using. 1.391 + */ 1.392 + 1.393 + /* get the expected key length for the passed in curve. 1.394 + * pk11_get_EC_PointLenInBytes only returns valid values for curves 1.395 + * NSS has traditionally recognized. If the curve is not recognized, 1.396 + * it will return '0', and we have to figure out if the key was 1.397 + * encoded or not heuristically. If the ecParams are invalid, it 1.398 + * will return -1 for the keyLen. 1.399 + */ 1.400 + keyLen = pk11_get_EC_PointLenInBytes(arena, ecParams); 1.401 + if (keyLen < 0) { 1.402 + return CKR_ATTRIBUTE_VALUE_INVALID; 1.403 + } 1.404 + 1.405 + 1.406 + /* If the point is uncompressed and the lengths match, it 1.407 + * must be an unencoded point */ 1.408 + if ((*((char *)ecPoint->pValue) == EC_POINT_FORM_UNCOMPRESSED) 1.409 + && (ecPoint->ulValueLen == keyLen)) { 1.410 + return pk11_Attr2SecItem(arena, ecPoint, publicKeyValue); 1.411 + } 1.412 + 1.413 + /* now assume the key passed to us was encoded and decode it */ 1.414 + if (*((char *)ecPoint->pValue) == SEC_ASN1_OCTET_STRING) { 1.415 + /* OK, now let's try to decode it and see if it's valid */ 1.416 + encodedPublicValue.data = ecPoint->pValue; 1.417 + encodedPublicValue.len = ecPoint->ulValueLen; 1.418 + rv = SEC_QuickDERDecodeItem(arena, publicKeyValue, 1.419 + SEC_ASN1_GET(SEC_OctetStringTemplate), &encodedPublicValue); 1.420 + 1.421 + /* it coded correctly & we know the key length (and they match) 1.422 + * then we are done, return the results. */ 1.423 + if (keyLen && rv == SECSuccess && publicKeyValue->len == keyLen) { 1.424 + return CKR_OK; 1.425 + } 1.426 + 1.427 + /* if we know the key length, one of the above tests should have 1.428 + * succeded. If it doesn't the module gave us bad data */ 1.429 + if (keyLen) { 1.430 + return CKR_ATTRIBUTE_VALUE_INVALID; 1.431 + } 1.432 + 1.433 + 1.434 + /* We don't know the key length, so we don't know deterministically 1.435 + * which encoding was used. We now will try to pick the most likely 1.436 + * form that's correct, with a preference for the encoded form if we 1.437 + * can't determine for sure. We do this by checking the key we got 1.438 + * back from SEC_QuickDERDecodeItem for defects. If no defects are 1.439 + * found, we assume the encoded parameter was was passed to us. 1.440 + * our defect tests include: 1.441 + * 1) it didn't decode. 1.442 + * 2) The decode key had an invalid length (must be odd). 1.443 + * 3) The decoded key wasn't an UNCOMPRESSED key. 1.444 + * 4) The decoded key didn't include the entire encoded block 1.445 + * except the DER encoding values. (fixing DER length to one 1.446 + * particular value). 1.447 + */ 1.448 + if ((rv != SECSuccess) 1.449 + || ((publicKeyValue->len & 1) != 1) 1.450 + || (publicKeyValue->data[0] != EC_POINT_FORM_UNCOMPRESSED) 1.451 + || (PORT_Memcmp(&encodedPublicValue.data[encodedPublicValue.len - 1.452 + publicKeyValue->len], publicKeyValue->data, 1.453 + publicKeyValue->len) != 0)) { 1.454 + /* The decoded public key was flawed, the original key must have 1.455 + * already been in decoded form. Do a quick sanity check then 1.456 + * return the original key value. 1.457 + */ 1.458 + if ((encodedPublicValue.len & 1) == 0) { 1.459 + return CKR_ATTRIBUTE_VALUE_INVALID; 1.460 + } 1.461 + return pk11_Attr2SecItem(arena, ecPoint, publicKeyValue); 1.462 + } 1.463 + 1.464 + /* as best we can figure, the passed in key was encoded, and we've 1.465 + * now decoded it. Note: there is a chance this could be wrong if the 1.466 + * following conditions hold: 1.467 + * 1) The first byte or bytes of the X point looks like a valid length 1.468 + * of precisely the right size (2*curveSize -1). this means for curves 1.469 + * less than 512 bits (64 bytes), this will happen 1 in 256 times*. 1.470 + * for curves between 512 and 1024, this will happen 1 in 65,536 times* 1.471 + * for curves between 1024 and 256K this will happen 1 in 16 million* 1.472 + * 2) The length of the 'DER length field' is odd 1.473 + * (making both the encoded and decode 1.474 + * values an odd length. this is true of all curves less than 512, 1.475 + * as well as curves between 1024 and 256K). 1.476 + * 3) The X[length of the 'DER length field'] == 0x04, 1 in 256. 1.477 + * 1.478 + * (* assuming all values are equally likely in the first byte, 1.479 + * This isn't true if the curve length is not a multiple of 8. In these 1.480 + * cases, if the DER length is possible, it's more likely, 1.481 + * if it's not possible, then we have no false decodes). 1.482 + * 1.483 + * For reference here are the odds for the various curves we currently 1.484 + * have support for (and the only curves SSL will negotiate at this 1.485 + * time). NOTE: None of the supported curves will show up here 1.486 + * because we return a valid length for all of these curves. 1.487 + * The only way to get here is to have some application (not SSL) 1.488 + * which supports some unknown curve and have some vendor supplied 1.489 + * PKCS #11 module support that curve. NOTE: in this case, one 1.490 + * presumes that that pkcs #11 module is likely to be using the 1.491 + * correct encodings. 1.492 + * 1.493 + * Prime Curves (GFp): 1.494 + * Bit False Odds of 1.495 + * Size DER Len False Decode Positive 1.496 + * 112 27 1 in 65536 1.497 + * 128 31 1 in 65536 1.498 + * 160 39 1 in 65536 1.499 + * 192 47 1 in 65536 1.500 + * 224 55 1 in 65536 1.501 + * 239 59 1 in 32768 (top byte can only be 0-127) 1.502 + * 256 63 1 in 65536 1.503 + * 521 129,131 0 (decoded value would be even) 1.504 + * 1.505 + * Binary curves (GF2m). 1.506 + * Bit False Odds of 1.507 + * Size DER Len False Decode Positive 1.508 + * 131 33 0 (top byte can only be 0-7) 1.509 + * 163 41 0 (top byte can only be 0-7) 1.510 + * 176 43 1 in 65536 1.511 + * 191 47 1 in 32768 (top byte can only be 0-127) 1.512 + * 193 49 0 (top byte can only be 0-1) 1.513 + * 208 51 1 in 65536 1.514 + * 233 59 0 (top byte can only be 0-1) 1.515 + * 239 59 1 in 32768 (top byte can only be 0-127) 1.516 + * 272 67 1 in 65536 1.517 + * 283 71 0 (top byte can only be 0-7) 1.518 + * 304 75 1 in 65536 1.519 + * 359 89 1 in 32768 (top byte can only be 0-127) 1.520 + * 368 91 1 in 65536 1.521 + * 409 103 0 (top byte can only be 0-1) 1.522 + * 431 107 1 in 32768 (top byte can only be 0-127) 1.523 + * 571 129,143 0 (decoded value would be even) 1.524 + * 1.525 + */ 1.526 + 1.527 + return CKR_OK; 1.528 + } 1.529 + 1.530 + /* In theory, we should handle the case where the curve == 0 and 1.531 + * the first byte is EC_POINT_FORM_UNCOMPRESSED, (which would be 1.532 + * handled by doing a santity check on the key length and returning 1.533 + * pk11_Attr2SecItem() to copy the ecPoint to the publicKeyValue). 1.534 + * 1.535 + * This test is unnecessary, however, due to the fact that 1.536 + * EC_POINT_FORM_UNCOMPRESSED == SEC_ASIN1_OCTET_STRING, that case is 1.537 + * handled in the above if. That means if we get here, the initial 1.538 + * byte of our ecPoint value was invalid, so we can safely return. 1.539 + * invalid attribute. 1.540 + */ 1.541 + 1.542 + return CKR_ATTRIBUTE_VALUE_INVALID; 1.543 +} 1.544 + 1.545 +/* 1.546 + * extract a public key from a slot and id 1.547 + */ 1.548 +SECKEYPublicKey * 1.549 +PK11_ExtractPublicKey(PK11SlotInfo *slot,KeyType keyType,CK_OBJECT_HANDLE id) 1.550 +{ 1.551 + CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; 1.552 + PLArenaPool *arena; 1.553 + PLArenaPool *tmp_arena; 1.554 + SECKEYPublicKey *pubKey; 1.555 + int templateCount = 0; 1.556 + CK_KEY_TYPE pk11KeyType; 1.557 + CK_RV crv; 1.558 + CK_ATTRIBUTE template[8]; 1.559 + CK_ATTRIBUTE *attrs= template; 1.560 + CK_ATTRIBUTE *modulus,*exponent,*base,*prime,*subprime,*value; 1.561 + CK_ATTRIBUTE *ecparams; 1.562 + 1.563 + /* if we didn't know the key type, get it */ 1.564 + if (keyType== nullKey) { 1.565 + 1.566 + pk11KeyType = PK11_ReadULongAttribute(slot,id,CKA_KEY_TYPE); 1.567 + if (pk11KeyType == CK_UNAVAILABLE_INFORMATION) { 1.568 + return NULL; 1.569 + } 1.570 + switch (pk11KeyType) { 1.571 + case CKK_RSA: 1.572 + keyType = rsaKey; 1.573 + break; 1.574 + case CKK_DSA: 1.575 + keyType = dsaKey; 1.576 + break; 1.577 + case CKK_DH: 1.578 + keyType = dhKey; 1.579 + break; 1.580 + case CKK_EC: 1.581 + keyType = ecKey; 1.582 + break; 1.583 + default: 1.584 + PORT_SetError( SEC_ERROR_BAD_KEY ); 1.585 + return NULL; 1.586 + } 1.587 + } 1.588 + 1.589 + 1.590 + /* now we need to create space for the public key */ 1.591 + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); 1.592 + if (arena == NULL) return NULL; 1.593 + tmp_arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); 1.594 + if (tmp_arena == NULL) { 1.595 + PORT_FreeArena (arena, PR_FALSE); 1.596 + return NULL; 1.597 + } 1.598 + 1.599 + 1.600 + pubKey = (SECKEYPublicKey *) 1.601 + PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey)); 1.602 + if (pubKey == NULL) { 1.603 + PORT_FreeArena (arena, PR_FALSE); 1.604 + PORT_FreeArena (tmp_arena, PR_FALSE); 1.605 + return NULL; 1.606 + } 1.607 + 1.608 + pubKey->arena = arena; 1.609 + pubKey->keyType = keyType; 1.610 + pubKey->pkcs11Slot = PK11_ReferenceSlot(slot); 1.611 + pubKey->pkcs11ID = id; 1.612 + PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, 1.613 + sizeof(keyClass)); attrs++; 1.614 + PK11_SETATTRS(attrs, CKA_KEY_TYPE, &pk11KeyType, 1.615 + sizeof(pk11KeyType) ); attrs++; 1.616 + switch (pubKey->keyType) { 1.617 + case rsaKey: 1.618 + modulus = attrs; 1.619 + PK11_SETATTRS(attrs, CKA_MODULUS, NULL, 0); attrs++; 1.620 + exponent = attrs; 1.621 + PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, NULL, 0); attrs++; 1.622 + 1.623 + templateCount = attrs - template; 1.624 + PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); 1.625 + crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount); 1.626 + if (crv != CKR_OK) break; 1.627 + 1.628 + if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_RSA)) { 1.629 + crv = CKR_OBJECT_HANDLE_INVALID; 1.630 + break; 1.631 + } 1.632 + crv = pk11_Attr2SecItem(arena,modulus,&pubKey->u.rsa.modulus); 1.633 + if (crv != CKR_OK) break; 1.634 + crv = pk11_Attr2SecItem(arena,exponent,&pubKey->u.rsa.publicExponent); 1.635 + if (crv != CKR_OK) break; 1.636 + break; 1.637 + case dsaKey: 1.638 + prime = attrs; 1.639 + PK11_SETATTRS(attrs, CKA_PRIME, NULL, 0); attrs++; 1.640 + subprime = attrs; 1.641 + PK11_SETATTRS(attrs, CKA_SUBPRIME, NULL, 0); attrs++; 1.642 + base = attrs; 1.643 + PK11_SETATTRS(attrs, CKA_BASE, NULL, 0); attrs++; 1.644 + value = attrs; 1.645 + PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0); attrs++; 1.646 + templateCount = attrs - template; 1.647 + PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); 1.648 + crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount); 1.649 + if (crv != CKR_OK) break; 1.650 + 1.651 + if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_DSA)) { 1.652 + crv = CKR_OBJECT_HANDLE_INVALID; 1.653 + break; 1.654 + } 1.655 + crv = pk11_Attr2SecItem(arena,prime,&pubKey->u.dsa.params.prime); 1.656 + if (crv != CKR_OK) break; 1.657 + crv = pk11_Attr2SecItem(arena,subprime,&pubKey->u.dsa.params.subPrime); 1.658 + if (crv != CKR_OK) break; 1.659 + crv = pk11_Attr2SecItem(arena,base,&pubKey->u.dsa.params.base); 1.660 + if (crv != CKR_OK) break; 1.661 + crv = pk11_Attr2SecItem(arena,value,&pubKey->u.dsa.publicValue); 1.662 + if (crv != CKR_OK) break; 1.663 + break; 1.664 + case dhKey: 1.665 + prime = attrs; 1.666 + PK11_SETATTRS(attrs, CKA_PRIME, NULL, 0); attrs++; 1.667 + base = attrs; 1.668 + PK11_SETATTRS(attrs, CKA_BASE, NULL, 0); attrs++; 1.669 + value =attrs; 1.670 + PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0); attrs++; 1.671 + templateCount = attrs - template; 1.672 + PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); 1.673 + crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount); 1.674 + if (crv != CKR_OK) break; 1.675 + 1.676 + if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_DH)) { 1.677 + crv = CKR_OBJECT_HANDLE_INVALID; 1.678 + break; 1.679 + } 1.680 + crv = pk11_Attr2SecItem(arena,prime,&pubKey->u.dh.prime); 1.681 + if (crv != CKR_OK) break; 1.682 + crv = pk11_Attr2SecItem(arena,base,&pubKey->u.dh.base); 1.683 + if (crv != CKR_OK) break; 1.684 + crv = pk11_Attr2SecItem(arena,value,&pubKey->u.dh.publicValue); 1.685 + if (crv != CKR_OK) break; 1.686 + break; 1.687 + case ecKey: 1.688 + pubKey->u.ec.size = 0; 1.689 + ecparams = attrs; 1.690 + PK11_SETATTRS(attrs, CKA_EC_PARAMS, NULL, 0); attrs++; 1.691 + value =attrs; 1.692 + PK11_SETATTRS(attrs, CKA_EC_POINT, NULL, 0); attrs++; 1.693 + templateCount = attrs - template; 1.694 + PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); 1.695 + crv = PK11_GetAttributes(arena,slot,id,template,templateCount); 1.696 + if (crv != CKR_OK) break; 1.697 + 1.698 + if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_EC)) { 1.699 + crv = CKR_OBJECT_HANDLE_INVALID; 1.700 + break; 1.701 + } 1.702 + 1.703 + crv = pk11_Attr2SecItem(arena,ecparams, 1.704 + &pubKey->u.ec.DEREncodedParams); 1.705 + if (crv != CKR_OK) break; 1.706 + crv = pk11_get_Decoded_ECPoint(arena, 1.707 + &pubKey->u.ec.DEREncodedParams, value, 1.708 + &pubKey->u.ec.publicValue); 1.709 + break; 1.710 + case fortezzaKey: 1.711 + case nullKey: 1.712 + default: 1.713 + crv = CKR_OBJECT_HANDLE_INVALID; 1.714 + break; 1.715 + } 1.716 + 1.717 + PORT_FreeArena(tmp_arena,PR_FALSE); 1.718 + 1.719 + if (crv != CKR_OK) { 1.720 + PORT_FreeArena(arena,PR_FALSE); 1.721 + PK11_FreeSlot(slot); 1.722 + PORT_SetError( PK11_MapError(crv) ); 1.723 + return NULL; 1.724 + } 1.725 + 1.726 + return pubKey; 1.727 +} 1.728 + 1.729 +/* 1.730 + * Build a Private Key structure from raw PKCS #11 information. 1.731 + */ 1.732 +SECKEYPrivateKey * 1.733 +PK11_MakePrivKey(PK11SlotInfo *slot, KeyType keyType, 1.734 + PRBool isTemp, CK_OBJECT_HANDLE privID, void *wincx) 1.735 +{ 1.736 + PLArenaPool *arena; 1.737 + SECKEYPrivateKey *privKey; 1.738 + PRBool isPrivate; 1.739 + SECStatus rv; 1.740 + 1.741 + /* don't know? look it up */ 1.742 + if (keyType == nullKey) { 1.743 + CK_KEY_TYPE pk11Type = CKK_RSA; 1.744 + 1.745 + pk11Type = PK11_ReadULongAttribute(slot,privID,CKA_KEY_TYPE); 1.746 + isTemp = (PRBool)!PK11_HasAttributeSet(slot,privID,CKA_TOKEN,PR_FALSE); 1.747 + switch (pk11Type) { 1.748 + case CKK_RSA: keyType = rsaKey; break; 1.749 + case CKK_DSA: keyType = dsaKey; break; 1.750 + case CKK_DH: keyType = dhKey; break; 1.751 + case CKK_KEA: keyType = fortezzaKey; break; 1.752 + case CKK_EC: keyType = ecKey; break; 1.753 + default: 1.754 + break; 1.755 + } 1.756 + } 1.757 + 1.758 + /* if the key is private, make sure we are authenticated to the 1.759 + * token before we try to use it */ 1.760 + isPrivate = (PRBool)PK11_HasAttributeSet(slot,privID,CKA_PRIVATE,PR_FALSE); 1.761 + if (isPrivate) { 1.762 + rv = PK11_Authenticate(slot, PR_TRUE, wincx); 1.763 + if (rv != SECSuccess) { 1.764 + return NULL; 1.765 + } 1.766 + } 1.767 + 1.768 + /* now we need to create space for the private key */ 1.769 + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); 1.770 + if (arena == NULL) return NULL; 1.771 + 1.772 + privKey = (SECKEYPrivateKey *) 1.773 + PORT_ArenaZAlloc(arena, sizeof(SECKEYPrivateKey)); 1.774 + if (privKey == NULL) { 1.775 + PORT_FreeArena(arena, PR_FALSE); 1.776 + return NULL; 1.777 + } 1.778 + 1.779 + privKey->arena = arena; 1.780 + privKey->keyType = keyType; 1.781 + privKey->pkcs11Slot = PK11_ReferenceSlot(slot); 1.782 + privKey->pkcs11ID = privID; 1.783 + privKey->pkcs11IsTemp = isTemp; 1.784 + privKey->wincx = wincx; 1.785 + 1.786 + return privKey; 1.787 +} 1.788 + 1.789 + 1.790 +PK11SlotInfo * 1.791 +PK11_GetSlotFromPrivateKey(SECKEYPrivateKey *key) 1.792 +{ 1.793 + PK11SlotInfo *slot = key->pkcs11Slot; 1.794 + slot = PK11_ReferenceSlot(slot); 1.795 + return slot; 1.796 +} 1.797 + 1.798 +/* 1.799 + * Get the modulus length for raw parsing 1.800 + */ 1.801 +int 1.802 +PK11_GetPrivateModulusLen(SECKEYPrivateKey *key) 1.803 +{ 1.804 + CK_ATTRIBUTE theTemplate = { CKA_MODULUS, NULL, 0 }; 1.805 + PK11SlotInfo *slot = key->pkcs11Slot; 1.806 + CK_RV crv; 1.807 + int length; 1.808 + 1.809 + switch (key->keyType) { 1.810 + case rsaKey: 1.811 + crv = PK11_GetAttributes(NULL, slot, key->pkcs11ID, &theTemplate, 1); 1.812 + if (crv != CKR_OK) { 1.813 + PORT_SetError( PK11_MapError(crv) ); 1.814 + return -1; 1.815 + } 1.816 + length = theTemplate.ulValueLen; 1.817 + if ( *(unsigned char *)theTemplate.pValue == 0) { 1.818 + length--; 1.819 + } 1.820 + if (theTemplate.pValue != NULL) 1.821 + PORT_Free(theTemplate.pValue); 1.822 + return (int) length; 1.823 + 1.824 + case fortezzaKey: 1.825 + case dsaKey: 1.826 + case dhKey: 1.827 + default: 1.828 + break; 1.829 + } 1.830 + if (theTemplate.pValue != NULL) 1.831 + PORT_Free(theTemplate.pValue); 1.832 + PORT_SetError( SEC_ERROR_INVALID_KEY ); 1.833 + return -1; 1.834 +} 1.835 + 1.836 + 1.837 + 1.838 +/* 1.839 + * take a private key in one pkcs11 module and load it into another: 1.840 + * NOTE: the source private key is a rare animal... it can't be sensitive. 1.841 + * This is used to do a key gen using one pkcs11 module and storing the 1.842 + * result into another. 1.843 + */ 1.844 +static SECKEYPrivateKey * 1.845 +pk11_loadPrivKeyWithFlags(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, 1.846 + SECKEYPublicKey *pubKey, PK11AttrFlags attrFlags) 1.847 +{ 1.848 + CK_ATTRIBUTE privTemplate[] = { 1.849 + /* class must be first */ 1.850 + { CKA_CLASS, NULL, 0 }, 1.851 + { CKA_KEY_TYPE, NULL, 0 }, 1.852 + { CKA_ID, NULL, 0 }, 1.853 + /* RSA - the attributes below will be replaced for other 1.854 + * key types. 1.855 + */ 1.856 + { CKA_MODULUS, NULL, 0 }, 1.857 + { CKA_PRIVATE_EXPONENT, NULL, 0 }, 1.858 + { CKA_PUBLIC_EXPONENT, NULL, 0 }, 1.859 + { CKA_PRIME_1, NULL, 0 }, 1.860 + { CKA_PRIME_2, NULL, 0 }, 1.861 + { CKA_EXPONENT_1, NULL, 0 }, 1.862 + { CKA_EXPONENT_2, NULL, 0 }, 1.863 + { CKA_COEFFICIENT, NULL, 0 }, 1.864 + { CKA_DECRYPT, NULL, 0 }, 1.865 + { CKA_DERIVE, NULL, 0 }, 1.866 + { CKA_SIGN, NULL, 0 }, 1.867 + { CKA_SIGN_RECOVER, NULL, 0 }, 1.868 + { CKA_UNWRAP, NULL, 0 }, 1.869 + /* reserve space for the attributes that may be 1.870 + * specified in attrFlags */ 1.871 + { CKA_TOKEN, NULL, 0 }, 1.872 + { CKA_PRIVATE, NULL, 0 }, 1.873 + { CKA_MODIFIABLE, NULL, 0 }, 1.874 + { CKA_SENSITIVE, NULL, 0 }, 1.875 + { CKA_EXTRACTABLE, NULL, 0 }, 1.876 +#define NUM_RESERVED_ATTRS 5 /* number of reserved attributes above */ 1.877 + }; 1.878 + CK_BBOOL cktrue = CK_TRUE; 1.879 + CK_BBOOL ckfalse = CK_FALSE; 1.880 + CK_ATTRIBUTE *attrs = NULL, *ap; 1.881 + const int templateSize = sizeof(privTemplate)/sizeof(privTemplate[0]); 1.882 + PLArenaPool *arena; 1.883 + CK_OBJECT_HANDLE objectID; 1.884 + int i, count = 0; 1.885 + int extra_count = 0; 1.886 + CK_RV crv; 1.887 + SECStatus rv; 1.888 + PRBool token = ((attrFlags & PK11_ATTR_TOKEN) != 0); 1.889 + 1.890 + if (pk11_BadAttrFlags(attrFlags)) { 1.891 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.892 + return NULL; 1.893 + } 1.894 + 1.895 + for (i=0; i < templateSize; i++) { 1.896 + if (privTemplate[i].type == CKA_MODULUS) { 1.897 + attrs= &privTemplate[i]; 1.898 + count = i; 1.899 + break; 1.900 + } 1.901 + } 1.902 + PORT_Assert(attrs != NULL); 1.903 + if (attrs == NULL) { 1.904 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.905 + return NULL; 1.906 + } 1.907 + 1.908 + ap = attrs; 1.909 + 1.910 + switch (privKey->keyType) { 1.911 + case rsaKey: 1.912 + count = templateSize - NUM_RESERVED_ATTRS; 1.913 + extra_count = count - (attrs - privTemplate); 1.914 + break; 1.915 + case dsaKey: 1.916 + ap->type = CKA_PRIME; ap++; count++; extra_count++; 1.917 + ap->type = CKA_SUBPRIME; ap++; count++; extra_count++; 1.918 + ap->type = CKA_BASE; ap++; count++; extra_count++; 1.919 + ap->type = CKA_VALUE; ap++; count++; extra_count++; 1.920 + ap->type = CKA_SIGN; ap++; count++; extra_count++; 1.921 + break; 1.922 + case dhKey: 1.923 + ap->type = CKA_PRIME; ap++; count++; extra_count++; 1.924 + ap->type = CKA_BASE; ap++; count++; extra_count++; 1.925 + ap->type = CKA_VALUE; ap++; count++; extra_count++; 1.926 + ap->type = CKA_DERIVE; ap++; count++; extra_count++; 1.927 + break; 1.928 + case ecKey: 1.929 + ap->type = CKA_EC_PARAMS; ap++; count++; extra_count++; 1.930 + ap->type = CKA_VALUE; ap++; count++; extra_count++; 1.931 + ap->type = CKA_DERIVE; ap++; count++; extra_count++; 1.932 + ap->type = CKA_SIGN; ap++; count++; extra_count++; 1.933 + break; 1.934 + default: 1.935 + count = 0; 1.936 + extra_count = 0; 1.937 + break; 1.938 + } 1.939 + 1.940 + if (count == 0) { 1.941 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.942 + return NULL; 1.943 + } 1.944 + 1.945 + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); 1.946 + if (arena == NULL) return NULL; 1.947 + /* 1.948 + * read out the old attributes. 1.949 + */ 1.950 + crv = PK11_GetAttributes(arena, privKey->pkcs11Slot, privKey->pkcs11ID, 1.951 + privTemplate,count); 1.952 + if (crv != CKR_OK) { 1.953 + PORT_SetError( PK11_MapError(crv) ); 1.954 + PORT_FreeArena(arena, PR_TRUE); 1.955 + return NULL; 1.956 + } 1.957 + 1.958 + /* Set token, private, modifiable, sensitive, and extractable */ 1.959 + count += pk11_AttrFlagsToAttributes(attrFlags, &privTemplate[count], 1.960 + &cktrue, &ckfalse); 1.961 + 1.962 + /* Not everyone can handle zero padded key values, give 1.963 + * them the raw data as unsigned */ 1.964 + for (ap=attrs; extra_count; ap++, extra_count--) { 1.965 + pk11_SignedToUnsigned(ap); 1.966 + } 1.967 + 1.968 + /* now Store the puppies */ 1.969 + rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, privTemplate, 1.970 + count, token, &objectID); 1.971 + PORT_FreeArena(arena, PR_TRUE); 1.972 + if (rv != SECSuccess) { 1.973 + return NULL; 1.974 + } 1.975 + 1.976 + /* try loading the public key */ 1.977 + if (pubKey) { 1.978 + PK11_ImportPublicKey(slot, pubKey, token); 1.979 + if (pubKey->pkcs11Slot) { 1.980 + PK11_FreeSlot(pubKey->pkcs11Slot); 1.981 + pubKey->pkcs11Slot = NULL; 1.982 + pubKey->pkcs11ID = CK_INVALID_HANDLE; 1.983 + } 1.984 + } 1.985 + 1.986 + /* build new key structure */ 1.987 + return PK11_MakePrivKey(slot, privKey->keyType, !token, 1.988 + objectID, privKey->wincx); 1.989 +} 1.990 + 1.991 +static SECKEYPrivateKey * 1.992 +pk11_loadPrivKey(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, 1.993 + SECKEYPublicKey *pubKey, PRBool token, PRBool sensitive) 1.994 +{ 1.995 + PK11AttrFlags attrFlags = 0; 1.996 + if (token) { 1.997 + attrFlags |= (PK11_ATTR_TOKEN | PK11_ATTR_PRIVATE); 1.998 + } else { 1.999 + attrFlags |= (PK11_ATTR_SESSION | PK11_ATTR_PUBLIC); 1.1000 + } 1.1001 + if (sensitive) { 1.1002 + attrFlags |= PK11_ATTR_SENSITIVE; 1.1003 + } else { 1.1004 + attrFlags |= PK11_ATTR_INSENSITIVE; 1.1005 + } 1.1006 + return pk11_loadPrivKeyWithFlags(slot, privKey, pubKey, attrFlags); 1.1007 +} 1.1008 + 1.1009 +/* 1.1010 + * export this for PSM 1.1011 + */ 1.1012 +SECKEYPrivateKey * 1.1013 +PK11_LoadPrivKey(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, 1.1014 + SECKEYPublicKey *pubKey, PRBool token, PRBool sensitive) 1.1015 +{ 1.1016 + return pk11_loadPrivKey(slot,privKey,pubKey,token,sensitive); 1.1017 +} 1.1018 + 1.1019 + 1.1020 +/* 1.1021 + * Use the token to generate a key pair. 1.1022 + */ 1.1023 +SECKEYPrivateKey * 1.1024 +PK11_GenerateKeyPairWithOpFlags(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, 1.1025 + void *param, SECKEYPublicKey **pubKey, PK11AttrFlags attrFlags, 1.1026 + CK_FLAGS opFlags, CK_FLAGS opFlagsMask, void *wincx) 1.1027 +{ 1.1028 + /* we have to use these native types because when we call PKCS 11 modules 1.1029 + * we have to make sure that we are using the correct sizes for all the 1.1030 + * parameters. */ 1.1031 + CK_BBOOL ckfalse = CK_FALSE; 1.1032 + CK_BBOOL cktrue = CK_TRUE; 1.1033 + CK_ULONG modulusBits; 1.1034 + CK_BYTE publicExponent[4]; 1.1035 + CK_ATTRIBUTE privTemplate[] = { 1.1036 + { CKA_SENSITIVE, NULL, 0}, 1.1037 + { CKA_TOKEN, NULL, 0}, 1.1038 + { CKA_PRIVATE, NULL, 0}, 1.1039 + { CKA_DERIVE, NULL, 0}, 1.1040 + { CKA_UNWRAP, NULL, 0}, 1.1041 + { CKA_SIGN, NULL, 0}, 1.1042 + { CKA_DECRYPT, NULL, 0}, 1.1043 + { CKA_EXTRACTABLE, NULL, 0}, 1.1044 + { CKA_MODIFIABLE, NULL, 0}, 1.1045 + }; 1.1046 + CK_ATTRIBUTE rsaPubTemplate[] = { 1.1047 + { CKA_MODULUS_BITS, NULL, 0}, 1.1048 + { CKA_PUBLIC_EXPONENT, NULL, 0}, 1.1049 + { CKA_TOKEN, NULL, 0}, 1.1050 + { CKA_DERIVE, NULL, 0}, 1.1051 + { CKA_WRAP, NULL, 0}, 1.1052 + { CKA_VERIFY, NULL, 0}, 1.1053 + { CKA_VERIFY_RECOVER, NULL, 0}, 1.1054 + { CKA_ENCRYPT, NULL, 0}, 1.1055 + { CKA_MODIFIABLE, NULL, 0}, 1.1056 + }; 1.1057 + CK_ATTRIBUTE dsaPubTemplate[] = { 1.1058 + { CKA_PRIME, NULL, 0 }, 1.1059 + { CKA_SUBPRIME, NULL, 0 }, 1.1060 + { CKA_BASE, NULL, 0 }, 1.1061 + { CKA_TOKEN, NULL, 0}, 1.1062 + { CKA_DERIVE, NULL, 0}, 1.1063 + { CKA_WRAP, NULL, 0}, 1.1064 + { CKA_VERIFY, NULL, 0}, 1.1065 + { CKA_VERIFY_RECOVER, NULL, 0}, 1.1066 + { CKA_ENCRYPT, NULL, 0}, 1.1067 + { CKA_MODIFIABLE, NULL, 0}, 1.1068 + }; 1.1069 + CK_ATTRIBUTE dhPubTemplate[] = { 1.1070 + { CKA_PRIME, NULL, 0 }, 1.1071 + { CKA_BASE, NULL, 0 }, 1.1072 + { CKA_TOKEN, NULL, 0}, 1.1073 + { CKA_DERIVE, NULL, 0}, 1.1074 + { CKA_WRAP, NULL, 0}, 1.1075 + { CKA_VERIFY, NULL, 0}, 1.1076 + { CKA_VERIFY_RECOVER, NULL, 0}, 1.1077 + { CKA_ENCRYPT, NULL, 0}, 1.1078 + { CKA_MODIFIABLE, NULL, 0}, 1.1079 + }; 1.1080 + CK_ATTRIBUTE ecPubTemplate[] = { 1.1081 + { CKA_EC_PARAMS, NULL, 0 }, 1.1082 + { CKA_TOKEN, NULL, 0}, 1.1083 + { CKA_DERIVE, NULL, 0}, 1.1084 + { CKA_WRAP, NULL, 0}, 1.1085 + { CKA_VERIFY, NULL, 0}, 1.1086 + { CKA_VERIFY_RECOVER, NULL, 0}, 1.1087 + { CKA_ENCRYPT, NULL, 0}, 1.1088 + { CKA_MODIFIABLE, NULL, 0}, 1.1089 + }; 1.1090 + SECKEYECParams * ecParams; 1.1091 + 1.1092 + /*CK_ULONG key_size = 0;*/ 1.1093 + CK_ATTRIBUTE *pubTemplate; 1.1094 + int privCount = 0; 1.1095 + int pubCount = 0; 1.1096 + PK11RSAGenParams *rsaParams; 1.1097 + SECKEYPQGParams *dsaParams; 1.1098 + SECKEYDHParams * dhParams; 1.1099 + CK_MECHANISM mechanism; 1.1100 + CK_MECHANISM test_mech; 1.1101 + CK_MECHANISM test_mech2; 1.1102 + CK_SESSION_HANDLE session_handle; 1.1103 + CK_RV crv; 1.1104 + CK_OBJECT_HANDLE privID,pubID; 1.1105 + SECKEYPrivateKey *privKey; 1.1106 + KeyType keyType; 1.1107 + PRBool restore; 1.1108 + int peCount,i; 1.1109 + CK_ATTRIBUTE *attrs; 1.1110 + CK_ATTRIBUTE *privattrs; 1.1111 + CK_ATTRIBUTE setTemplate; 1.1112 + CK_MECHANISM_INFO mechanism_info; 1.1113 + CK_OBJECT_CLASS keyClass; 1.1114 + SECItem *cka_id; 1.1115 + PRBool haslock = PR_FALSE; 1.1116 + PRBool pubIsToken = PR_FALSE; 1.1117 + PRBool token = ((attrFlags & PK11_ATTR_TOKEN) != 0); 1.1118 + /* subset of attrFlags applicable to the public key */ 1.1119 + PK11AttrFlags pubKeyAttrFlags = attrFlags & 1.1120 + (PK11_ATTR_TOKEN | PK11_ATTR_SESSION 1.1121 + | PK11_ATTR_MODIFIABLE | PK11_ATTR_UNMODIFIABLE); 1.1122 + 1.1123 + if (pk11_BadAttrFlags(attrFlags)) { 1.1124 + PORT_SetError( SEC_ERROR_INVALID_ARGS ); 1.1125 + return NULL; 1.1126 + } 1.1127 + 1.1128 + if (!param) { 1.1129 + PORT_SetError( SEC_ERROR_INVALID_ARGS ); 1.1130 + return NULL; 1.1131 + } 1.1132 + 1.1133 + /* 1.1134 + * The opFlags and opFlagMask parameters allow us to control the 1.1135 + * settings of the key usage attributes (CKA_ENCRYPT and friends). 1.1136 + * opFlagMask is set to one if the flag is specified in opFlags and 1.1137 + * zero if it is to take on a default value calculated by 1.1138 + * PK11_GenerateKeyPairWithOpFlags. 1.1139 + * opFlags specifies the actual value of the flag 1 or 0. 1.1140 + * Bits not corresponding to one bits in opFlagMask should be zero. 1.1141 + */ 1.1142 + 1.1143 + /* if we are trying to turn on a flag, it better be in the mask */ 1.1144 + PORT_Assert ((opFlags & ~opFlagsMask) == 0); 1.1145 + opFlags &= opFlagsMask; 1.1146 + 1.1147 + PORT_Assert(slot != NULL); 1.1148 + if (slot == NULL) { 1.1149 + PORT_SetError( SEC_ERROR_NO_MODULE); 1.1150 + return NULL; 1.1151 + } 1.1152 + 1.1153 + /* if our slot really doesn't do this mechanism, Generate the key 1.1154 + * in our internal token and write it out */ 1.1155 + if (!PK11_DoesMechanism(slot,type)) { 1.1156 + PK11SlotInfo *int_slot = PK11_GetInternalSlot(); 1.1157 + 1.1158 + /* don't loop forever looking for a slot */ 1.1159 + if (slot == int_slot) { 1.1160 + PK11_FreeSlot(int_slot); 1.1161 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.1162 + return NULL; 1.1163 + } 1.1164 + 1.1165 + /* if there isn't a suitable slot, then we can't do the keygen */ 1.1166 + if (int_slot == NULL) { 1.1167 + PORT_SetError( SEC_ERROR_NO_MODULE ); 1.1168 + return NULL; 1.1169 + } 1.1170 + 1.1171 + /* generate the temporary key to load */ 1.1172 + privKey = PK11_GenerateKeyPair(int_slot,type, param, pubKey, PR_FALSE, 1.1173 + PR_FALSE, wincx); 1.1174 + PK11_FreeSlot(int_slot); 1.1175 + 1.1176 + /* if successful, load the temp key into the new token */ 1.1177 + if (privKey != NULL) { 1.1178 + SECKEYPrivateKey *newPrivKey = pk11_loadPrivKeyWithFlags(slot, 1.1179 + privKey,*pubKey,attrFlags); 1.1180 + SECKEY_DestroyPrivateKey(privKey); 1.1181 + if (newPrivKey == NULL) { 1.1182 + SECKEY_DestroyPublicKey(*pubKey); 1.1183 + *pubKey = NULL; 1.1184 + } 1.1185 + return newPrivKey; 1.1186 + } 1.1187 + return NULL; 1.1188 + } 1.1189 + 1.1190 + 1.1191 + mechanism.mechanism = type; 1.1192 + mechanism.pParameter = NULL; 1.1193 + mechanism.ulParameterLen = 0; 1.1194 + test_mech.pParameter = NULL; 1.1195 + test_mech.ulParameterLen = 0; 1.1196 + test_mech2.mechanism = CKM_INVALID_MECHANISM; 1.1197 + test_mech2.pParameter = NULL; 1.1198 + test_mech2.ulParameterLen = 0; 1.1199 + 1.1200 + /* set up the private key template */ 1.1201 + privattrs = privTemplate; 1.1202 + privattrs += pk11_AttrFlagsToAttributes(attrFlags, privattrs, 1.1203 + &cktrue, &ckfalse); 1.1204 + 1.1205 + /* set up the mechanism specific info */ 1.1206 + switch (type) { 1.1207 + case CKM_RSA_PKCS_KEY_PAIR_GEN: 1.1208 + case CKM_RSA_X9_31_KEY_PAIR_GEN: 1.1209 + rsaParams = (PK11RSAGenParams *)param; 1.1210 + if (rsaParams->pe == 0) { 1.1211 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.1212 + return NULL; 1.1213 + } 1.1214 + modulusBits = rsaParams->keySizeInBits; 1.1215 + peCount = 0; 1.1216 + 1.1217 + /* convert pe to a PKCS #11 string */ 1.1218 + for (i=0; i < 4; i++) { 1.1219 + if (peCount || (rsaParams->pe & 1.1220 + ((unsigned long)0xff000000L >> (i*8)))) { 1.1221 + publicExponent[peCount] = 1.1222 + (CK_BYTE)((rsaParams->pe >> (3-i)*8) & 0xff); 1.1223 + peCount++; 1.1224 + } 1.1225 + } 1.1226 + PORT_Assert(peCount != 0); 1.1227 + attrs = rsaPubTemplate; 1.1228 + PK11_SETATTRS(attrs, CKA_MODULUS_BITS, 1.1229 + &modulusBits, sizeof(modulusBits)); attrs++; 1.1230 + PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, 1.1231 + publicExponent, peCount);attrs++; 1.1232 + pubTemplate = rsaPubTemplate; 1.1233 + keyType = rsaKey; 1.1234 + test_mech.mechanism = CKM_RSA_PKCS; 1.1235 + break; 1.1236 + case CKM_DSA_KEY_PAIR_GEN: 1.1237 + dsaParams = (SECKEYPQGParams *)param; 1.1238 + attrs = dsaPubTemplate; 1.1239 + PK11_SETATTRS(attrs, CKA_PRIME, dsaParams->prime.data, 1.1240 + dsaParams->prime.len); attrs++; 1.1241 + PK11_SETATTRS(attrs, CKA_SUBPRIME, dsaParams->subPrime.data, 1.1242 + dsaParams->subPrime.len); attrs++; 1.1243 + PK11_SETATTRS(attrs, CKA_BASE, dsaParams->base.data, 1.1244 + dsaParams->base.len); attrs++; 1.1245 + pubTemplate = dsaPubTemplate; 1.1246 + keyType = dsaKey; 1.1247 + test_mech.mechanism = CKM_DSA; 1.1248 + break; 1.1249 + case CKM_DH_PKCS_KEY_PAIR_GEN: 1.1250 + dhParams = (SECKEYDHParams *)param; 1.1251 + attrs = dhPubTemplate; 1.1252 + PK11_SETATTRS(attrs, CKA_PRIME, dhParams->prime.data, 1.1253 + dhParams->prime.len); attrs++; 1.1254 + PK11_SETATTRS(attrs, CKA_BASE, dhParams->base.data, 1.1255 + dhParams->base.len); attrs++; 1.1256 + pubTemplate = dhPubTemplate; 1.1257 + keyType = dhKey; 1.1258 + test_mech.mechanism = CKM_DH_PKCS_DERIVE; 1.1259 + break; 1.1260 + case CKM_EC_KEY_PAIR_GEN: 1.1261 + ecParams = (SECKEYECParams *)param; 1.1262 + attrs = ecPubTemplate; 1.1263 + PK11_SETATTRS(attrs, CKA_EC_PARAMS, ecParams->data, 1.1264 + ecParams->len); attrs++; 1.1265 + pubTemplate = ecPubTemplate; 1.1266 + keyType = ecKey; 1.1267 + /* 1.1268 + * ECC supports 2 different mechanism types (unlike RSA, which 1.1269 + * supports different usages with the same mechanism). 1.1270 + * We may need to query both mechanism types and or the results 1.1271 + * together -- but we only do that if either the user has 1.1272 + * requested both usages, or not specified any usages. 1.1273 + */ 1.1274 + if ((opFlags & (CKF_SIGN|CKF_DERIVE)) == (CKF_SIGN|CKF_DERIVE)) { 1.1275 + /* We've explicitly turned on both flags, use both mechanism */ 1.1276 + test_mech.mechanism = CKM_ECDH1_DERIVE; 1.1277 + test_mech2.mechanism = CKM_ECDSA; 1.1278 + } else if (opFlags & CKF_SIGN) { 1.1279 + /* just do signing */ 1.1280 + test_mech.mechanism = CKM_ECDSA; 1.1281 + } else if (opFlags & CKF_DERIVE) { 1.1282 + /* just do ECDH */ 1.1283 + test_mech.mechanism = CKM_ECDH1_DERIVE; 1.1284 + } else { 1.1285 + /* neither was specified default to both */ 1.1286 + test_mech.mechanism = CKM_ECDH1_DERIVE; 1.1287 + test_mech2.mechanism = CKM_ECDSA; 1.1288 + } 1.1289 + break; 1.1290 + default: 1.1291 + PORT_SetError( SEC_ERROR_BAD_KEY ); 1.1292 + return NULL; 1.1293 + } 1.1294 + 1.1295 + /* now query the slot to find out how "good" a key we can generate */ 1.1296 + if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot); 1.1297 + crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID, 1.1298 + test_mech.mechanism,&mechanism_info); 1.1299 + /* 1.1300 + * EC keys are used in multiple different types of mechanism, if we 1.1301 + * are using dual use keys, we need to query the second mechanism 1.1302 + * as well. 1.1303 + */ 1.1304 + if (test_mech2.mechanism != CKM_INVALID_MECHANISM) { 1.1305 + CK_MECHANISM_INFO mechanism_info2; 1.1306 + CK_RV crv2; 1.1307 + 1.1308 + if (crv != CKR_OK) { 1.1309 + /* the first failed, make sure there is no trash in the 1.1310 + * mechanism flags when we or it below */ 1.1311 + mechanism_info.flags = 0; 1.1312 + } 1.1313 + crv2 = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID, 1.1314 + test_mech2.mechanism, &mechanism_info2); 1.1315 + if (crv2 == CKR_OK) { 1.1316 + crv = CKR_OK; /* succeed if either mechnaism info succeeds */ 1.1317 + /* combine the 2 sets of mechnanism flags */ 1.1318 + mechanism_info.flags |= mechanism_info2.flags; 1.1319 + } 1.1320 + } 1.1321 + if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot); 1.1322 + if ((crv != CKR_OK) || (mechanism_info.flags == 0)) { 1.1323 + /* must be old module... guess what it should be... */ 1.1324 + switch (test_mech.mechanism) { 1.1325 + case CKM_RSA_PKCS: 1.1326 + mechanism_info.flags = (CKF_SIGN | CKF_DECRYPT | 1.1327 + CKF_WRAP | CKF_VERIFY_RECOVER | CKF_ENCRYPT | CKF_WRAP); 1.1328 + break; 1.1329 + case CKM_DSA: 1.1330 + mechanism_info.flags = CKF_SIGN | CKF_VERIFY; 1.1331 + break; 1.1332 + case CKM_DH_PKCS_DERIVE: 1.1333 + mechanism_info.flags = CKF_DERIVE; 1.1334 + break; 1.1335 + case CKM_ECDH1_DERIVE: 1.1336 + mechanism_info.flags = CKF_DERIVE; 1.1337 + if (test_mech2.mechanism == CKM_ECDSA) { 1.1338 + mechanism_info.flags |= CKF_SIGN | CKF_VERIFY; 1.1339 + } 1.1340 + break; 1.1341 + case CKM_ECDSA: 1.1342 + mechanism_info.flags = CKF_SIGN | CKF_VERIFY; 1.1343 + break; 1.1344 + default: 1.1345 + break; 1.1346 + } 1.1347 + } 1.1348 + /* now adjust our flags according to the user's key usage passed to us */ 1.1349 + mechanism_info.flags = (mechanism_info.flags & (~opFlagsMask)) | opFlags; 1.1350 + /* set the public key attributes */ 1.1351 + attrs += pk11_AttrFlagsToAttributes(pubKeyAttrFlags, attrs, 1.1352 + &cktrue, &ckfalse); 1.1353 + PK11_SETATTRS(attrs, CKA_DERIVE, 1.1354 + mechanism_info.flags & CKF_DERIVE ? &cktrue : &ckfalse, 1.1355 + sizeof(CK_BBOOL)); attrs++; 1.1356 + PK11_SETATTRS(attrs, CKA_WRAP, 1.1357 + mechanism_info.flags & CKF_WRAP ? &cktrue : &ckfalse, 1.1358 + sizeof(CK_BBOOL)); attrs++; 1.1359 + PK11_SETATTRS(attrs, CKA_VERIFY, 1.1360 + mechanism_info.flags & CKF_VERIFY ? &cktrue : &ckfalse, 1.1361 + sizeof(CK_BBOOL)); attrs++; 1.1362 + PK11_SETATTRS(attrs, CKA_VERIFY_RECOVER, 1.1363 + mechanism_info.flags & CKF_VERIFY_RECOVER ? &cktrue : &ckfalse, 1.1364 + sizeof(CK_BBOOL)); attrs++; 1.1365 + PK11_SETATTRS(attrs, CKA_ENCRYPT, 1.1366 + mechanism_info.flags & CKF_ENCRYPT? &cktrue : &ckfalse, 1.1367 + sizeof(CK_BBOOL)); attrs++; 1.1368 + /* set the private key attributes */ 1.1369 + PK11_SETATTRS(privattrs, CKA_DERIVE, 1.1370 + mechanism_info.flags & CKF_DERIVE ? &cktrue : &ckfalse, 1.1371 + sizeof(CK_BBOOL)); privattrs++; 1.1372 + PK11_SETATTRS(privattrs, CKA_UNWRAP, 1.1373 + mechanism_info.flags & CKF_UNWRAP ? &cktrue : &ckfalse, 1.1374 + sizeof(CK_BBOOL)); privattrs++; 1.1375 + PK11_SETATTRS(privattrs, CKA_SIGN, 1.1376 + mechanism_info.flags & CKF_SIGN ? &cktrue : &ckfalse, 1.1377 + sizeof(CK_BBOOL)); privattrs++; 1.1378 + PK11_SETATTRS(privattrs, CKA_DECRYPT, 1.1379 + mechanism_info.flags & CKF_DECRYPT ? &cktrue : &ckfalse, 1.1380 + sizeof(CK_BBOOL)); privattrs++; 1.1381 + 1.1382 + if (token) { 1.1383 + session_handle = PK11_GetRWSession(slot); 1.1384 + haslock = PK11_RWSessionHasLock(slot,session_handle); 1.1385 + restore = PR_TRUE; 1.1386 + } else { 1.1387 + session_handle = slot->session; 1.1388 + if (session_handle != CK_INVALID_SESSION) 1.1389 + PK11_EnterSlotMonitor(slot); 1.1390 + restore = PR_FALSE; 1.1391 + haslock = PR_TRUE; 1.1392 + } 1.1393 + 1.1394 + if (session_handle == CK_INVALID_SESSION) { 1.1395 + PORT_SetError(SEC_ERROR_BAD_DATA); 1.1396 + return NULL; 1.1397 + } 1.1398 + privCount = privattrs - privTemplate; 1.1399 + pubCount = attrs - pubTemplate; 1.1400 + crv = PK11_GETTAB(slot)->C_GenerateKeyPair(session_handle, &mechanism, 1.1401 + pubTemplate,pubCount,privTemplate,privCount,&pubID,&privID); 1.1402 + 1.1403 + if (crv != CKR_OK) { 1.1404 + if (restore) { 1.1405 + PK11_RestoreROSession(slot,session_handle); 1.1406 + } else PK11_ExitSlotMonitor(slot); 1.1407 + PORT_SetError( PK11_MapError(crv) ); 1.1408 + return NULL; 1.1409 + } 1.1410 + /* This locking code is dangerous and needs to be more thought 1.1411 + * out... the real problem is that we're holding the mutex open this long 1.1412 + */ 1.1413 + if (haslock) { PK11_ExitSlotMonitor(slot); } 1.1414 + 1.1415 + /* swap around the ID's for older PKCS #11 modules */ 1.1416 + keyClass = PK11_ReadULongAttribute(slot,pubID,CKA_CLASS); 1.1417 + if (keyClass != CKO_PUBLIC_KEY) { 1.1418 + CK_OBJECT_HANDLE tmp = pubID; 1.1419 + pubID = privID; 1.1420 + privID = tmp; 1.1421 + } 1.1422 + 1.1423 + *pubKey = PK11_ExtractPublicKey(slot, keyType, pubID); 1.1424 + if (*pubKey == NULL) { 1.1425 + if (restore) { 1.1426 + /* we may have to restore the mutex so it get's exited properly 1.1427 + * in RestoreROSession */ 1.1428 + if (haslock) PK11_EnterSlotMonitor(slot); 1.1429 + PK11_RestoreROSession(slot,session_handle); 1.1430 + } 1.1431 + PK11_DestroyObject(slot,pubID); 1.1432 + PK11_DestroyObject(slot,privID); 1.1433 + return NULL; 1.1434 + } 1.1435 + 1.1436 + /* set the ID to the public key so we can find it again */ 1.1437 + cka_id = pk11_MakeIDFromPublicKey(*pubKey); 1.1438 + pubIsToken = (PRBool)PK11_HasAttributeSet(slot,pubID, CKA_TOKEN,PR_FALSE); 1.1439 + 1.1440 + PK11_SETATTRS(&setTemplate, CKA_ID, cka_id->data, cka_id->len); 1.1441 + 1.1442 + if (haslock) { PK11_EnterSlotMonitor(slot); } 1.1443 + crv = PK11_GETTAB(slot)->C_SetAttributeValue(session_handle, privID, 1.1444 + &setTemplate, 1); 1.1445 + 1.1446 + if (crv == CKR_OK && pubIsToken) { 1.1447 + crv = PK11_GETTAB(slot)->C_SetAttributeValue(session_handle, pubID, 1.1448 + &setTemplate, 1); 1.1449 + } 1.1450 + 1.1451 + 1.1452 + if (restore) { 1.1453 + PK11_RestoreROSession(slot,session_handle); 1.1454 + } else { 1.1455 + PK11_ExitSlotMonitor(slot); 1.1456 + } 1.1457 + SECITEM_FreeItem(cka_id,PR_TRUE); 1.1458 + 1.1459 + 1.1460 + if (crv != CKR_OK) { 1.1461 + PK11_DestroyObject(slot,pubID); 1.1462 + PK11_DestroyObject(slot,privID); 1.1463 + PORT_SetError( PK11_MapError(crv) ); 1.1464 + *pubKey = NULL; 1.1465 + return NULL; 1.1466 + } 1.1467 + 1.1468 + privKey = PK11_MakePrivKey(slot,keyType,!token,privID,wincx); 1.1469 + if (privKey == NULL) { 1.1470 + SECKEY_DestroyPublicKey(*pubKey); 1.1471 + PK11_DestroyObject(slot,privID); 1.1472 + *pubKey = NULL; 1.1473 + return NULL; 1.1474 + } 1.1475 + 1.1476 + return privKey; 1.1477 +} 1.1478 + 1.1479 +SECKEYPrivateKey * 1.1480 +PK11_GenerateKeyPairWithFlags(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, 1.1481 + void *param, SECKEYPublicKey **pubKey, PK11AttrFlags attrFlags, void *wincx) 1.1482 +{ 1.1483 + return PK11_GenerateKeyPairWithOpFlags(slot,type,param,pubKey,attrFlags, 1.1484 + 0, 0, wincx); 1.1485 +} 1.1486 + 1.1487 +/* 1.1488 + * Use the token to generate a key pair. 1.1489 + */ 1.1490 +SECKEYPrivateKey * 1.1491 +PK11_GenerateKeyPair(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, 1.1492 + void *param, SECKEYPublicKey **pubKey, PRBool token, 1.1493 + PRBool sensitive, void *wincx) 1.1494 +{ 1.1495 + PK11AttrFlags attrFlags = 0; 1.1496 + 1.1497 + if (token) { 1.1498 + attrFlags |= PK11_ATTR_TOKEN; 1.1499 + } else { 1.1500 + attrFlags |= PK11_ATTR_SESSION; 1.1501 + } 1.1502 + if (sensitive) { 1.1503 + attrFlags |= (PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE); 1.1504 + } else { 1.1505 + attrFlags |= (PK11_ATTR_INSENSITIVE | PK11_ATTR_PUBLIC); 1.1506 + } 1.1507 + return PK11_GenerateKeyPairWithFlags(slot, type, param, pubKey, 1.1508 + attrFlags, wincx); 1.1509 +} 1.1510 + 1.1511 +/* build a public KEA key from the public value */ 1.1512 +SECKEYPublicKey * 1.1513 +PK11_MakeKEAPubKey(unsigned char *keyData,int length) 1.1514 +{ 1.1515 + SECKEYPublicKey *pubk; 1.1516 + SECItem pkData; 1.1517 + SECStatus rv; 1.1518 + PLArenaPool *arena; 1.1519 + 1.1520 + pkData.data = keyData; 1.1521 + pkData.len = length; 1.1522 + 1.1523 + arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE); 1.1524 + if (arena == NULL) 1.1525 + return NULL; 1.1526 + 1.1527 + pubk = (SECKEYPublicKey *) PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey)); 1.1528 + if (pubk == NULL) { 1.1529 + PORT_FreeArena (arena, PR_FALSE); 1.1530 + return NULL; 1.1531 + } 1.1532 + 1.1533 + pubk->arena = arena; 1.1534 + pubk->pkcs11Slot = 0; 1.1535 + pubk->pkcs11ID = CK_INVALID_HANDLE; 1.1536 + pubk->keyType = fortezzaKey; 1.1537 + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.KEAKey, &pkData); 1.1538 + if (rv != SECSuccess) { 1.1539 + PORT_FreeArena (arena, PR_FALSE); 1.1540 + return NULL; 1.1541 + } 1.1542 + return pubk; 1.1543 +} 1.1544 + 1.1545 +/* 1.1546 + * NOTE: This function doesn't return a SECKEYPrivateKey struct to represent 1.1547 + * the new private key object. If it were to create a session object that 1.1548 + * could later be looked up by its nickname, it would leak a SECKEYPrivateKey. 1.1549 + * So isPerm must be true. 1.1550 + */ 1.1551 +SECStatus 1.1552 +PK11_ImportEncryptedPrivateKeyInfo(PK11SlotInfo *slot, 1.1553 + SECKEYEncryptedPrivateKeyInfo *epki, SECItem *pwitem, 1.1554 + SECItem *nickname, SECItem *publicValue, PRBool isPerm, 1.1555 + PRBool isPrivate, KeyType keyType, 1.1556 + unsigned int keyUsage, void *wincx) 1.1557 +{ 1.1558 + if (!isPerm) { 1.1559 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.1560 + return SECFailure; 1.1561 + } 1.1562 + return PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(slot, epki, 1.1563 + pwitem, nickname, publicValue, isPerm, isPrivate, keyType, 1.1564 + keyUsage, NULL, wincx); 1.1565 +} 1.1566 + 1.1567 +SECStatus 1.1568 +PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, 1.1569 + SECKEYEncryptedPrivateKeyInfo *epki, SECItem *pwitem, 1.1570 + SECItem *nickname, SECItem *publicValue, PRBool isPerm, 1.1571 + PRBool isPrivate, KeyType keyType, 1.1572 + unsigned int keyUsage, SECKEYPrivateKey **privk, 1.1573 + void *wincx) 1.1574 +{ 1.1575 + CK_MECHANISM_TYPE pbeMechType; 1.1576 + SECItem *crypto_param = NULL; 1.1577 + PK11SymKey *key = NULL; 1.1578 + SECStatus rv = SECSuccess; 1.1579 + CK_MECHANISM_TYPE cryptoMechType; 1.1580 + SECKEYPrivateKey *privKey = NULL; 1.1581 + PRBool faulty3DES = PR_FALSE; 1.1582 + int usageCount = 0; 1.1583 + CK_KEY_TYPE key_type; 1.1584 + CK_ATTRIBUTE_TYPE *usage = NULL; 1.1585 + CK_ATTRIBUTE_TYPE rsaUsage[] = { 1.1586 + CKA_UNWRAP, CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER }; 1.1587 + CK_ATTRIBUTE_TYPE dsaUsage[] = { CKA_SIGN }; 1.1588 + CK_ATTRIBUTE_TYPE dhUsage[] = { CKA_DERIVE }; 1.1589 + CK_ATTRIBUTE_TYPE ecUsage[] = { CKA_SIGN, CKA_DERIVE }; 1.1590 + if((epki == NULL) || (pwitem == NULL)) 1.1591 + return SECFailure; 1.1592 + 1.1593 + pbeMechType = PK11_AlgtagToMechanism(SECOID_FindOIDTag( 1.1594 + &epki->algorithm.algorithm)); 1.1595 + 1.1596 + switch (keyType) { 1.1597 + default: 1.1598 + case rsaKey: 1.1599 + key_type = CKK_RSA; 1.1600 + switch (keyUsage & (KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE)) { 1.1601 + case KU_KEY_ENCIPHERMENT: 1.1602 + usage = rsaUsage; 1.1603 + usageCount = 2; 1.1604 + break; 1.1605 + case KU_DIGITAL_SIGNATURE: 1.1606 + usage = &rsaUsage[2]; 1.1607 + usageCount = 2; 1.1608 + break; 1.1609 + case KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE: 1.1610 + case 0: /* default to everything */ 1.1611 + usage = rsaUsage; 1.1612 + usageCount = 4; 1.1613 + break; 1.1614 + } 1.1615 + break; 1.1616 + case dhKey: 1.1617 + key_type = CKK_DH; 1.1618 + usage = dhUsage; 1.1619 + usageCount = sizeof(dhUsage)/sizeof(dhUsage[0]); 1.1620 + break; 1.1621 + case dsaKey: 1.1622 + key_type = CKK_DSA; 1.1623 + usage = dsaUsage; 1.1624 + usageCount = sizeof(dsaUsage)/sizeof(dsaUsage[0]); 1.1625 + break; 1.1626 + case ecKey: 1.1627 + key_type = CKK_EC; 1.1628 + switch (keyUsage & (KU_DIGITAL_SIGNATURE|KU_KEY_AGREEMENT)) { 1.1629 + case KU_DIGITAL_SIGNATURE: 1.1630 + usage = ecUsage; 1.1631 + usageCount = 1; 1.1632 + break; 1.1633 + case KU_KEY_AGREEMENT: 1.1634 + usage = &ecUsage[1]; 1.1635 + usageCount = 1; 1.1636 + break; 1.1637 + case KU_DIGITAL_SIGNATURE|KU_KEY_AGREEMENT: 1.1638 + default: /* default to everything */ 1.1639 + usage = ecUsage; 1.1640 + usageCount = 2; 1.1641 + break; 1.1642 + } 1.1643 + break; 1.1644 + } 1.1645 + 1.1646 +try_faulty_3des: 1.1647 + 1.1648 + key = PK11_PBEKeyGen(slot, &epki->algorithm, pwitem, faulty3DES, wincx); 1.1649 + if (key == NULL) { 1.1650 + rv = SECFailure; 1.1651 + goto done; 1.1652 + } 1.1653 + cryptoMechType = pk11_GetPBECryptoMechanism(&epki->algorithm, 1.1654 + &crypto_param, pwitem, faulty3DES); 1.1655 + if (cryptoMechType == CKM_INVALID_MECHANISM) { 1.1656 + rv = SECFailure; 1.1657 + goto done; 1.1658 + } 1.1659 + 1.1660 + 1.1661 + cryptoMechType = PK11_GetPadMechanism(cryptoMechType); 1.1662 + 1.1663 + PORT_Assert(usage != NULL); 1.1664 + PORT_Assert(usageCount != 0); 1.1665 + privKey = PK11_UnwrapPrivKey(slot, key, cryptoMechType, 1.1666 + crypto_param, &epki->encryptedData, 1.1667 + nickname, publicValue, isPerm, isPrivate, 1.1668 + key_type, usage, usageCount, wincx); 1.1669 + if(privKey) { 1.1670 + if (privk) { 1.1671 + *privk = privKey; 1.1672 + } else { 1.1673 + SECKEY_DestroyPrivateKey(privKey); 1.1674 + } 1.1675 + privKey = NULL; 1.1676 + rv = SECSuccess; 1.1677 + goto done; 1.1678 + } 1.1679 + 1.1680 + /* if we are unable to import the key and the pbeMechType is 1.1681 + * CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC, then it is possible that 1.1682 + * the encrypted blob was created with a buggy key generation method 1.1683 + * which is described in the PKCS 12 implementation notes. So we 1.1684 + * need to try importing via that method. 1.1685 + */ 1.1686 + if((pbeMechType == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC) && (!faulty3DES)) { 1.1687 + /* clean up after ourselves before redoing the key generation. */ 1.1688 + 1.1689 + PK11_FreeSymKey(key); 1.1690 + key = NULL; 1.1691 + 1.1692 + if(crypto_param) { 1.1693 + SECITEM_ZfreeItem(crypto_param, PR_TRUE); 1.1694 + crypto_param = NULL; 1.1695 + } 1.1696 + 1.1697 + faulty3DES = PR_TRUE; 1.1698 + goto try_faulty_3des; 1.1699 + } 1.1700 + 1.1701 + /* key import really did fail */ 1.1702 + rv = SECFailure; 1.1703 + 1.1704 +done: 1.1705 + if(crypto_param != NULL) { 1.1706 + SECITEM_ZfreeItem(crypto_param, PR_TRUE); 1.1707 + } 1.1708 + 1.1709 + if(key != NULL) { 1.1710 + PK11_FreeSymKey(key); 1.1711 + } 1.1712 + 1.1713 + return rv; 1.1714 +} 1.1715 + 1.1716 +SECKEYPrivateKeyInfo * 1.1717 +PK11_ExportPrivateKeyInfo(CERTCertificate *cert, void *wincx) 1.1718 +{ 1.1719 + SECKEYPrivateKeyInfo *pki = NULL; 1.1720 + SECKEYPrivateKey *pk = PK11_FindKeyByAnyCert(cert, wincx); 1.1721 + if (pk != NULL) { 1.1722 + pki = PK11_ExportPrivKeyInfo(pk, wincx); 1.1723 + SECKEY_DestroyPrivateKey(pk); 1.1724 + } 1.1725 + return pki; 1.1726 +} 1.1727 + 1.1728 +SECKEYEncryptedPrivateKeyInfo * 1.1729 +PK11_ExportEncryptedPrivKeyInfo( 1.1730 + PK11SlotInfo *slot, /* optional, encrypt key in this slot */ 1.1731 + SECOidTag algTag, /* encrypt key with this algorithm */ 1.1732 + SECItem *pwitem, /* password for PBE encryption */ 1.1733 + SECKEYPrivateKey *pk, /* encrypt this private key */ 1.1734 + int iteration, /* interations for PBE alg */ 1.1735 + void *wincx) /* context for password callback ? */ 1.1736 +{ 1.1737 + SECKEYEncryptedPrivateKeyInfo *epki = NULL; 1.1738 + PLArenaPool *arena = NULL; 1.1739 + SECAlgorithmID *algid; 1.1740 + SECOidTag pbeAlgTag = SEC_OID_UNKNOWN; 1.1741 + SECItem *crypto_param = NULL; 1.1742 + PK11SymKey *key = NULL; 1.1743 + SECKEYPrivateKey *tmpPK = NULL; 1.1744 + SECStatus rv = SECSuccess; 1.1745 + CK_RV crv; 1.1746 + CK_ULONG encBufLen; 1.1747 + CK_MECHANISM_TYPE pbeMechType; 1.1748 + CK_MECHANISM_TYPE cryptoMechType; 1.1749 + CK_MECHANISM cryptoMech; 1.1750 + 1.1751 + if (!pwitem || !pk) { 1.1752 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.1753 + return NULL; 1.1754 + } 1.1755 + 1.1756 + algid = sec_pkcs5CreateAlgorithmID(algTag, SEC_OID_UNKNOWN, SEC_OID_UNKNOWN, 1.1757 + &pbeAlgTag, 0, NULL, iteration); 1.1758 + if (algid == NULL) { 1.1759 + return NULL; 1.1760 + } 1.1761 + 1.1762 + arena = PORT_NewArena(2048); 1.1763 + if (arena) 1.1764 + epki = PORT_ArenaZNew(arena, SECKEYEncryptedPrivateKeyInfo); 1.1765 + if(epki == NULL) { 1.1766 + rv = SECFailure; 1.1767 + goto loser; 1.1768 + } 1.1769 + epki->arena = arena; 1.1770 + 1.1771 + 1.1772 + /* if we didn't specify a slot, use the slot the private key was in */ 1.1773 + if (!slot) { 1.1774 + slot = pk->pkcs11Slot; 1.1775 + } 1.1776 + 1.1777 + /* if we specified a different slot, and the private key slot can do the 1.1778 + * pbe key gen, generate the key in the private key slot so we don't have 1.1779 + * to move it later */ 1.1780 + pbeMechType = PK11_AlgtagToMechanism(pbeAlgTag); 1.1781 + if (slot != pk->pkcs11Slot) { 1.1782 + if (PK11_DoesMechanism(pk->pkcs11Slot,pbeMechType)) { 1.1783 + slot = pk->pkcs11Slot; 1.1784 + } 1.1785 + } 1.1786 + key = PK11_PBEKeyGen(slot, algid, pwitem, PR_FALSE, wincx); 1.1787 + if (key == NULL) { 1.1788 + rv = SECFailure; 1.1789 + goto loser; 1.1790 + } 1.1791 + 1.1792 + cryptoMechType = PK11_GetPBECryptoMechanism(algid, &crypto_param, pwitem); 1.1793 + if (cryptoMechType == CKM_INVALID_MECHANISM) { 1.1794 + rv = SECFailure; 1.1795 + goto loser; 1.1796 + } 1.1797 + 1.1798 + cryptoMech.mechanism = PK11_GetPadMechanism(cryptoMechType); 1.1799 + cryptoMech.pParameter = crypto_param ? crypto_param->data : NULL; 1.1800 + cryptoMech.ulParameterLen = crypto_param ? crypto_param->len : 0; 1.1801 + 1.1802 + /* If the key isn't in the private key slot, move it */ 1.1803 + if (key->slot != pk->pkcs11Slot) { 1.1804 + PK11SymKey *newkey = pk11_CopyToSlot(pk->pkcs11Slot, 1.1805 + key->type, CKA_WRAP, key); 1.1806 + if (newkey == NULL) { 1.1807 + /* couldn't import the wrapping key, try exporting the 1.1808 + * private key */ 1.1809 + tmpPK = pk11_loadPrivKey(key->slot, pk, NULL, PR_FALSE, PR_TRUE); 1.1810 + if (tmpPK == NULL) { 1.1811 + rv = SECFailure; 1.1812 + goto loser; 1.1813 + } 1.1814 + pk = tmpPK; 1.1815 + } else { 1.1816 + /* free the old key and use the new key */ 1.1817 + PK11_FreeSymKey(key); 1.1818 + key = newkey; 1.1819 + } 1.1820 + } 1.1821 + 1.1822 + /* we are extracting an encrypted privateKey structure. 1.1823 + * which needs to be freed along with the buffer into which it is 1.1824 + * returned. eventually, we should retrieve an encrypted key using 1.1825 + * pkcs8/pkcs5. 1.1826 + */ 1.1827 + encBufLen = 0; 1.1828 + PK11_EnterSlotMonitor(pk->pkcs11Slot); 1.1829 + crv = PK11_GETTAB(pk->pkcs11Slot)->C_WrapKey(pk->pkcs11Slot->session, 1.1830 + &cryptoMech, key->objectID, pk->pkcs11ID, NULL, 1.1831 + &encBufLen); 1.1832 + PK11_ExitSlotMonitor(pk->pkcs11Slot); 1.1833 + if (crv != CKR_OK) { 1.1834 + rv = SECFailure; 1.1835 + goto loser; 1.1836 + } 1.1837 + epki->encryptedData.data = PORT_ArenaAlloc(arena, encBufLen); 1.1838 + if (!epki->encryptedData.data) { 1.1839 + rv = SECFailure; 1.1840 + goto loser; 1.1841 + } 1.1842 + PK11_EnterSlotMonitor(pk->pkcs11Slot); 1.1843 + crv = PK11_GETTAB(pk->pkcs11Slot)->C_WrapKey(pk->pkcs11Slot->session, 1.1844 + &cryptoMech, key->objectID, pk->pkcs11ID, 1.1845 + epki->encryptedData.data, &encBufLen); 1.1846 + PK11_ExitSlotMonitor(pk->pkcs11Slot); 1.1847 + epki->encryptedData.len = (unsigned int) encBufLen; 1.1848 + if(crv != CKR_OK) { 1.1849 + rv = SECFailure; 1.1850 + goto loser; 1.1851 + } 1.1852 + 1.1853 + if(!epki->encryptedData.len) { 1.1854 + rv = SECFailure; 1.1855 + goto loser; 1.1856 + } 1.1857 + 1.1858 + rv = SECOID_CopyAlgorithmID(arena, &epki->algorithm, algid); 1.1859 + 1.1860 +loser: 1.1861 + if(crypto_param != NULL) { 1.1862 + SECITEM_ZfreeItem(crypto_param, PR_TRUE); 1.1863 + crypto_param = NULL; 1.1864 + } 1.1865 + 1.1866 + if(key != NULL) { 1.1867 + PK11_FreeSymKey(key); 1.1868 + } 1.1869 + if (tmpPK != NULL) { 1.1870 + SECKEY_DestroyPrivateKey(tmpPK); 1.1871 + } 1.1872 + SECOID_DestroyAlgorithmID(algid, PR_TRUE); 1.1873 + 1.1874 + if(rv == SECFailure) { 1.1875 + if(arena != NULL) { 1.1876 + PORT_FreeArena(arena, PR_TRUE); 1.1877 + } 1.1878 + epki = NULL; 1.1879 + } 1.1880 + 1.1881 + return epki; 1.1882 +} 1.1883 + 1.1884 +SECKEYEncryptedPrivateKeyInfo * 1.1885 +PK11_ExportEncryptedPrivateKeyInfo( 1.1886 + PK11SlotInfo *slot, /* optional, encrypt key in this slot */ 1.1887 + SECOidTag algTag, /* encrypt key with this algorithm */ 1.1888 + SECItem *pwitem, /* password for PBE encryption */ 1.1889 + CERTCertificate *cert, /* wrap priv key for this user cert */ 1.1890 + int iteration, /* interations for PBE alg */ 1.1891 + void *wincx) /* context for password callback ? */ 1.1892 +{ 1.1893 + SECKEYEncryptedPrivateKeyInfo *epki = NULL; 1.1894 + SECKEYPrivateKey *pk = PK11_FindKeyByAnyCert(cert, wincx); 1.1895 + if (pk != NULL) { 1.1896 + epki = PK11_ExportEncryptedPrivKeyInfo(slot, algTag, pwitem, pk, 1.1897 + iteration, wincx); 1.1898 + SECKEY_DestroyPrivateKey(pk); 1.1899 + } 1.1900 + return epki; 1.1901 +} 1.1902 + 1.1903 +SECItem* 1.1904 +PK11_DEREncodePublicKey(const SECKEYPublicKey *pubk) 1.1905 +{ 1.1906 + return SECKEY_EncodeDERSubjectPublicKeyInfo(pubk); 1.1907 +} 1.1908 + 1.1909 +char * 1.1910 +PK11_GetPrivateKeyNickname(SECKEYPrivateKey *privKey) 1.1911 +{ 1.1912 + return PK11_GetObjectNickname(privKey->pkcs11Slot,privKey->pkcs11ID); 1.1913 +} 1.1914 + 1.1915 +char * 1.1916 +PK11_GetPublicKeyNickname(SECKEYPublicKey *pubKey) 1.1917 +{ 1.1918 + return PK11_GetObjectNickname(pubKey->pkcs11Slot,pubKey->pkcs11ID); 1.1919 +} 1.1920 + 1.1921 +SECStatus 1.1922 +PK11_SetPrivateKeyNickname(SECKEYPrivateKey *privKey, const char *nickname) 1.1923 +{ 1.1924 + return PK11_SetObjectNickname(privKey->pkcs11Slot, 1.1925 + privKey->pkcs11ID,nickname); 1.1926 +} 1.1927 + 1.1928 +SECStatus 1.1929 +PK11_SetPublicKeyNickname(SECKEYPublicKey *pubKey, const char *nickname) 1.1930 +{ 1.1931 + return PK11_SetObjectNickname(pubKey->pkcs11Slot, 1.1932 + pubKey->pkcs11ID,nickname); 1.1933 +} 1.1934 + 1.1935 +SECKEYPQGParams * 1.1936 +PK11_GetPQGParamsFromPrivateKey(SECKEYPrivateKey *privKey) 1.1937 +{ 1.1938 + CK_ATTRIBUTE pTemplate[] = { 1.1939 + { CKA_PRIME, NULL, 0 }, 1.1940 + { CKA_SUBPRIME, NULL, 0 }, 1.1941 + { CKA_BASE, NULL, 0 }, 1.1942 + }; 1.1943 + int pTemplateLen = sizeof(pTemplate)/sizeof(pTemplate[0]); 1.1944 + PLArenaPool *arena = NULL; 1.1945 + SECKEYPQGParams *params; 1.1946 + CK_RV crv; 1.1947 + 1.1948 + 1.1949 + arena = PORT_NewArena(2048); 1.1950 + if (arena == NULL) { 1.1951 + goto loser; 1.1952 + } 1.1953 + params=(SECKEYPQGParams *)PORT_ArenaZAlloc(arena,sizeof(SECKEYPQGParams)); 1.1954 + if (params == NULL) { 1.1955 + goto loser; 1.1956 + } 1.1957 + 1.1958 + crv = PK11_GetAttributes(arena, privKey->pkcs11Slot, privKey->pkcs11ID, 1.1959 + pTemplate, pTemplateLen); 1.1960 + if (crv != CKR_OK) { 1.1961 + PORT_SetError( PK11_MapError(crv) ); 1.1962 + goto loser; 1.1963 + } 1.1964 + 1.1965 + params->arena = arena; 1.1966 + params->prime.data = pTemplate[0].pValue; 1.1967 + params->prime.len = pTemplate[0].ulValueLen; 1.1968 + params->subPrime.data = pTemplate[1].pValue; 1.1969 + params->subPrime.len = pTemplate[1].ulValueLen; 1.1970 + params->base.data = pTemplate[2].pValue; 1.1971 + params->base.len = pTemplate[2].ulValueLen; 1.1972 + 1.1973 + return params; 1.1974 + 1.1975 +loser: 1.1976 + if (arena != NULL) { 1.1977 + PORT_FreeArena(arena,PR_FALSE); 1.1978 + } 1.1979 + return NULL; 1.1980 +} 1.1981 + 1.1982 +SECKEYPrivateKey* 1.1983 +PK11_CopyTokenPrivKeyToSessionPrivKey(PK11SlotInfo *destSlot, 1.1984 + SECKEYPrivateKey *privKey) 1.1985 +{ 1.1986 + CK_RV crv; 1.1987 + CK_OBJECT_HANDLE newKeyID; 1.1988 + 1.1989 + static const CK_BBOOL ckfalse = CK_FALSE; 1.1990 + static const CK_ATTRIBUTE template[1] = { 1.1991 + { CKA_TOKEN, (CK_BBOOL *)&ckfalse, sizeof ckfalse } 1.1992 + }; 1.1993 + 1.1994 + if (destSlot && destSlot != privKey->pkcs11Slot) { 1.1995 + SECKEYPrivateKey *newKey = 1.1996 + pk11_loadPrivKey(destSlot, 1.1997 + privKey, 1.1998 + NULL, /* pubKey */ 1.1999 + PR_FALSE, /* token */ 1.2000 + PR_FALSE);/* sensitive */ 1.2001 + if (newKey) 1.2002 + return newKey; 1.2003 + } 1.2004 + destSlot = privKey->pkcs11Slot; 1.2005 + PK11_Authenticate(destSlot, PR_TRUE, privKey->wincx); 1.2006 + PK11_EnterSlotMonitor(destSlot); 1.2007 + crv = PK11_GETTAB(destSlot)->C_CopyObject( destSlot->session, 1.2008 + privKey->pkcs11ID, 1.2009 + (CK_ATTRIBUTE *)template, 1.2010 + 1, &newKeyID); 1.2011 + PK11_ExitSlotMonitor(destSlot); 1.2012 + 1.2013 + if (crv != CKR_OK) { 1.2014 + PORT_SetError( PK11_MapError(crv) ); 1.2015 + return NULL; 1.2016 + } 1.2017 + 1.2018 + return PK11_MakePrivKey(destSlot, privKey->keyType, PR_TRUE /*isTemp*/, 1.2019 + newKeyID, privKey->wincx); 1.2020 +} 1.2021 + 1.2022 +SECKEYPrivateKey* 1.2023 +PK11_ConvertSessionPrivKeyToTokenPrivKey(SECKEYPrivateKey *privk, void* wincx) 1.2024 +{ 1.2025 + PK11SlotInfo* slot = privk->pkcs11Slot; 1.2026 + CK_ATTRIBUTE template[1]; 1.2027 + CK_ATTRIBUTE *attrs = template; 1.2028 + CK_BBOOL cktrue = CK_TRUE; 1.2029 + CK_RV crv; 1.2030 + CK_OBJECT_HANDLE newKeyID; 1.2031 + CK_SESSION_HANDLE rwsession; 1.2032 + 1.2033 + PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); attrs++; 1.2034 + 1.2035 + PK11_Authenticate(slot, PR_TRUE, wincx); 1.2036 + rwsession = PK11_GetRWSession(slot); 1.2037 + if (rwsession == CK_INVALID_SESSION) { 1.2038 + PORT_SetError(SEC_ERROR_BAD_DATA); 1.2039 + return NULL; 1.2040 + } 1.2041 + crv = PK11_GETTAB(slot)->C_CopyObject(rwsession, privk->pkcs11ID, 1.2042 + template, 1, &newKeyID); 1.2043 + PK11_RestoreROSession(slot, rwsession); 1.2044 + 1.2045 + if (crv != CKR_OK) { 1.2046 + PORT_SetError( PK11_MapError(crv) ); 1.2047 + return NULL; 1.2048 + } 1.2049 + 1.2050 + return PK11_MakePrivKey(slot, nullKey /*KeyType*/, PR_FALSE /*isTemp*/, 1.2051 + newKeyID, NULL /*wincx*/); 1.2052 +} 1.2053 + 1.2054 +/* 1.2055 + * destroy a private key if there are no matching certs. 1.2056 + * this function also frees the privKey structure. 1.2057 + */ 1.2058 +SECStatus 1.2059 +PK11_DeleteTokenPrivateKey(SECKEYPrivateKey *privKey, PRBool force) 1.2060 +{ 1.2061 + CERTCertificate *cert=PK11_GetCertFromPrivateKey(privKey); 1.2062 + SECStatus rv = SECWouldBlock; 1.2063 + 1.2064 + if (!cert || force) { 1.2065 + /* now, then it's safe for the key to go away */ 1.2066 + rv = PK11_DestroyTokenObject(privKey->pkcs11Slot,privKey->pkcs11ID); 1.2067 + } 1.2068 + if (cert) { 1.2069 + CERT_DestroyCertificate(cert); 1.2070 + } 1.2071 + SECKEY_DestroyPrivateKey(privKey); 1.2072 + return rv; 1.2073 +} 1.2074 + 1.2075 +/* 1.2076 + * destroy a private key if there are no matching certs. 1.2077 + * this function also frees the privKey structure. 1.2078 + */ 1.2079 +SECStatus 1.2080 +PK11_DeleteTokenPublicKey(SECKEYPublicKey *pubKey) 1.2081 +{ 1.2082 + /* now, then it's safe for the key to go away */ 1.2083 + if (pubKey->pkcs11Slot == NULL) { 1.2084 + return SECFailure; 1.2085 + } 1.2086 + PK11_DestroyTokenObject(pubKey->pkcs11Slot,pubKey->pkcs11ID); 1.2087 + SECKEY_DestroyPublicKey(pubKey); 1.2088 + return SECSuccess; 1.2089 +} 1.2090 + 1.2091 +/* 1.2092 + * key call back structure. 1.2093 + */ 1.2094 +typedef struct pk11KeyCallbackStr { 1.2095 + SECStatus (* callback)(SECKEYPrivateKey *,void *); 1.2096 + void *callbackArg; 1.2097 + void *wincx; 1.2098 +} pk11KeyCallback; 1.2099 + 1.2100 +/* 1.2101 + * callback to map Object Handles to Private Keys; 1.2102 + */ 1.2103 +SECStatus 1.2104 +pk11_DoKeys(PK11SlotInfo *slot, CK_OBJECT_HANDLE keyHandle, void *arg) 1.2105 +{ 1.2106 + SECStatus rv = SECSuccess; 1.2107 + SECKEYPrivateKey *privKey; 1.2108 + pk11KeyCallback *keycb = (pk11KeyCallback *) arg; 1.2109 + if (!arg) { 1.2110 + return SECFailure; 1.2111 + } 1.2112 + 1.2113 + privKey = PK11_MakePrivKey(slot,nullKey,PR_TRUE,keyHandle,keycb->wincx); 1.2114 + 1.2115 + if (privKey == NULL) { 1.2116 + return SECFailure; 1.2117 + } 1.2118 + 1.2119 + if (keycb->callback) { 1.2120 + rv = (*keycb->callback)(privKey,keycb->callbackArg); 1.2121 + } 1.2122 + 1.2123 + SECKEY_DestroyPrivateKey(privKey); 1.2124 + return rv; 1.2125 +} 1.2126 + 1.2127 +/*********************************************************************** 1.2128 + * PK11_TraversePrivateKeysInSlot 1.2129 + * 1.2130 + * Traverses all the private keys on a slot. 1.2131 + * 1.2132 + * INPUTS 1.2133 + * slot 1.2134 + * The PKCS #11 slot whose private keys you want to traverse. 1.2135 + * callback 1.2136 + * A callback function that will be called for each key. 1.2137 + * arg 1.2138 + * An argument that will be passed to the callback function. 1.2139 + */ 1.2140 +SECStatus 1.2141 +PK11_TraversePrivateKeysInSlot( PK11SlotInfo *slot, 1.2142 + SECStatus(* callback)(SECKEYPrivateKey*, void*), void *arg) 1.2143 +{ 1.2144 + pk11KeyCallback perKeyCB; 1.2145 + pk11TraverseSlot perObjectCB; 1.2146 + CK_OBJECT_CLASS privkClass = CKO_PRIVATE_KEY; 1.2147 + CK_BBOOL ckTrue = CK_TRUE; 1.2148 + CK_ATTRIBUTE theTemplate[2]; 1.2149 + int templateSize = 2; 1.2150 + 1.2151 + theTemplate[0].type = CKA_CLASS; 1.2152 + theTemplate[0].pValue = &privkClass; 1.2153 + theTemplate[0].ulValueLen = sizeof(privkClass); 1.2154 + theTemplate[1].type = CKA_TOKEN; 1.2155 + theTemplate[1].pValue = &ckTrue; 1.2156 + theTemplate[1].ulValueLen = sizeof(ckTrue); 1.2157 + 1.2158 + if(slot==NULL) { 1.2159 + return SECSuccess; 1.2160 + } 1.2161 + 1.2162 + perObjectCB.callback = pk11_DoKeys; 1.2163 + perObjectCB.callbackArg = &perKeyCB; 1.2164 + perObjectCB.findTemplate = theTemplate; 1.2165 + perObjectCB.templateCount = templateSize; 1.2166 + perKeyCB.callback = callback; 1.2167 + perKeyCB.callbackArg = arg; 1.2168 + perKeyCB.wincx = NULL; 1.2169 + 1.2170 + return PK11_TraverseSlot(slot, &perObjectCB); 1.2171 +} 1.2172 + 1.2173 +/* 1.2174 + * return the private key with the given ID 1.2175 + */ 1.2176 +CK_OBJECT_HANDLE 1.2177 +pk11_FindPrivateKeyFromCertID(PK11SlotInfo *slot, SECItem *keyID) 1.2178 +{ 1.2179 + CK_OBJECT_CLASS privKey = CKO_PRIVATE_KEY; 1.2180 + CK_ATTRIBUTE theTemplate[] = { 1.2181 + { CKA_ID, NULL, 0 }, 1.2182 + { CKA_CLASS, NULL, 0 }, 1.2183 + }; 1.2184 + /* if you change the array, change the variable below as well */ 1.2185 + int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); 1.2186 + CK_ATTRIBUTE *attrs = theTemplate; 1.2187 + 1.2188 + PK11_SETATTRS(attrs, CKA_ID, keyID->data, keyID->len ); attrs++; 1.2189 + PK11_SETATTRS(attrs, CKA_CLASS, &privKey, sizeof(privKey)); 1.2190 + 1.2191 + return pk11_FindObjectByTemplate(slot,theTemplate,tsize); 1.2192 +} 1.2193 + 1.2194 + 1.2195 +SECKEYPrivateKey * 1.2196 +PK11_FindKeyByKeyID(PK11SlotInfo *slot, SECItem *keyID, void *wincx) 1.2197 +{ 1.2198 + CK_OBJECT_HANDLE keyHandle; 1.2199 + SECKEYPrivateKey *privKey; 1.2200 + 1.2201 + keyHandle = pk11_FindPrivateKeyFromCertID(slot, keyID); 1.2202 + if (keyHandle == CK_INVALID_HANDLE) { 1.2203 + return NULL; 1.2204 + } 1.2205 + privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx); 1.2206 + return privKey; 1.2207 +} 1.2208 + 1.2209 +/* 1.2210 + * Generate a CKA_ID from the relevant public key data. The CKA_ID is generated 1.2211 + * from the pubKeyData by SHA1_Hashing it to produce a smaller CKA_ID (to make 1.2212 + * smart cards happy. 1.2213 + */ 1.2214 +SECItem * 1.2215 +PK11_MakeIDFromPubKey(SECItem *pubKeyData) 1.2216 +{ 1.2217 + PK11Context *context; 1.2218 + SECItem *certCKA_ID; 1.2219 + SECStatus rv; 1.2220 + 1.2221 + if (pubKeyData->len <= SHA1_LENGTH) { 1.2222 + /* probably an already hashed value. The strongest known public 1.2223 + * key values <= 160 bits would be less than 40 bit symetric in 1.2224 + * strength. Don't hash them, just return the value. There are 1.2225 + * none at the time of this writing supported by previous versions 1.2226 + * of NSS, so change is binary compatible safe */ 1.2227 + return SECITEM_DupItem(pubKeyData); 1.2228 + } 1.2229 + 1.2230 + context = PK11_CreateDigestContext(SEC_OID_SHA1); 1.2231 + if (context == NULL) { 1.2232 + return NULL; 1.2233 + } 1.2234 + 1.2235 + rv = PK11_DigestBegin(context); 1.2236 + if (rv == SECSuccess) { 1.2237 + rv = PK11_DigestOp(context,pubKeyData->data,pubKeyData->len); 1.2238 + } 1.2239 + if (rv != SECSuccess) { 1.2240 + PK11_DestroyContext(context,PR_TRUE); 1.2241 + return NULL; 1.2242 + } 1.2243 + 1.2244 + certCKA_ID = (SECItem *)PORT_Alloc(sizeof(SECItem)); 1.2245 + if (certCKA_ID == NULL) { 1.2246 + PK11_DestroyContext(context,PR_TRUE); 1.2247 + return NULL; 1.2248 + } 1.2249 + 1.2250 + certCKA_ID->len = SHA1_LENGTH; 1.2251 + certCKA_ID->data = (unsigned char*)PORT_Alloc(certCKA_ID->len); 1.2252 + if (certCKA_ID->data == NULL) { 1.2253 + PORT_Free(certCKA_ID); 1.2254 + PK11_DestroyContext(context,PR_TRUE); 1.2255 + return NULL; 1.2256 + } 1.2257 + 1.2258 + rv = PK11_DigestFinal(context,certCKA_ID->data,&certCKA_ID->len, 1.2259 + SHA1_LENGTH); 1.2260 + PK11_DestroyContext(context,PR_TRUE); 1.2261 + if (rv != SECSuccess) { 1.2262 + SECITEM_FreeItem(certCKA_ID,PR_TRUE); 1.2263 + return NULL; 1.2264 + } 1.2265 + 1.2266 + return certCKA_ID; 1.2267 +} 1.2268 + 1.2269 +/* Looking for PK11_GetKeyIDFromPrivateKey? 1.2270 + * Call PK11_GetLowLevelKeyIDForPrivateKey instead. 1.2271 + */ 1.2272 + 1.2273 + 1.2274 +SECItem * 1.2275 +PK11_GetLowLevelKeyIDForPrivateKey(SECKEYPrivateKey *privKey) 1.2276 +{ 1.2277 + return pk11_GetLowLevelKeyFromHandle(privKey->pkcs11Slot,privKey->pkcs11ID); 1.2278 +} 1.2279 + 1.2280 +static SECStatus 1.2281 +privateKeyListCallback(SECKEYPrivateKey *key, void *arg) 1.2282 +{ 1.2283 + SECKEYPrivateKeyList *list = (SECKEYPrivateKeyList*)arg; 1.2284 + return SECKEY_AddPrivateKeyToListTail(list, SECKEY_CopyPrivateKey(key)); 1.2285 +} 1.2286 + 1.2287 +SECKEYPrivateKeyList* 1.2288 +PK11_ListPrivateKeysInSlot(PK11SlotInfo *slot) 1.2289 +{ 1.2290 + SECStatus status; 1.2291 + SECKEYPrivateKeyList *keys; 1.2292 + 1.2293 + keys = SECKEY_NewPrivateKeyList(); 1.2294 + if(keys == NULL) return NULL; 1.2295 + 1.2296 + status = PK11_TraversePrivateKeysInSlot(slot, privateKeyListCallback, 1.2297 + (void*)keys); 1.2298 + 1.2299 + if( status != SECSuccess ) { 1.2300 + SECKEY_DestroyPrivateKeyList(keys); 1.2301 + keys = NULL; 1.2302 + } 1.2303 + 1.2304 + return keys; 1.2305 +} 1.2306 + 1.2307 +SECKEYPublicKeyList* 1.2308 +PK11_ListPublicKeysInSlot(PK11SlotInfo *slot, char *nickname) 1.2309 +{ 1.2310 + CK_ATTRIBUTE findTemp[4]; 1.2311 + CK_ATTRIBUTE *attrs; 1.2312 + CK_BBOOL ckTrue = CK_TRUE; 1.2313 + CK_OBJECT_CLASS keyclass = CKO_PUBLIC_KEY; 1.2314 + int tsize = 0; 1.2315 + int objCount = 0; 1.2316 + CK_OBJECT_HANDLE *key_ids; 1.2317 + SECKEYPublicKeyList *keys; 1.2318 + int i,len; 1.2319 + 1.2320 + 1.2321 + attrs = findTemp; 1.2322 + PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++; 1.2323 + PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++; 1.2324 + if (nickname) { 1.2325 + len = PORT_Strlen(nickname); 1.2326 + PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++; 1.2327 + } 1.2328 + tsize = attrs - findTemp; 1.2329 + PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE)); 1.2330 + 1.2331 + key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount); 1.2332 + if (key_ids == NULL) { 1.2333 + return NULL; 1.2334 + } 1.2335 + keys = SECKEY_NewPublicKeyList(); 1.2336 + if (keys == NULL) { 1.2337 + PORT_Free(key_ids); 1.2338 + return NULL; 1.2339 + } 1.2340 + 1.2341 + for (i=0; i < objCount ; i++) { 1.2342 + SECKEYPublicKey *pubKey = 1.2343 + PK11_ExtractPublicKey(slot,nullKey,key_ids[i]); 1.2344 + if (pubKey) { 1.2345 + SECKEY_AddPublicKeyToListTail(keys, pubKey); 1.2346 + } 1.2347 + } 1.2348 + 1.2349 + PORT_Free(key_ids); 1.2350 + return keys; 1.2351 +} 1.2352 + 1.2353 +SECKEYPrivateKeyList* 1.2354 +PK11_ListPrivKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx) 1.2355 +{ 1.2356 + CK_ATTRIBUTE findTemp[4]; 1.2357 + CK_ATTRIBUTE *attrs; 1.2358 + CK_BBOOL ckTrue = CK_TRUE; 1.2359 + CK_OBJECT_CLASS keyclass = CKO_PRIVATE_KEY; 1.2360 + int tsize = 0; 1.2361 + int objCount = 0; 1.2362 + CK_OBJECT_HANDLE *key_ids; 1.2363 + SECKEYPrivateKeyList *keys; 1.2364 + int i,len; 1.2365 + 1.2366 + 1.2367 + attrs = findTemp; 1.2368 + PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++; 1.2369 + PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++; 1.2370 + if (nickname) { 1.2371 + len = PORT_Strlen(nickname); 1.2372 + PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++; 1.2373 + } 1.2374 + tsize = attrs - findTemp; 1.2375 + PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE)); 1.2376 + 1.2377 + key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount); 1.2378 + if (key_ids == NULL) { 1.2379 + return NULL; 1.2380 + } 1.2381 + keys = SECKEY_NewPrivateKeyList(); 1.2382 + if (keys == NULL) { 1.2383 + PORT_Free(key_ids); 1.2384 + return NULL; 1.2385 + } 1.2386 + 1.2387 + for (i=0; i < objCount ; i++) { 1.2388 + SECKEYPrivateKey *privKey = 1.2389 + PK11_MakePrivKey(slot,nullKey,PR_TRUE,key_ids[i],wincx); 1.2390 + SECKEY_AddPrivateKeyToListTail(keys, privKey); 1.2391 + } 1.2392 + 1.2393 + PORT_Free(key_ids); 1.2394 + return keys; 1.2395 +} 1.2396 +