diff options
Diffstat (limited to 'security/nss/lib')
28 files changed, 1233 insertions, 147 deletions
diff --git a/security/nss/lib/certhigh/certvfy.c b/security/nss/lib/certhigh/certvfy.c index 580e3063b..25d0eaf42 100644 --- a/security/nss/lib/certhigh/certvfy.c +++ b/security/nss/lib/certhigh/certvfy.c @@ -1139,14 +1139,14 @@ done: return rv; } -#define NEXT_ITERATION() { \ +#define NEXT_USAGE() { \ i*=2; \ certUsage++; \ continue; \ } #define VALID_USAGE() { \ - NEXT_ITERATION(); \ + NEXT_USAGE(); \ } #define INVALID_USAGE() { \ @@ -1156,7 +1156,7 @@ done: if (PR_TRUE == requiredUsage) { \ valid = SECFailure; \ } \ - NEXT_ITERATION(); \ + NEXT_USAGE(); \ } /* @@ -1233,7 +1233,7 @@ CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert, for (i=1;i<=certificateUsageHighest && !(SECFailure == valid && !returnedUsages) ;) { PRBool requiredUsage = (i & requiredUsages) ? PR_TRUE : PR_FALSE; if (PR_FALSE == requiredUsage && PR_FALSE == checkAllUsages) { - NEXT_ITERATION(); + NEXT_USAGE(); } if (returnedUsages) { *returnedUsages |= i; /* start off assuming this usage is valid */ @@ -1264,7 +1264,7 @@ CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert, case certUsageUserCertImport: case certUsageVerifyCA: /* these usages cannot be verified */ - NEXT_ITERATION(); + NEXT_USAGE(); default: PORT_Assert(0); @@ -1408,7 +1408,7 @@ CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert, } } - NEXT_ITERATION(); + NEXT_USAGE(); } return(valid); diff --git a/security/nss/lib/cryptohi/secsign.c b/security/nss/lib/cryptohi/secsign.c index 13b75abcc..68447be26 100644 --- a/security/nss/lib/cryptohi/secsign.c +++ b/security/nss/lib/cryptohi/secsign.c @@ -201,7 +201,7 @@ SGN_Update(SGNContext *cx, unsigned char *input, unsigned inputLen) SECStatus SGN_End(SGNContext *cx, SECItem *result) { - unsigned char digest[32]; + unsigned char digest[HASH_LENGTH_MAX]; unsigned part1, signatureLen; SECStatus rv; SECItem digder, sigitem; diff --git a/security/nss/lib/cryptohi/secvfy.c b/security/nss/lib/cryptohi/secvfy.c index a9e3970da..4a5de4e0f 100644 --- a/security/nss/lib/cryptohi/secvfy.c +++ b/security/nss/lib/cryptohi/secvfy.c @@ -83,7 +83,7 @@ DecryptSigBlock(SECOidTag *tagp, unsigned char *digest, SECKEYPublicKey *key, */ tag = SECOID_GetAlgorithmTag(&di->digestAlgorithm); /* XXX Check that tag is an appropriate algorithm? */ - if (di->digest.len > 32) { + if (di->digest.len > HASH_LENGTH_MAX) { PORT_SetError(SEC_ERROR_OUTPUT_LEN); goto loser; } @@ -110,8 +110,11 @@ struct VFYContextStr { SECOidTag alg; VerifyType type; SECKEYPublicKey *key; - /* digest holds the full dsa signature... 40 bytes */ - unsigned char digest[DSA_SIGNATURE_LEN]; + /* + * digest holds either the hash (<= HASH_LENGTH_MAX=64 bytes) + * in the RSA signature, or the full DSA signature (40 bytes). + */ + unsigned char digest[HASH_LENGTH_MAX]; void * wincx; void *hashcx; const SECHashObject *hashobj; @@ -350,7 +353,7 @@ VFY_Update(VFYContext *cx, unsigned char *input, unsigned inputLen) SECStatus VFY_EndWithSignature(VFYContext *cx, SECItem *sig) { - unsigned char final[32]; + unsigned char final[HASH_LENGTH_MAX]; unsigned part; SECItem hash,dsasig; /* dsasig is also used for ECDSA */ SECStatus rv; diff --git a/security/nss/lib/dev/devslot.c b/security/nss/lib/dev/devslot.c index 9f51c6a35..586531f9c 100644 --- a/security/nss/lib/dev/devslot.c +++ b/security/nss/lib/dev/devslot.c @@ -356,8 +356,10 @@ nssSlot_IsTokenPresent ( if (session->handle != CK_INVALID_SESSION) { return PR_TRUE; } else { - /* the token has been removed, and reinserted, invalidate all the old - * information we had on this token */ + /* the token has been removed, and reinserted, or the slot contains + * a token it doesn't recognize. invalidate all the old + * information we had on this token, if we can't refresh, clear + * the present flag */ #ifdef NSS_3_4_CODE nssToken_NotifyCertsNotVisible(slot->token); #endif /* NSS_3_4_CODE */ @@ -366,6 +368,7 @@ nssSlot_IsTokenPresent ( nssrv = nssSlot_Refresh(slot); if (nssrv != PR_SUCCESS) { slot->token->base.name[0] = 0; /* XXX */ + slot->ckFlags &= ~CKF_TOKEN_PRESENT; return PR_FALSE; } return PR_TRUE; diff --git a/security/nss/lib/freebl/dsa.c b/security/nss/lib/freebl/dsa.c index fe710cb64..85ceb2e51 100644 --- a/security/nss/lib/freebl/dsa.c +++ b/security/nss/lib/freebl/dsa.c @@ -188,11 +188,12 @@ dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest, /* FIPS-compliance dictates that digest is a SHA1 hash. */ /* Check args. */ if (!key || !signature || !digest || - (signature->len != DSA_SIGNATURE_LEN) || + (signature->len < DSA_SIGNATURE_LEN) || (digest->len != SHA1_LENGTH)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } + /* Initialize MPI integers. */ MP_DIGITS(&p) = 0; MP_DIGITS(&q) = 0; @@ -253,6 +254,7 @@ dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest, DSA_SUBPRIME_LEN); if (err < 0) goto cleanup; err = MP_OKAY; + signature->len = DSA_SIGNATURE_LEN; cleanup: mp_clear(&p); mp_clear(&q); diff --git a/security/nss/lib/freebl/loader.c b/security/nss/lib/freebl/loader.c index 37bdaf839..3b3c4a68a 100644 --- a/security/nss/lib/freebl/loader.c +++ b/security/nss/lib/freebl/loader.c @@ -123,12 +123,38 @@ bl_LoadLibrary(const char *name) { BLLibrary *lib; const char *error; + Dl_info dli; lib = PR_NEWZAP(BLLibrary); if (NULL == lib) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return NULL; } + + /* + * In setuid applications, Solaris is unwilling to load freebl unless + * we specify an absolute path. We construct one from the path of the + * library that contains this function. + */ + if (dladdr((void *)bl_LoadLibrary, &dli) != 0) { + const char *slash = strrchr(dli.dli_fname, '/'); + if (slash) { + size_t dirsize = slash - dli.dli_fname + 1; + char *pathname = PR_Malloc(dirsize + strlen(name) + 1); + if (NULL == pathname) { + PR_Free(lib); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + memcpy(pathname, dli.dli_fname, dirsize); + strcpy(pathname + dirsize, name); + lib->dlh = dlopen(pathname, RTLD_NOW | RTLD_LOCAL); + PR_Free(pathname); + if (NULL != lib->dlh) + return lib; + } + } + lib->dlh = dlopen(name, RTLD_NOW | RTLD_LOCAL); if (NULL == lib->dlh) { PR_SetError(PR_LOAD_LIBRARY_ERROR, 0); diff --git a/security/nss/lib/freebl/rsa.c b/security/nss/lib/freebl/rsa.c index d1ec6cfc5..33d41f1fc 100644 --- a/security/nss/lib/freebl/rsa.c +++ b/security/nss/lib/freebl/rsa.c @@ -66,6 +66,11 @@ #define MAX_RSA_MODULUS 1024 /* bytes, 8k bits */ #define MAX_RSA_EXPONENT 8 /* bytes, 64 bits */ +/* exponent should not be greater than modulus */ +#define BAD_RSA_KEY_SIZE(modLen, expLen) \ + ((expLen) > (modLen) || (modLen) > MAX_RSA_MODULUS || \ + (expLen) > MAX_RSA_EXPONENT) + /* ** RSABlindingParamsStr ** @@ -231,7 +236,8 @@ RSA_NewKey(int keySizeInBits, SECItem *publicExponent) RSAPrivateKey *key = NULL; PRArenaPool *arena = NULL; /* Require key size to be a multiple of 16 bits. */ - if (!publicExponent || keySizeInBits % 16 != 0) { + if (!publicExponent || keySizeInBits % 16 != 0 || + BAD_RSA_KEY_SIZE(keySizeInBits/8, publicExponent->len)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } @@ -334,8 +340,7 @@ RSA_PublicKeyOp(RSAPublicKey *key, modLen = rsa_modulusLen(&key->modulus); expLen = rsa_modulusLen(&key->publicExponent); /* 1. Obtain public key (n, e) */ - if (expLen > modLen || modLen > MAX_RSA_MODULUS || expLen > MAX_RSA_EXPONENT) { - /* exponent should not be greater than modulus */ + if (BAD_RSA_KEY_SIZE(modLen, expLen)) { PORT_SetError(SEC_ERROR_INVALID_KEY); rv = SECFailure; goto cleanup; diff --git a/security/nss/lib/freebl/unix_rand.c b/security/nss/lib/freebl/unix_rand.c index 22f8931b8..f61da8b29 100644 --- a/security/nss/lib/freebl/unix_rand.c +++ b/security/nss/lib/freebl/unix_rand.c @@ -833,7 +833,7 @@ for the small amount of entropy it provides. * is running on. */ if (environ != NULL) { - cp = environ; + cp = (const char * const *) environ; while (*cp) { RNG_RandomUpdate(*cp, strlen(*cp)); cp++; diff --git a/security/nss/lib/nss/nss.def b/security/nss/lib/nss/nss.def index 2ef0b4434..208638a77 100644 --- a/security/nss/lib/nss/nss.def +++ b/security/nss/lib/nss/nss.def @@ -850,3 +850,10 @@ NSS_Get_CERT_SignedCrlTemplate; ;+ local: ;+ *; ;+}; +;+NSS_3.10.2 { # NSS 3.10.2 release +;+ global: +PK11_TokenKeyGenWithFlags; +PK11_GenerateKeyPairWithFlags; +;+ local: +;+ *; +;+}; diff --git a/security/nss/lib/nss/nss.h b/security/nss/lib/nss/nss.h index 71f42a44d..0a5ed026c 100644 --- a/security/nss/lib/nss/nss.h +++ b/security/nss/lib/nss/nss.h @@ -52,11 +52,11 @@ SEC_BEGIN_PROTOS * The format of the version string should be * "<major version>.<minor version>[.<patch level>] [<Beta>]" */ -#define NSS_VERSION "3.10.1 Beta" +#define NSS_VERSION "3.10.2" #define NSS_VMAJOR 3 #define NSS_VMINOR 10 -#define NSS_VPATCH 1 -#define NSS_BETA PR_TRUE +#define NSS_VPATCH 2 +#define NSS_BETA PR_FALSE /* 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/pk11auth.c b/security/nss/lib/pk11wrap/pk11auth.c index 18dc08806..a9bc39943 100644 --- a/security/nss/lib/pk11wrap/pk11auth.c +++ b/security/nss/lib/pk11wrap/pk11auth.c @@ -80,7 +80,7 @@ static struct PK11GlobalStruct { SECStatus pk11_CheckPassword(PK11SlotInfo *slot,char *pw) { - int len = PORT_Strlen(pw); + int len = 0; CK_RV crv; SECStatus rv; int64 currtime = PR_Now(); @@ -88,6 +88,11 @@ pk11_CheckPassword(PK11SlotInfo *slot,char *pw) if (slot->protectedAuthPath) { len = 0; pw = NULL; + } else if (pw == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } else { + len = PORT_Strlen(pw); } PK11_EnterSlotMonitor(slot); @@ -121,7 +126,7 @@ pk11_CheckPassword(PK11SlotInfo *slot,char *pw) SECStatus PK11_CheckUserPassword(PK11SlotInfo *slot,char *pw) { - int len = PORT_Strlen(pw); + int len = 0; CK_RV crv; SECStatus rv; int64 currtime = PR_Now(); @@ -129,6 +134,11 @@ PK11_CheckUserPassword(PK11SlotInfo *slot,char *pw) if (slot->protectedAuthPath) { len = 0; pw = NULL; + } else if (pw == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } else { + len = PORT_Strlen(pw); } /* force a logout */ @@ -312,15 +322,23 @@ PK11_CheckSSOPassword(PK11SlotInfo *slot, char *ssopw) CK_SESSION_HANDLE rwsession; CK_RV crv; SECStatus rv = SECFailure; - int len = PORT_Strlen(ssopw); + int len = 0; /* get a rwsession */ rwsession = PK11_GetRWSession(slot); - if (rwsession == CK_INVALID_SESSION) return rv; + if (rwsession == CK_INVALID_SESSION) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return rv; + } if (slot->protectedAuthPath) { len = 0; ssopw = NULL; + } else if (ssopw == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } else { + len = PORT_Strlen(ssopw); } /* check the password */ @@ -383,7 +401,11 @@ PK11_InitPin(PK11SlotInfo *slot,char *ssopw, char *userpw) /* get a rwsession */ rwsession = PK11_GetRWSession(slot); - if (rwsession == CK_INVALID_SESSION) goto done; + if (rwsession == CK_INVALID_SESSION) { + PORT_SetError(SEC_ERROR_BAD_DATA); + slot->lastLoginCheck = 0; + return rv; + } if (slot->protectedAuthPath) { len = 0; @@ -443,6 +465,10 @@ PK11_ChangePW(PK11SlotInfo *slot,char *oldpw, char *newpw) /* get a rwsession */ rwsession = PK11_GetRWSession(slot); + if (rwsession == CK_INVALID_SESSION) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return rv; + } crv = PK11_GETTAB(slot)->C_SetPIN(rwsession, (unsigned char *)oldpw,oldLen,(unsigned char *)newpw,newLen); @@ -534,7 +560,34 @@ PK11_DoPassword(PK11SlotInfo *slot, PRBool loadCerts, void *wincx) * (3) the password was successful. */ while ((password = pk11_GetPassword(slot, attempt, wincx)) != NULL) { + /* if the token has a protectedAuthPath, the application may have + * already issued the C_Login as part of it's pk11_GetPassword call. + * In this case the application will tell us what the results were in + * the password value (retry or the authentication was successful) so + * we can skip our own C_Login call (which would force the token to + * try to login again). + * + * Applications that don't know about protectedAuthPath will return a + * password, which we will ignore and trigger the token to + * 'authenticate' itself anyway. Hopefully the blinking display on + * the reader, or the flashing light under the thumbprint reader will + * attract the user's attention */ attempt = PR_TRUE; + if (slot->protectedAuthPath) { + /* application tried to authenticate and failed. it wants to try + * again, continue looping */ + if (strcmp(password, PK11_PW_RETRY) == 0) { + rv = SECWouldBlock; + PORT_Free(password); + continue; + } + /* applicaton tried to authenticate and succeeded we're done */ + if (strcmp(password, PK11_PW_AUTHENTICATED) == 0) { + rv = SECSuccess; + PORT_Free(password); + break; + } + } rv = pk11_CheckPassword(slot,password); PORT_Memset(password, 0, PORT_Strlen(password)); PORT_Free(password); diff --git a/security/nss/lib/pk11wrap/pk11load.c b/security/nss/lib/pk11wrap/pk11load.c index 0906fc5f7..6017361ae 100644 --- a/security/nss/lib/pk11wrap/pk11load.c +++ b/security/nss/lib/pk11wrap/pk11load.c @@ -277,6 +277,8 @@ SECMOD_LoadPKCS11Module(SECMODModule *mod) { /* all 2.0 are a priori *not* thread safe */ if (info.cryptokiVersion.minor < 1) mod->isThreadSafe = PR_FALSE; + mod->cryptokiVersion = info.cryptokiVersion; + /* If we don't have a common name, get it from the PKCS 11 module */ if ((mod->commonName == NULL) || (mod->commonName[0] == 0)) { diff --git a/security/nss/lib/pk11wrap/pk11nobj.c b/security/nss/lib/pk11wrap/pk11nobj.c index 4a4f1147a..523e0dafe 100644 --- a/security/nss/lib/pk11wrap/pk11nobj.c +++ b/security/nss/lib/pk11wrap/pk11nobj.c @@ -256,11 +256,12 @@ PK11_LookupCrls(CERTCrlHeadNode *nodes, int type, void *wincx) { CK_ATTRIBUTE theTemplate[2]; CK_ATTRIBUTE *attrs; CK_OBJECT_CLASS certClass = CKO_NETSCAPE_CRL; + CK_BBOOL isKrl = CK_FALSE; attrs = theTemplate; PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass)); attrs++; if (type != -1) { - CK_BBOOL isKrl = (CK_BBOOL) (type == SEC_KRL_TYPE); + isKrl = (CK_BBOOL) (type == SEC_KRL_TYPE); PK11_SETATTRS(attrs, CKA_NETSCAPE_KRL, &isKrl, sizeof(isKrl)); attrs++; } 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 51a7a0525..51cce7c62 100644 --- a/security/nss/lib/pk11wrap/pk11pub.h +++ b/security/nss/lib/pk11wrap/pk11pub.h @@ -236,6 +236,10 @@ PK11SymKey *PK11_KeyGen(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, PK11SymKey *PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param, int keySize, SECItem *keyid, PRBool isToken, void *wincx); +PK11SymKey *PK11_TokenKeyGenWithFlags(PK11SlotInfo *slot, + CK_MECHANISM_TYPE type, SECItem *param, + 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); @@ -345,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 ea6d7012d..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++; @@ -766,9 +766,131 @@ PK11_MoveSymKey(PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, /* - * 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. keySize must be 'zero' for fixed key + * length algorithms. A nonzero keySize causes the CKA_VALUE_LEN attribute + * to be added to the template for the key. PKCS #11 modules fail if you + * specify the CKA_VALUE_LEN attribute for keys with fixed length. + * 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 opFlags, + PK11AttrFlags attrFlags, void *wincx) +{ + PK11SymKey *symKey; + CK_ATTRIBUTE genTemplate[MAX_TEMPL_ATTRS]; + CK_ATTRIBUTE *attrs = genTemplate; + int count = sizeof(genTemplate)/sizeof(genTemplate[0]); + CK_SESSION_HANDLE session; + 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 */ + + PK11_SETATTRS(attrs, CKA_VALUE_LEN, &ck_key_size, sizeof(ck_key_size)); + attrs++; + } + + /* Include key id value if provided */ + if (keyid) { + PK11_SETATTRS(attrs, CKA_ID, keyid->data, keyid->len); attrs++; + } + + attrs += pk11_AttrFlagsToAttributes(attrFlags, attrs, &cktrue, &ckfalse); + attrs += pk11_OpFlagsToAttributes(opFlags, attrs, &cktrue); + + count = attrs - genTemplate; + PR_ASSERT(count <= sizeof(genTemplate)/sizeof(CK_ATTRIBUTE)); + + /* find a slot to generate the key into */ + /* Only do slot management if this is not a token key */ + if (!isToken && (slot == NULL || !PK11_DoesMechanism(slot,type))) { + PK11SlotInfo *bestSlot; + + bestSlot = PK11_GetBestSlot(type,wincx); + if (bestSlot == NULL) { + PORT_SetError( SEC_ERROR_NO_MODULE ); + return NULL; + } + + symKey = pk11_CreateSymKey(bestSlot, type, !isToken, wincx); + + PK11_FreeSlot(bestSlot); + } else { + symKey = pk11_CreateSymKey(slot, type, !isToken, wincx); + } + if (symKey == NULL) return NULL; + + symKey->size = keySize; + symKey->origin = PK11_OriginGenerated; + + /* Initialize the Key Gen Mechanism */ + mechanism.mechanism = PK11_GetKeyGenWithSize(type, keySize); + if (mechanism.mechanism == CKM_FAKE_RANDOM) { + PORT_SetError( SEC_ERROR_NO_MODULE ); + return NULL; + } + + /* Set the parameters for the key gen if provided */ + mechanism.pParameter = NULL; + mechanism.ulParameterLen = 0; + if (param) { + mechanism.pParameter = param->data; + mechanism.ulParameterLen = param->len; + } + + /* Get session and perform locking */ + if (isToken) { + PK11_Authenticate(symKey->slot,PR_TRUE,wincx); + session = PK11_GetRWSession(symKey->slot); /* Should always be original slot */ + symKey->owner = PR_FALSE; + } else { + session = symKey->session; + pk11_EnterKeyMonitor(symKey); + } + + crv = PK11_GETTAB(symKey->slot)->C_GenerateKey(session, + &mechanism, genTemplate, count, &symKey->objectID); + + /* Release lock and session */ + if (isToken) { + PK11_RestoreROSession(symKey->slot, session); + } else { + pk11_ExitKeyMonitor(symKey); + } + + if (crv != CKR_OK) { + PK11_FreeSymKey(symKey); + PORT_SetError( PK11_MapError(crv) ); + return NULL; + } + + return symKey; +} + +/* + * Use the token to generate a key. keySize must be 'zero' for fixed key + * length algorithms. A nonzero keySize causes the CKA_VALUE_LEN attribute + * to be added to the template for the key. PKCS #11 modules fail if you + * specify the CKA_VALUE_LEN attribute for keys with fixed length. + * 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. */ PK11SymKey * PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param, @@ -821,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; @@ -1164,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); } @@ -1184,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); } @@ -1847,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); @@ -1870,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, @@ -1907,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); @@ -1937,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/pk11util.c b/security/nss/lib/pk11wrap/pk11util.c index 3108d5dbd..5c6998da8 100644 --- a/security/nss/lib/pk11wrap/pk11util.c +++ b/security/nss/lib/pk11wrap/pk11util.c @@ -1060,6 +1060,13 @@ SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, unsigned long flags, CK_RV crv; PK11SlotInfo *slot; + if ((mod->cryptokiVersion.major == 2) && + (mod->cryptokiVersion.minor < 1)) { + /* if the module is version 2.0, + * C_WaitForSlotEvent() doesn't exist */ + return secmod_HandleWaitForSlotEvent(mod, flags, latency); + } + /* first the the PKCS #11 call */ PZ_Lock(mod->refLock); if (mod->evControlMask & SECMOD_END_WAIT) { 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..cc63eddc7 100644 --- a/security/nss/lib/pk11wrap/secmodt.h +++ b/security/nss/lib/pk11wrap/secmodt.h @@ -40,6 +40,7 @@ #include "nssilckt.h" #include "secoid.h" #include "secasn1.h" +#include "pkcs11t.h" /* find a better home for these... */ extern const SEC_ASN1Template SECKEY_PointerToEncryptedPrivateKeyInfoTemplate[]; @@ -97,6 +98,7 @@ struct SECMODModuleStr { int cipherOrder; /* order for cipher operations */ unsigned long evControlMask; /* control the running and shutdown of slot * events (SECMOD_WaitForAnyTokenEvent) */ + CK_VERSION cryptokiVersion; /* version of this library */ }; /* evControlMask flags */ @@ -194,6 +196,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 */ @@ -252,6 +389,23 @@ typedef PRBool (PR_CALLBACK *PK11VerifyPasswordFunc)(PK11SlotInfo *slot, void *a typedef PRBool (PR_CALLBACK *PK11IsLoggedInFunc)(PK11SlotInfo *slot, void *arg); /* + * Special strings the password callback function can return only if + * the slot is an protected auth path slot. + */ +#define PK11_PW_RETRY "RETRY" /* an failed attempt to authenticate + * has already been made, just retry + * the operation */ +#define PK11_PW_AUTHENTICATED "AUTH" /* a successful attempt to authenticate + * has completed. Continue without + * another call to C_Login */ +/* All other non-null values mean that that NSS could call C_Login to force + * the authentication. The following define is to aid applications in + * documenting that is what it's trying to do */ +#define PK11_PW_TRY "TRY" /* Default: a prompt has been presented + * to the user, initiate a C_Login + * to authenticate the token */ + +/* * PKCS #11 key structures */ diff --git a/security/nss/lib/pki/pkistore.c b/security/nss/lib/pki/pkistore.c index 9e573ad1b..d069846cf 100644 --- a/security/nss/lib/pki/pkistore.c +++ b/security/nss/lib/pki/pkistore.c @@ -99,10 +99,12 @@ static PRIntn subject_list_sort(void *v1, void *v2) NSSCertificate *c2 = (NSSCertificate *)v2; nssDecodedCert *dc1 = nssCertificate_GetDecoding(c1); nssDecodedCert *dc2 = nssCertificate_GetDecoding(c2); - if (dc1->isNewerThan(dc1, dc2)) { + if (!dc1) { + return dc2 ? 1 : 0; + } else if (!dc2) { return -1; } else { - return 1; + return dc1->isNewerThan(dc1, dc2) ? -1 : 1; } } diff --git a/security/nss/lib/pki/tdcache.c b/security/nss/lib/pki/tdcache.c index cbf6d2361..b85e88143 100644 --- a/security/nss/lib/pki/tdcache.c +++ b/security/nss/lib/pki/tdcache.c @@ -157,10 +157,12 @@ static PRIntn subject_list_sort(void *v1, void *v2) NSSCertificate *c2 = (NSSCertificate *)v2; nssDecodedCert *dc1 = nssCertificate_GetDecoding(c1); nssDecodedCert *dc2 = nssCertificate_GetDecoding(c2); - if (dc1->isNewerThan(dc1, dc2)) { + if (!dc1) { + return dc2 ? 1 : 0; + } else if (!dc2) { return -1; - } else { - return 1; + } else { + return dc1->isNewerThan(dc1, dc2) ? -1 : 1; } } diff --git a/security/nss/lib/smime/cmslocal.h b/security/nss/lib/smime/cmslocal.h index 78e093c12..666eeb033 100644 --- a/security/nss/lib/smime/cmslocal.h +++ b/security/nss/lib/smime/cmslocal.h @@ -333,6 +333,13 @@ NSS_CMSAttributeArray_AddAttr(PLArenaPool *poolp, NSSCMSAttribute ***attrs, NSSC extern SECStatus NSS_CMSAttributeArray_SetAttr(PLArenaPool *poolp, NSSCMSAttribute ***attrs, SECOidTag type, SECItem *value, PRBool encoded); +/* + * NSS_CMSSignedData_AddTempCertificate - add temporary certificate references. + * They may be needed for signature verification on the data, for example. + */ +extern SECStatus +NSS_CMSSignedData_AddTempCertificate(NSSCMSSignedData *sigd, CERTCertificate *cert); + /************************************************************************/ SEC_END_PROTOS diff --git a/security/nss/lib/smime/cmssigdata.c b/security/nss/lib/smime/cmssigdata.c index b3b435c23..0ba771d65 100644 --- a/security/nss/lib/smime/cmssigdata.c +++ b/security/nss/lib/smime/cmssigdata.c @@ -86,7 +86,7 @@ loser: void NSS_CMSSignedData_Destroy(NSSCMSSignedData *sigd) { - CERTCertificate **certs, *cert; + CERTCertificate **certs, **tempCerts, *cert; CERTCertificateList **certlists, *certlist; NSSCMSSignerInfo **signerinfos, *si; @@ -94,6 +94,7 @@ NSS_CMSSignedData_Destroy(NSSCMSSignedData *sigd) return; certs = sigd->certs; + tempCerts = sigd->tempCerts; certlists = sigd->certLists; signerinfos = sigd->signerInfos; @@ -102,6 +103,11 @@ NSS_CMSSignedData_Destroy(NSSCMSSignedData *sigd) CERT_DestroyCertificate (cert); } + if (tempCerts != NULL) { + while ((cert = *tempCerts++) != NULL) + CERT_DestroyCertificate (cert); + } + if (certlists != NULL) { while ((certlist = *certlists++) != NULL) CERT_DestroyCertificateList (certlist); @@ -550,6 +556,13 @@ NSS_CMSSignedData_ImportCerts(NSSCMSSignedData *sigd, CERTCertDBHandle *certdb, goto loser; } + /* save the certs so they don't get destroyed */ + for (i=0; i < certcount; i++) { + CERTCertificate *cert = certArray[i]; + if (cert) + NSS_CMSSignedData_AddTempCertificate(sigd, cert); + } + if (!keepcerts) { goto done; } @@ -782,6 +795,22 @@ NSS_CMSSignedData_AddCertChain(NSSCMSSignedData *sigd, CERTCertificate *cert) return rv; } +extern SECStatus +NSS_CMSSignedData_AddTempCertificate(NSSCMSSignedData *sigd, CERTCertificate *cert) +{ + CERTCertificate *c; + SECStatus rv; + + if (!sigd || !cert) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + c = CERT_DupCertificate(cert); + rv = NSS_CMSArray_Add(sigd->cmsg->poolp, (void ***)&(sigd->tempCerts), (void *)c); + return rv; +} + SECStatus NSS_CMSSignedData_AddCertificate(NSSCMSSignedData *sigd, CERTCertificate *cert) { diff --git a/security/nss/lib/smime/cmst.h b/security/nss/lib/smime/cmst.h index a1c1bd65a..82f24da14 100644 --- a/security/nss/lib/smime/cmst.h +++ b/security/nss/lib/smime/cmst.h @@ -202,6 +202,9 @@ struct NSSCMSSignedDataStr { SECItem ** digests; CERTCertificate ** certs; CERTCertificateList ** certLists; + CERTCertificate ** tempCerts; /* temporary certs, needed + * for example for signature + * verification */ }; #define NSS_CMS_SIGNED_DATA_VERSION_BASIC 1 /* what we *create* */ #define NSS_CMS_SIGNED_DATA_VERSION_EXT 3 /* what we *create* */ diff --git a/security/nss/lib/softoken/pkcs11.c b/security/nss/lib/softoken/pkcs11.c index 91c02254f..f9090a925 100644 --- a/security/nss/lib/softoken/pkcs11.c +++ b/security/nss/lib/softoken/pkcs11.c @@ -62,6 +62,7 @@ #include "secport.h" #include "pcert.h" #include "secrng.h" +#include "nss.h" #include "keydbi.h" @@ -2911,8 +2912,8 @@ CK_RV NSC_GetInfo(CK_INFO_PTR pInfo) pInfo->cryptokiVersion.major = 2; pInfo->cryptokiVersion.minor = 11; PORT_Memcpy(pInfo->manufacturerID,manufacturerID,32); - pInfo->libraryVersion.major = 3; - pInfo->libraryVersion.minor = 8; + pInfo->libraryVersion.major = NSS_VMAJOR; + pInfo->libraryVersion.minor = NSS_VMINOR; PORT_Memcpy(pInfo->libraryDescription,libraryDescription,32); pInfo->flags = 0; return CKR_OK; @@ -2953,8 +2954,8 @@ CK_RV NSC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) pInfo->flags = CKF_TOKEN_PRESENT; /* ok we really should read it out of the keydb file. */ /* pInfo->hardwareVersion.major = NSSLOWKEY_DB_FILE_VERSION; */ - pInfo->hardwareVersion.major = 3; - pInfo->hardwareVersion.minor = 8; + pInfo->hardwareVersion.major = NSS_VMAJOR; + pInfo->hardwareVersion.minor = NSS_VMINOR; return CKR_OK; } diff --git a/security/nss/lib/util/secasn1e.c b/security/nss/lib/util/secasn1e.c index 778aff08c..db7792cb1 100644 --- a/security/nss/lib/util/secasn1e.c +++ b/security/nss/lib/util/secasn1e.c @@ -63,6 +63,14 @@ typedef enum { needBytes } sec_asn1e_parse_status; +typedef enum { + hdr_normal = 0, /* encode header normally */ + hdr_any = 1, /* header already encoded in content */ + hdr_decoder = 2, /* template only used by decoder. skip it. */ + hdr_optional = 3, /* optional component, to be omitted */ + hdr_placeholder = 4 /* place holder for from_buf content */ +} sec_asn1e_hdr_encoding; + typedef struct sec_asn1e_state_struct { SEC_ASN1EncoderContext *top; const SEC_ASN1Template *theTemplate; @@ -308,7 +316,7 @@ sec_asn1e_init_state_based_on_template (sec_asn1e_state *state) * (tag, optional status, etc.). * * NB: ALL the following flags in the subtemplate are disallowed - * and/or ignored: ECPLICIT, OPTIONAL, INNER< INLINE< POINTER. + * and/or ignored: EXPLICIT, OPTIONAL, INNER, INLINE, POINTER. */ under_kind = state->theTemplate->kind; @@ -501,7 +509,8 @@ sec_asn1e_which_choice static unsigned long sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src, - PRBool disallowStreaming, PRBool *noheaderp) + PRBool disallowStreaming, PRBool insideIndefinite, + sec_asn1e_hdr_encoding *pHdrException) { unsigned long encode_kind, underlying_kind; PRBool isExplicit, optional, universal, may_stream; @@ -540,21 +549,27 @@ sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src, /* Just clear this to get it out of the way; we do not need it here */ encode_kind &= ~SEC_ASN1_DYNAMIC; + + if (encode_kind & SEC_ASN1_NO_STREAM) { + disallowStreaming = PR_TRUE; + } encode_kind &= ~SEC_ASN1_NO_STREAM; - if( encode_kind & SEC_ASN1_CHOICE ) { - void *src2; - int indx = sec_asn1e_which_choice(src, theTemplate); - if( 0 == indx ) { - /* XXX set an error? "choice not found" */ - /* state->top->status = encodeError; */ - return 0; - } + if (encode_kind & SEC_ASN1_CHOICE) { + void *src2; + int indx = sec_asn1e_which_choice(src, theTemplate); + if (0 == indx) { + /* XXX set an error? "choice not found" */ + /* state->top->status = encodeError; */ + return 0; + } - src2 = (void *)((char *)src - theTemplate->offset + theTemplate[indx].offset); + src2 = (void *) + ((char *)src - theTemplate->offset + theTemplate[indx].offset); - return sec_asn1e_contents_length(&theTemplate[indx], src2, - PR_FALSE, noheaderp); + return sec_asn1e_contents_length(&theTemplate[indx], src2, + disallowStreaming, insideIndefinite, + pHdrException); } if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || !universal) { @@ -563,10 +578,7 @@ sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src, if (encode_kind & SEC_ASN1_POINTER) { src = *(void **)src; if (src == NULL) { - if (optional) - *noheaderp = PR_TRUE; - else - *noheaderp = PR_FALSE; + *pHdrException = optional ? hdr_optional : hdr_normal; return 0; } } else if (encode_kind & SEC_ASN1_INLINE) { @@ -578,7 +590,7 @@ sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src, SECItem* target = (SECItem*)src; if (!target || !target->data || !target->len) { /* no valid data to encode subtemplate */ - *noheaderp = PR_TRUE; + *pHdrException = hdr_optional; return 0; } } else { @@ -591,14 +603,17 @@ sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src, src = (char *)src + theTemplate->offset; /* recurse to find the length of the subtemplate */ - len = sec_asn1e_contents_length (theTemplate, src, PR_FALSE, noheaderp); + len = sec_asn1e_contents_length (theTemplate, src, disallowStreaming, + insideIndefinite, pHdrException); if (len == 0 && optional) { - *noheaderp = PR_TRUE; + *pHdrException = hdr_optional; } else if (isExplicit) { - if (*noheaderp) { - /* Okay, *we* do not want to add in a header, but our caller still does. */ - *noheaderp = PR_FALSE; - } else { + if (*pHdrException == hdr_any) { + /* *we* do not want to add in a header, + ** but our caller still does. + */ + *pHdrException = hdr_normal; + } else if (*pHdrException == hdr_normal) { /* if the inner content exists, our length is * len(identifier) + len(length) + len(innercontent) * XXX we currently assume len(identifier) == 1; @@ -615,7 +630,7 @@ sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src, if (underlying_kind & SEC_ASN1_SAVE) { /* check that there are no extraneous bits */ PORT_Assert (underlying_kind == SEC_ASN1_SAVE); - *noheaderp = PR_TRUE; + *pHdrException = hdr_decoder; return 0; } @@ -628,18 +643,20 @@ sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src, underlying_kind &= ~UNEXPECTED_FLAGS; #undef UNEXPECTED_FLAGS - if( underlying_kind & SEC_ASN1_CHOICE ) { - void *src2; - int indx = sec_asn1e_which_choice(src, theTemplate); - if( 0 == indx ) { - /* XXX set an error? "choice not found" */ - /* state->top->status = encodeError; */ - return 0; - } + if (underlying_kind & SEC_ASN1_CHOICE) { + void *src2; + int indx = sec_asn1e_which_choice(src, theTemplate); + if (0 == indx) { + /* XXX set an error? "choice not found" */ + /* state->top->status = encodeError; */ + return 0; + } - src2 = (void *)((char *)src - theTemplate->offset + theTemplate[indx].offset); - len = sec_asn1e_contents_length(&theTemplate[indx], src2, PR_FALSE, - noheaderp); + src2 = (void *) + ((char *)src - theTemplate->offset + theTemplate[indx].offset); + len = sec_asn1e_contents_length(&theTemplate[indx], src2, + disallowStreaming, insideIndefinite, + pHdrException); } else { switch (underlying_kind) { case SEC_ASN1_SEQUENCE_OF: @@ -660,14 +677,16 @@ sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src, for (; *group != NULL; group++) { sub_src = (char *)(*group) + tmpt->offset; - sub_len = sec_asn1e_contents_length (tmpt, sub_src, PR_FALSE, - noheaderp); + sub_len = sec_asn1e_contents_length (tmpt, sub_src, + disallowStreaming, + insideIndefinite, + pHdrException); len += sub_len; /* * XXX The 1 below is the presumed length of the identifier; * to support a high-tag-number this would need to be smarter. */ - if (!*noheaderp) + if (*pHdrException == hdr_normal) len += 1 + SEC_ASN1LengthLength (sub_len); } } @@ -683,14 +702,16 @@ sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src, len = 0; for (tmpt = theTemplate + 1; tmpt->kind; tmpt++) { sub_src = (char *)src + tmpt->offset; - sub_len = sec_asn1e_contents_length (tmpt, sub_src, PR_FALSE, - noheaderp); + sub_len = sec_asn1e_contents_length (tmpt, sub_src, + disallowStreaming, + insideIndefinite, + pHdrException); len += sub_len; /* * XXX The 1 below is the presumed length of the identifier; * to support a high-tag-number this would need to be smarter. */ - if (!*noheaderp) + if (*pHdrException == hdr_normal) len += 1 + SEC_ASN1LengthLength (sub_len); } } @@ -735,16 +756,23 @@ sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src, default: len = ((SECItem *)src)->len; - if (may_stream && len == 0 && !disallowStreaming) - len = 1; /* if we're streaming, we may have a secitem w/len 0 as placeholder */ break; + } /* end switch */ + +#ifndef WHAT_PROBLEM_DOES_THIS_SOLVE + /* if we're streaming, we may have a secitem w/len 0 as placeholder */ + if (!len && insideIndefinite && may_stream && !disallowStreaming) { + len = 1; } - } +#endif + } /* end else */ - if ((len == 0 && optional) || underlying_kind == SEC_ASN1_ANY) - *noheaderp = PR_TRUE; + if (len == 0 && optional) + *pHdrException = hdr_optional; + else if (underlying_kind == SEC_ASN1_ANY) + *pHdrException = hdr_any; else - *noheaderp = PR_FALSE; + *pHdrException = hdr_normal; return len; } @@ -755,7 +783,8 @@ sec_asn1e_write_header (sec_asn1e_state *state) { unsigned long contents_length; unsigned char tag_number, tag_modifiers; - PRBool noheader; + sec_asn1e_hdr_encoding hdrException = hdr_normal; + PRBool indefinite = PR_FALSE; PORT_Assert (state->place == beforeHeader); @@ -767,66 +796,79 @@ sec_asn1e_write_header (sec_asn1e_state *state) return; } - if( state->underlying_kind & SEC_ASN1_CHOICE ) { - int indx = sec_asn1e_which_choice(state->src, state->theTemplate); - if( 0 == indx ) { - /* XXX set an error? "choice not found" */ - state->top->status = encodeError; - return; - } - - state->place = afterChoice; - state = sec_asn1e_push_state(state->top, &state->theTemplate[indx], - (char *)state->src - state->theTemplate->offset, - PR_TRUE); - - if( (sec_asn1e_state *)NULL != state ) { - /* - * Do the "before" field notification. - */ - sec_asn1e_notify_before (state->top, state->src, state->depth); - state = sec_asn1e_init_state_based_on_template (state); - } - - return; + if (state->underlying_kind & SEC_ASN1_CHOICE) { + int indx = sec_asn1e_which_choice(state->src, state->theTemplate); + if( 0 == indx ) { + /* XXX set an error? "choice not found" */ + state->top->status = encodeError; + return; + } + state->place = afterChoice; + state = sec_asn1e_push_state(state->top, &state->theTemplate[indx], + (char *)state->src - state->theTemplate->offset, + PR_TRUE); + if (state) { + /* + * Do the "before" field notification. + */ + sec_asn1e_notify_before (state->top, state->src, state->depth); + state = sec_asn1e_init_state_based_on_template (state); + } + return; } + /* The !isString test below is apparently intended to ensure that all + ** constructed types receive indefinite length encoding. + */ + indefinite = (PRBool) + (state->top->streaming && state->may_stream && + (state->top->from_buf || !state->is_string)); + /* - * We are doing a definite-length encoding. First we have to + * If we are doing a definite-length encoding, first we have to * walk the data structure to calculate the entire contents length. + * If we are doing an indefinite-length encoding, we still need to + * know if the contents is: + * optional and to be omitted, or + * an ANY (header is pre-encoded), or + * a SAVE or some other kind of template used only by the decoder. + * So, we call this function either way. */ contents_length = sec_asn1e_contents_length (state->theTemplate, state->src, state->disallowStreaming, - &noheader); + indefinite, + &hdrException); /* * We might be told explicitly not to put out a header. * But it can also be the case, via a pushed subtemplate, that * sec_asn1e_contents_length could not know that this field is * really optional. So check for that explicitly, too. */ - if (noheader || (contents_length == 0 && state->optional)) { + if (hdrException != hdr_normal || + (contents_length == 0 && state->optional)) { state->place = afterContents; - if (state->top->streaming && state->may_stream && state->top->from_buf) - /* we did not find an optional indefinite string, so we don't encode it. - * However, if TakeFromBuf is on, we stop here anyway to give our caller - * a chance to intercept at the same point where we would stop if the - * field were present. */ + if (state->top->streaming && + state->may_stream && + state->top->from_buf) { + /* we did not find an optional indefinite string, so we + * don't encode it. However, if TakeFromBuf is on, we stop + * here anyway to give our caller a chance to intercept at the + * same point where we would stop if the field were present. + */ state->top->status = needBytes; + } return; } - if (state->top->streaming && state->may_stream - && (state->top->from_buf || !state->is_string)) { + if (indefinite) { /* * We need to put out an indefinite-length encoding. - */ - state->indefinite = PR_TRUE; - /* * The only universal types that can be constructed are SETs, * SEQUENCEs, and strings; so check that it is one of those, * or that it is not universal (e.g. context-specific). */ + state->indefinite = PR_TRUE; PORT_Assert ((tag_number == SEC_ASN1_SET) || (tag_number == SEC_ASN1_SEQUENCE) || ((tag_modifiers & SEC_ASN1_CLASS_MASK) != 0) diff --git a/security/nss/lib/util/secport.h b/security/nss/lib/util/secport.h index 783d40911..65c14def0 100644 --- a/security/nss/lib/util/secport.h +++ b/security/nss/lib/util/secport.h @@ -37,10 +37,6 @@ /* * secport.h - portability interfaces for security libraries * - * This file abstracts out libc functionality that libsec depends on - * - * NOTE - These are not public interfaces - * * $Id$ */ @@ -98,12 +94,6 @@ #include <sys/types.h> #endif -#ifdef notdef -#ifdef XP_MAC -#include "NSString.h" -#endif -#endif - #include <ctype.h> #include <string.h> #if defined(_WIN32_WCE) |