diff options
author | wtchang%redhat.com <devnull@localhost> | 2005-09-09 00:03:10 +0000 |
---|---|---|
committer | wtchang%redhat.com <devnull@localhost> | 2005-09-09 00:03:10 +0000 |
commit | 0f8d84f0e231ca0258db620ab4c696b35cfad597 (patch) | |
tree | 27c9abf3a9575451b15d2e5cff6eebfcfe63769f | |
parent | f16e7cfdaacb42476a299d24d0b111e8e0ab168c (diff) | |
download | nss-hg-0f8d84f0e231ca0258db620ab4c696b35cfad597.tar.gz |
Bugzilla Bug 299197: ported the fix back to the NSS_3_10_BRANCH. Added
the PK11AttrFlags type and the PK11_ATTR_XXX bitflags. Added
PK11_GenerateKeyPairWithFlags and changed PK11_TokenKeyGenWithFlags to
use PK11AttrFlags.
Modified Files:
Tag: NSS_3_10_BRANCH
nss/nss.def pk11wrap/pk11akey.c pk11wrap/pk11obj.c
pk11wrap/pk11pub.h pk11wrap/pk11skey.c pk11wrap/secmodi.h
pk11wrap/secmodt.h
-rw-r--r-- | security/nss/lib/nss/nss.def | 1 | ||||
-rw-r--r-- | security/nss/lib/pk11wrap/pk11akey.c | 566 | ||||
-rw-r--r-- | security/nss/lib/pk11wrap/pk11obj.c | 48 | ||||
-rw-r--r-- | security/nss/lib/pk11wrap/pk11pub.h | 13 | ||||
-rw-r--r-- | security/nss/lib/pk11wrap/pk11skey.c | 38 | ||||
-rw-r--r-- | security/nss/lib/pk11wrap/secmodi.h | 8 | ||||
-rw-r--r-- | security/nss/lib/pk11wrap/secmodt.h | 135 |
7 files changed, 786 insertions, 23 deletions
diff --git a/security/nss/lib/nss/nss.def b/security/nss/lib/nss/nss.def index 9418d9293..208638a77 100644 --- a/security/nss/lib/nss/nss.def +++ b/security/nss/lib/nss/nss.def @@ -853,6 +853,7 @@ NSS_Get_CERT_SignedCrlTemplate; ;+NSS_3.10.2 { # NSS 3.10.2 release ;+ global: PK11_TokenKeyGenWithFlags; +PK11_GenerateKeyPairWithFlags; ;+ local: ;+ *; ;+}; diff --git a/security/nss/lib/pk11wrap/pk11akey.c b/security/nss/lib/pk11wrap/pk11akey.c index 4e1745adc..55db33995 100644 --- a/security/nss/lib/pk11wrap/pk11akey.c +++ b/security/nss/lib/pk11wrap/pk11akey.c @@ -767,6 +767,148 @@ failure: * This is used to do a key gen using one pkcs11 module and storing the * result into another. */ +static SECKEYPrivateKey * +pk11_loadPrivKeyWithFlags(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, + SECKEYPublicKey *pubKey, PK11AttrFlags attrFlags) +{ + CK_ATTRIBUTE privTemplate[] = { + /* class must be first */ + { CKA_CLASS, NULL, 0 }, + { CKA_KEY_TYPE, NULL, 0 }, + { CKA_ID, NULL, 0 }, +#ifdef notdef + { CKA_LABEL, NULL, 0 }, + { CKA_SUBJECT, NULL, 0 }, +#endif + /* RSA */ + { CKA_MODULUS, NULL, 0 }, + { CKA_PRIVATE_EXPONENT, NULL, 0 }, + { CKA_PUBLIC_EXPONENT, NULL, 0 }, + { CKA_PRIME_1, NULL, 0 }, + { CKA_PRIME_2, NULL, 0 }, + { CKA_EXPONENT_1, NULL, 0 }, + { CKA_EXPONENT_2, NULL, 0 }, + { CKA_COEFFICIENT, NULL, 0 }, + /* reserve space for the attributes that may be + * specified in attrFlags */ + { CKA_TOKEN, NULL, 0 }, + { CKA_PRIVATE, NULL, 0 }, + { CKA_MODIFIABLE, NULL, 0 }, + { CKA_SENSITIVE, NULL, 0 }, + { CKA_EXTRACTABLE, NULL, 0 }, +#define NUM_RESERVED_ATTRS 5 /* number of reserved attributes above */ + }; + CK_BBOOL cktrue = CK_TRUE; + CK_BBOOL ckfalse = CK_FALSE; + CK_ATTRIBUTE *attrs = NULL, *ap; + const int templateSize = sizeof(privTemplate)/sizeof(privTemplate[0]); + PRArenaPool *arena; + CK_OBJECT_HANDLE objectID; + int i, count = 0; + int extra_count = 0; + CK_RV crv; + SECStatus rv; + PRBool token = ((attrFlags & PK11_ATTR_TOKEN) != 0); + + if (pk11_BadAttrFlags(attrFlags)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return NULL; + } + + for (i=0; i < templateSize; i++) { + if (privTemplate[i].type == CKA_MODULUS) { + attrs= &privTemplate[i]; + count = i; + break; + } + } + PORT_Assert(attrs != NULL); + if (attrs == NULL) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return NULL; + } + + ap = attrs; + + switch (privKey->keyType) { + case rsaKey: + count = templateSize - NUM_RESERVED_ATTRS; + extra_count = count - (attrs - privTemplate); + break; + case dsaKey: + ap->type = CKA_PRIME; ap++; count++; extra_count++; + ap->type = CKA_SUBPRIME; ap++; count++; extra_count++; + ap->type = CKA_BASE; ap++; count++; extra_count++; + ap->type = CKA_VALUE; ap++; count++; extra_count++; + break; + case dhKey: + ap->type = CKA_PRIME; ap++; count++; extra_count++; + ap->type = CKA_BASE; ap++; count++; extra_count++; + ap->type = CKA_VALUE; ap++; count++; extra_count++; + break; +#ifdef NSS_ENABLE_ECC + case ecKey: + ap->type = CKA_EC_PARAMS; ap++; count++; extra_count++; + ap->type = CKA_VALUE; ap++; count++; extra_count++; + break; +#endif /* NSS_ENABLE_ECC */ + default: + count = 0; + extra_count = 0; + break; + } + + if (count == 0) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return NULL; + } + + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) return NULL; + /* + * read out the old attributes. + */ + crv = PK11_GetAttributes(arena, privKey->pkcs11Slot, privKey->pkcs11ID, + privTemplate,count); + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + PORT_FreeArena(arena, PR_TRUE); + return NULL; + } + + /* Set token, private, modifiable, sensitive, and extractable */ + count += pk11_AttrFlagsToAttributes(attrFlags, &privTemplate[count], + &cktrue, &ckfalse); + + /* Not everyone can handle zero padded key values, give + * them the raw data as unsigned */ + for (ap=attrs; extra_count; ap++, extra_count--) { + pk11_SignedToUnsigned(ap); + } + + /* now Store the puppies */ + rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, privTemplate, + count, token, &objectID); + PORT_FreeArena(arena, PR_TRUE); + if (rv != SECSuccess) { + return NULL; + } + + /* try loading the public key */ + if (pubKey) { + PK11_ImportPublicKey(slot, pubKey, token); + if (pubKey->pkcs11Slot) { + PK11_FreeSlot(pubKey->pkcs11Slot); + pubKey->pkcs11Slot = NULL; + pubKey->pkcs11ID = CK_INVALID_HANDLE; + } + } + + /* build new key structure */ + return PK11_MakePrivKey(slot, privKey->keyType, !token, + objectID, privKey->wincx); +} + SECKEYPrivateKey * pk11_loadPrivKey(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey, PRBool token, PRBool sensitive) @@ -910,9 +1052,427 @@ PK11_LoadPrivKey(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, /* - * Use the token to Generate a key. keySize must be 'zero' for fixed key - * length algorithms. NOTE: this means we can never generate a DES2 key - * from this interface! + * Use the token to generate a key pair. + */ +SECKEYPrivateKey * +PK11_GenerateKeyPairWithFlags(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, + void *param, SECKEYPublicKey **pubKey, PK11AttrFlags attrFlags, void *wincx) +{ + /* we have to use these native types because when we call PKCS 11 modules + * we have to make sure that we are using the correct sizes for all the + * parameters. */ + CK_BBOOL ckfalse = CK_FALSE; + CK_BBOOL cktrue = CK_TRUE; + CK_ULONG modulusBits; + CK_BYTE publicExponent[4]; + CK_ATTRIBUTE privTemplate[] = { + { CKA_SENSITIVE, NULL, 0}, + { CKA_TOKEN, NULL, 0}, + { CKA_PRIVATE, NULL, 0}, + { CKA_DERIVE, NULL, 0}, + { CKA_UNWRAP, NULL, 0}, + { CKA_SIGN, NULL, 0}, + { CKA_DECRYPT, NULL, 0}, + { CKA_EXTRACTABLE, NULL, 0}, + { CKA_MODIFIABLE, NULL, 0}, + }; + CK_ATTRIBUTE rsaPubTemplate[] = { + { CKA_MODULUS_BITS, NULL, 0}, + { CKA_PUBLIC_EXPONENT, NULL, 0}, + { CKA_TOKEN, NULL, 0}, + { CKA_DERIVE, NULL, 0}, + { CKA_WRAP, NULL, 0}, + { CKA_VERIFY, NULL, 0}, + { CKA_VERIFY_RECOVER, NULL, 0}, + { CKA_ENCRYPT, NULL, 0}, + { CKA_MODIFIABLE, NULL, 0}, + }; + CK_ATTRIBUTE dsaPubTemplate[] = { + { CKA_PRIME, NULL, 0 }, + { CKA_SUBPRIME, NULL, 0 }, + { CKA_BASE, NULL, 0 }, + { CKA_TOKEN, NULL, 0}, + { CKA_DERIVE, NULL, 0}, + { CKA_WRAP, NULL, 0}, + { CKA_VERIFY, NULL, 0}, + { CKA_VERIFY_RECOVER, NULL, 0}, + { CKA_ENCRYPT, NULL, 0}, + { CKA_MODIFIABLE, NULL, 0}, + }; + CK_ATTRIBUTE dhPubTemplate[] = { + { CKA_PRIME, NULL, 0 }, + { CKA_BASE, NULL, 0 }, + { CKA_TOKEN, NULL, 0}, + { CKA_DERIVE, NULL, 0}, + { CKA_WRAP, NULL, 0}, + { CKA_VERIFY, NULL, 0}, + { CKA_VERIFY_RECOVER, NULL, 0}, + { CKA_ENCRYPT, NULL, 0}, + { CKA_MODIFIABLE, NULL, 0}, + }; +#ifdef NSS_ENABLE_ECC + CK_ATTRIBUTE ecPubTemplate[] = { + { CKA_EC_PARAMS, NULL, 0 }, + { CKA_TOKEN, NULL, 0}, + { CKA_DERIVE, NULL, 0}, + { CKA_WRAP, NULL, 0}, + { CKA_VERIFY, NULL, 0}, + { CKA_VERIFY_RECOVER, NULL, 0}, + { CKA_ENCRYPT, NULL, 0}, + { CKA_MODIFIABLE, NULL, 0}, + }; + SECKEYECParams * ecParams; +#endif /* NSS_ENABLE_ECC */ + + /*CK_ULONG key_size = 0;*/ + CK_ATTRIBUTE *pubTemplate; + int privCount = 0; + int pubCount = 0; + PK11RSAGenParams *rsaParams; + SECKEYPQGParams *dsaParams; + SECKEYDHParams * dhParams; + CK_MECHANISM mechanism; + CK_MECHANISM test_mech; + CK_SESSION_HANDLE session_handle; + CK_RV crv; + CK_OBJECT_HANDLE privID,pubID; + SECKEYPrivateKey *privKey; + KeyType keyType; + PRBool restore; + int peCount,i; + CK_ATTRIBUTE *attrs; + CK_ATTRIBUTE *privattrs; + SECItem *pubKeyIndex; + CK_ATTRIBUTE setTemplate; + SECStatus rv; + CK_MECHANISM_INFO mechanism_info; + CK_OBJECT_CLASS keyClass; + SECItem *cka_id; + PRBool haslock = PR_FALSE; + PRBool pubIsToken = PR_FALSE; + PRBool token = ((attrFlags & PK11_ATTR_TOKEN) != 0); + /* subset of attrFlags applicable to the public key */ + PK11AttrFlags pubKeyAttrFlags = attrFlags & + (PK11_ATTR_TOKEN | PK11_ATTR_SESSION + | PK11_ATTR_MODIFIABLE | PK11_ATTR_UNMODIFIABLE); + + if (pk11_BadAttrFlags(attrFlags)) { + PORT_SetError( SEC_ERROR_INVALID_ARGS ); + return NULL; + } + + PORT_Assert(slot != NULL); + if (slot == NULL) { + PORT_SetError( SEC_ERROR_NO_MODULE); + return NULL; + } + + /* if our slot really doesn't do this mechanism, Generate the key + * in our internal token and write it out */ + if (!PK11_DoesMechanism(slot,type)) { + PK11SlotInfo *int_slot = PK11_GetInternalSlot(); + + /* don't loop forever looking for a slot */ + if (slot == int_slot) { + PK11_FreeSlot(int_slot); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return NULL; + } + + /* if there isn't a suitable slot, then we can't do the keygen */ + if (int_slot == NULL) { + PORT_SetError( SEC_ERROR_NO_MODULE ); + return NULL; + } + + /* generate the temporary key to load */ + privKey = PK11_GenerateKeyPair(int_slot,type, param, pubKey, PR_FALSE, + PR_FALSE, wincx); + PK11_FreeSlot(int_slot); + + /* if successful, load the temp key into the new token */ + if (privKey != NULL) { + SECKEYPrivateKey *newPrivKey = pk11_loadPrivKeyWithFlags(slot, + privKey,*pubKey,attrFlags); + SECKEY_DestroyPrivateKey(privKey); + if (newPrivKey == NULL) { + SECKEY_DestroyPublicKey(*pubKey); + *pubKey = NULL; + } + return newPrivKey; + } + return NULL; + } + + + mechanism.mechanism = type; + mechanism.pParameter = NULL; + mechanism.ulParameterLen = 0; + test_mech.pParameter = NULL; + test_mech.ulParameterLen = 0; + + /* set up the private key template */ + privattrs = privTemplate; + privattrs += pk11_AttrFlagsToAttributes(attrFlags, privattrs, + &cktrue, &ckfalse); + + /* set up the mechanism specific info */ + switch (type) { + case CKM_RSA_PKCS_KEY_PAIR_GEN: + rsaParams = (PK11RSAGenParams *)param; + modulusBits = rsaParams->keySizeInBits; + peCount = 0; + + /* convert pe to a PKCS #11 string */ + for (i=0; i < 4; i++) { + if (peCount || (rsaParams->pe & + ((unsigned long)0xff000000L >> (i*8)))) { + publicExponent[peCount] = + (CK_BYTE)((rsaParams->pe >> (3-i)*8) & 0xff); + peCount++; + } + } + PORT_Assert(peCount != 0); + attrs = rsaPubTemplate; + PK11_SETATTRS(attrs, CKA_MODULUS_BITS, + &modulusBits, sizeof(modulusBits)); attrs++; + PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, + publicExponent, peCount);attrs++; + pubTemplate = rsaPubTemplate; + keyType = rsaKey; + test_mech.mechanism = CKM_RSA_PKCS; + break; + case CKM_DSA_KEY_PAIR_GEN: + dsaParams = (SECKEYPQGParams *)param; + attrs = dsaPubTemplate; + PK11_SETATTRS(attrs, CKA_PRIME, dsaParams->prime.data, + dsaParams->prime.len); attrs++; + PK11_SETATTRS(attrs, CKA_SUBPRIME, dsaParams->subPrime.data, + dsaParams->subPrime.len); attrs++; + PK11_SETATTRS(attrs, CKA_BASE, dsaParams->base.data, + dsaParams->base.len); attrs++; + pubTemplate = dsaPubTemplate; + keyType = dsaKey; + test_mech.mechanism = CKM_DSA; + break; + case CKM_DH_PKCS_KEY_PAIR_GEN: + dhParams = (SECKEYDHParams *)param; + attrs = dhPubTemplate; + PK11_SETATTRS(attrs, CKA_PRIME, dhParams->prime.data, + dhParams->prime.len); attrs++; + PK11_SETATTRS(attrs, CKA_BASE, dhParams->base.data, + dhParams->base.len); attrs++; + pubTemplate = dhPubTemplate; + keyType = dhKey; + test_mech.mechanism = CKM_DH_PKCS_DERIVE; + break; +#ifdef NSS_ENABLE_ECC + case CKM_EC_KEY_PAIR_GEN: + ecParams = (SECKEYECParams *)param; + attrs = ecPubTemplate; + PK11_SETATTRS(attrs, CKA_EC_PARAMS, ecParams->data, + ecParams->len); attrs++; + pubTemplate = ecPubTemplate; + keyType = ecKey; + /* XXX An EC key can be used for other mechanisms too such + * as CKM_ECDSA and CKM_ECDSA_SHA1. How can we reflect + * that in test_mech.mechanism so the CKA_SIGN, CKA_VERIFY + * attributes are set correctly? + */ + test_mech.mechanism = CKM_ECDH1_DERIVE; + break; +#endif /* NSS_ENABLE_ECC */ + default: + PORT_SetError( SEC_ERROR_BAD_KEY ); + return NULL; + } + + /* now query the slot to find out how "good" a key we can generate */ + if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID, + test_mech.mechanism,&mechanism_info); + if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot); + if ((crv != CKR_OK) || (mechanism_info.flags == 0)) { + /* must be old module... guess what it should be... */ + switch (test_mech.mechanism) { + case CKM_RSA_PKCS: + mechanism_info.flags = (CKF_SIGN | CKF_DECRYPT | + CKF_WRAP | CKF_VERIFY_RECOVER | CKF_ENCRYPT | CKF_WRAP);; + break; + case CKM_DSA: + mechanism_info.flags = CKF_SIGN | CKF_VERIFY; + break; + case CKM_DH_PKCS_DERIVE: + mechanism_info.flags = CKF_DERIVE; + break; +#ifdef NSS_ENABLE_ECC + case CKM_ECDH1_DERIVE: + mechanism_info.flags = CKF_DERIVE; + break; + case CKM_ECDSA: + case CKM_ECDSA_SHA1: + mechanism_info.flags = CKF_SIGN | CKF_VERIFY; + break; +#endif /* NSS_ENABLE_ECC */ + default: + break; + } + } + /* set the public key attributes */ + attrs += pk11_AttrFlagsToAttributes(pubKeyAttrFlags, attrs, + &cktrue, &ckfalse); + PK11_SETATTRS(attrs, CKA_DERIVE, + mechanism_info.flags & CKF_DERIVE ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); attrs++; + PK11_SETATTRS(attrs, CKA_WRAP, + mechanism_info.flags & CKF_WRAP ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); attrs++; + PK11_SETATTRS(attrs, CKA_VERIFY, + mechanism_info.flags & CKF_VERIFY ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); attrs++; + PK11_SETATTRS(attrs, CKA_VERIFY_RECOVER, + mechanism_info.flags & CKF_VERIFY_RECOVER ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); attrs++; + PK11_SETATTRS(attrs, CKA_ENCRYPT, + mechanism_info.flags & CKF_ENCRYPT? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); attrs++; + /* set the private key attributes */ + PK11_SETATTRS(privattrs, CKA_DERIVE, + mechanism_info.flags & CKF_DERIVE ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); privattrs++; + PK11_SETATTRS(privattrs, CKA_UNWRAP, + mechanism_info.flags & CKF_UNWRAP ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); privattrs++; + PK11_SETATTRS(privattrs, CKA_SIGN, + mechanism_info.flags & CKF_SIGN ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); privattrs++; + PK11_SETATTRS(privattrs, CKA_DECRYPT, + mechanism_info.flags & CKF_DECRYPT ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); privattrs++; + + if (token) { + session_handle = PK11_GetRWSession(slot); + haslock = PK11_RWSessionHasLock(slot,session_handle); + restore = PR_TRUE; + } else { + PK11_EnterSlotMonitor(slot); /* gross!! */ + session_handle = slot->session; + restore = PR_FALSE; + haslock = PR_TRUE; + } + + privCount = privattrs - privTemplate; + pubCount = attrs - pubTemplate; + crv = PK11_GETTAB(slot)->C_GenerateKeyPair(session_handle, &mechanism, + pubTemplate,pubCount,privTemplate,privCount,&pubID,&privID); + + if (crv != CKR_OK) { + if (restore) { + PK11_RestoreROSession(slot,session_handle); + } else PK11_ExitSlotMonitor(slot); + PORT_SetError( PK11_MapError(crv) ); + return NULL; + } + /* This locking code is dangerous and needs to be more thought + * out... the real problem is that we're holding the mutex open this long + */ + if (haslock) { PK11_ExitSlotMonitor(slot); } + + /* swap around the ID's for older PKCS #11 modules */ + keyClass = PK11_ReadULongAttribute(slot,pubID,CKA_CLASS); + if (keyClass != CKO_PUBLIC_KEY) { + CK_OBJECT_HANDLE tmp = pubID; + pubID = privID; + privID = tmp; + } + + *pubKey = PK11_ExtractPublicKey(slot, keyType, pubID); + if (*pubKey == NULL) { + if (restore) { + /* we may have to restore the mutex so it get's exited properly + * in RestoreROSession */ + if (haslock) PK11_EnterSlotMonitor(slot); + PK11_RestoreROSession(slot,session_handle); + } + PK11_DestroyObject(slot,pubID); + PK11_DestroyObject(slot,privID); + return NULL; + } + + /* set the ID to the public key so we can find it again */ + pubKeyIndex = NULL; + switch (type) { + case CKM_RSA_PKCS_KEY_PAIR_GEN: + pubKeyIndex = &(*pubKey)->u.rsa.modulus; + break; + case CKM_DSA_KEY_PAIR_GEN: + pubKeyIndex = &(*pubKey)->u.dsa.publicValue; + break; + case CKM_DH_PKCS_KEY_PAIR_GEN: + pubKeyIndex = &(*pubKey)->u.dh.publicValue; + break; +#ifdef NSS_ENABLE_ECC + case CKM_EC_KEY_PAIR_GEN: + pubKeyIndex = &(*pubKey)->u.ec.publicValue; + break; +#endif /* NSS_ENABLE_ECC */ + } + PORT_Assert(pubKeyIndex != NULL); + + cka_id = PK11_MakeIDFromPubKey(pubKeyIndex); + pubIsToken = (PRBool)PK11_HasAttributeSet(slot,pubID, CKA_TOKEN); + + PK11_SETATTRS(&setTemplate, CKA_ID, cka_id->data, cka_id->len); + + if (haslock) { PK11_EnterSlotMonitor(slot); } + crv = PK11_GETTAB(slot)->C_SetAttributeValue(session_handle, privID, + &setTemplate, 1); + + if (crv == CKR_OK && pubIsToken) { + crv = PK11_GETTAB(slot)->C_SetAttributeValue(session_handle, pubID, + &setTemplate, 1); + } + + + if (restore) { + PK11_RestoreROSession(slot,session_handle); + } else { + PK11_ExitSlotMonitor(slot); + } + SECITEM_FreeItem(cka_id,PR_TRUE); + + + if (crv != CKR_OK) { + PK11_DestroyObject(slot,pubID); + PK11_DestroyObject(slot,privID); + PORT_SetError( PK11_MapError(crv) ); + *pubKey = NULL; + return NULL; + } + + privKey = PK11_MakePrivKey(slot,keyType,!token,privID,wincx); + if (privKey == NULL) { + SECKEY_DestroyPublicKey(*pubKey); + PK11_DestroyObject(slot,privID); + *pubKey = NULL; + return NULL; + } + + /* Perform PKCS #11 pairwise consistency check. */ + rv = pk11_PairwiseConsistencyCheck( *pubKey, privKey, &test_mech, wincx ); + if( rv != SECSuccess ) { + SECKEY_DestroyPublicKey( *pubKey ); + SECKEY_DestroyPrivateKey( privKey ); + *pubKey = NULL; + privKey = NULL; + return NULL; /* due to pairwise consistency check */ + } + + return privKey; +} + +/* + * Use the token to generate a key pair. */ SECKEYPrivateKey * PK11_GenerateKeyPair(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, diff --git a/security/nss/lib/pk11wrap/pk11obj.c b/security/nss/lib/pk11wrap/pk11obj.c index 8d065f928..0af025539 100644 --- a/security/nss/lib/pk11wrap/pk11obj.c +++ b/security/nss/lib/pk11wrap/pk11obj.c @@ -408,7 +408,7 @@ PK11_CreateNewObject(PK11SlotInfo *slot, CK_SESSION_HANDLE session, unsigned int -pk11_FlagsToAttributes(CK_FLAGS flags, CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue) +pk11_OpFlagsToAttributes(CK_FLAGS flags, CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue) { const static CK_ATTRIBUTE_TYPE attrTypes[12] = { @@ -436,6 +436,52 @@ pk11_FlagsToAttributes(CK_FLAGS flags, CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue) } /* + * Check for conflicting flags, for example, if both PK11_ATTR_PRIVATE + * and PK11_ATTR_PUBLIC are set. + */ +PRBool +pk11_BadAttrFlags(PK11AttrFlags attrFlags) +{ + PK11AttrFlags trueFlags = attrFlags & 0x55555555; + PK11AttrFlags falseFlags = (attrFlags >> 1) & 0x55555555; + return ((trueFlags & falseFlags) != 0); +} + +/* + * This function may add a maximum of 5 attributes. + * The caller must make sure the attribute flags don't have conflicts. + */ +unsigned int +pk11_AttrFlagsToAttributes(PK11AttrFlags attrFlags, CK_ATTRIBUTE *attrs, + CK_BBOOL *ckTrue, CK_BBOOL *ckFalse) +{ + const static CK_ATTRIBUTE_TYPE attrTypes[5] = { + CKA_TOKEN, CKA_PRIVATE, CKA_MODIFIABLE, CKA_SENSITIVE, + CKA_EXTRACTABLE + }; + + const CK_ATTRIBUTE_TYPE *pType = attrTypes; + CK_ATTRIBUTE *attr = attrs; + PK11AttrFlags test = PK11_ATTR_TOKEN; + + PR_ASSERT(!pk11_BadAttrFlags(attrFlags)); + + /* we test two related bitflags in each iteration */ + for (; attrFlags && test <= PK11_ATTR_EXTRACTABLE; test <<= 2, ++pType) { + if (test & attrFlags) { + attrFlags ^= test; + PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue); + ++attr; + } else if ((test << 1) & attrFlags) { + attrFlags ^= (test << 1); + PK11_SETATTRS(attr, *pType, ckFalse, sizeof *ckFalse); + ++attr; + } + } + return (attr - attrs); +} + +/* * Some non-compliant PKCS #11 vendors do not give us the modulus, so actually * set up a signature to get the signaure length. */ diff --git a/security/nss/lib/pk11wrap/pk11pub.h b/security/nss/lib/pk11wrap/pk11pub.h index 462f5573b..51cce7c62 100644 --- a/security/nss/lib/pk11wrap/pk11pub.h +++ b/security/nss/lib/pk11wrap/pk11pub.h @@ -238,8 +238,8 @@ PK11SymKey *PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, PRBool isToken, void *wincx); PK11SymKey *PK11_TokenKeyGenWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param, - int keySize, SECItem *keyid, CK_FLAGS flags, - PRBool isToken, void *wincx); + int keySize, SECItem *keyid, CK_FLAGS opFlags, + PK11AttrFlags attrFlags, void *wincx); PK11SymKey * PK11_ListFixedKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx); PK11SymKey *PK11_GetNextSymKey(PK11SymKey *symKey); @@ -349,6 +349,15 @@ SECStatus PK11_ExtractKeyValue(PK11SymKey *symKey); SECItem * PK11_GetKeyData(PK11SymKey *symKey); PK11SlotInfo * PK11_GetSlotFromKey(PK11SymKey *symKey); void *PK11_GetWindow(PK11SymKey *symKey); +/* + * The attrFlags is the logical OR of the PK11_ATTR_XXX bitflags. + * These flags apply to the private key. The PK11_ATTR_TOKEN, + * PK11_ATTR_SESSION, PK11_ATTR_MODIFIABLE, and PK11_ATTR_UNMODIFIABLE + * flags also apply to the public key. + */ +SECKEYPrivateKey *PK11_GenerateKeyPairWithFlags(PK11SlotInfo *slot, + CK_MECHANISM_TYPE type, void *param, SECKEYPublicKey **pubk, + PK11AttrFlags attrFlags, void *wincx); SECKEYPrivateKey *PK11_GenerateKeyPair(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, void *param, SECKEYPublicKey **pubk, PRBool isPerm, PRBool isSensitive, void *wincx); diff --git a/security/nss/lib/pk11wrap/pk11skey.c b/security/nss/lib/pk11wrap/pk11skey.c index 7fa1285c1..299702a48 100644 --- a/security/nss/lib/pk11wrap/pk11skey.c +++ b/security/nss/lib/pk11wrap/pk11skey.c @@ -409,7 +409,7 @@ PK11_ImportSymKeyWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, * default for secret keys */ PK11_SETATTRS(attrs, CKA_PRIVATE, &cktrue, sizeof(cktrue) ); attrs++; } - attrs += pk11_FlagsToAttributes(flags, attrs, &cktrue); + attrs += pk11_OpFlagsToAttributes(flags, attrs, &cktrue); if ((operation != CKA_FLAGS_ONLY) && !pk11_FindAttrInTemplate(keyTemplate, attrs-keyTemplate, operation)) { PK11_SETATTRS(attrs, operation, &cktrue, sizeof(cktrue)); attrs++; @@ -773,11 +773,14 @@ PK11_MoveSymKey(PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, * NOTE: this means to generate a DES2 key from this interface you must * specify CKM_DES2_KEY_GEN as the mechanism directly; specifying * CKM_DES3_CBC as the mechanism and 16 as keySize currently doesn't work. + * + * CK_FLAGS flags: key operation flags + * PK11AttrFlags attrFlags: PK11_ATTR_XXX key attribute flags */ PK11SymKey * PK11_TokenKeyGenWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, - SECItem *param, int keySize, SECItem *keyid, CK_FLAGS flags, - PRBool isToken, void *wincx) + SECItem *param, int keySize, SECItem *keyid, CK_FLAGS opFlags, + PK11AttrFlags attrFlags, void *wincx) { PK11SymKey *symKey; CK_ATTRIBUTE genTemplate[MAX_TEMPL_ATTRS]; @@ -787,7 +790,14 @@ PK11_TokenKeyGenWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, CK_MECHANISM mechanism; CK_RV crv; CK_BBOOL cktrue = CK_TRUE; + CK_BBOOL ckfalse = CK_FALSE; CK_ULONG ck_key_size; /* only used for variable-length keys */ + PRBool isToken = ((attrFlags & PK11_ATTR_TOKEN) != 0); + + if (pk11_BadAttrFlags(attrFlags)) { + PORT_SetError( SEC_ERROR_INVALID_ARGS ); + return NULL; + } if (keySize != 0) { ck_key_size = keySize; /* Convert to PK11 type */ @@ -801,12 +811,8 @@ PK11_TokenKeyGenWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, PK11_SETATTRS(attrs, CKA_ID, keyid->data, keyid->len); attrs++; } - if (isToken) { - PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); attrs++; - PK11_SETATTRS(attrs, CKA_PRIVATE, &cktrue, sizeof(cktrue)); attrs++; - } - - attrs += pk11_FlagsToAttributes(flags, attrs, &cktrue); + attrs += pk11_AttrFlagsToAttributes(attrFlags, attrs, &cktrue, &ckfalse); + attrs += pk11_OpFlagsToAttributes(opFlags, attrs, &cktrue); count = attrs - genTemplate; PR_ASSERT(count <= sizeof(genTemplate)/sizeof(CK_ATTRIBUTE)); @@ -937,7 +943,7 @@ PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param, if (!isToken && (slot == NULL || !PK11_DoesMechanism(slot,type))) { PK11SlotInfo *bestSlot; - bestSlot = PK11_GetBestSlot(type,wincx); /* TNH: references the slot? */ + bestSlot = PK11_GetBestSlot(type,wincx); if (bestSlot == NULL) { PORT_SetError( SEC_ERROR_NO_MODULE ); return NULL; @@ -1280,7 +1286,7 @@ PK11_DeriveWithFlags( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS]; unsigned int templateCount; - templateCount = pk11_FlagsToAttributes(flags, keyTemplate, &ckTrue); + templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue); return pk11_DeriveWithTemplate(baseKey, derive, param, target, operation, keySize, keyTemplate, templateCount, PR_FALSE); } @@ -1300,7 +1306,7 @@ PK11_DeriveWithFlagsPerm( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); attrs++; } templateCount = attrs - keyTemplate; - templateCount += pk11_FlagsToAttributes(flags, attrs, &cktrue); + templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue); return pk11_DeriveWithTemplate(baseKey, derive, param, target, operation, keySize, keyTemplate, templateCount, isPerm); } @@ -1963,7 +1969,7 @@ PK11_UnwrapSymKeyWithFlags(PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType, CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS]; unsigned int templateCount; - templateCount = pk11_FlagsToAttributes(flags, keyTemplate, &ckTrue); + templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue); return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID, wrapType, param, wrappedKey, target, operation, keySize, wrappingKey->cx, keyTemplate, templateCount, PR_FALSE); @@ -1986,7 +1992,7 @@ PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey, PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); attrs++; } templateCount = attrs-keyTemplate; - templateCount += pk11_FlagsToAttributes(flags, attrs, &cktrue); + templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue); return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID, wrapType, param, wrappedKey, target, operation, keySize, @@ -2023,7 +2029,7 @@ PK11_PubUnwrapSymKeyWithFlags(SECKEYPrivateKey *wrappingKey, unsigned int templateCount; PK11SlotInfo *slot = wrappingKey->pkcs11Slot; - templateCount = pk11_FlagsToAttributes(flags, keyTemplate, &ckTrue); + templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue); if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) { PK11_HandlePasswordCheck(slot,wrappingKey->wincx); @@ -2053,7 +2059,7 @@ PK11_PubUnwrapSymKeyWithFlagsPerm(SECKEYPrivateKey *wrappingKey, } templateCount = attrs-keyTemplate; - templateCount += pk11_FlagsToAttributes(flags, attrs, &cktrue); + templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue); if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) { PK11_HandlePasswordCheck(slot,wrappingKey->wincx); diff --git a/security/nss/lib/pk11wrap/secmodi.h b/security/nss/lib/pk11wrap/secmodi.h index d8c4b1d3a..4514cdaf5 100644 --- a/security/nss/lib/pk11wrap/secmodi.h +++ b/security/nss/lib/pk11wrap/secmodi.h @@ -124,8 +124,14 @@ CK_SESSION_HANDLE pk11_GetNewSession(PK11SlotInfo *slot, PRBool *owner); void pk11_CloseSession(PK11SlotInfo *slot, CK_SESSION_HANDLE sess, PRBool own); PK11SymKey *pk11_ForceSlot(PK11SymKey *symKey, CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation); -unsigned int pk11_FlagsToAttributes(CK_FLAGS flags, +/* Convert key operation flags to PKCS #11 attributes. */ +unsigned int pk11_OpFlagsToAttributes(CK_FLAGS flags, CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue); +/* Check for bad (conflicting) attribute flags */ +PRBool pk11_BadAttrFlags(PK11AttrFlags attrFlags); +/* Convert key attribute flags to PKCS #11 attributes. */ +unsigned int pk11_AttrFlagsToAttributes(PK11AttrFlags attrFlags, + CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue, CK_BBOOL *ckFalse); PRBool pk11_FindAttrInTemplate(CK_ATTRIBUTE *attr, unsigned int numAttrs, CK_ATTRIBUTE_TYPE target); diff --git a/security/nss/lib/pk11wrap/secmodt.h b/security/nss/lib/pk11wrap/secmodt.h index 7a07f5302..73d14f726 100644 --- a/security/nss/lib/pk11wrap/secmodt.h +++ b/security/nss/lib/pk11wrap/secmodt.h @@ -194,6 +194,141 @@ struct PK11DefaultArrayEntryStr { #define CKA_DIGEST 0x81000000L #define CKA_FLAGS_ONLY 0 /* CKA_CLASS */ +/* + * PK11AttrFlags + * + * A 32-bit bitmask of PK11_ATTR_XXX flags + */ +typedef PRUint32 PK11AttrFlags; + +/* + * PK11_ATTR_XXX + * + * The following PK11_ATTR_XXX bitflags are used to specify + * PKCS #11 object attributes that have Boolean values. Some NSS + * functions have a "PK11AttrFlags attrFlags" parameter whose value + * is the logical OR of these bitflags. NSS use these bitflags on + * private keys or secret keys. Some of these bitflags also apply + * to the public keys associated with the private keys. + * + * For each PKCS #11 object attribute, we need two bitflags to + * specify not only "true" and "false" but also "default". For + * example, PK11_ATTR_PRIVATE and PK11_ATTR_PUBLIC control the + * CKA_PRIVATE attribute. If PK11_ATTR_PRIVATE is set, we add + * { CKA_PRIVATE, &cktrue, sizeof(CK_BBOOL) } + * to the template. If PK11_ATTR_PUBLIC is set, we add + * { CKA_PRIVATE, &ckfalse, sizeof(CK_BBOOL) } + * to the template. If neither flag is set, we don't add any + * CKA_PRIVATE entry to the template. + */ + +/* + * Attributes for PKCS #11 storage objects, which include not only + * keys but also certificates and domain parameters. + */ + +/* + * PK11_ATTR_TOKEN + * PK11_ATTR_SESSION + * + * These two flags determine whether the object is a token or + * session object. + * + * These two flags are related and cannot both be set. + * If the PK11_ATTR_TOKEN flag is set, the object is a token + * object. If the PK11_ATTR_SESSION flag is set, the object is + * a session object. If neither flag is set, the object is *by + * default* a session object. + * + * These two flags specify the value of the PKCS #11 CKA_TOKEN + * attribute. + */ +#define PK11_ATTR_TOKEN 0x00000001L +#define PK11_ATTR_SESSION 0x00000002L + +/* + * PK11_ATTR_PRIVATE + * PK11_ATTR_PUBLIC + * + * These two flags determine whether the object is a private or + * public object. A user may not access a private object until the + * user has authenticated to the token. + * + * These two flags are related and cannot both be set. + * If the PK11_ATTR_PRIVATE flag is set, the object is a private + * object. If the PK11_ATTR_PUBLIC flag is set, the object is a + * public object. If neither flag is set, it is token-specific + * whether the object is private or public. + * + * These two flags specify the value of the PKCS #11 CKA_PRIVATE + * attribute. NSS only uses this attribute on private and secret + * keys, so public keys created by NSS get the token-specific + * default value of the CKA_PRIVATE attribute. + */ +#define PK11_ATTR_PRIVATE 0x00000004L +#define PK11_ATTR_PUBLIC 0x00000008L + +/* + * PK11_ATTR_MODIFIABLE + * PK11_ATTR_UNMODIFIABLE + * + * These two flags determine whether the object is modifiable or + * read-only. + * + * These two flags are related and cannot both be set. + * If the PK11_ATTR_MODIFIABLE flag is set, the object can be + * modified. If the PK11_ATTR_UNMODIFIABLE flag is set, the object + * is read-only. If neither flag is set, the object is *by default* + * modifiable. + * + * These two flags specify the value of the PKCS #11 CKA_MODIFIABLE + * attribute. + */ +#define PK11_ATTR_MODIFIABLE 0x00000010L +#define PK11_ATTR_UNMODIFIABLE 0x00000020L + +/* Attributes for PKCS #11 key objects. */ + +/* + * PK11_ATTR_SENSITIVE + * PK11_ATTR_INSENSITIVE + * + * These two flags are related and cannot both be set. + * If the PK11_ATTR_SENSITIVE flag is set, the key is sensitive. + * If the PK11_ATTR_INSENSITIVE flag is set, the key is not + * sensitive. If neither flag is set, it is token-specific whether + * the key is sensitive or not. + * + * If a key is sensitive, certain attributes of the key cannot be + * revealed in plaintext outside the token. + * + * This flag specifies the value of the PKCS #11 CKA_SENSITIVE + * attribute. Although the default value of the CKA_SENSITIVE + * attribute for secret keys is CK_FALSE per PKCS #11, some FIPS + * tokens set the default value to CK_TRUE because only CK_TRUE + * is allowed. So in practice the default value of this attribute + * is token-specific, hence the need for two bitflags. + */ +#define PK11_ATTR_SENSITIVE 0x00000040L +#define PK11_ATTR_INSENSITIVE 0x00000080L + +/* + * PK11_ATTR_EXTRACTABLE + * PK11_ATTR_UNEXTRACTABLE + * + * These two flags are related and cannot both be set. + * If the PK11_ATTR_EXTRACTABLE flag is set, the key is extractable + * and can be wrapped. If the PK11_ATTR_UNEXTRACTABLE flag is set, + * the key is not extractable, and certain attributes of the key + * cannot be revealed in plaintext outside the token (just like a + * sensitive key). If neither flag is set, it is token-specific + * whether the key is extractable or not. + * + * These two flags specify the value of the PKCS #11 CKA_EXTRACTABLE + * attribute. + */ +#define PK11_ATTR_EXTRACTABLE 0x00000100L +#define PK11_ATTR_UNEXTRACTABLE 0x00000200L /* Cryptographic module types */ #define SECMOD_EXTERNAL 0 /* external module */ |