SECStatus PKCS11_Derive(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *hKey, CK_MECHANISM *pMech, int *dummy) { CK_RV crv; CK_OBJECT_HANDLE newKey; CK_BBOOL cktrue = CK_TRUE; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; CK_ATTRIBUTE keyTemplate[3]; CK_ATTRIBUTE *attrs = keyTemplate; PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); attrs++; PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); attrs++; PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, 1); attrs++; crv = NSC_DeriveKey(session, pMech, *hKey, keyTemplate, 3, &newKey); if (crv != CKR_OK) { printf("Derive Failed CK_RV=0x%x\n", (int)crv); return SECFailure; } return SECSuccess; }
static int nss_load_key(struct connectdata *conn, int sockindex, char *key_file) { #ifdef HAVE_PK11_CREATEGENERICOBJECT PK11SlotInfo * slot = NULL; CK_ATTRIBUTE *attrs; CK_ATTRIBUTE theTemplate[20]; CK_BBOOL cktrue = CK_TRUE; CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY; CK_SLOT_ID slotID; char slotname[SLOTSIZE]; struct ssl_connect_data *sslconn = &conn->ssl[sockindex]; attrs = theTemplate; /* FIXME: grok the various file types */ slotID = 1; /* hardcoded for now */ snprintf(slotname, sizeof(slotname), "PEM Token #%ld", slotID); slot = PK11_FindSlotByName(slotname); if(!slot) return 0; PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++; PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++; PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)key_file, strlen(key_file)+1); attrs++; /* When adding an encrypted key the PKCS#11 will be set as removed */ sslconn->key = PK11_CreateGenericObject(slot, theTemplate, 3, PR_FALSE /* isPerm */); if(sslconn->key == NULL) { PR_SetError(SEC_ERROR_BAD_KEY, 0); return 0; } /* This will force the token to be seen as re-inserted */ SECMOD_WaitForAnyTokenEvent(mod, 0, 0); PK11_IsPresent(slot); /* parg is initialized in nss_Init_Tokens() */ if(PK11_Authenticate(slot, PR_TRUE, conn->data->set.str[STRING_KEY_PASSWD]) != SECSuccess) { PK11_FreeSlot(slot); return 0; } PK11_FreeSlot(slot); return 1; #else /* If we don't have PK11_CreateGenericObject then we can't load a file-based * key. */ (void)conn; /* unused */ (void)key_file; /* unused */ return 0; #endif }
static CERTCertificate *load_cert_file(sxc_client_t *sx, const char *file, struct PK11_ctx *ctx) { const char *slot_name = "PEM Token #0"; CK_OBJECT_CLASS obj_class; CK_ATTRIBUTE attrs[/* max count of attributes */ 4]; unsigned attr_cnt = 0; CK_BBOOL cktrue = CK_TRUE; SECMODModule *mod; CERTCertificate *cert = NULL; if(!file || !ctx) { sxi_seterr(sx, SXE_EARG, "NULL argument"); return NULL; } memset(ctx, 0, sizeof(*ctx)); mod = SECMOD_LoadUserModule("library=libnsspem.so name=PEM", NULL, PR_FALSE); if (!mod || !mod->loaded) { if (mod) SECMOD_DestroyModule(mod); sxi_setsyserr(sx, SXE_ECFG, "Failed to load NSS PEM library"); return NULL; } sxi_crypto_check_ver(NULL); ctx->slot = PK11_FindSlotByName(slot_name); if (ctx->slot) { obj_class = CKO_CERTIFICATE; PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class)); PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)file, strlen(file) + 1); if(CKO_CERTIFICATE == obj_class) { CK_BBOOL *pval = &cktrue; PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval)); } ctx->obj = PK11_CreateGenericObject(ctx->slot, attrs, attr_cnt, PR_FALSE); if (!ctx->obj) { sxi_seterr(sx, SXE_ECFG, "Cannot load certificate from '%s': %s, %s", file, PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT), PR_ErrorToName(PR_GetError())); return NULL; } ctx->list = PK11_ListCertsInSlot(ctx->slot); if (ctx->list) { CERTCertListNode *node = CERT_LIST_HEAD(ctx->list); cert = node ? node->cert : NULL; } } else { sxi_seterr(sx, SXE_ECFG, "Failed to initialize NSS PEM token"); return NULL; } return cert; }
/* Call PK11_CreateGenericObject() with the given obj_class and filename. If * the call succeeds, append the object handle to the list of objects so that * the object can be destroyed in Curl_nss_close(). */ static CURLcode nss_create_object(struct ssl_connect_data *ssl, CK_OBJECT_CLASS obj_class, const char *filename, bool cacert) { PK11SlotInfo *slot; PK11GenericObject *obj; CK_BBOOL cktrue = CK_TRUE; CK_BBOOL ckfalse = CK_FALSE; CK_ATTRIBUTE attrs[/* max count of attributes */ 4]; int attr_cnt = 0; CURLcode err = (cacert) ? CURLE_SSL_CACERT_BADFILE : CURLE_SSL_CERTPROBLEM; const int slot_id = (cacert) ? 0 : 1; char *slot_name = aprintf("PEM Token #%d", slot_id); if(!slot_name) return CURLE_OUT_OF_MEMORY; slot = PK11_FindSlotByName(slot_name); free(slot_name); if(!slot) return err; PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class)); PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)filename, strlen(filename) + 1); if(CKO_CERTIFICATE == obj_class) { CK_BBOOL *pval = (cacert) ? (&cktrue) : (&ckfalse); PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval)); } obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE); PK11_FreeSlot(slot); if(!obj) return err; if(!Curl_llist_insert_next(ssl->obj_list, ssl->obj_list->tail, obj)) { PK11_DestroyGenericObject(obj); return CURLE_OUT_OF_MEMORY; } if(!cacert && CKO_CERTIFICATE == obj_class) /* store reference to a client certificate */ ssl->obj_clicert = obj; return CURLE_OK; }
/* * Return a list of all the CRLs . * CRLs are allocated in the list's arena. */ SECStatus PK11_LookupCrls(CERTCrlHeadNode *nodes, int type, void *wincx) { pk11TraverseSlot creater; 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) { isKrl = (CK_BBOOL) (type == SEC_KRL_TYPE); PK11_SETATTRS(attrs, CKA_NETSCAPE_KRL, &isKrl, sizeof(isKrl)); attrs++; } creater.callback = pk11_CollectCrls; creater.callbackArg = (void *) nodes; creater.findTemplate = theTemplate; creater.templateCount = (attrs - theTemplate); return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx); }
/* * Return a list of CRLs matching specified issuer and type * CRLs are not allocated in the list's arena, but rather in their own, * arena, so that they can be used individually in the CRL cache . * CRLs are always partially decoded for efficiency. */ SECStatus pk11_RetrieveCrls(CERTCrlHeadNode *nodes, SECItem* issuer, void *wincx) { pk11TraverseSlot creater; CK_ATTRIBUTE theTemplate[2]; CK_ATTRIBUTE *attrs; CK_OBJECT_CLASS crlClass = CKO_NETSCAPE_CRL; crlOptions options; attrs = theTemplate; PK11_SETATTRS(attrs, CKA_CLASS, &crlClass, sizeof(crlClass)); attrs++; options.head = nodes; /* - do a partial decoding - we don't need to decode the entries while fetching - don't copy the DER for optimal performance - CRL can be very large - have the CRL objects adopt the DER, so SEC_DestroyCrl will free it - keep bad CRL objects. The CRL cache is interested in them, for security purposes. Bad CRL objects are a sign of something amiss. */ options.decodeOptions = CRL_DECODE_SKIP_ENTRIES | CRL_DECODE_DONT_COPY_DER | CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_KEEP_BAD_CRL; if (issuer) { PK11_SETATTRS(attrs, CKA_SUBJECT, issuer->data, issuer->len); attrs++; } creater.callback = pk11_RetrieveCrlsCallback; creater.callbackArg = (void *) &options; creater.findTemplate = theTemplate; creater.templateCount = (attrs - theTemplate); return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx); }
PRBool pk11_HandleTrustObject(PK11SlotInfo *slot, CERTCertificate *cert, CERTCertTrust *trust) { PRArenaPool *arena; CK_ATTRIBUTE tobjTemplate[] = { { CKA_CLASS, NULL, 0 }, { CKA_CERT_SHA1_HASH, NULL, 0 }, }; CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST; CK_OBJECT_HANDLE tobjID; unsigned char sha1_hash[SHA1_LENGTH]; CK_TRUST serverAuth, codeSigning, emailProtection, clientAuth; PK11_HashBuf(SEC_OID_SHA1, sha1_hash, cert->derCert.data, cert->derCert.len); PK11_SETATTRS(&tobjTemplate[0], CKA_CLASS, &tobjc, sizeof(tobjc)); PK11_SETATTRS(&tobjTemplate[1], CKA_CERT_SHA1_HASH, sha1_hash, SHA1_LENGTH); tobjID = pk11_FindObjectByTemplate(slot, tobjTemplate, sizeof(tobjTemplate)/sizeof(tobjTemplate[0])); if( CK_INVALID_HANDLE == tobjID ) { return PR_FALSE; } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if( NULL == arena ) return PR_FALSE; /* Unfortunately, it seems that PK11_GetAttributes doesn't deal * well with nonexistent attributes. I guess we have to check * the trust info fields one at a time. */ /* We could verify CKA_CERT_HASH here */ /* We could verify CKA_EXPIRES here */ /* "Purpose" trust information */ serverAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_SERVER_AUTH); clientAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CLIENT_AUTH); codeSigning = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CODE_SIGNING); emailProtection = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_EMAIL_PROTECTION); /* Here's where the fun logic happens. We have to map back from the * key usage, extended key usage, purpose, and possibly other trust values * into the old trust-flags bits. */ /* First implementation: keep it simple for testing. We can study what other * mappings would be appropriate and add them later.. fgmr 20000724 */ if ( serverAuth == CKT_NSS_TRUSTED ) { trust->sslFlags |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED; } if ( serverAuth == CKT_NSS_TRUSTED_DELEGATOR ) { trust->sslFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA; } if ( clientAuth == CKT_NSS_TRUSTED_DELEGATOR ) { trust->sslFlags |= CERTDB_TRUSTED_CLIENT_CA ; } if ( emailProtection == CKT_NSS_TRUSTED ) { trust->emailFlags |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED; } if ( emailProtection == CKT_NSS_TRUSTED_DELEGATOR ) { trust->emailFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA; } if( codeSigning == CKT_NSS_TRUSTED ) { trust->objectSigningFlags |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED; } if( codeSigning == CKT_NSS_TRUSTED_DELEGATOR ) { trust->objectSigningFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA; } /* There's certainly a lot more logic that can go here.. */ PORT_FreeArena(arena, PR_FALSE); return PR_TRUE; }
SECStatus PK11_SaveSMimeProfile(PK11SlotInfo *slot, char *emailAddr, SECItem *derSubj, SECItem *emailProfile, SECItem *profileTime) { CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME; CK_BBOOL ck_true = CK_TRUE; CK_ATTRIBUTE theTemplate[] = { { CKA_CLASS, NULL, 0 }, { CKA_TOKEN, NULL, 0 }, { CKA_SUBJECT, NULL, 0 }, { CKA_NETSCAPE_EMAIL, NULL, 0 }, { CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0 }, { CKA_VALUE, NULL, 0 } }; /* if you change the array, change the variable below as well */ int realSize = 0; CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE; CK_ATTRIBUTE *attrs = theTemplate; CK_SESSION_HANDLE rwsession; PK11SlotInfo *free_slot = NULL; CK_RV crv; #ifdef DEBUG int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); #endif PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++; PK11_SETATTRS(attrs, CKA_TOKEN, &ck_true, sizeof(ck_true)); attrs++; PK11_SETATTRS(attrs, CKA_SUBJECT, derSubj->data, derSubj->len); attrs++; PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, emailAddr, PORT_Strlen(emailAddr)+1); attrs++; if (profileTime) { PK11_SETATTRS(attrs, CKA_NETSCAPE_SMIME_TIMESTAMP, profileTime->data, profileTime->len); attrs++; PK11_SETATTRS(attrs, CKA_VALUE,emailProfile->data, emailProfile->len); attrs++; } realSize = attrs - theTemplate; PORT_Assert (realSize <= tsize); if (slot == NULL) { free_slot = slot = PK11_GetInternalKeySlot(); /* we need to free the key slot in the end!!! */ } rwsession = PK11_GetRWSession(slot); if (rwsession == CK_INVALID_SESSION) { PORT_SetError(SEC_ERROR_READ_ONLY); if (free_slot) { PK11_FreeSlot(free_slot); } return SECFailure; } crv = PK11_GETTAB(slot)-> C_CreateObject(rwsession,theTemplate,realSize,&smimeh); if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); } PK11_RestoreROSession(slot,rwsession); if (free_slot) { PK11_FreeSlot(free_slot); } return SECSuccess; }
/* * return the certificate associated with a derCert */ SECItem * PK11_FindSMimeProfile(PK11SlotInfo **slot, char *emailAddr, SECItem *name, SECItem **profileTime) { CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME; CK_ATTRIBUTE theTemplate[] = { { CKA_SUBJECT, NULL, 0 }, { CKA_CLASS, NULL, 0 }, { CKA_NETSCAPE_EMAIL, NULL, 0 }, }; CK_ATTRIBUTE smimeData[] = { { CKA_SUBJECT, NULL, 0 }, { CKA_VALUE, NULL, 0 }, }; /* if you change the array, change the variable below as well */ int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE; CK_ATTRIBUTE *attrs = theTemplate; CK_RV crv; SECItem *emailProfile = NULL; if (!emailAddr || !emailAddr[0]) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len); attrs++; PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++; PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, emailAddr, strlen(emailAddr)); attrs++; if (*slot) { smimeh = pk11_FindObjectByTemplate(*slot,theTemplate,tsize); } else { PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE,PR_TRUE,NULL); PK11SlotListElement *le; if (!list) { return NULL; } /* loop through all the slots */ for (le = list->head; le; le = le->next) { smimeh = pk11_FindObjectByTemplate(le->slot,theTemplate,tsize); if (smimeh != CK_INVALID_HANDLE) { *slot = PK11_ReferenceSlot(le->slot); break; } } PK11_FreeSlotList(list); } if (smimeh == CK_INVALID_HANDLE) { PORT_SetError(SEC_ERROR_NO_KRL); return NULL; } if (profileTime) { PK11_SETATTRS(smimeData, CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0); } crv = PK11_GetAttributes(NULL,*slot,smimeh,smimeData,2); if (crv != CKR_OK) { PORT_SetError(PK11_MapError (crv)); goto loser; } if (!profileTime) { SECItem profileSubject; profileSubject.data = (unsigned char*) smimeData[0].pValue; profileSubject.len = smimeData[0].ulValueLen; if (!SECITEM_ItemsAreEqual(&profileSubject,name)) { goto loser; } } emailProfile = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); if (emailProfile == NULL) { goto loser; } emailProfile->data = (unsigned char*) smimeData[1].pValue; emailProfile->len = smimeData[1].ulValueLen; if (profileTime) { *profileTime = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); if (*profileTime) { (*profileTime)->data = (unsigned char*) smimeData[0].pValue; (*profileTime)->len = smimeData[0].ulValueLen; } } loser: if (emailProfile == NULL) { if (smimeData[1].pValue) { PORT_Free(smimeData[1].pValue); } } if (profileTime == NULL || *profileTime == NULL) { if (smimeData[0].pValue) { PORT_Free(smimeData[0].pValue); } } return emailProfile; }
static int nss_load_cert(struct ssl_connect_data *ssl, const char *filename, PRBool cacert) { #ifdef HAVE_PK11_CREATEGENERICOBJECT CK_SLOT_ID slotID; PK11SlotInfo * slot = NULL; CK_ATTRIBUTE *attrs; CK_ATTRIBUTE theTemplate[20]; CK_BBOOL cktrue = CK_TRUE; CK_BBOOL ckfalse = CK_FALSE; CK_OBJECT_CLASS objClass = CKO_CERTIFICATE; char slotname[SLOTSIZE]; #endif CERTCertificate *cert; char *nickname = NULL; char *n = NULL; /* If there is no slash in the filename it is assumed to be a regular * NSS nickname. */ if(is_file(filename)) { n = strrchr(filename, '/'); if(n) n++; if(!mod) return 1; } else { /* A nickname from the NSS internal database */ if(cacert) return 0; /* You can't specify an NSS CA nickname this way */ nickname = strdup(filename); if(!nickname) return 0; goto done; } #ifdef HAVE_PK11_CREATEGENERICOBJECT attrs = theTemplate; /* All CA and trust objects go into slot 0. Other slots are used * for storing certificates. With each new user certificate we increment * the slot count. We only support 1 user certificate right now. */ if(cacert) slotID = 0; else slotID = 1; snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID); nickname = aprintf("PEM Token #%ld:%s", slotID, n); if(!nickname) return 0; slot = PK11_FindSlotByName(slotname); if(!slot) { free(nickname); return 0; } PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++; PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++; PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)filename, strlen(filename)+1); attrs++; if(cacert) { PK11_SETATTRS(attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); } else { PK11_SETATTRS(attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); } attrs++; /* This load the certificate in our PEM module into the appropriate * slot. */ ssl->cacert[slotID] = PK11_CreateGenericObject(slot, theTemplate, 4, PR_FALSE /* isPerm */); PK11_FreeSlot(slot); if(ssl->cacert[slotID] == NULL) { free(nickname); return 0; } #else /* We don't have PK11_CreateGenericObject but a file-based cert was passed * in. We need to fail. */ return 0; #endif done: /* Double-check that the certificate or nickname requested exists in * either the token or the NSS certificate database. */ if(!cacert) { cert = PK11_FindCertFromNickname((char *)nickname, NULL); /* An invalid nickname was passed in */ if(cert == NULL) { free(nickname); PR_SetError(SEC_ERROR_UNKNOWN_CERT, 0); return 0; } CERT_DestroyCertificate(cert); } free(nickname); return 1; }
SECStatus PK11_ImportAndReturnPrivateKey(PK11SlotInfo *slot, SECKEYRawPrivateKey *lpk, SECItem *nickname, SECItem *publicValue, PRBool isPerm, PRBool isPrivate, unsigned int keyUsage, SECKEYPrivateKey **privk, void *wincx) { CK_BBOOL cktrue = CK_TRUE; CK_BBOOL ckfalse = CK_FALSE; CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_RSA; CK_OBJECT_HANDLE objectID; CK_ATTRIBUTE theTemplate[20]; int templateCount = 0; SECStatus rv = SECFailure; PRArenaPool *arena; CK_ATTRIBUTE *attrs; CK_ATTRIBUTE *signedattr = NULL; int signedcount = 0; CK_ATTRIBUTE *ap; SECItem *ck_id = NULL; arena = PORT_NewArena(2048); if(!arena) { return SECFailure; } attrs = theTemplate; PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++; PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++; PK11_SETATTRS(attrs, CKA_TOKEN, isPerm ? &cktrue : &ckfalse, sizeof(CK_BBOOL) ); attrs++; PK11_SETATTRS(attrs, CKA_SENSITIVE, isPrivate ? &cktrue : &ckfalse, sizeof(CK_BBOOL) ); attrs++; PK11_SETATTRS(attrs, CKA_PRIVATE, isPrivate ? &cktrue : &ckfalse, sizeof(CK_BBOOL) ); attrs++; switch (lpk->keyType) { case rsaKey: keyType = CKK_RSA; PK11_SETATTRS(attrs, CKA_UNWRAP, (keyUsage & KU_KEY_ENCIPHERMENT) ? &cktrue : &ckfalse, sizeof(CK_BBOOL) ); attrs++; PK11_SETATTRS(attrs, CKA_DECRYPT, (keyUsage & KU_DATA_ENCIPHERMENT) ? &cktrue : &ckfalse, sizeof(CK_BBOOL) ); attrs++; PK11_SETATTRS(attrs, CKA_SIGN, (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue : &ckfalse, sizeof(CK_BBOOL) ); attrs++; PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue : &ckfalse, sizeof(CK_BBOOL) ); attrs++; ck_id = PK11_MakeIDFromPubKey(&lpk->u.rsa.modulus); if (ck_id == NULL) { goto loser; } PK11_SETATTRS(attrs, CKA_ID, ck_id->data,ck_id->len); attrs++; if (nickname) { PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len); attrs++; } signedattr = attrs; PK11_SETATTRS(attrs, CKA_MODULUS, lpk->u.rsa.modulus.data, lpk->u.rsa.modulus.len); attrs++; PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, lpk->u.rsa.publicExponent.data, lpk->u.rsa.publicExponent.len); attrs++; PK11_SETATTRS(attrs, CKA_PRIVATE_EXPONENT, lpk->u.rsa.privateExponent.data, lpk->u.rsa.privateExponent.len); attrs++; PK11_SETATTRS(attrs, CKA_PRIME_1, lpk->u.rsa.prime1.data, lpk->u.rsa.prime1.len); attrs++; PK11_SETATTRS(attrs, CKA_PRIME_2, lpk->u.rsa.prime2.data, lpk->u.rsa.prime2.len); attrs++; PK11_SETATTRS(attrs, CKA_EXPONENT_1, lpk->u.rsa.exponent1.data, lpk->u.rsa.exponent1.len); attrs++; PK11_SETATTRS(attrs, CKA_EXPONENT_2, lpk->u.rsa.exponent2.data, lpk->u.rsa.exponent2.len); attrs++; PK11_SETATTRS(attrs, CKA_COEFFICIENT, lpk->u.rsa.coefficient.data, lpk->u.rsa.coefficient.len); attrs++; break; case dsaKey: keyType = CKK_DSA; /* To make our intenal PKCS #11 module work correctly with * our database, we need to pass in the public key value for * this dsa key. We have a netscape only CKA_ value to do this. * Only send it to internal slots */ if( publicValue == NULL ) { goto loser; } if (PK11_IsInternal(slot)) { PK11_SETATTRS(attrs, CKA_NETSCAPE_DB, publicValue->data, publicValue->len); attrs++; } PK11_SETATTRS(attrs, CKA_SIGN, &cktrue, sizeof(CK_BBOOL)); attrs++; PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, &cktrue, sizeof(CK_BBOOL)); attrs++; if(nickname) { PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len); attrs++; } ck_id = PK11_MakeIDFromPubKey(publicValue); if (ck_id == NULL) { goto loser; } PK11_SETATTRS(attrs, CKA_ID, ck_id->data,ck_id->len); attrs++; signedattr = attrs; PK11_SETATTRS(attrs, CKA_PRIME, lpk->u.dsa.params.prime.data, lpk->u.dsa.params.prime.len); attrs++; PK11_SETATTRS(attrs,CKA_SUBPRIME,lpk->u.dsa.params.subPrime.data, lpk->u.dsa.params.subPrime.len); attrs++; PK11_SETATTRS(attrs, CKA_BASE, lpk->u.dsa.params.base.data, lpk->u.dsa.params.base.len); attrs++; PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.dsa.privateValue.data, lpk->u.dsa.privateValue.len); attrs++; break; case dhKey: keyType = CKK_DH; /* To make our intenal PKCS #11 module work correctly with * our database, we need to pass in the public key value for * this dh key. We have a netscape only CKA_ value to do this. * Only send it to internal slots */ if (PK11_IsInternal(slot)) { PK11_SETATTRS(attrs, CKA_NETSCAPE_DB, publicValue->data, publicValue->len); attrs++; } PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL)); attrs++; if(nickname) { PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len); attrs++; } ck_id = PK11_MakeIDFromPubKey(publicValue); if (ck_id == NULL) { goto loser; } PK11_SETATTRS(attrs, CKA_ID, ck_id->data,ck_id->len); attrs++; signedattr = attrs; PK11_SETATTRS(attrs, CKA_PRIME, lpk->u.dh.prime.data, lpk->u.dh.prime.len); attrs++; PK11_SETATTRS(attrs, CKA_BASE, lpk->u.dh.base.data, lpk->u.dh.base.len); attrs++; PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.dh.privateValue.data, lpk->u.dh.privateValue.len); attrs++; break; /* what about fortezza??? */ default: PORT_SetError(SEC_ERROR_BAD_KEY); goto loser; } templateCount = attrs - theTemplate; PORT_Assert(templateCount <= sizeof(theTemplate)/sizeof(CK_ATTRIBUTE)); PORT_Assert(signedattr != NULL); signedcount = attrs - signedattr; for (ap=signedattr; signedcount; ap++, signedcount--) { pk11_SignedToUnsigned(ap); } rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, theTemplate, templateCount, isPerm, &objectID); /* create and return a SECKEYPrivateKey */ if( rv == SECSuccess && privk != NULL) { *privk = PK11_MakePrivKey(slot, lpk->keyType, !isPerm, objectID, wincx); if( *privk == NULL ) { rv = SECFailure; } } loser: if (ck_id) { SECITEM_ZfreeItem(ck_id, PR_TRUE); } return rv; }
static int nss_load_key(struct connectdata *conn, char *key_file) { #ifdef HAVE_PK11_CREATEGENERICOBJECT PK11SlotInfo * slot = NULL; PK11GenericObject *rv; CK_ATTRIBUTE *attrs; CK_ATTRIBUTE theTemplate[20]; CK_BBOOL cktrue = CK_TRUE; CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY; CK_SLOT_ID slotID; char *slotname = NULL; pphrase_arg_t *parg = NULL; attrs = theTemplate; /* FIXME: grok the various file types */ slotID = 1; /* hardcoded for now */ slotname = (char *)malloc(SLOTSIZE); snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID); slot = PK11_FindSlotByName(slotname); free(slotname); if(!slot) return 0; PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++; PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++; PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)key_file, strlen(key_file)+1); attrs++; /* When adding an encrypted key the PKCS#11 will be set as removed */ rv = PK11_CreateGenericObject(slot, theTemplate, 3, PR_FALSE /* isPerm */); if(rv == NULL) { PR_SetError(SEC_ERROR_BAD_KEY, 0); return 0; } /* This will force the token to be seen as re-inserted */ SECMOD_WaitForAnyTokenEvent(mod, 0, 0); PK11_IsPresent(slot); parg = (pphrase_arg_t *) malloc(sizeof(*parg)); parg->retryCount = 0; parg->data = conn->data; /* parg is initialized in nss_Init_Tokens() */ if(PK11_Authenticate(slot, PR_TRUE, parg) != SECSuccess) { free(parg); return 0; } free(parg); return 1; #else /* If we don't have PK11_CreateGenericObject then we can't load a file-based * key. */ (void)conn; /* unused */ (void)key_file; /* unused */ return 0; #endif }