security/nss/lib/pk11wrap/pk11akey.c

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

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

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

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 /*
michael@0 5 * This file contains functions to manage asymetric keys, (public and
michael@0 6 * private keys).
michael@0 7 */
michael@0 8 #include "seccomon.h"
michael@0 9 #include "secmod.h"
michael@0 10 #include "secmodi.h"
michael@0 11 #include "secmodti.h"
michael@0 12 #include "pkcs11.h"
michael@0 13 #include "pkcs11t.h"
michael@0 14 #include "pk11func.h"
michael@0 15 #include "cert.h"
michael@0 16 #include "key.h"
michael@0 17 #include "secitem.h"
michael@0 18 #include "secasn1.h"
michael@0 19 #include "secoid.h"
michael@0 20 #include "secerr.h"
michael@0 21 #include "sslerr.h"
michael@0 22 #include "sechash.h"
michael@0 23
michael@0 24 #include "secpkcs5.h"
michael@0 25 #include "blapit.h"
michael@0 26
michael@0 27 static SECItem *
michael@0 28 pk11_MakeIDFromPublicKey(SECKEYPublicKey *pubKey)
michael@0 29 {
michael@0 30 /* set the ID to the public key so we can find it again */
michael@0 31 SECItem *pubKeyIndex = NULL;
michael@0 32 switch (pubKey->keyType) {
michael@0 33 case rsaKey:
michael@0 34 pubKeyIndex = &pubKey->u.rsa.modulus;
michael@0 35 break;
michael@0 36 case dsaKey:
michael@0 37 pubKeyIndex = &pubKey->u.dsa.publicValue;
michael@0 38 break;
michael@0 39 case dhKey:
michael@0 40 pubKeyIndex = &pubKey->u.dh.publicValue;
michael@0 41 break;
michael@0 42 case ecKey:
michael@0 43 pubKeyIndex = &pubKey->u.ec.publicValue;
michael@0 44 break;
michael@0 45 default:
michael@0 46 return NULL;
michael@0 47 }
michael@0 48 PORT_Assert(pubKeyIndex != NULL);
michael@0 49
michael@0 50 return PK11_MakeIDFromPubKey(pubKeyIndex);
michael@0 51 }
michael@0 52
michael@0 53 /*
michael@0 54 * import a public key into the desired slot
michael@0 55 *
michael@0 56 * This function takes a public key structure and creates a public key in a
michael@0 57 * given slot. If isToken is set, then a persistant public key is created.
michael@0 58 *
michael@0 59 * Note: it is possible for this function to return a handle for a key which
michael@0 60 * is persistant, even if isToken is not set.
michael@0 61 */
michael@0 62 CK_OBJECT_HANDLE
michael@0 63 PK11_ImportPublicKey(PK11SlotInfo *slot, SECKEYPublicKey *pubKey,
michael@0 64 PRBool isToken)
michael@0 65 {
michael@0 66 CK_BBOOL cktrue = CK_TRUE;
michael@0 67 CK_BBOOL ckfalse = CK_FALSE;
michael@0 68 CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
michael@0 69 CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
michael@0 70 CK_OBJECT_HANDLE objectID;
michael@0 71 CK_ATTRIBUTE theTemplate[11];
michael@0 72 CK_ATTRIBUTE *signedattr = NULL;
michael@0 73 CK_ATTRIBUTE *attrs = theTemplate;
michael@0 74 SECItem *ckaId = NULL;
michael@0 75 SECItem *pubValue = NULL;
michael@0 76 int signedcount = 0;
michael@0 77 int templateCount = 0;
michael@0 78 SECStatus rv;
michael@0 79
michael@0 80 /* if we already have an object in the desired slot, use it */
michael@0 81 if (!isToken && pubKey->pkcs11Slot == slot) {
michael@0 82 return pubKey->pkcs11ID;
michael@0 83 }
michael@0 84
michael@0 85 /* free the existing key */
michael@0 86 if (pubKey->pkcs11Slot != NULL) {
michael@0 87 PK11SlotInfo *oSlot = pubKey->pkcs11Slot;
michael@0 88 if (!PK11_IsPermObject(pubKey->pkcs11Slot,pubKey->pkcs11ID)) {
michael@0 89 PK11_EnterSlotMonitor(oSlot);
michael@0 90 (void) PK11_GETTAB(oSlot)->C_DestroyObject(oSlot->session,
michael@0 91 pubKey->pkcs11ID);
michael@0 92 PK11_ExitSlotMonitor(oSlot);
michael@0 93 }
michael@0 94 PK11_FreeSlot(oSlot);
michael@0 95 pubKey->pkcs11Slot = NULL;
michael@0 96 }
michael@0 97 PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++;
michael@0 98 PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++;
michael@0 99 PK11_SETATTRS(attrs, CKA_TOKEN, isToken ? &cktrue : &ckfalse,
michael@0 100 sizeof(CK_BBOOL) ); attrs++;
michael@0 101 if (isToken) {
michael@0 102 ckaId = pk11_MakeIDFromPublicKey(pubKey);
michael@0 103 if (ckaId == NULL) {
michael@0 104 PORT_SetError( SEC_ERROR_BAD_KEY );
michael@0 105 return CK_INVALID_HANDLE;
michael@0 106 }
michael@0 107 PK11_SETATTRS(attrs, CKA_ID, ckaId->data, ckaId->len); attrs++;
michael@0 108 }
michael@0 109
michael@0 110 /* now import the key */
michael@0 111 {
michael@0 112 switch (pubKey->keyType) {
michael@0 113 case rsaKey:
michael@0 114 keyType = CKK_RSA;
michael@0 115 PK11_SETATTRS(attrs, CKA_WRAP, &cktrue, sizeof(CK_BBOOL) ); attrs++;
michael@0 116 PK11_SETATTRS(attrs, CKA_ENCRYPT, &cktrue,
michael@0 117 sizeof(CK_BBOOL) ); attrs++;
michael@0 118 PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL)); attrs++;
michael@0 119 signedattr = attrs;
michael@0 120 PK11_SETATTRS(attrs, CKA_MODULUS, pubKey->u.rsa.modulus.data,
michael@0 121 pubKey->u.rsa.modulus.len); attrs++;
michael@0 122 PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT,
michael@0 123 pubKey->u.rsa.publicExponent.data,
michael@0 124 pubKey->u.rsa.publicExponent.len); attrs++;
michael@0 125 break;
michael@0 126 case dsaKey:
michael@0 127 keyType = CKK_DSA;
michael@0 128 PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++;
michael@0 129 signedattr = attrs;
michael@0 130 PK11_SETATTRS(attrs, CKA_PRIME, pubKey->u.dsa.params.prime.data,
michael@0 131 pubKey->u.dsa.params.prime.len); attrs++;
michael@0 132 PK11_SETATTRS(attrs,CKA_SUBPRIME,pubKey->u.dsa.params.subPrime.data,
michael@0 133 pubKey->u.dsa.params.subPrime.len); attrs++;
michael@0 134 PK11_SETATTRS(attrs, CKA_BASE, pubKey->u.dsa.params.base.data,
michael@0 135 pubKey->u.dsa.params.base.len); attrs++;
michael@0 136 PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.dsa.publicValue.data,
michael@0 137 pubKey->u.dsa.publicValue.len); attrs++;
michael@0 138 break;
michael@0 139 case fortezzaKey:
michael@0 140 keyType = CKK_DSA;
michael@0 141 PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++;
michael@0 142 signedattr = attrs;
michael@0 143 PK11_SETATTRS(attrs, CKA_PRIME,pubKey->u.fortezza.params.prime.data,
michael@0 144 pubKey->u.fortezza.params.prime.len); attrs++;
michael@0 145 PK11_SETATTRS(attrs,CKA_SUBPRIME,
michael@0 146 pubKey->u.fortezza.params.subPrime.data,
michael@0 147 pubKey->u.fortezza.params.subPrime.len);attrs++;
michael@0 148 PK11_SETATTRS(attrs, CKA_BASE, pubKey->u.fortezza.params.base.data,
michael@0 149 pubKey->u.fortezza.params.base.len); attrs++;
michael@0 150 PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.fortezza.DSSKey.data,
michael@0 151 pubKey->u.fortezza.DSSKey.len); attrs++;
michael@0 152 break;
michael@0 153 case dhKey:
michael@0 154 keyType = CKK_DH;
michael@0 155 PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));attrs++;
michael@0 156 signedattr = attrs;
michael@0 157 PK11_SETATTRS(attrs, CKA_PRIME, pubKey->u.dh.prime.data,
michael@0 158 pubKey->u.dh.prime.len); attrs++;
michael@0 159 PK11_SETATTRS(attrs, CKA_BASE, pubKey->u.dh.base.data,
michael@0 160 pubKey->u.dh.base.len); attrs++;
michael@0 161 PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.dh.publicValue.data,
michael@0 162 pubKey->u.dh.publicValue.len); attrs++;
michael@0 163 break;
michael@0 164 case ecKey:
michael@0 165 keyType = CKK_EC;
michael@0 166 PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++;
michael@0 167 PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));attrs++;
michael@0 168 signedattr = attrs;
michael@0 169 PK11_SETATTRS(attrs, CKA_EC_PARAMS,
michael@0 170 pubKey->u.ec.DEREncodedParams.data,
michael@0 171 pubKey->u.ec.DEREncodedParams.len); attrs++;
michael@0 172 if (PR_GetEnv("NSS_USE_DECODED_CKA_EC_POINT")) {
michael@0 173 PK11_SETATTRS(attrs, CKA_EC_POINT,
michael@0 174 pubKey->u.ec.publicValue.data,
michael@0 175 pubKey->u.ec.publicValue.len); attrs++;
michael@0 176 } else {
michael@0 177 pubValue = SEC_ASN1EncodeItem(NULL, NULL,
michael@0 178 &pubKey->u.ec.publicValue,
michael@0 179 SEC_ASN1_GET(SEC_OctetStringTemplate));
michael@0 180 if (pubValue == NULL) {
michael@0 181 if (ckaId) {
michael@0 182 SECITEM_FreeItem(ckaId,PR_TRUE);
michael@0 183 }
michael@0 184 return CK_INVALID_HANDLE;
michael@0 185 }
michael@0 186 PK11_SETATTRS(attrs, CKA_EC_POINT,
michael@0 187 pubValue->data, pubValue->len); attrs++;
michael@0 188 }
michael@0 189 break;
michael@0 190 default:
michael@0 191 if (ckaId) {
michael@0 192 SECITEM_FreeItem(ckaId,PR_TRUE);
michael@0 193 }
michael@0 194 PORT_SetError( SEC_ERROR_BAD_KEY );
michael@0 195 return CK_INVALID_HANDLE;
michael@0 196 }
michael@0 197
michael@0 198 templateCount = attrs - theTemplate;
michael@0 199 signedcount = attrs - signedattr;
michael@0 200 PORT_Assert(templateCount <= (sizeof(theTemplate)/sizeof(CK_ATTRIBUTE)));
michael@0 201 for (attrs=signedattr; signedcount; attrs++, signedcount--) {
michael@0 202 pk11_SignedToUnsigned(attrs);
michael@0 203 }
michael@0 204 rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, theTemplate,
michael@0 205 templateCount, isToken, &objectID);
michael@0 206 if (ckaId) {
michael@0 207 SECITEM_FreeItem(ckaId,PR_TRUE);
michael@0 208 }
michael@0 209 if (pubValue) {
michael@0 210 SECITEM_FreeItem(pubValue,PR_TRUE);
michael@0 211 }
michael@0 212 if ( rv != SECSuccess) {
michael@0 213 return CK_INVALID_HANDLE;
michael@0 214 }
michael@0 215 }
michael@0 216
michael@0 217 pubKey->pkcs11ID = objectID;
michael@0 218 pubKey->pkcs11Slot = PK11_ReferenceSlot(slot);
michael@0 219
michael@0 220 return objectID;
michael@0 221 }
michael@0 222
michael@0 223 /*
michael@0 224 * take an attribute and copy it into a secitem
michael@0 225 */
michael@0 226 static CK_RV
michael@0 227 pk11_Attr2SecItem(PLArenaPool *arena, const CK_ATTRIBUTE *attr, SECItem *item)
michael@0 228 {
michael@0 229 item->data = NULL;
michael@0 230
michael@0 231 (void)SECITEM_AllocItem(arena, item, attr->ulValueLen);
michael@0 232 if (item->data == NULL) {
michael@0 233 return CKR_HOST_MEMORY;
michael@0 234 }
michael@0 235 PORT_Memcpy(item->data, attr->pValue, item->len);
michael@0 236 return CKR_OK;
michael@0 237 }
michael@0 238
michael@0 239
michael@0 240 /*
michael@0 241 * get a curve length from a set of ecParams.
michael@0 242 *
michael@0 243 * We need this so we can reliably determine if the ecPoint passed to us
michael@0 244 * was encoded or not. With out this, for many curves, we would incorrectly
michael@0 245 * identify an unencoded curve as an encoded curve 1 in 65536 times, and for
michael@0 246 * a few we would make that same mistake 1 in 32768 times. These are bad
michael@0 247 * numbers since they are rare enough to pass tests, but common enough to
michael@0 248 * be tripped over in the field.
michael@0 249 *
michael@0 250 * This function will only work for curves we recognized as of March 2009.
michael@0 251 * The assumption is curves in use after March of 2009 would be supplied by
michael@0 252 * PKCS #11 modules that already pass the correct encoding to us.
michael@0 253 *
michael@0 254 * Point length = (Roundup(curveLenInBits/8)*2+1)
michael@0 255 */
michael@0 256 static int
michael@0 257 pk11_get_EC_PointLenInBytes(PLArenaPool *arena, const SECItem *ecParams)
michael@0 258 {
michael@0 259 SECItem oid;
michael@0 260 SECOidTag tag;
michael@0 261 SECStatus rv;
michael@0 262
michael@0 263 /* decode the OID tag */
michael@0 264 rv = SEC_QuickDERDecodeItem(arena, &oid,
michael@0 265 SEC_ASN1_GET(SEC_ObjectIDTemplate), ecParams);
michael@0 266 if (rv != SECSuccess) {
michael@0 267 /* could be explict curves, allow them to work if the
michael@0 268 * PKCS #11 module support them. If we try to parse the
michael@0 269 * explicit curve value in the future, we may return -1 here
michael@0 270 * to indicate an invalid parameter if the explicit curve
michael@0 271 * decode fails. */
michael@0 272 return 0;
michael@0 273 }
michael@0 274
michael@0 275 tag = SECOID_FindOIDTag(&oid);
michael@0 276 switch (tag) {
michael@0 277 case SEC_OID_SECG_EC_SECP112R1:
michael@0 278 case SEC_OID_SECG_EC_SECP112R2:
michael@0 279 return 29; /* curve len in bytes = 14 bytes */
michael@0 280 case SEC_OID_SECG_EC_SECT113R1:
michael@0 281 case SEC_OID_SECG_EC_SECT113R2:
michael@0 282 return 31; /* curve len in bytes = 15 bytes */
michael@0 283 case SEC_OID_SECG_EC_SECP128R1:
michael@0 284 case SEC_OID_SECG_EC_SECP128R2:
michael@0 285 return 33; /* curve len in bytes = 16 bytes */
michael@0 286 case SEC_OID_SECG_EC_SECT131R1:
michael@0 287 case SEC_OID_SECG_EC_SECT131R2:
michael@0 288 return 35; /* curve len in bytes = 17 bytes */
michael@0 289 case SEC_OID_SECG_EC_SECP160K1:
michael@0 290 case SEC_OID_SECG_EC_SECP160R1:
michael@0 291 case SEC_OID_SECG_EC_SECP160R2:
michael@0 292 return 41; /* curve len in bytes = 20 bytes */
michael@0 293 case SEC_OID_SECG_EC_SECT163K1:
michael@0 294 case SEC_OID_SECG_EC_SECT163R1:
michael@0 295 case SEC_OID_SECG_EC_SECT163R2:
michael@0 296 case SEC_OID_ANSIX962_EC_C2PNB163V1:
michael@0 297 case SEC_OID_ANSIX962_EC_C2PNB163V2:
michael@0 298 case SEC_OID_ANSIX962_EC_C2PNB163V3:
michael@0 299 return 43; /* curve len in bytes = 21 bytes */
michael@0 300 case SEC_OID_ANSIX962_EC_C2PNB176V1:
michael@0 301 return 45; /* curve len in bytes = 22 bytes */
michael@0 302 case SEC_OID_ANSIX962_EC_C2TNB191V1:
michael@0 303 case SEC_OID_ANSIX962_EC_C2TNB191V2:
michael@0 304 case SEC_OID_ANSIX962_EC_C2TNB191V3:
michael@0 305 case SEC_OID_SECG_EC_SECP192K1:
michael@0 306 case SEC_OID_ANSIX962_EC_PRIME192V1:
michael@0 307 case SEC_OID_ANSIX962_EC_PRIME192V2:
michael@0 308 case SEC_OID_ANSIX962_EC_PRIME192V3:
michael@0 309 return 49; /*curve len in bytes = 24 bytes */
michael@0 310 case SEC_OID_SECG_EC_SECT193R1:
michael@0 311 case SEC_OID_SECG_EC_SECT193R2:
michael@0 312 return 51; /*curve len in bytes = 25 bytes */
michael@0 313 case SEC_OID_ANSIX962_EC_C2PNB208W1:
michael@0 314 return 53; /*curve len in bytes = 26 bytes */
michael@0 315 case SEC_OID_SECG_EC_SECP224K1:
michael@0 316 case SEC_OID_SECG_EC_SECP224R1:
michael@0 317 return 57; /*curve len in bytes = 28 bytes */
michael@0 318 case SEC_OID_SECG_EC_SECT233K1:
michael@0 319 case SEC_OID_SECG_EC_SECT233R1:
michael@0 320 case SEC_OID_SECG_EC_SECT239K1:
michael@0 321 case SEC_OID_ANSIX962_EC_PRIME239V1:
michael@0 322 case SEC_OID_ANSIX962_EC_PRIME239V2:
michael@0 323 case SEC_OID_ANSIX962_EC_PRIME239V3:
michael@0 324 case SEC_OID_ANSIX962_EC_C2TNB239V1:
michael@0 325 case SEC_OID_ANSIX962_EC_C2TNB239V2:
michael@0 326 case SEC_OID_ANSIX962_EC_C2TNB239V3:
michael@0 327 return 61; /*curve len in bytes = 30 bytes */
michael@0 328 case SEC_OID_ANSIX962_EC_PRIME256V1:
michael@0 329 case SEC_OID_SECG_EC_SECP256K1:
michael@0 330 return 65; /*curve len in bytes = 32 bytes */
michael@0 331 case SEC_OID_ANSIX962_EC_C2PNB272W1:
michael@0 332 return 69; /*curve len in bytes = 34 bytes */
michael@0 333 case SEC_OID_SECG_EC_SECT283K1:
michael@0 334 case SEC_OID_SECG_EC_SECT283R1:
michael@0 335 return 73; /*curve len in bytes = 36 bytes */
michael@0 336 case SEC_OID_ANSIX962_EC_C2PNB304W1:
michael@0 337 return 77; /*curve len in bytes = 38 bytes */
michael@0 338 case SEC_OID_ANSIX962_EC_C2TNB359V1:
michael@0 339 return 91; /*curve len in bytes = 45 bytes */
michael@0 340 case SEC_OID_ANSIX962_EC_C2PNB368W1:
michael@0 341 return 93; /*curve len in bytes = 46 bytes */
michael@0 342 case SEC_OID_SECG_EC_SECP384R1:
michael@0 343 return 97; /*curve len in bytes = 48 bytes */
michael@0 344 case SEC_OID_SECG_EC_SECT409K1:
michael@0 345 case SEC_OID_SECG_EC_SECT409R1:
michael@0 346 return 105; /*curve len in bytes = 52 bytes */
michael@0 347 case SEC_OID_ANSIX962_EC_C2TNB431R1:
michael@0 348 return 109; /*curve len in bytes = 54 bytes */
michael@0 349 case SEC_OID_SECG_EC_SECP521R1:
michael@0 350 return 133; /*curve len in bytes = 66 bytes */
michael@0 351 case SEC_OID_SECG_EC_SECT571K1:
michael@0 352 case SEC_OID_SECG_EC_SECT571R1:
michael@0 353 return 145; /*curve len in bytes = 72 bytes */
michael@0 354 /* unknown or unrecognized OIDs. return unknown length */
michael@0 355 default:
michael@0 356 break;
michael@0 357 }
michael@0 358 return 0;
michael@0 359 }
michael@0 360
michael@0 361 /*
michael@0 362 * returns the decoded point. In some cases the point may already be decoded.
michael@0 363 * this function tries to detect those cases and return the point in
michael@0 364 * publicKeyValue. In other cases it's DER encoded. In those cases the point
michael@0 365 * is first decoded and returned. Space for the point is allocated out of
michael@0 366 * the passed in arena.
michael@0 367 */
michael@0 368 static CK_RV
michael@0 369 pk11_get_Decoded_ECPoint(PLArenaPool *arena, const SECItem *ecParams,
michael@0 370 const CK_ATTRIBUTE *ecPoint, SECItem *publicKeyValue)
michael@0 371 {
michael@0 372 SECItem encodedPublicValue;
michael@0 373 SECStatus rv;
michael@0 374 int keyLen;
michael@0 375
michael@0 376 if (ecPoint->ulValueLen == 0) {
michael@0 377 return CKR_ATTRIBUTE_VALUE_INVALID;
michael@0 378 }
michael@0 379
michael@0 380 /*
michael@0 381 * The PKCS #11 spec requires ecPoints to be encoded as a DER OCTET String.
michael@0 382 * NSS has mistakenly passed unencoded values, and some PKCS #11 vendors
michael@0 383 * followed that mistake. Now we need to detect which encoding we were
michael@0 384 * passed in. The task is made more complicated by the fact the the
michael@0 385 * DER encoding byte (SEC_ASN_OCTET_STRING) is the same as the
michael@0 386 * EC_POINT_FORM_UNCOMPRESSED byte (0x04), so we can't use that to
michael@0 387 * determine which curve we are using.
michael@0 388 */
michael@0 389
michael@0 390 /* get the expected key length for the passed in curve.
michael@0 391 * pk11_get_EC_PointLenInBytes only returns valid values for curves
michael@0 392 * NSS has traditionally recognized. If the curve is not recognized,
michael@0 393 * it will return '0', and we have to figure out if the key was
michael@0 394 * encoded or not heuristically. If the ecParams are invalid, it
michael@0 395 * will return -1 for the keyLen.
michael@0 396 */
michael@0 397 keyLen = pk11_get_EC_PointLenInBytes(arena, ecParams);
michael@0 398 if (keyLen < 0) {
michael@0 399 return CKR_ATTRIBUTE_VALUE_INVALID;
michael@0 400 }
michael@0 401
michael@0 402
michael@0 403 /* If the point is uncompressed and the lengths match, it
michael@0 404 * must be an unencoded point */
michael@0 405 if ((*((char *)ecPoint->pValue) == EC_POINT_FORM_UNCOMPRESSED)
michael@0 406 && (ecPoint->ulValueLen == keyLen)) {
michael@0 407 return pk11_Attr2SecItem(arena, ecPoint, publicKeyValue);
michael@0 408 }
michael@0 409
michael@0 410 /* now assume the key passed to us was encoded and decode it */
michael@0 411 if (*((char *)ecPoint->pValue) == SEC_ASN1_OCTET_STRING) {
michael@0 412 /* OK, now let's try to decode it and see if it's valid */
michael@0 413 encodedPublicValue.data = ecPoint->pValue;
michael@0 414 encodedPublicValue.len = ecPoint->ulValueLen;
michael@0 415 rv = SEC_QuickDERDecodeItem(arena, publicKeyValue,
michael@0 416 SEC_ASN1_GET(SEC_OctetStringTemplate), &encodedPublicValue);
michael@0 417
michael@0 418 /* it coded correctly & we know the key length (and they match)
michael@0 419 * then we are done, return the results. */
michael@0 420 if (keyLen && rv == SECSuccess && publicKeyValue->len == keyLen) {
michael@0 421 return CKR_OK;
michael@0 422 }
michael@0 423
michael@0 424 /* if we know the key length, one of the above tests should have
michael@0 425 * succeded. If it doesn't the module gave us bad data */
michael@0 426 if (keyLen) {
michael@0 427 return CKR_ATTRIBUTE_VALUE_INVALID;
michael@0 428 }
michael@0 429
michael@0 430
michael@0 431 /* We don't know the key length, so we don't know deterministically
michael@0 432 * which encoding was used. We now will try to pick the most likely
michael@0 433 * form that's correct, with a preference for the encoded form if we
michael@0 434 * can't determine for sure. We do this by checking the key we got
michael@0 435 * back from SEC_QuickDERDecodeItem for defects. If no defects are
michael@0 436 * found, we assume the encoded parameter was was passed to us.
michael@0 437 * our defect tests include:
michael@0 438 * 1) it didn't decode.
michael@0 439 * 2) The decode key had an invalid length (must be odd).
michael@0 440 * 3) The decoded key wasn't an UNCOMPRESSED key.
michael@0 441 * 4) The decoded key didn't include the entire encoded block
michael@0 442 * except the DER encoding values. (fixing DER length to one
michael@0 443 * particular value).
michael@0 444 */
michael@0 445 if ((rv != SECSuccess)
michael@0 446 || ((publicKeyValue->len & 1) != 1)
michael@0 447 || (publicKeyValue->data[0] != EC_POINT_FORM_UNCOMPRESSED)
michael@0 448 || (PORT_Memcmp(&encodedPublicValue.data[encodedPublicValue.len -
michael@0 449 publicKeyValue->len], publicKeyValue->data,
michael@0 450 publicKeyValue->len) != 0)) {
michael@0 451 /* The decoded public key was flawed, the original key must have
michael@0 452 * already been in decoded form. Do a quick sanity check then
michael@0 453 * return the original key value.
michael@0 454 */
michael@0 455 if ((encodedPublicValue.len & 1) == 0) {
michael@0 456 return CKR_ATTRIBUTE_VALUE_INVALID;
michael@0 457 }
michael@0 458 return pk11_Attr2SecItem(arena, ecPoint, publicKeyValue);
michael@0 459 }
michael@0 460
michael@0 461 /* as best we can figure, the passed in key was encoded, and we've
michael@0 462 * now decoded it. Note: there is a chance this could be wrong if the
michael@0 463 * following conditions hold:
michael@0 464 * 1) The first byte or bytes of the X point looks like a valid length
michael@0 465 * of precisely the right size (2*curveSize -1). this means for curves
michael@0 466 * less than 512 bits (64 bytes), this will happen 1 in 256 times*.
michael@0 467 * for curves between 512 and 1024, this will happen 1 in 65,536 times*
michael@0 468 * for curves between 1024 and 256K this will happen 1 in 16 million*
michael@0 469 * 2) The length of the 'DER length field' is odd
michael@0 470 * (making both the encoded and decode
michael@0 471 * values an odd length. this is true of all curves less than 512,
michael@0 472 * as well as curves between 1024 and 256K).
michael@0 473 * 3) The X[length of the 'DER length field'] == 0x04, 1 in 256.
michael@0 474 *
michael@0 475 * (* assuming all values are equally likely in the first byte,
michael@0 476 * This isn't true if the curve length is not a multiple of 8. In these
michael@0 477 * cases, if the DER length is possible, it's more likely,
michael@0 478 * if it's not possible, then we have no false decodes).
michael@0 479 *
michael@0 480 * For reference here are the odds for the various curves we currently
michael@0 481 * have support for (and the only curves SSL will negotiate at this
michael@0 482 * time). NOTE: None of the supported curves will show up here
michael@0 483 * because we return a valid length for all of these curves.
michael@0 484 * The only way to get here is to have some application (not SSL)
michael@0 485 * which supports some unknown curve and have some vendor supplied
michael@0 486 * PKCS #11 module support that curve. NOTE: in this case, one
michael@0 487 * presumes that that pkcs #11 module is likely to be using the
michael@0 488 * correct encodings.
michael@0 489 *
michael@0 490 * Prime Curves (GFp):
michael@0 491 * Bit False Odds of
michael@0 492 * Size DER Len False Decode Positive
michael@0 493 * 112 27 1 in 65536
michael@0 494 * 128 31 1 in 65536
michael@0 495 * 160 39 1 in 65536
michael@0 496 * 192 47 1 in 65536
michael@0 497 * 224 55 1 in 65536
michael@0 498 * 239 59 1 in 32768 (top byte can only be 0-127)
michael@0 499 * 256 63 1 in 65536
michael@0 500 * 521 129,131 0 (decoded value would be even)
michael@0 501 *
michael@0 502 * Binary curves (GF2m).
michael@0 503 * Bit False Odds of
michael@0 504 * Size DER Len False Decode Positive
michael@0 505 * 131 33 0 (top byte can only be 0-7)
michael@0 506 * 163 41 0 (top byte can only be 0-7)
michael@0 507 * 176 43 1 in 65536
michael@0 508 * 191 47 1 in 32768 (top byte can only be 0-127)
michael@0 509 * 193 49 0 (top byte can only be 0-1)
michael@0 510 * 208 51 1 in 65536
michael@0 511 * 233 59 0 (top byte can only be 0-1)
michael@0 512 * 239 59 1 in 32768 (top byte can only be 0-127)
michael@0 513 * 272 67 1 in 65536
michael@0 514 * 283 71 0 (top byte can only be 0-7)
michael@0 515 * 304 75 1 in 65536
michael@0 516 * 359 89 1 in 32768 (top byte can only be 0-127)
michael@0 517 * 368 91 1 in 65536
michael@0 518 * 409 103 0 (top byte can only be 0-1)
michael@0 519 * 431 107 1 in 32768 (top byte can only be 0-127)
michael@0 520 * 571 129,143 0 (decoded value would be even)
michael@0 521 *
michael@0 522 */
michael@0 523
michael@0 524 return CKR_OK;
michael@0 525 }
michael@0 526
michael@0 527 /* In theory, we should handle the case where the curve == 0 and
michael@0 528 * the first byte is EC_POINT_FORM_UNCOMPRESSED, (which would be
michael@0 529 * handled by doing a santity check on the key length and returning
michael@0 530 * pk11_Attr2SecItem() to copy the ecPoint to the publicKeyValue).
michael@0 531 *
michael@0 532 * This test is unnecessary, however, due to the fact that
michael@0 533 * EC_POINT_FORM_UNCOMPRESSED == SEC_ASIN1_OCTET_STRING, that case is
michael@0 534 * handled in the above if. That means if we get here, the initial
michael@0 535 * byte of our ecPoint value was invalid, so we can safely return.
michael@0 536 * invalid attribute.
michael@0 537 */
michael@0 538
michael@0 539 return CKR_ATTRIBUTE_VALUE_INVALID;
michael@0 540 }
michael@0 541
michael@0 542 /*
michael@0 543 * extract a public key from a slot and id
michael@0 544 */
michael@0 545 SECKEYPublicKey *
michael@0 546 PK11_ExtractPublicKey(PK11SlotInfo *slot,KeyType keyType,CK_OBJECT_HANDLE id)
michael@0 547 {
michael@0 548 CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
michael@0 549 PLArenaPool *arena;
michael@0 550 PLArenaPool *tmp_arena;
michael@0 551 SECKEYPublicKey *pubKey;
michael@0 552 int templateCount = 0;
michael@0 553 CK_KEY_TYPE pk11KeyType;
michael@0 554 CK_RV crv;
michael@0 555 CK_ATTRIBUTE template[8];
michael@0 556 CK_ATTRIBUTE *attrs= template;
michael@0 557 CK_ATTRIBUTE *modulus,*exponent,*base,*prime,*subprime,*value;
michael@0 558 CK_ATTRIBUTE *ecparams;
michael@0 559
michael@0 560 /* if we didn't know the key type, get it */
michael@0 561 if (keyType== nullKey) {
michael@0 562
michael@0 563 pk11KeyType = PK11_ReadULongAttribute(slot,id,CKA_KEY_TYPE);
michael@0 564 if (pk11KeyType == CK_UNAVAILABLE_INFORMATION) {
michael@0 565 return NULL;
michael@0 566 }
michael@0 567 switch (pk11KeyType) {
michael@0 568 case CKK_RSA:
michael@0 569 keyType = rsaKey;
michael@0 570 break;
michael@0 571 case CKK_DSA:
michael@0 572 keyType = dsaKey;
michael@0 573 break;
michael@0 574 case CKK_DH:
michael@0 575 keyType = dhKey;
michael@0 576 break;
michael@0 577 case CKK_EC:
michael@0 578 keyType = ecKey;
michael@0 579 break;
michael@0 580 default:
michael@0 581 PORT_SetError( SEC_ERROR_BAD_KEY );
michael@0 582 return NULL;
michael@0 583 }
michael@0 584 }
michael@0 585
michael@0 586
michael@0 587 /* now we need to create space for the public key */
michael@0 588 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
michael@0 589 if (arena == NULL) return NULL;
michael@0 590 tmp_arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
michael@0 591 if (tmp_arena == NULL) {
michael@0 592 PORT_FreeArena (arena, PR_FALSE);
michael@0 593 return NULL;
michael@0 594 }
michael@0 595
michael@0 596
michael@0 597 pubKey = (SECKEYPublicKey *)
michael@0 598 PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey));
michael@0 599 if (pubKey == NULL) {
michael@0 600 PORT_FreeArena (arena, PR_FALSE);
michael@0 601 PORT_FreeArena (tmp_arena, PR_FALSE);
michael@0 602 return NULL;
michael@0 603 }
michael@0 604
michael@0 605 pubKey->arena = arena;
michael@0 606 pubKey->keyType = keyType;
michael@0 607 pubKey->pkcs11Slot = PK11_ReferenceSlot(slot);
michael@0 608 pubKey->pkcs11ID = id;
michael@0 609 PK11_SETATTRS(attrs, CKA_CLASS, &keyClass,
michael@0 610 sizeof(keyClass)); attrs++;
michael@0 611 PK11_SETATTRS(attrs, CKA_KEY_TYPE, &pk11KeyType,
michael@0 612 sizeof(pk11KeyType) ); attrs++;
michael@0 613 switch (pubKey->keyType) {
michael@0 614 case rsaKey:
michael@0 615 modulus = attrs;
michael@0 616 PK11_SETATTRS(attrs, CKA_MODULUS, NULL, 0); attrs++;
michael@0 617 exponent = attrs;
michael@0 618 PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, NULL, 0); attrs++;
michael@0 619
michael@0 620 templateCount = attrs - template;
michael@0 621 PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE));
michael@0 622 crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount);
michael@0 623 if (crv != CKR_OK) break;
michael@0 624
michael@0 625 if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_RSA)) {
michael@0 626 crv = CKR_OBJECT_HANDLE_INVALID;
michael@0 627 break;
michael@0 628 }
michael@0 629 crv = pk11_Attr2SecItem(arena,modulus,&pubKey->u.rsa.modulus);
michael@0 630 if (crv != CKR_OK) break;
michael@0 631 crv = pk11_Attr2SecItem(arena,exponent,&pubKey->u.rsa.publicExponent);
michael@0 632 if (crv != CKR_OK) break;
michael@0 633 break;
michael@0 634 case dsaKey:
michael@0 635 prime = attrs;
michael@0 636 PK11_SETATTRS(attrs, CKA_PRIME, NULL, 0); attrs++;
michael@0 637 subprime = attrs;
michael@0 638 PK11_SETATTRS(attrs, CKA_SUBPRIME, NULL, 0); attrs++;
michael@0 639 base = attrs;
michael@0 640 PK11_SETATTRS(attrs, CKA_BASE, NULL, 0); attrs++;
michael@0 641 value = attrs;
michael@0 642 PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0); attrs++;
michael@0 643 templateCount = attrs - template;
michael@0 644 PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE));
michael@0 645 crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount);
michael@0 646 if (crv != CKR_OK) break;
michael@0 647
michael@0 648 if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_DSA)) {
michael@0 649 crv = CKR_OBJECT_HANDLE_INVALID;
michael@0 650 break;
michael@0 651 }
michael@0 652 crv = pk11_Attr2SecItem(arena,prime,&pubKey->u.dsa.params.prime);
michael@0 653 if (crv != CKR_OK) break;
michael@0 654 crv = pk11_Attr2SecItem(arena,subprime,&pubKey->u.dsa.params.subPrime);
michael@0 655 if (crv != CKR_OK) break;
michael@0 656 crv = pk11_Attr2SecItem(arena,base,&pubKey->u.dsa.params.base);
michael@0 657 if (crv != CKR_OK) break;
michael@0 658 crv = pk11_Attr2SecItem(arena,value,&pubKey->u.dsa.publicValue);
michael@0 659 if (crv != CKR_OK) break;
michael@0 660 break;
michael@0 661 case dhKey:
michael@0 662 prime = attrs;
michael@0 663 PK11_SETATTRS(attrs, CKA_PRIME, NULL, 0); attrs++;
michael@0 664 base = attrs;
michael@0 665 PK11_SETATTRS(attrs, CKA_BASE, NULL, 0); attrs++;
michael@0 666 value =attrs;
michael@0 667 PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0); attrs++;
michael@0 668 templateCount = attrs - template;
michael@0 669 PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE));
michael@0 670 crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount);
michael@0 671 if (crv != CKR_OK) break;
michael@0 672
michael@0 673 if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_DH)) {
michael@0 674 crv = CKR_OBJECT_HANDLE_INVALID;
michael@0 675 break;
michael@0 676 }
michael@0 677 crv = pk11_Attr2SecItem(arena,prime,&pubKey->u.dh.prime);
michael@0 678 if (crv != CKR_OK) break;
michael@0 679 crv = pk11_Attr2SecItem(arena,base,&pubKey->u.dh.base);
michael@0 680 if (crv != CKR_OK) break;
michael@0 681 crv = pk11_Attr2SecItem(arena,value,&pubKey->u.dh.publicValue);
michael@0 682 if (crv != CKR_OK) break;
michael@0 683 break;
michael@0 684 case ecKey:
michael@0 685 pubKey->u.ec.size = 0;
michael@0 686 ecparams = attrs;
michael@0 687 PK11_SETATTRS(attrs, CKA_EC_PARAMS, NULL, 0); attrs++;
michael@0 688 value =attrs;
michael@0 689 PK11_SETATTRS(attrs, CKA_EC_POINT, NULL, 0); attrs++;
michael@0 690 templateCount = attrs - template;
michael@0 691 PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE));
michael@0 692 crv = PK11_GetAttributes(arena,slot,id,template,templateCount);
michael@0 693 if (crv != CKR_OK) break;
michael@0 694
michael@0 695 if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_EC)) {
michael@0 696 crv = CKR_OBJECT_HANDLE_INVALID;
michael@0 697 break;
michael@0 698 }
michael@0 699
michael@0 700 crv = pk11_Attr2SecItem(arena,ecparams,
michael@0 701 &pubKey->u.ec.DEREncodedParams);
michael@0 702 if (crv != CKR_OK) break;
michael@0 703 crv = pk11_get_Decoded_ECPoint(arena,
michael@0 704 &pubKey->u.ec.DEREncodedParams, value,
michael@0 705 &pubKey->u.ec.publicValue);
michael@0 706 break;
michael@0 707 case fortezzaKey:
michael@0 708 case nullKey:
michael@0 709 default:
michael@0 710 crv = CKR_OBJECT_HANDLE_INVALID;
michael@0 711 break;
michael@0 712 }
michael@0 713
michael@0 714 PORT_FreeArena(tmp_arena,PR_FALSE);
michael@0 715
michael@0 716 if (crv != CKR_OK) {
michael@0 717 PORT_FreeArena(arena,PR_FALSE);
michael@0 718 PK11_FreeSlot(slot);
michael@0 719 PORT_SetError( PK11_MapError(crv) );
michael@0 720 return NULL;
michael@0 721 }
michael@0 722
michael@0 723 return pubKey;
michael@0 724 }
michael@0 725
michael@0 726 /*
michael@0 727 * Build a Private Key structure from raw PKCS #11 information.
michael@0 728 */
michael@0 729 SECKEYPrivateKey *
michael@0 730 PK11_MakePrivKey(PK11SlotInfo *slot, KeyType keyType,
michael@0 731 PRBool isTemp, CK_OBJECT_HANDLE privID, void *wincx)
michael@0 732 {
michael@0 733 PLArenaPool *arena;
michael@0 734 SECKEYPrivateKey *privKey;
michael@0 735 PRBool isPrivate;
michael@0 736 SECStatus rv;
michael@0 737
michael@0 738 /* don't know? look it up */
michael@0 739 if (keyType == nullKey) {
michael@0 740 CK_KEY_TYPE pk11Type = CKK_RSA;
michael@0 741
michael@0 742 pk11Type = PK11_ReadULongAttribute(slot,privID,CKA_KEY_TYPE);
michael@0 743 isTemp = (PRBool)!PK11_HasAttributeSet(slot,privID,CKA_TOKEN,PR_FALSE);
michael@0 744 switch (pk11Type) {
michael@0 745 case CKK_RSA: keyType = rsaKey; break;
michael@0 746 case CKK_DSA: keyType = dsaKey; break;
michael@0 747 case CKK_DH: keyType = dhKey; break;
michael@0 748 case CKK_KEA: keyType = fortezzaKey; break;
michael@0 749 case CKK_EC: keyType = ecKey; break;
michael@0 750 default:
michael@0 751 break;
michael@0 752 }
michael@0 753 }
michael@0 754
michael@0 755 /* if the key is private, make sure we are authenticated to the
michael@0 756 * token before we try to use it */
michael@0 757 isPrivate = (PRBool)PK11_HasAttributeSet(slot,privID,CKA_PRIVATE,PR_FALSE);
michael@0 758 if (isPrivate) {
michael@0 759 rv = PK11_Authenticate(slot, PR_TRUE, wincx);
michael@0 760 if (rv != SECSuccess) {
michael@0 761 return NULL;
michael@0 762 }
michael@0 763 }
michael@0 764
michael@0 765 /* now we need to create space for the private key */
michael@0 766 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
michael@0 767 if (arena == NULL) return NULL;
michael@0 768
michael@0 769 privKey = (SECKEYPrivateKey *)
michael@0 770 PORT_ArenaZAlloc(arena, sizeof(SECKEYPrivateKey));
michael@0 771 if (privKey == NULL) {
michael@0 772 PORT_FreeArena(arena, PR_FALSE);
michael@0 773 return NULL;
michael@0 774 }
michael@0 775
michael@0 776 privKey->arena = arena;
michael@0 777 privKey->keyType = keyType;
michael@0 778 privKey->pkcs11Slot = PK11_ReferenceSlot(slot);
michael@0 779 privKey->pkcs11ID = privID;
michael@0 780 privKey->pkcs11IsTemp = isTemp;
michael@0 781 privKey->wincx = wincx;
michael@0 782
michael@0 783 return privKey;
michael@0 784 }
michael@0 785
michael@0 786
michael@0 787 PK11SlotInfo *
michael@0 788 PK11_GetSlotFromPrivateKey(SECKEYPrivateKey *key)
michael@0 789 {
michael@0 790 PK11SlotInfo *slot = key->pkcs11Slot;
michael@0 791 slot = PK11_ReferenceSlot(slot);
michael@0 792 return slot;
michael@0 793 }
michael@0 794
michael@0 795 /*
michael@0 796 * Get the modulus length for raw parsing
michael@0 797 */
michael@0 798 int
michael@0 799 PK11_GetPrivateModulusLen(SECKEYPrivateKey *key)
michael@0 800 {
michael@0 801 CK_ATTRIBUTE theTemplate = { CKA_MODULUS, NULL, 0 };
michael@0 802 PK11SlotInfo *slot = key->pkcs11Slot;
michael@0 803 CK_RV crv;
michael@0 804 int length;
michael@0 805
michael@0 806 switch (key->keyType) {
michael@0 807 case rsaKey:
michael@0 808 crv = PK11_GetAttributes(NULL, slot, key->pkcs11ID, &theTemplate, 1);
michael@0 809 if (crv != CKR_OK) {
michael@0 810 PORT_SetError( PK11_MapError(crv) );
michael@0 811 return -1;
michael@0 812 }
michael@0 813 length = theTemplate.ulValueLen;
michael@0 814 if ( *(unsigned char *)theTemplate.pValue == 0) {
michael@0 815 length--;
michael@0 816 }
michael@0 817 if (theTemplate.pValue != NULL)
michael@0 818 PORT_Free(theTemplate.pValue);
michael@0 819 return (int) length;
michael@0 820
michael@0 821 case fortezzaKey:
michael@0 822 case dsaKey:
michael@0 823 case dhKey:
michael@0 824 default:
michael@0 825 break;
michael@0 826 }
michael@0 827 if (theTemplate.pValue != NULL)
michael@0 828 PORT_Free(theTemplate.pValue);
michael@0 829 PORT_SetError( SEC_ERROR_INVALID_KEY );
michael@0 830 return -1;
michael@0 831 }
michael@0 832
michael@0 833
michael@0 834
michael@0 835 /*
michael@0 836 * take a private key in one pkcs11 module and load it into another:
michael@0 837 * NOTE: the source private key is a rare animal... it can't be sensitive.
michael@0 838 * This is used to do a key gen using one pkcs11 module and storing the
michael@0 839 * result into another.
michael@0 840 */
michael@0 841 static SECKEYPrivateKey *
michael@0 842 pk11_loadPrivKeyWithFlags(PK11SlotInfo *slot,SECKEYPrivateKey *privKey,
michael@0 843 SECKEYPublicKey *pubKey, PK11AttrFlags attrFlags)
michael@0 844 {
michael@0 845 CK_ATTRIBUTE privTemplate[] = {
michael@0 846 /* class must be first */
michael@0 847 { CKA_CLASS, NULL, 0 },
michael@0 848 { CKA_KEY_TYPE, NULL, 0 },
michael@0 849 { CKA_ID, NULL, 0 },
michael@0 850 /* RSA - the attributes below will be replaced for other
michael@0 851 * key types.
michael@0 852 */
michael@0 853 { CKA_MODULUS, NULL, 0 },
michael@0 854 { CKA_PRIVATE_EXPONENT, NULL, 0 },
michael@0 855 { CKA_PUBLIC_EXPONENT, NULL, 0 },
michael@0 856 { CKA_PRIME_1, NULL, 0 },
michael@0 857 { CKA_PRIME_2, NULL, 0 },
michael@0 858 { CKA_EXPONENT_1, NULL, 0 },
michael@0 859 { CKA_EXPONENT_2, NULL, 0 },
michael@0 860 { CKA_COEFFICIENT, NULL, 0 },
michael@0 861 { CKA_DECRYPT, NULL, 0 },
michael@0 862 { CKA_DERIVE, NULL, 0 },
michael@0 863 { CKA_SIGN, NULL, 0 },
michael@0 864 { CKA_SIGN_RECOVER, NULL, 0 },
michael@0 865 { CKA_UNWRAP, NULL, 0 },
michael@0 866 /* reserve space for the attributes that may be
michael@0 867 * specified in attrFlags */
michael@0 868 { CKA_TOKEN, NULL, 0 },
michael@0 869 { CKA_PRIVATE, NULL, 0 },
michael@0 870 { CKA_MODIFIABLE, NULL, 0 },
michael@0 871 { CKA_SENSITIVE, NULL, 0 },
michael@0 872 { CKA_EXTRACTABLE, NULL, 0 },
michael@0 873 #define NUM_RESERVED_ATTRS 5 /* number of reserved attributes above */
michael@0 874 };
michael@0 875 CK_BBOOL cktrue = CK_TRUE;
michael@0 876 CK_BBOOL ckfalse = CK_FALSE;
michael@0 877 CK_ATTRIBUTE *attrs = NULL, *ap;
michael@0 878 const int templateSize = sizeof(privTemplate)/sizeof(privTemplate[0]);
michael@0 879 PLArenaPool *arena;
michael@0 880 CK_OBJECT_HANDLE objectID;
michael@0 881 int i, count = 0;
michael@0 882 int extra_count = 0;
michael@0 883 CK_RV crv;
michael@0 884 SECStatus rv;
michael@0 885 PRBool token = ((attrFlags & PK11_ATTR_TOKEN) != 0);
michael@0 886
michael@0 887 if (pk11_BadAttrFlags(attrFlags)) {
michael@0 888 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 889 return NULL;
michael@0 890 }
michael@0 891
michael@0 892 for (i=0; i < templateSize; i++) {
michael@0 893 if (privTemplate[i].type == CKA_MODULUS) {
michael@0 894 attrs= &privTemplate[i];
michael@0 895 count = i;
michael@0 896 break;
michael@0 897 }
michael@0 898 }
michael@0 899 PORT_Assert(attrs != NULL);
michael@0 900 if (attrs == NULL) {
michael@0 901 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 902 return NULL;
michael@0 903 }
michael@0 904
michael@0 905 ap = attrs;
michael@0 906
michael@0 907 switch (privKey->keyType) {
michael@0 908 case rsaKey:
michael@0 909 count = templateSize - NUM_RESERVED_ATTRS;
michael@0 910 extra_count = count - (attrs - privTemplate);
michael@0 911 break;
michael@0 912 case dsaKey:
michael@0 913 ap->type = CKA_PRIME; ap++; count++; extra_count++;
michael@0 914 ap->type = CKA_SUBPRIME; ap++; count++; extra_count++;
michael@0 915 ap->type = CKA_BASE; ap++; count++; extra_count++;
michael@0 916 ap->type = CKA_VALUE; ap++; count++; extra_count++;
michael@0 917 ap->type = CKA_SIGN; ap++; count++; extra_count++;
michael@0 918 break;
michael@0 919 case dhKey:
michael@0 920 ap->type = CKA_PRIME; ap++; count++; extra_count++;
michael@0 921 ap->type = CKA_BASE; ap++; count++; extra_count++;
michael@0 922 ap->type = CKA_VALUE; ap++; count++; extra_count++;
michael@0 923 ap->type = CKA_DERIVE; ap++; count++; extra_count++;
michael@0 924 break;
michael@0 925 case ecKey:
michael@0 926 ap->type = CKA_EC_PARAMS; ap++; count++; extra_count++;
michael@0 927 ap->type = CKA_VALUE; ap++; count++; extra_count++;
michael@0 928 ap->type = CKA_DERIVE; ap++; count++; extra_count++;
michael@0 929 ap->type = CKA_SIGN; ap++; count++; extra_count++;
michael@0 930 break;
michael@0 931 default:
michael@0 932 count = 0;
michael@0 933 extra_count = 0;
michael@0 934 break;
michael@0 935 }
michael@0 936
michael@0 937 if (count == 0) {
michael@0 938 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 939 return NULL;
michael@0 940 }
michael@0 941
michael@0 942 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
michael@0 943 if (arena == NULL) return NULL;
michael@0 944 /*
michael@0 945 * read out the old attributes.
michael@0 946 */
michael@0 947 crv = PK11_GetAttributes(arena, privKey->pkcs11Slot, privKey->pkcs11ID,
michael@0 948 privTemplate,count);
michael@0 949 if (crv != CKR_OK) {
michael@0 950 PORT_SetError( PK11_MapError(crv) );
michael@0 951 PORT_FreeArena(arena, PR_TRUE);
michael@0 952 return NULL;
michael@0 953 }
michael@0 954
michael@0 955 /* Set token, private, modifiable, sensitive, and extractable */
michael@0 956 count += pk11_AttrFlagsToAttributes(attrFlags, &privTemplate[count],
michael@0 957 &cktrue, &ckfalse);
michael@0 958
michael@0 959 /* Not everyone can handle zero padded key values, give
michael@0 960 * them the raw data as unsigned */
michael@0 961 for (ap=attrs; extra_count; ap++, extra_count--) {
michael@0 962 pk11_SignedToUnsigned(ap);
michael@0 963 }
michael@0 964
michael@0 965 /* now Store the puppies */
michael@0 966 rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, privTemplate,
michael@0 967 count, token, &objectID);
michael@0 968 PORT_FreeArena(arena, PR_TRUE);
michael@0 969 if (rv != SECSuccess) {
michael@0 970 return NULL;
michael@0 971 }
michael@0 972
michael@0 973 /* try loading the public key */
michael@0 974 if (pubKey) {
michael@0 975 PK11_ImportPublicKey(slot, pubKey, token);
michael@0 976 if (pubKey->pkcs11Slot) {
michael@0 977 PK11_FreeSlot(pubKey->pkcs11Slot);
michael@0 978 pubKey->pkcs11Slot = NULL;
michael@0 979 pubKey->pkcs11ID = CK_INVALID_HANDLE;
michael@0 980 }
michael@0 981 }
michael@0 982
michael@0 983 /* build new key structure */
michael@0 984 return PK11_MakePrivKey(slot, privKey->keyType, !token,
michael@0 985 objectID, privKey->wincx);
michael@0 986 }
michael@0 987
michael@0 988 static SECKEYPrivateKey *
michael@0 989 pk11_loadPrivKey(PK11SlotInfo *slot,SECKEYPrivateKey *privKey,
michael@0 990 SECKEYPublicKey *pubKey, PRBool token, PRBool sensitive)
michael@0 991 {
michael@0 992 PK11AttrFlags attrFlags = 0;
michael@0 993 if (token) {
michael@0 994 attrFlags |= (PK11_ATTR_TOKEN | PK11_ATTR_PRIVATE);
michael@0 995 } else {
michael@0 996 attrFlags |= (PK11_ATTR_SESSION | PK11_ATTR_PUBLIC);
michael@0 997 }
michael@0 998 if (sensitive) {
michael@0 999 attrFlags |= PK11_ATTR_SENSITIVE;
michael@0 1000 } else {
michael@0 1001 attrFlags |= PK11_ATTR_INSENSITIVE;
michael@0 1002 }
michael@0 1003 return pk11_loadPrivKeyWithFlags(slot, privKey, pubKey, attrFlags);
michael@0 1004 }
michael@0 1005
michael@0 1006 /*
michael@0 1007 * export this for PSM
michael@0 1008 */
michael@0 1009 SECKEYPrivateKey *
michael@0 1010 PK11_LoadPrivKey(PK11SlotInfo *slot,SECKEYPrivateKey *privKey,
michael@0 1011 SECKEYPublicKey *pubKey, PRBool token, PRBool sensitive)
michael@0 1012 {
michael@0 1013 return pk11_loadPrivKey(slot,privKey,pubKey,token,sensitive);
michael@0 1014 }
michael@0 1015
michael@0 1016
michael@0 1017 /*
michael@0 1018 * Use the token to generate a key pair.
michael@0 1019 */
michael@0 1020 SECKEYPrivateKey *
michael@0 1021 PK11_GenerateKeyPairWithOpFlags(PK11SlotInfo *slot,CK_MECHANISM_TYPE type,
michael@0 1022 void *param, SECKEYPublicKey **pubKey, PK11AttrFlags attrFlags,
michael@0 1023 CK_FLAGS opFlags, CK_FLAGS opFlagsMask, void *wincx)
michael@0 1024 {
michael@0 1025 /* we have to use these native types because when we call PKCS 11 modules
michael@0 1026 * we have to make sure that we are using the correct sizes for all the
michael@0 1027 * parameters. */
michael@0 1028 CK_BBOOL ckfalse = CK_FALSE;
michael@0 1029 CK_BBOOL cktrue = CK_TRUE;
michael@0 1030 CK_ULONG modulusBits;
michael@0 1031 CK_BYTE publicExponent[4];
michael@0 1032 CK_ATTRIBUTE privTemplate[] = {
michael@0 1033 { CKA_SENSITIVE, NULL, 0},
michael@0 1034 { CKA_TOKEN, NULL, 0},
michael@0 1035 { CKA_PRIVATE, NULL, 0},
michael@0 1036 { CKA_DERIVE, NULL, 0},
michael@0 1037 { CKA_UNWRAP, NULL, 0},
michael@0 1038 { CKA_SIGN, NULL, 0},
michael@0 1039 { CKA_DECRYPT, NULL, 0},
michael@0 1040 { CKA_EXTRACTABLE, NULL, 0},
michael@0 1041 { CKA_MODIFIABLE, NULL, 0},
michael@0 1042 };
michael@0 1043 CK_ATTRIBUTE rsaPubTemplate[] = {
michael@0 1044 { CKA_MODULUS_BITS, NULL, 0},
michael@0 1045 { CKA_PUBLIC_EXPONENT, NULL, 0},
michael@0 1046 { CKA_TOKEN, NULL, 0},
michael@0 1047 { CKA_DERIVE, NULL, 0},
michael@0 1048 { CKA_WRAP, NULL, 0},
michael@0 1049 { CKA_VERIFY, NULL, 0},
michael@0 1050 { CKA_VERIFY_RECOVER, NULL, 0},
michael@0 1051 { CKA_ENCRYPT, NULL, 0},
michael@0 1052 { CKA_MODIFIABLE, NULL, 0},
michael@0 1053 };
michael@0 1054 CK_ATTRIBUTE dsaPubTemplate[] = {
michael@0 1055 { CKA_PRIME, NULL, 0 },
michael@0 1056 { CKA_SUBPRIME, NULL, 0 },
michael@0 1057 { CKA_BASE, NULL, 0 },
michael@0 1058 { CKA_TOKEN, NULL, 0},
michael@0 1059 { CKA_DERIVE, NULL, 0},
michael@0 1060 { CKA_WRAP, NULL, 0},
michael@0 1061 { CKA_VERIFY, NULL, 0},
michael@0 1062 { CKA_VERIFY_RECOVER, NULL, 0},
michael@0 1063 { CKA_ENCRYPT, NULL, 0},
michael@0 1064 { CKA_MODIFIABLE, NULL, 0},
michael@0 1065 };
michael@0 1066 CK_ATTRIBUTE dhPubTemplate[] = {
michael@0 1067 { CKA_PRIME, NULL, 0 },
michael@0 1068 { CKA_BASE, NULL, 0 },
michael@0 1069 { CKA_TOKEN, NULL, 0},
michael@0 1070 { CKA_DERIVE, NULL, 0},
michael@0 1071 { CKA_WRAP, NULL, 0},
michael@0 1072 { CKA_VERIFY, NULL, 0},
michael@0 1073 { CKA_VERIFY_RECOVER, NULL, 0},
michael@0 1074 { CKA_ENCRYPT, NULL, 0},
michael@0 1075 { CKA_MODIFIABLE, NULL, 0},
michael@0 1076 };
michael@0 1077 CK_ATTRIBUTE ecPubTemplate[] = {
michael@0 1078 { CKA_EC_PARAMS, NULL, 0 },
michael@0 1079 { CKA_TOKEN, NULL, 0},
michael@0 1080 { CKA_DERIVE, NULL, 0},
michael@0 1081 { CKA_WRAP, NULL, 0},
michael@0 1082 { CKA_VERIFY, NULL, 0},
michael@0 1083 { CKA_VERIFY_RECOVER, NULL, 0},
michael@0 1084 { CKA_ENCRYPT, NULL, 0},
michael@0 1085 { CKA_MODIFIABLE, NULL, 0},
michael@0 1086 };
michael@0 1087 SECKEYECParams * ecParams;
michael@0 1088
michael@0 1089 /*CK_ULONG key_size = 0;*/
michael@0 1090 CK_ATTRIBUTE *pubTemplate;
michael@0 1091 int privCount = 0;
michael@0 1092 int pubCount = 0;
michael@0 1093 PK11RSAGenParams *rsaParams;
michael@0 1094 SECKEYPQGParams *dsaParams;
michael@0 1095 SECKEYDHParams * dhParams;
michael@0 1096 CK_MECHANISM mechanism;
michael@0 1097 CK_MECHANISM test_mech;
michael@0 1098 CK_MECHANISM test_mech2;
michael@0 1099 CK_SESSION_HANDLE session_handle;
michael@0 1100 CK_RV crv;
michael@0 1101 CK_OBJECT_HANDLE privID,pubID;
michael@0 1102 SECKEYPrivateKey *privKey;
michael@0 1103 KeyType keyType;
michael@0 1104 PRBool restore;
michael@0 1105 int peCount,i;
michael@0 1106 CK_ATTRIBUTE *attrs;
michael@0 1107 CK_ATTRIBUTE *privattrs;
michael@0 1108 CK_ATTRIBUTE setTemplate;
michael@0 1109 CK_MECHANISM_INFO mechanism_info;
michael@0 1110 CK_OBJECT_CLASS keyClass;
michael@0 1111 SECItem *cka_id;
michael@0 1112 PRBool haslock = PR_FALSE;
michael@0 1113 PRBool pubIsToken = PR_FALSE;
michael@0 1114 PRBool token = ((attrFlags & PK11_ATTR_TOKEN) != 0);
michael@0 1115 /* subset of attrFlags applicable to the public key */
michael@0 1116 PK11AttrFlags pubKeyAttrFlags = attrFlags &
michael@0 1117 (PK11_ATTR_TOKEN | PK11_ATTR_SESSION
michael@0 1118 | PK11_ATTR_MODIFIABLE | PK11_ATTR_UNMODIFIABLE);
michael@0 1119
michael@0 1120 if (pk11_BadAttrFlags(attrFlags)) {
michael@0 1121 PORT_SetError( SEC_ERROR_INVALID_ARGS );
michael@0 1122 return NULL;
michael@0 1123 }
michael@0 1124
michael@0 1125 if (!param) {
michael@0 1126 PORT_SetError( SEC_ERROR_INVALID_ARGS );
michael@0 1127 return NULL;
michael@0 1128 }
michael@0 1129
michael@0 1130 /*
michael@0 1131 * The opFlags and opFlagMask parameters allow us to control the
michael@0 1132 * settings of the key usage attributes (CKA_ENCRYPT and friends).
michael@0 1133 * opFlagMask is set to one if the flag is specified in opFlags and
michael@0 1134 * zero if it is to take on a default value calculated by
michael@0 1135 * PK11_GenerateKeyPairWithOpFlags.
michael@0 1136 * opFlags specifies the actual value of the flag 1 or 0.
michael@0 1137 * Bits not corresponding to one bits in opFlagMask should be zero.
michael@0 1138 */
michael@0 1139
michael@0 1140 /* if we are trying to turn on a flag, it better be in the mask */
michael@0 1141 PORT_Assert ((opFlags & ~opFlagsMask) == 0);
michael@0 1142 opFlags &= opFlagsMask;
michael@0 1143
michael@0 1144 PORT_Assert(slot != NULL);
michael@0 1145 if (slot == NULL) {
michael@0 1146 PORT_SetError( SEC_ERROR_NO_MODULE);
michael@0 1147 return NULL;
michael@0 1148 }
michael@0 1149
michael@0 1150 /* if our slot really doesn't do this mechanism, Generate the key
michael@0 1151 * in our internal token and write it out */
michael@0 1152 if (!PK11_DoesMechanism(slot,type)) {
michael@0 1153 PK11SlotInfo *int_slot = PK11_GetInternalSlot();
michael@0 1154
michael@0 1155 /* don't loop forever looking for a slot */
michael@0 1156 if (slot == int_slot) {
michael@0 1157 PK11_FreeSlot(int_slot);
michael@0 1158 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 1159 return NULL;
michael@0 1160 }
michael@0 1161
michael@0 1162 /* if there isn't a suitable slot, then we can't do the keygen */
michael@0 1163 if (int_slot == NULL) {
michael@0 1164 PORT_SetError( SEC_ERROR_NO_MODULE );
michael@0 1165 return NULL;
michael@0 1166 }
michael@0 1167
michael@0 1168 /* generate the temporary key to load */
michael@0 1169 privKey = PK11_GenerateKeyPair(int_slot,type, param, pubKey, PR_FALSE,
michael@0 1170 PR_FALSE, wincx);
michael@0 1171 PK11_FreeSlot(int_slot);
michael@0 1172
michael@0 1173 /* if successful, load the temp key into the new token */
michael@0 1174 if (privKey != NULL) {
michael@0 1175 SECKEYPrivateKey *newPrivKey = pk11_loadPrivKeyWithFlags(slot,
michael@0 1176 privKey,*pubKey,attrFlags);
michael@0 1177 SECKEY_DestroyPrivateKey(privKey);
michael@0 1178 if (newPrivKey == NULL) {
michael@0 1179 SECKEY_DestroyPublicKey(*pubKey);
michael@0 1180 *pubKey = NULL;
michael@0 1181 }
michael@0 1182 return newPrivKey;
michael@0 1183 }
michael@0 1184 return NULL;
michael@0 1185 }
michael@0 1186
michael@0 1187
michael@0 1188 mechanism.mechanism = type;
michael@0 1189 mechanism.pParameter = NULL;
michael@0 1190 mechanism.ulParameterLen = 0;
michael@0 1191 test_mech.pParameter = NULL;
michael@0 1192 test_mech.ulParameterLen = 0;
michael@0 1193 test_mech2.mechanism = CKM_INVALID_MECHANISM;
michael@0 1194 test_mech2.pParameter = NULL;
michael@0 1195 test_mech2.ulParameterLen = 0;
michael@0 1196
michael@0 1197 /* set up the private key template */
michael@0 1198 privattrs = privTemplate;
michael@0 1199 privattrs += pk11_AttrFlagsToAttributes(attrFlags, privattrs,
michael@0 1200 &cktrue, &ckfalse);
michael@0 1201
michael@0 1202 /* set up the mechanism specific info */
michael@0 1203 switch (type) {
michael@0 1204 case CKM_RSA_PKCS_KEY_PAIR_GEN:
michael@0 1205 case CKM_RSA_X9_31_KEY_PAIR_GEN:
michael@0 1206 rsaParams = (PK11RSAGenParams *)param;
michael@0 1207 if (rsaParams->pe == 0) {
michael@0 1208 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 1209 return NULL;
michael@0 1210 }
michael@0 1211 modulusBits = rsaParams->keySizeInBits;
michael@0 1212 peCount = 0;
michael@0 1213
michael@0 1214 /* convert pe to a PKCS #11 string */
michael@0 1215 for (i=0; i < 4; i++) {
michael@0 1216 if (peCount || (rsaParams->pe &
michael@0 1217 ((unsigned long)0xff000000L >> (i*8)))) {
michael@0 1218 publicExponent[peCount] =
michael@0 1219 (CK_BYTE)((rsaParams->pe >> (3-i)*8) & 0xff);
michael@0 1220 peCount++;
michael@0 1221 }
michael@0 1222 }
michael@0 1223 PORT_Assert(peCount != 0);
michael@0 1224 attrs = rsaPubTemplate;
michael@0 1225 PK11_SETATTRS(attrs, CKA_MODULUS_BITS,
michael@0 1226 &modulusBits, sizeof(modulusBits)); attrs++;
michael@0 1227 PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT,
michael@0 1228 publicExponent, peCount);attrs++;
michael@0 1229 pubTemplate = rsaPubTemplate;
michael@0 1230 keyType = rsaKey;
michael@0 1231 test_mech.mechanism = CKM_RSA_PKCS;
michael@0 1232 break;
michael@0 1233 case CKM_DSA_KEY_PAIR_GEN:
michael@0 1234 dsaParams = (SECKEYPQGParams *)param;
michael@0 1235 attrs = dsaPubTemplate;
michael@0 1236 PK11_SETATTRS(attrs, CKA_PRIME, dsaParams->prime.data,
michael@0 1237 dsaParams->prime.len); attrs++;
michael@0 1238 PK11_SETATTRS(attrs, CKA_SUBPRIME, dsaParams->subPrime.data,
michael@0 1239 dsaParams->subPrime.len); attrs++;
michael@0 1240 PK11_SETATTRS(attrs, CKA_BASE, dsaParams->base.data,
michael@0 1241 dsaParams->base.len); attrs++;
michael@0 1242 pubTemplate = dsaPubTemplate;
michael@0 1243 keyType = dsaKey;
michael@0 1244 test_mech.mechanism = CKM_DSA;
michael@0 1245 break;
michael@0 1246 case CKM_DH_PKCS_KEY_PAIR_GEN:
michael@0 1247 dhParams = (SECKEYDHParams *)param;
michael@0 1248 attrs = dhPubTemplate;
michael@0 1249 PK11_SETATTRS(attrs, CKA_PRIME, dhParams->prime.data,
michael@0 1250 dhParams->prime.len); attrs++;
michael@0 1251 PK11_SETATTRS(attrs, CKA_BASE, dhParams->base.data,
michael@0 1252 dhParams->base.len); attrs++;
michael@0 1253 pubTemplate = dhPubTemplate;
michael@0 1254 keyType = dhKey;
michael@0 1255 test_mech.mechanism = CKM_DH_PKCS_DERIVE;
michael@0 1256 break;
michael@0 1257 case CKM_EC_KEY_PAIR_GEN:
michael@0 1258 ecParams = (SECKEYECParams *)param;
michael@0 1259 attrs = ecPubTemplate;
michael@0 1260 PK11_SETATTRS(attrs, CKA_EC_PARAMS, ecParams->data,
michael@0 1261 ecParams->len); attrs++;
michael@0 1262 pubTemplate = ecPubTemplate;
michael@0 1263 keyType = ecKey;
michael@0 1264 /*
michael@0 1265 * ECC supports 2 different mechanism types (unlike RSA, which
michael@0 1266 * supports different usages with the same mechanism).
michael@0 1267 * We may need to query both mechanism types and or the results
michael@0 1268 * together -- but we only do that if either the user has
michael@0 1269 * requested both usages, or not specified any usages.
michael@0 1270 */
michael@0 1271 if ((opFlags & (CKF_SIGN|CKF_DERIVE)) == (CKF_SIGN|CKF_DERIVE)) {
michael@0 1272 /* We've explicitly turned on both flags, use both mechanism */
michael@0 1273 test_mech.mechanism = CKM_ECDH1_DERIVE;
michael@0 1274 test_mech2.mechanism = CKM_ECDSA;
michael@0 1275 } else if (opFlags & CKF_SIGN) {
michael@0 1276 /* just do signing */
michael@0 1277 test_mech.mechanism = CKM_ECDSA;
michael@0 1278 } else if (opFlags & CKF_DERIVE) {
michael@0 1279 /* just do ECDH */
michael@0 1280 test_mech.mechanism = CKM_ECDH1_DERIVE;
michael@0 1281 } else {
michael@0 1282 /* neither was specified default to both */
michael@0 1283 test_mech.mechanism = CKM_ECDH1_DERIVE;
michael@0 1284 test_mech2.mechanism = CKM_ECDSA;
michael@0 1285 }
michael@0 1286 break;
michael@0 1287 default:
michael@0 1288 PORT_SetError( SEC_ERROR_BAD_KEY );
michael@0 1289 return NULL;
michael@0 1290 }
michael@0 1291
michael@0 1292 /* now query the slot to find out how "good" a key we can generate */
michael@0 1293 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
michael@0 1294 crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
michael@0 1295 test_mech.mechanism,&mechanism_info);
michael@0 1296 /*
michael@0 1297 * EC keys are used in multiple different types of mechanism, if we
michael@0 1298 * are using dual use keys, we need to query the second mechanism
michael@0 1299 * as well.
michael@0 1300 */
michael@0 1301 if (test_mech2.mechanism != CKM_INVALID_MECHANISM) {
michael@0 1302 CK_MECHANISM_INFO mechanism_info2;
michael@0 1303 CK_RV crv2;
michael@0 1304
michael@0 1305 if (crv != CKR_OK) {
michael@0 1306 /* the first failed, make sure there is no trash in the
michael@0 1307 * mechanism flags when we or it below */
michael@0 1308 mechanism_info.flags = 0;
michael@0 1309 }
michael@0 1310 crv2 = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
michael@0 1311 test_mech2.mechanism, &mechanism_info2);
michael@0 1312 if (crv2 == CKR_OK) {
michael@0 1313 crv = CKR_OK; /* succeed if either mechnaism info succeeds */
michael@0 1314 /* combine the 2 sets of mechnanism flags */
michael@0 1315 mechanism_info.flags |= mechanism_info2.flags;
michael@0 1316 }
michael@0 1317 }
michael@0 1318 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
michael@0 1319 if ((crv != CKR_OK) || (mechanism_info.flags == 0)) {
michael@0 1320 /* must be old module... guess what it should be... */
michael@0 1321 switch (test_mech.mechanism) {
michael@0 1322 case CKM_RSA_PKCS:
michael@0 1323 mechanism_info.flags = (CKF_SIGN | CKF_DECRYPT |
michael@0 1324 CKF_WRAP | CKF_VERIFY_RECOVER | CKF_ENCRYPT | CKF_WRAP);
michael@0 1325 break;
michael@0 1326 case CKM_DSA:
michael@0 1327 mechanism_info.flags = CKF_SIGN | CKF_VERIFY;
michael@0 1328 break;
michael@0 1329 case CKM_DH_PKCS_DERIVE:
michael@0 1330 mechanism_info.flags = CKF_DERIVE;
michael@0 1331 break;
michael@0 1332 case CKM_ECDH1_DERIVE:
michael@0 1333 mechanism_info.flags = CKF_DERIVE;
michael@0 1334 if (test_mech2.mechanism == CKM_ECDSA) {
michael@0 1335 mechanism_info.flags |= CKF_SIGN | CKF_VERIFY;
michael@0 1336 }
michael@0 1337 break;
michael@0 1338 case CKM_ECDSA:
michael@0 1339 mechanism_info.flags = CKF_SIGN | CKF_VERIFY;
michael@0 1340 break;
michael@0 1341 default:
michael@0 1342 break;
michael@0 1343 }
michael@0 1344 }
michael@0 1345 /* now adjust our flags according to the user's key usage passed to us */
michael@0 1346 mechanism_info.flags = (mechanism_info.flags & (~opFlagsMask)) | opFlags;
michael@0 1347 /* set the public key attributes */
michael@0 1348 attrs += pk11_AttrFlagsToAttributes(pubKeyAttrFlags, attrs,
michael@0 1349 &cktrue, &ckfalse);
michael@0 1350 PK11_SETATTRS(attrs, CKA_DERIVE,
michael@0 1351 mechanism_info.flags & CKF_DERIVE ? &cktrue : &ckfalse,
michael@0 1352 sizeof(CK_BBOOL)); attrs++;
michael@0 1353 PK11_SETATTRS(attrs, CKA_WRAP,
michael@0 1354 mechanism_info.flags & CKF_WRAP ? &cktrue : &ckfalse,
michael@0 1355 sizeof(CK_BBOOL)); attrs++;
michael@0 1356 PK11_SETATTRS(attrs, CKA_VERIFY,
michael@0 1357 mechanism_info.flags & CKF_VERIFY ? &cktrue : &ckfalse,
michael@0 1358 sizeof(CK_BBOOL)); attrs++;
michael@0 1359 PK11_SETATTRS(attrs, CKA_VERIFY_RECOVER,
michael@0 1360 mechanism_info.flags & CKF_VERIFY_RECOVER ? &cktrue : &ckfalse,
michael@0 1361 sizeof(CK_BBOOL)); attrs++;
michael@0 1362 PK11_SETATTRS(attrs, CKA_ENCRYPT,
michael@0 1363 mechanism_info.flags & CKF_ENCRYPT? &cktrue : &ckfalse,
michael@0 1364 sizeof(CK_BBOOL)); attrs++;
michael@0 1365 /* set the private key attributes */
michael@0 1366 PK11_SETATTRS(privattrs, CKA_DERIVE,
michael@0 1367 mechanism_info.flags & CKF_DERIVE ? &cktrue : &ckfalse,
michael@0 1368 sizeof(CK_BBOOL)); privattrs++;
michael@0 1369 PK11_SETATTRS(privattrs, CKA_UNWRAP,
michael@0 1370 mechanism_info.flags & CKF_UNWRAP ? &cktrue : &ckfalse,
michael@0 1371 sizeof(CK_BBOOL)); privattrs++;
michael@0 1372 PK11_SETATTRS(privattrs, CKA_SIGN,
michael@0 1373 mechanism_info.flags & CKF_SIGN ? &cktrue : &ckfalse,
michael@0 1374 sizeof(CK_BBOOL)); privattrs++;
michael@0 1375 PK11_SETATTRS(privattrs, CKA_DECRYPT,
michael@0 1376 mechanism_info.flags & CKF_DECRYPT ? &cktrue : &ckfalse,
michael@0 1377 sizeof(CK_BBOOL)); privattrs++;
michael@0 1378
michael@0 1379 if (token) {
michael@0 1380 session_handle = PK11_GetRWSession(slot);
michael@0 1381 haslock = PK11_RWSessionHasLock(slot,session_handle);
michael@0 1382 restore = PR_TRUE;
michael@0 1383 } else {
michael@0 1384 session_handle = slot->session;
michael@0 1385 if (session_handle != CK_INVALID_SESSION)
michael@0 1386 PK11_EnterSlotMonitor(slot);
michael@0 1387 restore = PR_FALSE;
michael@0 1388 haslock = PR_TRUE;
michael@0 1389 }
michael@0 1390
michael@0 1391 if (session_handle == CK_INVALID_SESSION) {
michael@0 1392 PORT_SetError(SEC_ERROR_BAD_DATA);
michael@0 1393 return NULL;
michael@0 1394 }
michael@0 1395 privCount = privattrs - privTemplate;
michael@0 1396 pubCount = attrs - pubTemplate;
michael@0 1397 crv = PK11_GETTAB(slot)->C_GenerateKeyPair(session_handle, &mechanism,
michael@0 1398 pubTemplate,pubCount,privTemplate,privCount,&pubID,&privID);
michael@0 1399
michael@0 1400 if (crv != CKR_OK) {
michael@0 1401 if (restore) {
michael@0 1402 PK11_RestoreROSession(slot,session_handle);
michael@0 1403 } else PK11_ExitSlotMonitor(slot);
michael@0 1404 PORT_SetError( PK11_MapError(crv) );
michael@0 1405 return NULL;
michael@0 1406 }
michael@0 1407 /* This locking code is dangerous and needs to be more thought
michael@0 1408 * out... the real problem is that we're holding the mutex open this long
michael@0 1409 */
michael@0 1410 if (haslock) { PK11_ExitSlotMonitor(slot); }
michael@0 1411
michael@0 1412 /* swap around the ID's for older PKCS #11 modules */
michael@0 1413 keyClass = PK11_ReadULongAttribute(slot,pubID,CKA_CLASS);
michael@0 1414 if (keyClass != CKO_PUBLIC_KEY) {
michael@0 1415 CK_OBJECT_HANDLE tmp = pubID;
michael@0 1416 pubID = privID;
michael@0 1417 privID = tmp;
michael@0 1418 }
michael@0 1419
michael@0 1420 *pubKey = PK11_ExtractPublicKey(slot, keyType, pubID);
michael@0 1421 if (*pubKey == NULL) {
michael@0 1422 if (restore) {
michael@0 1423 /* we may have to restore the mutex so it get's exited properly
michael@0 1424 * in RestoreROSession */
michael@0 1425 if (haslock) PK11_EnterSlotMonitor(slot);
michael@0 1426 PK11_RestoreROSession(slot,session_handle);
michael@0 1427 }
michael@0 1428 PK11_DestroyObject(slot,pubID);
michael@0 1429 PK11_DestroyObject(slot,privID);
michael@0 1430 return NULL;
michael@0 1431 }
michael@0 1432
michael@0 1433 /* set the ID to the public key so we can find it again */
michael@0 1434 cka_id = pk11_MakeIDFromPublicKey(*pubKey);
michael@0 1435 pubIsToken = (PRBool)PK11_HasAttributeSet(slot,pubID, CKA_TOKEN,PR_FALSE);
michael@0 1436
michael@0 1437 PK11_SETATTRS(&setTemplate, CKA_ID, cka_id->data, cka_id->len);
michael@0 1438
michael@0 1439 if (haslock) { PK11_EnterSlotMonitor(slot); }
michael@0 1440 crv = PK11_GETTAB(slot)->C_SetAttributeValue(session_handle, privID,
michael@0 1441 &setTemplate, 1);
michael@0 1442
michael@0 1443 if (crv == CKR_OK && pubIsToken) {
michael@0 1444 crv = PK11_GETTAB(slot)->C_SetAttributeValue(session_handle, pubID,
michael@0 1445 &setTemplate, 1);
michael@0 1446 }
michael@0 1447
michael@0 1448
michael@0 1449 if (restore) {
michael@0 1450 PK11_RestoreROSession(slot,session_handle);
michael@0 1451 } else {
michael@0 1452 PK11_ExitSlotMonitor(slot);
michael@0 1453 }
michael@0 1454 SECITEM_FreeItem(cka_id,PR_TRUE);
michael@0 1455
michael@0 1456
michael@0 1457 if (crv != CKR_OK) {
michael@0 1458 PK11_DestroyObject(slot,pubID);
michael@0 1459 PK11_DestroyObject(slot,privID);
michael@0 1460 PORT_SetError( PK11_MapError(crv) );
michael@0 1461 *pubKey = NULL;
michael@0 1462 return NULL;
michael@0 1463 }
michael@0 1464
michael@0 1465 privKey = PK11_MakePrivKey(slot,keyType,!token,privID,wincx);
michael@0 1466 if (privKey == NULL) {
michael@0 1467 SECKEY_DestroyPublicKey(*pubKey);
michael@0 1468 PK11_DestroyObject(slot,privID);
michael@0 1469 *pubKey = NULL;
michael@0 1470 return NULL;
michael@0 1471 }
michael@0 1472
michael@0 1473 return privKey;
michael@0 1474 }
michael@0 1475
michael@0 1476 SECKEYPrivateKey *
michael@0 1477 PK11_GenerateKeyPairWithFlags(PK11SlotInfo *slot,CK_MECHANISM_TYPE type,
michael@0 1478 void *param, SECKEYPublicKey **pubKey, PK11AttrFlags attrFlags, void *wincx)
michael@0 1479 {
michael@0 1480 return PK11_GenerateKeyPairWithOpFlags(slot,type,param,pubKey,attrFlags,
michael@0 1481 0, 0, wincx);
michael@0 1482 }
michael@0 1483
michael@0 1484 /*
michael@0 1485 * Use the token to generate a key pair.
michael@0 1486 */
michael@0 1487 SECKEYPrivateKey *
michael@0 1488 PK11_GenerateKeyPair(PK11SlotInfo *slot,CK_MECHANISM_TYPE type,
michael@0 1489 void *param, SECKEYPublicKey **pubKey, PRBool token,
michael@0 1490 PRBool sensitive, void *wincx)
michael@0 1491 {
michael@0 1492 PK11AttrFlags attrFlags = 0;
michael@0 1493
michael@0 1494 if (token) {
michael@0 1495 attrFlags |= PK11_ATTR_TOKEN;
michael@0 1496 } else {
michael@0 1497 attrFlags |= PK11_ATTR_SESSION;
michael@0 1498 }
michael@0 1499 if (sensitive) {
michael@0 1500 attrFlags |= (PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE);
michael@0 1501 } else {
michael@0 1502 attrFlags |= (PK11_ATTR_INSENSITIVE | PK11_ATTR_PUBLIC);
michael@0 1503 }
michael@0 1504 return PK11_GenerateKeyPairWithFlags(slot, type, param, pubKey,
michael@0 1505 attrFlags, wincx);
michael@0 1506 }
michael@0 1507
michael@0 1508 /* build a public KEA key from the public value */
michael@0 1509 SECKEYPublicKey *
michael@0 1510 PK11_MakeKEAPubKey(unsigned char *keyData,int length)
michael@0 1511 {
michael@0 1512 SECKEYPublicKey *pubk;
michael@0 1513 SECItem pkData;
michael@0 1514 SECStatus rv;
michael@0 1515 PLArenaPool *arena;
michael@0 1516
michael@0 1517 pkData.data = keyData;
michael@0 1518 pkData.len = length;
michael@0 1519
michael@0 1520 arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
michael@0 1521 if (arena == NULL)
michael@0 1522 return NULL;
michael@0 1523
michael@0 1524 pubk = (SECKEYPublicKey *) PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey));
michael@0 1525 if (pubk == NULL) {
michael@0 1526 PORT_FreeArena (arena, PR_FALSE);
michael@0 1527 return NULL;
michael@0 1528 }
michael@0 1529
michael@0 1530 pubk->arena = arena;
michael@0 1531 pubk->pkcs11Slot = 0;
michael@0 1532 pubk->pkcs11ID = CK_INVALID_HANDLE;
michael@0 1533 pubk->keyType = fortezzaKey;
michael@0 1534 rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.KEAKey, &pkData);
michael@0 1535 if (rv != SECSuccess) {
michael@0 1536 PORT_FreeArena (arena, PR_FALSE);
michael@0 1537 return NULL;
michael@0 1538 }
michael@0 1539 return pubk;
michael@0 1540 }
michael@0 1541
michael@0 1542 /*
michael@0 1543 * NOTE: This function doesn't return a SECKEYPrivateKey struct to represent
michael@0 1544 * the new private key object. If it were to create a session object that
michael@0 1545 * could later be looked up by its nickname, it would leak a SECKEYPrivateKey.
michael@0 1546 * So isPerm must be true.
michael@0 1547 */
michael@0 1548 SECStatus
michael@0 1549 PK11_ImportEncryptedPrivateKeyInfo(PK11SlotInfo *slot,
michael@0 1550 SECKEYEncryptedPrivateKeyInfo *epki, SECItem *pwitem,
michael@0 1551 SECItem *nickname, SECItem *publicValue, PRBool isPerm,
michael@0 1552 PRBool isPrivate, KeyType keyType,
michael@0 1553 unsigned int keyUsage, void *wincx)
michael@0 1554 {
michael@0 1555 if (!isPerm) {
michael@0 1556 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 1557 return SECFailure;
michael@0 1558 }
michael@0 1559 return PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(slot, epki,
michael@0 1560 pwitem, nickname, publicValue, isPerm, isPrivate, keyType,
michael@0 1561 keyUsage, NULL, wincx);
michael@0 1562 }
michael@0 1563
michael@0 1564 SECStatus
michael@0 1565 PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot,
michael@0 1566 SECKEYEncryptedPrivateKeyInfo *epki, SECItem *pwitem,
michael@0 1567 SECItem *nickname, SECItem *publicValue, PRBool isPerm,
michael@0 1568 PRBool isPrivate, KeyType keyType,
michael@0 1569 unsigned int keyUsage, SECKEYPrivateKey **privk,
michael@0 1570 void *wincx)
michael@0 1571 {
michael@0 1572 CK_MECHANISM_TYPE pbeMechType;
michael@0 1573 SECItem *crypto_param = NULL;
michael@0 1574 PK11SymKey *key = NULL;
michael@0 1575 SECStatus rv = SECSuccess;
michael@0 1576 CK_MECHANISM_TYPE cryptoMechType;
michael@0 1577 SECKEYPrivateKey *privKey = NULL;
michael@0 1578 PRBool faulty3DES = PR_FALSE;
michael@0 1579 int usageCount = 0;
michael@0 1580 CK_KEY_TYPE key_type;
michael@0 1581 CK_ATTRIBUTE_TYPE *usage = NULL;
michael@0 1582 CK_ATTRIBUTE_TYPE rsaUsage[] = {
michael@0 1583 CKA_UNWRAP, CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER };
michael@0 1584 CK_ATTRIBUTE_TYPE dsaUsage[] = { CKA_SIGN };
michael@0 1585 CK_ATTRIBUTE_TYPE dhUsage[] = { CKA_DERIVE };
michael@0 1586 CK_ATTRIBUTE_TYPE ecUsage[] = { CKA_SIGN, CKA_DERIVE };
michael@0 1587 if((epki == NULL) || (pwitem == NULL))
michael@0 1588 return SECFailure;
michael@0 1589
michael@0 1590 pbeMechType = PK11_AlgtagToMechanism(SECOID_FindOIDTag(
michael@0 1591 &epki->algorithm.algorithm));
michael@0 1592
michael@0 1593 switch (keyType) {
michael@0 1594 default:
michael@0 1595 case rsaKey:
michael@0 1596 key_type = CKK_RSA;
michael@0 1597 switch (keyUsage & (KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE)) {
michael@0 1598 case KU_KEY_ENCIPHERMENT:
michael@0 1599 usage = rsaUsage;
michael@0 1600 usageCount = 2;
michael@0 1601 break;
michael@0 1602 case KU_DIGITAL_SIGNATURE:
michael@0 1603 usage = &rsaUsage[2];
michael@0 1604 usageCount = 2;
michael@0 1605 break;
michael@0 1606 case KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE:
michael@0 1607 case 0: /* default to everything */
michael@0 1608 usage = rsaUsage;
michael@0 1609 usageCount = 4;
michael@0 1610 break;
michael@0 1611 }
michael@0 1612 break;
michael@0 1613 case dhKey:
michael@0 1614 key_type = CKK_DH;
michael@0 1615 usage = dhUsage;
michael@0 1616 usageCount = sizeof(dhUsage)/sizeof(dhUsage[0]);
michael@0 1617 break;
michael@0 1618 case dsaKey:
michael@0 1619 key_type = CKK_DSA;
michael@0 1620 usage = dsaUsage;
michael@0 1621 usageCount = sizeof(dsaUsage)/sizeof(dsaUsage[0]);
michael@0 1622 break;
michael@0 1623 case ecKey:
michael@0 1624 key_type = CKK_EC;
michael@0 1625 switch (keyUsage & (KU_DIGITAL_SIGNATURE|KU_KEY_AGREEMENT)) {
michael@0 1626 case KU_DIGITAL_SIGNATURE:
michael@0 1627 usage = ecUsage;
michael@0 1628 usageCount = 1;
michael@0 1629 break;
michael@0 1630 case KU_KEY_AGREEMENT:
michael@0 1631 usage = &ecUsage[1];
michael@0 1632 usageCount = 1;
michael@0 1633 break;
michael@0 1634 case KU_DIGITAL_SIGNATURE|KU_KEY_AGREEMENT:
michael@0 1635 default: /* default to everything */
michael@0 1636 usage = ecUsage;
michael@0 1637 usageCount = 2;
michael@0 1638 break;
michael@0 1639 }
michael@0 1640 break;
michael@0 1641 }
michael@0 1642
michael@0 1643 try_faulty_3des:
michael@0 1644
michael@0 1645 key = PK11_PBEKeyGen(slot, &epki->algorithm, pwitem, faulty3DES, wincx);
michael@0 1646 if (key == NULL) {
michael@0 1647 rv = SECFailure;
michael@0 1648 goto done;
michael@0 1649 }
michael@0 1650 cryptoMechType = pk11_GetPBECryptoMechanism(&epki->algorithm,
michael@0 1651 &crypto_param, pwitem, faulty3DES);
michael@0 1652 if (cryptoMechType == CKM_INVALID_MECHANISM) {
michael@0 1653 rv = SECFailure;
michael@0 1654 goto done;
michael@0 1655 }
michael@0 1656
michael@0 1657
michael@0 1658 cryptoMechType = PK11_GetPadMechanism(cryptoMechType);
michael@0 1659
michael@0 1660 PORT_Assert(usage != NULL);
michael@0 1661 PORT_Assert(usageCount != 0);
michael@0 1662 privKey = PK11_UnwrapPrivKey(slot, key, cryptoMechType,
michael@0 1663 crypto_param, &epki->encryptedData,
michael@0 1664 nickname, publicValue, isPerm, isPrivate,
michael@0 1665 key_type, usage, usageCount, wincx);
michael@0 1666 if(privKey) {
michael@0 1667 if (privk) {
michael@0 1668 *privk = privKey;
michael@0 1669 } else {
michael@0 1670 SECKEY_DestroyPrivateKey(privKey);
michael@0 1671 }
michael@0 1672 privKey = NULL;
michael@0 1673 rv = SECSuccess;
michael@0 1674 goto done;
michael@0 1675 }
michael@0 1676
michael@0 1677 /* if we are unable to import the key and the pbeMechType is
michael@0 1678 * CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC, then it is possible that
michael@0 1679 * the encrypted blob was created with a buggy key generation method
michael@0 1680 * which is described in the PKCS 12 implementation notes. So we
michael@0 1681 * need to try importing via that method.
michael@0 1682 */
michael@0 1683 if((pbeMechType == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC) && (!faulty3DES)) {
michael@0 1684 /* clean up after ourselves before redoing the key generation. */
michael@0 1685
michael@0 1686 PK11_FreeSymKey(key);
michael@0 1687 key = NULL;
michael@0 1688
michael@0 1689 if(crypto_param) {
michael@0 1690 SECITEM_ZfreeItem(crypto_param, PR_TRUE);
michael@0 1691 crypto_param = NULL;
michael@0 1692 }
michael@0 1693
michael@0 1694 faulty3DES = PR_TRUE;
michael@0 1695 goto try_faulty_3des;
michael@0 1696 }
michael@0 1697
michael@0 1698 /* key import really did fail */
michael@0 1699 rv = SECFailure;
michael@0 1700
michael@0 1701 done:
michael@0 1702 if(crypto_param != NULL) {
michael@0 1703 SECITEM_ZfreeItem(crypto_param, PR_TRUE);
michael@0 1704 }
michael@0 1705
michael@0 1706 if(key != NULL) {
michael@0 1707 PK11_FreeSymKey(key);
michael@0 1708 }
michael@0 1709
michael@0 1710 return rv;
michael@0 1711 }
michael@0 1712
michael@0 1713 SECKEYPrivateKeyInfo *
michael@0 1714 PK11_ExportPrivateKeyInfo(CERTCertificate *cert, void *wincx)
michael@0 1715 {
michael@0 1716 SECKEYPrivateKeyInfo *pki = NULL;
michael@0 1717 SECKEYPrivateKey *pk = PK11_FindKeyByAnyCert(cert, wincx);
michael@0 1718 if (pk != NULL) {
michael@0 1719 pki = PK11_ExportPrivKeyInfo(pk, wincx);
michael@0 1720 SECKEY_DestroyPrivateKey(pk);
michael@0 1721 }
michael@0 1722 return pki;
michael@0 1723 }
michael@0 1724
michael@0 1725 SECKEYEncryptedPrivateKeyInfo *
michael@0 1726 PK11_ExportEncryptedPrivKeyInfo(
michael@0 1727 PK11SlotInfo *slot, /* optional, encrypt key in this slot */
michael@0 1728 SECOidTag algTag, /* encrypt key with this algorithm */
michael@0 1729 SECItem *pwitem, /* password for PBE encryption */
michael@0 1730 SECKEYPrivateKey *pk, /* encrypt this private key */
michael@0 1731 int iteration, /* interations for PBE alg */
michael@0 1732 void *wincx) /* context for password callback ? */
michael@0 1733 {
michael@0 1734 SECKEYEncryptedPrivateKeyInfo *epki = NULL;
michael@0 1735 PLArenaPool *arena = NULL;
michael@0 1736 SECAlgorithmID *algid;
michael@0 1737 SECOidTag pbeAlgTag = SEC_OID_UNKNOWN;
michael@0 1738 SECItem *crypto_param = NULL;
michael@0 1739 PK11SymKey *key = NULL;
michael@0 1740 SECKEYPrivateKey *tmpPK = NULL;
michael@0 1741 SECStatus rv = SECSuccess;
michael@0 1742 CK_RV crv;
michael@0 1743 CK_ULONG encBufLen;
michael@0 1744 CK_MECHANISM_TYPE pbeMechType;
michael@0 1745 CK_MECHANISM_TYPE cryptoMechType;
michael@0 1746 CK_MECHANISM cryptoMech;
michael@0 1747
michael@0 1748 if (!pwitem || !pk) {
michael@0 1749 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 1750 return NULL;
michael@0 1751 }
michael@0 1752
michael@0 1753 algid = sec_pkcs5CreateAlgorithmID(algTag, SEC_OID_UNKNOWN, SEC_OID_UNKNOWN,
michael@0 1754 &pbeAlgTag, 0, NULL, iteration);
michael@0 1755 if (algid == NULL) {
michael@0 1756 return NULL;
michael@0 1757 }
michael@0 1758
michael@0 1759 arena = PORT_NewArena(2048);
michael@0 1760 if (arena)
michael@0 1761 epki = PORT_ArenaZNew(arena, SECKEYEncryptedPrivateKeyInfo);
michael@0 1762 if(epki == NULL) {
michael@0 1763 rv = SECFailure;
michael@0 1764 goto loser;
michael@0 1765 }
michael@0 1766 epki->arena = arena;
michael@0 1767
michael@0 1768
michael@0 1769 /* if we didn't specify a slot, use the slot the private key was in */
michael@0 1770 if (!slot) {
michael@0 1771 slot = pk->pkcs11Slot;
michael@0 1772 }
michael@0 1773
michael@0 1774 /* if we specified a different slot, and the private key slot can do the
michael@0 1775 * pbe key gen, generate the key in the private key slot so we don't have
michael@0 1776 * to move it later */
michael@0 1777 pbeMechType = PK11_AlgtagToMechanism(pbeAlgTag);
michael@0 1778 if (slot != pk->pkcs11Slot) {
michael@0 1779 if (PK11_DoesMechanism(pk->pkcs11Slot,pbeMechType)) {
michael@0 1780 slot = pk->pkcs11Slot;
michael@0 1781 }
michael@0 1782 }
michael@0 1783 key = PK11_PBEKeyGen(slot, algid, pwitem, PR_FALSE, wincx);
michael@0 1784 if (key == NULL) {
michael@0 1785 rv = SECFailure;
michael@0 1786 goto loser;
michael@0 1787 }
michael@0 1788
michael@0 1789 cryptoMechType = PK11_GetPBECryptoMechanism(algid, &crypto_param, pwitem);
michael@0 1790 if (cryptoMechType == CKM_INVALID_MECHANISM) {
michael@0 1791 rv = SECFailure;
michael@0 1792 goto loser;
michael@0 1793 }
michael@0 1794
michael@0 1795 cryptoMech.mechanism = PK11_GetPadMechanism(cryptoMechType);
michael@0 1796 cryptoMech.pParameter = crypto_param ? crypto_param->data : NULL;
michael@0 1797 cryptoMech.ulParameterLen = crypto_param ? crypto_param->len : 0;
michael@0 1798
michael@0 1799 /* If the key isn't in the private key slot, move it */
michael@0 1800 if (key->slot != pk->pkcs11Slot) {
michael@0 1801 PK11SymKey *newkey = pk11_CopyToSlot(pk->pkcs11Slot,
michael@0 1802 key->type, CKA_WRAP, key);
michael@0 1803 if (newkey == NULL) {
michael@0 1804 /* couldn't import the wrapping key, try exporting the
michael@0 1805 * private key */
michael@0 1806 tmpPK = pk11_loadPrivKey(key->slot, pk, NULL, PR_FALSE, PR_TRUE);
michael@0 1807 if (tmpPK == NULL) {
michael@0 1808 rv = SECFailure;
michael@0 1809 goto loser;
michael@0 1810 }
michael@0 1811 pk = tmpPK;
michael@0 1812 } else {
michael@0 1813 /* free the old key and use the new key */
michael@0 1814 PK11_FreeSymKey(key);
michael@0 1815 key = newkey;
michael@0 1816 }
michael@0 1817 }
michael@0 1818
michael@0 1819 /* we are extracting an encrypted privateKey structure.
michael@0 1820 * which needs to be freed along with the buffer into which it is
michael@0 1821 * returned. eventually, we should retrieve an encrypted key using
michael@0 1822 * pkcs8/pkcs5.
michael@0 1823 */
michael@0 1824 encBufLen = 0;
michael@0 1825 PK11_EnterSlotMonitor(pk->pkcs11Slot);
michael@0 1826 crv = PK11_GETTAB(pk->pkcs11Slot)->C_WrapKey(pk->pkcs11Slot->session,
michael@0 1827 &cryptoMech, key->objectID, pk->pkcs11ID, NULL,
michael@0 1828 &encBufLen);
michael@0 1829 PK11_ExitSlotMonitor(pk->pkcs11Slot);
michael@0 1830 if (crv != CKR_OK) {
michael@0 1831 rv = SECFailure;
michael@0 1832 goto loser;
michael@0 1833 }
michael@0 1834 epki->encryptedData.data = PORT_ArenaAlloc(arena, encBufLen);
michael@0 1835 if (!epki->encryptedData.data) {
michael@0 1836 rv = SECFailure;
michael@0 1837 goto loser;
michael@0 1838 }
michael@0 1839 PK11_EnterSlotMonitor(pk->pkcs11Slot);
michael@0 1840 crv = PK11_GETTAB(pk->pkcs11Slot)->C_WrapKey(pk->pkcs11Slot->session,
michael@0 1841 &cryptoMech, key->objectID, pk->pkcs11ID,
michael@0 1842 epki->encryptedData.data, &encBufLen);
michael@0 1843 PK11_ExitSlotMonitor(pk->pkcs11Slot);
michael@0 1844 epki->encryptedData.len = (unsigned int) encBufLen;
michael@0 1845 if(crv != CKR_OK) {
michael@0 1846 rv = SECFailure;
michael@0 1847 goto loser;
michael@0 1848 }
michael@0 1849
michael@0 1850 if(!epki->encryptedData.len) {
michael@0 1851 rv = SECFailure;
michael@0 1852 goto loser;
michael@0 1853 }
michael@0 1854
michael@0 1855 rv = SECOID_CopyAlgorithmID(arena, &epki->algorithm, algid);
michael@0 1856
michael@0 1857 loser:
michael@0 1858 if(crypto_param != NULL) {
michael@0 1859 SECITEM_ZfreeItem(crypto_param, PR_TRUE);
michael@0 1860 crypto_param = NULL;
michael@0 1861 }
michael@0 1862
michael@0 1863 if(key != NULL) {
michael@0 1864 PK11_FreeSymKey(key);
michael@0 1865 }
michael@0 1866 if (tmpPK != NULL) {
michael@0 1867 SECKEY_DestroyPrivateKey(tmpPK);
michael@0 1868 }
michael@0 1869 SECOID_DestroyAlgorithmID(algid, PR_TRUE);
michael@0 1870
michael@0 1871 if(rv == SECFailure) {
michael@0 1872 if(arena != NULL) {
michael@0 1873 PORT_FreeArena(arena, PR_TRUE);
michael@0 1874 }
michael@0 1875 epki = NULL;
michael@0 1876 }
michael@0 1877
michael@0 1878 return epki;
michael@0 1879 }
michael@0 1880
michael@0 1881 SECKEYEncryptedPrivateKeyInfo *
michael@0 1882 PK11_ExportEncryptedPrivateKeyInfo(
michael@0 1883 PK11SlotInfo *slot, /* optional, encrypt key in this slot */
michael@0 1884 SECOidTag algTag, /* encrypt key with this algorithm */
michael@0 1885 SECItem *pwitem, /* password for PBE encryption */
michael@0 1886 CERTCertificate *cert, /* wrap priv key for this user cert */
michael@0 1887 int iteration, /* interations for PBE alg */
michael@0 1888 void *wincx) /* context for password callback ? */
michael@0 1889 {
michael@0 1890 SECKEYEncryptedPrivateKeyInfo *epki = NULL;
michael@0 1891 SECKEYPrivateKey *pk = PK11_FindKeyByAnyCert(cert, wincx);
michael@0 1892 if (pk != NULL) {
michael@0 1893 epki = PK11_ExportEncryptedPrivKeyInfo(slot, algTag, pwitem, pk,
michael@0 1894 iteration, wincx);
michael@0 1895 SECKEY_DestroyPrivateKey(pk);
michael@0 1896 }
michael@0 1897 return epki;
michael@0 1898 }
michael@0 1899
michael@0 1900 SECItem*
michael@0 1901 PK11_DEREncodePublicKey(const SECKEYPublicKey *pubk)
michael@0 1902 {
michael@0 1903 return SECKEY_EncodeDERSubjectPublicKeyInfo(pubk);
michael@0 1904 }
michael@0 1905
michael@0 1906 char *
michael@0 1907 PK11_GetPrivateKeyNickname(SECKEYPrivateKey *privKey)
michael@0 1908 {
michael@0 1909 return PK11_GetObjectNickname(privKey->pkcs11Slot,privKey->pkcs11ID);
michael@0 1910 }
michael@0 1911
michael@0 1912 char *
michael@0 1913 PK11_GetPublicKeyNickname(SECKEYPublicKey *pubKey)
michael@0 1914 {
michael@0 1915 return PK11_GetObjectNickname(pubKey->pkcs11Slot,pubKey->pkcs11ID);
michael@0 1916 }
michael@0 1917
michael@0 1918 SECStatus
michael@0 1919 PK11_SetPrivateKeyNickname(SECKEYPrivateKey *privKey, const char *nickname)
michael@0 1920 {
michael@0 1921 return PK11_SetObjectNickname(privKey->pkcs11Slot,
michael@0 1922 privKey->pkcs11ID,nickname);
michael@0 1923 }
michael@0 1924
michael@0 1925 SECStatus
michael@0 1926 PK11_SetPublicKeyNickname(SECKEYPublicKey *pubKey, const char *nickname)
michael@0 1927 {
michael@0 1928 return PK11_SetObjectNickname(pubKey->pkcs11Slot,
michael@0 1929 pubKey->pkcs11ID,nickname);
michael@0 1930 }
michael@0 1931
michael@0 1932 SECKEYPQGParams *
michael@0 1933 PK11_GetPQGParamsFromPrivateKey(SECKEYPrivateKey *privKey)
michael@0 1934 {
michael@0 1935 CK_ATTRIBUTE pTemplate[] = {
michael@0 1936 { CKA_PRIME, NULL, 0 },
michael@0 1937 { CKA_SUBPRIME, NULL, 0 },
michael@0 1938 { CKA_BASE, NULL, 0 },
michael@0 1939 };
michael@0 1940 int pTemplateLen = sizeof(pTemplate)/sizeof(pTemplate[0]);
michael@0 1941 PLArenaPool *arena = NULL;
michael@0 1942 SECKEYPQGParams *params;
michael@0 1943 CK_RV crv;
michael@0 1944
michael@0 1945
michael@0 1946 arena = PORT_NewArena(2048);
michael@0 1947 if (arena == NULL) {
michael@0 1948 goto loser;
michael@0 1949 }
michael@0 1950 params=(SECKEYPQGParams *)PORT_ArenaZAlloc(arena,sizeof(SECKEYPQGParams));
michael@0 1951 if (params == NULL) {
michael@0 1952 goto loser;
michael@0 1953 }
michael@0 1954
michael@0 1955 crv = PK11_GetAttributes(arena, privKey->pkcs11Slot, privKey->pkcs11ID,
michael@0 1956 pTemplate, pTemplateLen);
michael@0 1957 if (crv != CKR_OK) {
michael@0 1958 PORT_SetError( PK11_MapError(crv) );
michael@0 1959 goto loser;
michael@0 1960 }
michael@0 1961
michael@0 1962 params->arena = arena;
michael@0 1963 params->prime.data = pTemplate[0].pValue;
michael@0 1964 params->prime.len = pTemplate[0].ulValueLen;
michael@0 1965 params->subPrime.data = pTemplate[1].pValue;
michael@0 1966 params->subPrime.len = pTemplate[1].ulValueLen;
michael@0 1967 params->base.data = pTemplate[2].pValue;
michael@0 1968 params->base.len = pTemplate[2].ulValueLen;
michael@0 1969
michael@0 1970 return params;
michael@0 1971
michael@0 1972 loser:
michael@0 1973 if (arena != NULL) {
michael@0 1974 PORT_FreeArena(arena,PR_FALSE);
michael@0 1975 }
michael@0 1976 return NULL;
michael@0 1977 }
michael@0 1978
michael@0 1979 SECKEYPrivateKey*
michael@0 1980 PK11_CopyTokenPrivKeyToSessionPrivKey(PK11SlotInfo *destSlot,
michael@0 1981 SECKEYPrivateKey *privKey)
michael@0 1982 {
michael@0 1983 CK_RV crv;
michael@0 1984 CK_OBJECT_HANDLE newKeyID;
michael@0 1985
michael@0 1986 static const CK_BBOOL ckfalse = CK_FALSE;
michael@0 1987 static const CK_ATTRIBUTE template[1] = {
michael@0 1988 { CKA_TOKEN, (CK_BBOOL *)&ckfalse, sizeof ckfalse }
michael@0 1989 };
michael@0 1990
michael@0 1991 if (destSlot && destSlot != privKey->pkcs11Slot) {
michael@0 1992 SECKEYPrivateKey *newKey =
michael@0 1993 pk11_loadPrivKey(destSlot,
michael@0 1994 privKey,
michael@0 1995 NULL, /* pubKey */
michael@0 1996 PR_FALSE, /* token */
michael@0 1997 PR_FALSE);/* sensitive */
michael@0 1998 if (newKey)
michael@0 1999 return newKey;
michael@0 2000 }
michael@0 2001 destSlot = privKey->pkcs11Slot;
michael@0 2002 PK11_Authenticate(destSlot, PR_TRUE, privKey->wincx);
michael@0 2003 PK11_EnterSlotMonitor(destSlot);
michael@0 2004 crv = PK11_GETTAB(destSlot)->C_CopyObject( destSlot->session,
michael@0 2005 privKey->pkcs11ID,
michael@0 2006 (CK_ATTRIBUTE *)template,
michael@0 2007 1, &newKeyID);
michael@0 2008 PK11_ExitSlotMonitor(destSlot);
michael@0 2009
michael@0 2010 if (crv != CKR_OK) {
michael@0 2011 PORT_SetError( PK11_MapError(crv) );
michael@0 2012 return NULL;
michael@0 2013 }
michael@0 2014
michael@0 2015 return PK11_MakePrivKey(destSlot, privKey->keyType, PR_TRUE /*isTemp*/,
michael@0 2016 newKeyID, privKey->wincx);
michael@0 2017 }
michael@0 2018
michael@0 2019 SECKEYPrivateKey*
michael@0 2020 PK11_ConvertSessionPrivKeyToTokenPrivKey(SECKEYPrivateKey *privk, void* wincx)
michael@0 2021 {
michael@0 2022 PK11SlotInfo* slot = privk->pkcs11Slot;
michael@0 2023 CK_ATTRIBUTE template[1];
michael@0 2024 CK_ATTRIBUTE *attrs = template;
michael@0 2025 CK_BBOOL cktrue = CK_TRUE;
michael@0 2026 CK_RV crv;
michael@0 2027 CK_OBJECT_HANDLE newKeyID;
michael@0 2028 CK_SESSION_HANDLE rwsession;
michael@0 2029
michael@0 2030 PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); attrs++;
michael@0 2031
michael@0 2032 PK11_Authenticate(slot, PR_TRUE, wincx);
michael@0 2033 rwsession = PK11_GetRWSession(slot);
michael@0 2034 if (rwsession == CK_INVALID_SESSION) {
michael@0 2035 PORT_SetError(SEC_ERROR_BAD_DATA);
michael@0 2036 return NULL;
michael@0 2037 }
michael@0 2038 crv = PK11_GETTAB(slot)->C_CopyObject(rwsession, privk->pkcs11ID,
michael@0 2039 template, 1, &newKeyID);
michael@0 2040 PK11_RestoreROSession(slot, rwsession);
michael@0 2041
michael@0 2042 if (crv != CKR_OK) {
michael@0 2043 PORT_SetError( PK11_MapError(crv) );
michael@0 2044 return NULL;
michael@0 2045 }
michael@0 2046
michael@0 2047 return PK11_MakePrivKey(slot, nullKey /*KeyType*/, PR_FALSE /*isTemp*/,
michael@0 2048 newKeyID, NULL /*wincx*/);
michael@0 2049 }
michael@0 2050
michael@0 2051 /*
michael@0 2052 * destroy a private key if there are no matching certs.
michael@0 2053 * this function also frees the privKey structure.
michael@0 2054 */
michael@0 2055 SECStatus
michael@0 2056 PK11_DeleteTokenPrivateKey(SECKEYPrivateKey *privKey, PRBool force)
michael@0 2057 {
michael@0 2058 CERTCertificate *cert=PK11_GetCertFromPrivateKey(privKey);
michael@0 2059 SECStatus rv = SECWouldBlock;
michael@0 2060
michael@0 2061 if (!cert || force) {
michael@0 2062 /* now, then it's safe for the key to go away */
michael@0 2063 rv = PK11_DestroyTokenObject(privKey->pkcs11Slot,privKey->pkcs11ID);
michael@0 2064 }
michael@0 2065 if (cert) {
michael@0 2066 CERT_DestroyCertificate(cert);
michael@0 2067 }
michael@0 2068 SECKEY_DestroyPrivateKey(privKey);
michael@0 2069 return rv;
michael@0 2070 }
michael@0 2071
michael@0 2072 /*
michael@0 2073 * destroy a private key if there are no matching certs.
michael@0 2074 * this function also frees the privKey structure.
michael@0 2075 */
michael@0 2076 SECStatus
michael@0 2077 PK11_DeleteTokenPublicKey(SECKEYPublicKey *pubKey)
michael@0 2078 {
michael@0 2079 /* now, then it's safe for the key to go away */
michael@0 2080 if (pubKey->pkcs11Slot == NULL) {
michael@0 2081 return SECFailure;
michael@0 2082 }
michael@0 2083 PK11_DestroyTokenObject(pubKey->pkcs11Slot,pubKey->pkcs11ID);
michael@0 2084 SECKEY_DestroyPublicKey(pubKey);
michael@0 2085 return SECSuccess;
michael@0 2086 }
michael@0 2087
michael@0 2088 /*
michael@0 2089 * key call back structure.
michael@0 2090 */
michael@0 2091 typedef struct pk11KeyCallbackStr {
michael@0 2092 SECStatus (* callback)(SECKEYPrivateKey *,void *);
michael@0 2093 void *callbackArg;
michael@0 2094 void *wincx;
michael@0 2095 } pk11KeyCallback;
michael@0 2096
michael@0 2097 /*
michael@0 2098 * callback to map Object Handles to Private Keys;
michael@0 2099 */
michael@0 2100 SECStatus
michael@0 2101 pk11_DoKeys(PK11SlotInfo *slot, CK_OBJECT_HANDLE keyHandle, void *arg)
michael@0 2102 {
michael@0 2103 SECStatus rv = SECSuccess;
michael@0 2104 SECKEYPrivateKey *privKey;
michael@0 2105 pk11KeyCallback *keycb = (pk11KeyCallback *) arg;
michael@0 2106 if (!arg) {
michael@0 2107 return SECFailure;
michael@0 2108 }
michael@0 2109
michael@0 2110 privKey = PK11_MakePrivKey(slot,nullKey,PR_TRUE,keyHandle,keycb->wincx);
michael@0 2111
michael@0 2112 if (privKey == NULL) {
michael@0 2113 return SECFailure;
michael@0 2114 }
michael@0 2115
michael@0 2116 if (keycb->callback) {
michael@0 2117 rv = (*keycb->callback)(privKey,keycb->callbackArg);
michael@0 2118 }
michael@0 2119
michael@0 2120 SECKEY_DestroyPrivateKey(privKey);
michael@0 2121 return rv;
michael@0 2122 }
michael@0 2123
michael@0 2124 /***********************************************************************
michael@0 2125 * PK11_TraversePrivateKeysInSlot
michael@0 2126 *
michael@0 2127 * Traverses all the private keys on a slot.
michael@0 2128 *
michael@0 2129 * INPUTS
michael@0 2130 * slot
michael@0 2131 * The PKCS #11 slot whose private keys you want to traverse.
michael@0 2132 * callback
michael@0 2133 * A callback function that will be called for each key.
michael@0 2134 * arg
michael@0 2135 * An argument that will be passed to the callback function.
michael@0 2136 */
michael@0 2137 SECStatus
michael@0 2138 PK11_TraversePrivateKeysInSlot( PK11SlotInfo *slot,
michael@0 2139 SECStatus(* callback)(SECKEYPrivateKey*, void*), void *arg)
michael@0 2140 {
michael@0 2141 pk11KeyCallback perKeyCB;
michael@0 2142 pk11TraverseSlot perObjectCB;
michael@0 2143 CK_OBJECT_CLASS privkClass = CKO_PRIVATE_KEY;
michael@0 2144 CK_BBOOL ckTrue = CK_TRUE;
michael@0 2145 CK_ATTRIBUTE theTemplate[2];
michael@0 2146 int templateSize = 2;
michael@0 2147
michael@0 2148 theTemplate[0].type = CKA_CLASS;
michael@0 2149 theTemplate[0].pValue = &privkClass;
michael@0 2150 theTemplate[0].ulValueLen = sizeof(privkClass);
michael@0 2151 theTemplate[1].type = CKA_TOKEN;
michael@0 2152 theTemplate[1].pValue = &ckTrue;
michael@0 2153 theTemplate[1].ulValueLen = sizeof(ckTrue);
michael@0 2154
michael@0 2155 if(slot==NULL) {
michael@0 2156 return SECSuccess;
michael@0 2157 }
michael@0 2158
michael@0 2159 perObjectCB.callback = pk11_DoKeys;
michael@0 2160 perObjectCB.callbackArg = &perKeyCB;
michael@0 2161 perObjectCB.findTemplate = theTemplate;
michael@0 2162 perObjectCB.templateCount = templateSize;
michael@0 2163 perKeyCB.callback = callback;
michael@0 2164 perKeyCB.callbackArg = arg;
michael@0 2165 perKeyCB.wincx = NULL;
michael@0 2166
michael@0 2167 return PK11_TraverseSlot(slot, &perObjectCB);
michael@0 2168 }
michael@0 2169
michael@0 2170 /*
michael@0 2171 * return the private key with the given ID
michael@0 2172 */
michael@0 2173 CK_OBJECT_HANDLE
michael@0 2174 pk11_FindPrivateKeyFromCertID(PK11SlotInfo *slot, SECItem *keyID)
michael@0 2175 {
michael@0 2176 CK_OBJECT_CLASS privKey = CKO_PRIVATE_KEY;
michael@0 2177 CK_ATTRIBUTE theTemplate[] = {
michael@0 2178 { CKA_ID, NULL, 0 },
michael@0 2179 { CKA_CLASS, NULL, 0 },
michael@0 2180 };
michael@0 2181 /* if you change the array, change the variable below as well */
michael@0 2182 int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
michael@0 2183 CK_ATTRIBUTE *attrs = theTemplate;
michael@0 2184
michael@0 2185 PK11_SETATTRS(attrs, CKA_ID, keyID->data, keyID->len ); attrs++;
michael@0 2186 PK11_SETATTRS(attrs, CKA_CLASS, &privKey, sizeof(privKey));
michael@0 2187
michael@0 2188 return pk11_FindObjectByTemplate(slot,theTemplate,tsize);
michael@0 2189 }
michael@0 2190
michael@0 2191
michael@0 2192 SECKEYPrivateKey *
michael@0 2193 PK11_FindKeyByKeyID(PK11SlotInfo *slot, SECItem *keyID, void *wincx)
michael@0 2194 {
michael@0 2195 CK_OBJECT_HANDLE keyHandle;
michael@0 2196 SECKEYPrivateKey *privKey;
michael@0 2197
michael@0 2198 keyHandle = pk11_FindPrivateKeyFromCertID(slot, keyID);
michael@0 2199 if (keyHandle == CK_INVALID_HANDLE) {
michael@0 2200 return NULL;
michael@0 2201 }
michael@0 2202 privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx);
michael@0 2203 return privKey;
michael@0 2204 }
michael@0 2205
michael@0 2206 /*
michael@0 2207 * Generate a CKA_ID from the relevant public key data. The CKA_ID is generated
michael@0 2208 * from the pubKeyData by SHA1_Hashing it to produce a smaller CKA_ID (to make
michael@0 2209 * smart cards happy.
michael@0 2210 */
michael@0 2211 SECItem *
michael@0 2212 PK11_MakeIDFromPubKey(SECItem *pubKeyData)
michael@0 2213 {
michael@0 2214 PK11Context *context;
michael@0 2215 SECItem *certCKA_ID;
michael@0 2216 SECStatus rv;
michael@0 2217
michael@0 2218 if (pubKeyData->len <= SHA1_LENGTH) {
michael@0 2219 /* probably an already hashed value. The strongest known public
michael@0 2220 * key values <= 160 bits would be less than 40 bit symetric in
michael@0 2221 * strength. Don't hash them, just return the value. There are
michael@0 2222 * none at the time of this writing supported by previous versions
michael@0 2223 * of NSS, so change is binary compatible safe */
michael@0 2224 return SECITEM_DupItem(pubKeyData);
michael@0 2225 }
michael@0 2226
michael@0 2227 context = PK11_CreateDigestContext(SEC_OID_SHA1);
michael@0 2228 if (context == NULL) {
michael@0 2229 return NULL;
michael@0 2230 }
michael@0 2231
michael@0 2232 rv = PK11_DigestBegin(context);
michael@0 2233 if (rv == SECSuccess) {
michael@0 2234 rv = PK11_DigestOp(context,pubKeyData->data,pubKeyData->len);
michael@0 2235 }
michael@0 2236 if (rv != SECSuccess) {
michael@0 2237 PK11_DestroyContext(context,PR_TRUE);
michael@0 2238 return NULL;
michael@0 2239 }
michael@0 2240
michael@0 2241 certCKA_ID = (SECItem *)PORT_Alloc(sizeof(SECItem));
michael@0 2242 if (certCKA_ID == NULL) {
michael@0 2243 PK11_DestroyContext(context,PR_TRUE);
michael@0 2244 return NULL;
michael@0 2245 }
michael@0 2246
michael@0 2247 certCKA_ID->len = SHA1_LENGTH;
michael@0 2248 certCKA_ID->data = (unsigned char*)PORT_Alloc(certCKA_ID->len);
michael@0 2249 if (certCKA_ID->data == NULL) {
michael@0 2250 PORT_Free(certCKA_ID);
michael@0 2251 PK11_DestroyContext(context,PR_TRUE);
michael@0 2252 return NULL;
michael@0 2253 }
michael@0 2254
michael@0 2255 rv = PK11_DigestFinal(context,certCKA_ID->data,&certCKA_ID->len,
michael@0 2256 SHA1_LENGTH);
michael@0 2257 PK11_DestroyContext(context,PR_TRUE);
michael@0 2258 if (rv != SECSuccess) {
michael@0 2259 SECITEM_FreeItem(certCKA_ID,PR_TRUE);
michael@0 2260 return NULL;
michael@0 2261 }
michael@0 2262
michael@0 2263 return certCKA_ID;
michael@0 2264 }
michael@0 2265
michael@0 2266 /* Looking for PK11_GetKeyIDFromPrivateKey?
michael@0 2267 * Call PK11_GetLowLevelKeyIDForPrivateKey instead.
michael@0 2268 */
michael@0 2269
michael@0 2270
michael@0 2271 SECItem *
michael@0 2272 PK11_GetLowLevelKeyIDForPrivateKey(SECKEYPrivateKey *privKey)
michael@0 2273 {
michael@0 2274 return pk11_GetLowLevelKeyFromHandle(privKey->pkcs11Slot,privKey->pkcs11ID);
michael@0 2275 }
michael@0 2276
michael@0 2277 static SECStatus
michael@0 2278 privateKeyListCallback(SECKEYPrivateKey *key, void *arg)
michael@0 2279 {
michael@0 2280 SECKEYPrivateKeyList *list = (SECKEYPrivateKeyList*)arg;
michael@0 2281 return SECKEY_AddPrivateKeyToListTail(list, SECKEY_CopyPrivateKey(key));
michael@0 2282 }
michael@0 2283
michael@0 2284 SECKEYPrivateKeyList*
michael@0 2285 PK11_ListPrivateKeysInSlot(PK11SlotInfo *slot)
michael@0 2286 {
michael@0 2287 SECStatus status;
michael@0 2288 SECKEYPrivateKeyList *keys;
michael@0 2289
michael@0 2290 keys = SECKEY_NewPrivateKeyList();
michael@0 2291 if(keys == NULL) return NULL;
michael@0 2292
michael@0 2293 status = PK11_TraversePrivateKeysInSlot(slot, privateKeyListCallback,
michael@0 2294 (void*)keys);
michael@0 2295
michael@0 2296 if( status != SECSuccess ) {
michael@0 2297 SECKEY_DestroyPrivateKeyList(keys);
michael@0 2298 keys = NULL;
michael@0 2299 }
michael@0 2300
michael@0 2301 return keys;
michael@0 2302 }
michael@0 2303
michael@0 2304 SECKEYPublicKeyList*
michael@0 2305 PK11_ListPublicKeysInSlot(PK11SlotInfo *slot, char *nickname)
michael@0 2306 {
michael@0 2307 CK_ATTRIBUTE findTemp[4];
michael@0 2308 CK_ATTRIBUTE *attrs;
michael@0 2309 CK_BBOOL ckTrue = CK_TRUE;
michael@0 2310 CK_OBJECT_CLASS keyclass = CKO_PUBLIC_KEY;
michael@0 2311 int tsize = 0;
michael@0 2312 int objCount = 0;
michael@0 2313 CK_OBJECT_HANDLE *key_ids;
michael@0 2314 SECKEYPublicKeyList *keys;
michael@0 2315 int i,len;
michael@0 2316
michael@0 2317
michael@0 2318 attrs = findTemp;
michael@0 2319 PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++;
michael@0 2320 PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++;
michael@0 2321 if (nickname) {
michael@0 2322 len = PORT_Strlen(nickname);
michael@0 2323 PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++;
michael@0 2324 }
michael@0 2325 tsize = attrs - findTemp;
michael@0 2326 PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
michael@0 2327
michael@0 2328 key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount);
michael@0 2329 if (key_ids == NULL) {
michael@0 2330 return NULL;
michael@0 2331 }
michael@0 2332 keys = SECKEY_NewPublicKeyList();
michael@0 2333 if (keys == NULL) {
michael@0 2334 PORT_Free(key_ids);
michael@0 2335 return NULL;
michael@0 2336 }
michael@0 2337
michael@0 2338 for (i=0; i < objCount ; i++) {
michael@0 2339 SECKEYPublicKey *pubKey =
michael@0 2340 PK11_ExtractPublicKey(slot,nullKey,key_ids[i]);
michael@0 2341 if (pubKey) {
michael@0 2342 SECKEY_AddPublicKeyToListTail(keys, pubKey);
michael@0 2343 }
michael@0 2344 }
michael@0 2345
michael@0 2346 PORT_Free(key_ids);
michael@0 2347 return keys;
michael@0 2348 }
michael@0 2349
michael@0 2350 SECKEYPrivateKeyList*
michael@0 2351 PK11_ListPrivKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx)
michael@0 2352 {
michael@0 2353 CK_ATTRIBUTE findTemp[4];
michael@0 2354 CK_ATTRIBUTE *attrs;
michael@0 2355 CK_BBOOL ckTrue = CK_TRUE;
michael@0 2356 CK_OBJECT_CLASS keyclass = CKO_PRIVATE_KEY;
michael@0 2357 int tsize = 0;
michael@0 2358 int objCount = 0;
michael@0 2359 CK_OBJECT_HANDLE *key_ids;
michael@0 2360 SECKEYPrivateKeyList *keys;
michael@0 2361 int i,len;
michael@0 2362
michael@0 2363
michael@0 2364 attrs = findTemp;
michael@0 2365 PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++;
michael@0 2366 PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++;
michael@0 2367 if (nickname) {
michael@0 2368 len = PORT_Strlen(nickname);
michael@0 2369 PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++;
michael@0 2370 }
michael@0 2371 tsize = attrs - findTemp;
michael@0 2372 PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
michael@0 2373
michael@0 2374 key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount);
michael@0 2375 if (key_ids == NULL) {
michael@0 2376 return NULL;
michael@0 2377 }
michael@0 2378 keys = SECKEY_NewPrivateKeyList();
michael@0 2379 if (keys == NULL) {
michael@0 2380 PORT_Free(key_ids);
michael@0 2381 return NULL;
michael@0 2382 }
michael@0 2383
michael@0 2384 for (i=0; i < objCount ; i++) {
michael@0 2385 SECKEYPrivateKey *privKey =
michael@0 2386 PK11_MakePrivKey(slot,nullKey,PR_TRUE,key_ids[i],wincx);
michael@0 2387 SECKEY_AddPrivateKeyToListTail(keys, privKey);
michael@0 2388 }
michael@0 2389
michael@0 2390 PORT_Free(key_ids);
michael@0 2391 return keys;
michael@0 2392 }
michael@0 2393

mercurial