static nssCryptokiInstance * get_cert_instance(NSSCertificate *c) { nssCryptokiObject *instance, **ci; nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object); if (!instances) { return NULL; } instance = NULL; for (ci = instances; *ci; ci++) { if (!instance) { instance = nssCryptokiObject_Clone(*ci); } else { /* This only really works for two instances... But 3.4 can't * handle more anyway. The logic is, if there are multiple * instances, prefer the one that is not internal (e.g., on * a hardware device. */ if (PK11_IsInternal(instance->token->pk11slot)) { nssCryptokiObject_Destroy(instance); instance = nssCryptokiObject_Clone(*ci); } } } nssCryptokiObjectArray_Destroy(instances); return instance; }
NSSToken * nssToken_CreateFromPK11SlotInfo(NSSTrustDomain *td, PK11SlotInfo *nss3slot) { NSSToken *rvToken; NSSArena *arena; /* Don't create a token object for a disabled slot */ if (nss3slot->disabled) { PORT_SetError(SEC_ERROR_NO_TOKEN); return NULL; } arena = nssArena_Create(); if (!arena) { return NULL; } rvToken = nss_ZNEW(arena, NSSToken); if (!rvToken) { nssArena_Destroy(arena); return NULL; } rvToken->base.refCount = 1; rvToken->base.lock = PZ_NewLock(nssILockOther); if (!rvToken->base.lock) { nssArena_Destroy(arena); return NULL; } rvToken->base.arena = arena; rvToken->pk11slot = nss3slot; rvToken->epv = nss3slot->functionList; rvToken->defaultSession = nssSession_ImportNSS3Session(td->arena, nss3slot->session, nss3slot->sessionLock, nss3slot->defRWSession); /* continue, even if rvToken->defaultSession is NULL */ if (!PK11_IsInternal(nss3slot) && PK11_IsHW(nss3slot)) { rvToken->cache = nssTokenObjectCache_Create(rvToken, PR_TRUE, PR_TRUE, PR_TRUE); if (!rvToken->cache) goto loser; } rvToken->trustDomain = td; /* Grab the token name from the PKCS#11 fixed-length buffer */ rvToken->base.name = nssUTF8_Duplicate(nss3slot->token_name,td->arena); rvToken->slot = nssSlot_CreateFromPK11SlotInfo(td, nss3slot); if (!rvToken->slot) { goto loser; } rvToken->slot->token = rvToken; if (rvToken->defaultSession) rvToken->defaultSession->slot = rvToken->slot; return rvToken; loser: PZ_DestroyLock(rvToken->base.lock); nssArena_Destroy(arena); return NULL; }
char * STAN_GetCERTCertificateNameForInstance ( PLArenaPool *arenaOpt, NSSCertificate *c, nssCryptokiInstance *instance ) { NSSCryptoContext *context = c->object.cryptoContext; PRStatus nssrv; int nicklen, tokenlen, len; NSSUTF8 *tokenName = NULL; NSSUTF8 *stanNick = NULL; char *nickname = NULL; char *nick; if (instance) { stanNick = instance->label; } else if (context) { stanNick = c->object.tempName; } if (stanNick) { /* fill other fields needed by NSS3 functions using CERTCertificate */ if (instance && (!PK11_IsInternal(instance->token->pk11slot) || PORT_Strchr(stanNick, ':') != NULL) ) { tokenName = nssToken_GetName(instance->token); tokenlen = nssUTF8_Size(tokenName, &nssrv); } else { /* don't use token name for internal slot; 3.3 didn't */ tokenlen = 0; } nicklen = nssUTF8_Size(stanNick, &nssrv); len = tokenlen + nicklen; if (arenaOpt) { nickname = PORT_ArenaAlloc(arenaOpt, len); } else { nickname = PORT_Alloc(len); } nick = nickname; if (tokenName) { memcpy(nick, tokenName, tokenlen-1); nick += tokenlen-1; *nick++ = ':'; } memcpy(nick, stanNick, nicklen-1); nickname[len-1] = '\0'; } return nickname; }
nsresult nsNSSCertificate::MarkForPermDeletion() { nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) return NS_ERROR_NOT_AVAILABLE; // make sure user is logged in to the token nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext(); if (PK11_NeedLogin(mCert->slot) && !PK11_NeedUserInit(mCert->slot) && !PK11_IsInternal(mCert->slot)) { if (SECSuccess != PK11_Authenticate(mCert->slot, true, ctx)) { return NS_ERROR_FAILURE; } } mPermDelete = true; return NS_OK; }
NSS_EXTERN PRStatus STAN_ChangeCertTrust(CERTCertificate *cc, CERTCertTrust *trust) { PRStatus nssrv; NSSCertificate *c = STAN_GetNSSCertificate(cc); NSSToken *tok; NSSTrustDomain *td; NSSTrust *nssTrust; NSSArena *arena; CERTCertTrust *oldTrust; CERTCertTrust *newTrust; nssListIterator *tokens; PRBool moving_object; nssCryptokiObject *newInstance; nssPKIObject *pkiob; if (c == NULL) { return PR_FAILURE; } oldTrust = nssTrust_GetCERTCertTrustForCert(c, cc); if (oldTrust) { if (memcmp(oldTrust, trust, sizeof (CERTCertTrust)) == 0) { /* ... and the new trust is no different, done) */ return PR_SUCCESS; } else { /* take over memory already allocated in cc's arena */ newTrust = oldTrust; } } else { newTrust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust)); } memcpy(newTrust, trust, sizeof(CERTCertTrust)); CERT_LockCertTrust(cc); cc->trust = newTrust; CERT_UnlockCertTrust(cc); /* Set the NSSCerticate's trust */ arena = nssArena_Create(); if (!arena) return PR_FAILURE; nssTrust = nss_ZNEW(arena, NSSTrust); if (!nssTrust) { nssArena_Destroy(arena); return PR_FAILURE; } pkiob = nssPKIObject_Create(arena, NULL, cc->dbhandle, NULL, nssPKILock); if (!pkiob) { nssArena_Destroy(arena); return PR_FAILURE; } nssTrust->object = *pkiob; nssTrust->certificate = c; nssTrust->serverAuth = get_stan_trust(trust->sslFlags, PR_FALSE); nssTrust->clientAuth = get_stan_trust(trust->sslFlags, PR_TRUE); nssTrust->emailProtection = get_stan_trust(trust->emailFlags, PR_FALSE); nssTrust->codeSigning = get_stan_trust(trust->objectSigningFlags, PR_FALSE); nssTrust->stepUpApproved = (PRBool)(trust->sslFlags & CERTDB_GOVT_APPROVED_CA); if (c->object.cryptoContext != NULL) { /* The cert is in a context, set the trust there */ NSSCryptoContext *cc = c->object.cryptoContext; nssrv = nssCryptoContext_ImportTrust(cc, nssTrust); if (nssrv != PR_SUCCESS) { goto done; } if (c->object.numInstances == 0) { /* The context is the only instance, finished */ goto done; } } td = STAN_GetDefaultTrustDomain(); tok = stan_GetTrustToken(c); moving_object = PR_FALSE; if (tok && PK11_IsReadOnly(tok->pk11slot)) { NSSRWLock_LockRead(td->tokensLock); tokens = nssList_CreateIterator(td->tokenList); if (!tokens) { nssrv = PR_FAILURE; NSSRWLock_UnlockRead(td->tokensLock); goto done; } for (tok = (NSSToken *)nssListIterator_Start(tokens); tok != (NSSToken *)NULL; tok = (NSSToken *)nssListIterator_Next(tokens)) { if (!PK11_IsReadOnly(tok->pk11slot)) break; } nssListIterator_Finish(tokens); nssListIterator_Destroy(tokens); NSSRWLock_UnlockRead(td->tokensLock); moving_object = PR_TRUE; } if (tok) { if (moving_object) { /* this is kind of hacky. the softoken needs the cert * object in order to store trust. forcing it to be perm */ NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL); NSSASCII7 *email = NULL; if (PK11_IsInternal(tok->pk11slot)) { email = c->email; } newInstance = nssToken_ImportCertificate(tok, NULL, NSSCertificateType_PKIX, &c->id, nickname, &c->encoding, &c->issuer, &c->subject, &c->serial, email, PR_TRUE); nss_ZFreeIf(nickname); nickname = NULL; if (!newInstance) { nssrv = PR_FAILURE; goto done; } nssPKIObject_AddInstance(&c->object, newInstance); } newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding, &c->issuer, &c->serial, nssTrust->serverAuth, nssTrust->clientAuth, nssTrust->codeSigning, nssTrust->emailProtection, nssTrust->stepUpApproved, PR_TRUE); /* If the selected token can't handle trust, dump the trust on * the internal token */ if (!newInstance && !PK11_IsInternalKeySlot(tok->pk11slot)) { PK11SlotInfo *slot = PK11_GetInternalKeySlot(); NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL); NSSASCII7 *email = c->email; tok = PK11Slot_GetNSSToken(slot); PK11_FreeSlot(slot); newInstance = nssToken_ImportCertificate(tok, NULL, NSSCertificateType_PKIX, &c->id, nickname, &c->encoding, &c->issuer, &c->subject, &c->serial, email, PR_TRUE); nss_ZFreeIf(nickname); nickname = NULL; if (!newInstance) { nssrv = PR_FAILURE; goto done; } nssPKIObject_AddInstance(&c->object, newInstance); newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding, &c->issuer, &c->serial, nssTrust->serverAuth, nssTrust->clientAuth, nssTrust->codeSigning, nssTrust->emailProtection, nssTrust->stepUpApproved, PR_TRUE); } if (newInstance) { nssCryptokiObject_Destroy(newInstance); nssrv = PR_SUCCESS; } else { nssrv = PR_FAILURE; } } else { nssrv = PR_FAILURE; } done: (void)nssTrust_Destroy(nssTrust); return nssrv; }
static void fill_CERTCertificateFields(NSSCertificate *c, CERTCertificate *cc, PRBool forced) { CERTCertTrust* trust = NULL; NSSTrust *nssTrust; NSSCryptoContext *context = c->object.cryptoContext; nssCryptokiInstance *instance; NSSUTF8 *stanNick = NULL; /* We are holding the base class object's lock on entry of this function * This lock protects writes to fields of the CERTCertificate . * It is also needed by some functions to compute values such as trust. */ instance = get_cert_instance(c); if (instance) { stanNick = instance->label; } else if (context) { stanNick = c->object.tempName; } /* fill other fields needed by NSS3 functions using CERTCertificate */ if ((!cc->nickname && stanNick) || forced) { PRStatus nssrv; int nicklen, tokenlen, len; NSSUTF8 *tokenName = NULL; char *nick; if (instance && (!PK11_IsInternal(instance->token->pk11slot) || (stanNick && PORT_Strchr(stanNick, ':') != NULL))) { tokenName = nssToken_GetName(instance->token); tokenlen = nssUTF8_Size(tokenName, &nssrv); } else { /* don't use token name for internal slot; 3.3 didn't */ tokenlen = 0; } if (stanNick) { nicklen = nssUTF8_Size(stanNick, &nssrv); len = tokenlen + nicklen; nick = PORT_ArenaAlloc(cc->arena, len); if (tokenName) { memcpy(nick, tokenName, tokenlen-1); nick[tokenlen-1] = ':'; memcpy(nick+tokenlen, stanNick, nicklen-1); } else { memcpy(nick, stanNick, nicklen-1); } nick[len-1] = '\0'; cc->nickname = nick; } else { cc->nickname = NULL; } } if (context) { /* trust */ nssTrust = nssCryptoContext_FindTrustForCertificate(context, c); if (nssTrust) { trust = cert_trust_from_stan_trust(nssTrust, cc->arena); if (trust) { /* we should destroy cc->trust before replacing it, but it's allocated in cc->arena, so memory growth will occur on each refresh */ cc->trust = trust; } nssTrust_Destroy(nssTrust); } } else if (instance) { /* slot */ if (cc->slot != instance->token->pk11slot) { if (cc->slot) { PK11_FreeSlot(cc->slot); } cc->slot = PK11_ReferenceSlot(instance->token->pk11slot); } cc->ownSlot = PR_TRUE; /* pkcs11ID */ cc->pkcs11ID = instance->handle; /* trust */ trust = nssTrust_GetCERTCertTrustForCert(c, cc); if (trust) { /* we should destroy cc->trust before replacing it, but it's allocated in cc->arena, so memory growth will occur on each refresh */ cc->trust = trust; } nssCryptokiObject_Destroy(instance); } /* database handle is now the trust domain */ cc->dbhandle = c->object.trustDomain; /* subjectList ? */ /* istemp and isperm are supported in NSS 3.4 */ cc->istemp = PR_FALSE; /* CERT_NewTemp will override this */ cc->isperm = PR_TRUE; /* by default */ /* pointer back */ cc->nssCertificate = c; if (trust) { /* force the cert type to be recomputed to include trust info */ PRUint32 nsCertType = cert_ComputeCertType(cc); /* Assert that it is safe to cast &cc->nsCertType to "PRInt32 *" */ PORT_Assert(sizeof(cc->nsCertType) == sizeof(PRInt32)); PR_AtomicSet((PRInt32 *)&cc->nsCertType, nsCertType); } }
/* * generate an RSA signature key * * e is fixed at 3, without discussion. That would not be wise if these * keys were to be used for encryption, but for signatures there are some * real speed advantages. * See also: https://www.imperialviolet.org/2012/03/16/rsae.html */ void rsasigkey(int nbits, int seedbits, char *configdir, char *password) { SECStatus rv; PK11RSAGenParams rsaparams = { nbits, (long) E }; secuPWData pwdata = { PW_NONE, NULL }; PK11SlotInfo *slot = NULL; SECKEYPrivateKey *privkey = NULL; SECKEYPublicKey *pubkey = NULL; realtime_t now = realnow(); if (password == NULL) { pwdata.source = PW_NONE; } else { /* check if passwd == configdir/nsspassword */ size_t cdl = strlen(configdir); size_t pwl = strlen(password); static const char suf[] = "/nsspassword"; if (pwl == cdl + sizeof(suf) - 1 && memeq(password, configdir, cdl) && memeq(password + cdl, suf, sizeof(suf))) pwdata.source = PW_FROMFILE; else pwdata.source = PW_PLAINTEXT; } pwdata.data = password; lsw_nss_buf_t err; if (!lsw_nss_setup(configdir, FALSE/*rw*/, GetModulePassword, err)) { fprintf(stderr, "%s: %s\n", me, err); exit(1); } #ifdef FIPS_CHECK if (PK11_IsFIPS() && !FIPSCHECK_verify(NULL, NULL)) { fprintf(stderr, "FIPS HMAC integrity verification test failed.\n"); exit(1); } #endif if (PK11_IsFIPS() && password == NULL) { fprintf(stderr, "%s: On FIPS mode a password is required\n", me); exit(1); } /* Good for now but someone may want to use a hardware token */ slot = PK11_GetInternalKeySlot(); /* In which case this may be better */ /* slot = PK11_GetBestSlot(CKM_RSA_PKCS_KEY_PAIR_GEN, password ? &pwdata : NULL); */ /* or the user may specify the name of a token. */ #if 0 if (PK11_IsFIPS() || !PK11_IsInternal(slot)) { rv = PK11_Authenticate(slot, PR_FALSE, &pwdata); if (rv != SECSuccess) { fprintf(stderr, "%s: could not authenticate to token '%s'\n", me, PK11_GetTokenName(slot)); return; } } #endif /* 0 */ /* Do some random-number initialization. */ UpdateNSS_RNG(seedbits); /* Log in to the token */ if (password != NULL) { rv = PK11_Authenticate(slot, PR_FALSE, &pwdata); if (rv != SECSuccess) { fprintf(stderr, "%s: could not authenticate to token '%s'\n", me, PK11_GetTokenName(slot)); return; } } privkey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaparams, &pubkey, PR_TRUE, password != NULL? PR_TRUE : PR_FALSE, &pwdata); /* inTheToken, isSensitive, passwordCallbackFunction */ if (privkey == NULL) { fprintf(stderr, "%s: key pair generation failed: \"%d\"\n", me, PORT_GetError()); return; } chunk_t public_modulus = { .ptr = pubkey->u.rsa.modulus.data, .len = pubkey->u.rsa.modulus.len, }; chunk_t public_exponent = { .ptr = pubkey->u.rsa.publicExponent.data, .len = pubkey->u.rsa.publicExponent.len, }; char *hex_ckaid; { SECItem *ckaid = PK11_GetLowLevelKeyIDForPrivateKey(privkey); if (ckaid == NULL) { fprintf(stderr, "%s: 'CKAID' calculation failed\n", me); exit(1); } hex_ckaid = strdup(conv(ckaid->data, ckaid->len, 16)); SECITEM_FreeItem(ckaid, PR_TRUE); } /*privkey->wincx = &pwdata;*/ PORT_Assert(pubkey != NULL); fprintf(stderr, "Generated RSA key pair with CKAID %s was stored in the NSS database\n", hex_ckaid); /* and the output */ report("output...\n"); /* deliberate extra newline */ printf("\t# RSA %d bits %s %s", nbits, outputhostname, ctime(&now.real_secs)); /* ctime provides \n */ printf("\t# for signatures only, UNSAFE FOR ENCRYPTION\n"); printf("\t#ckaid=%s\n", hex_ckaid); /* RFC2537/RFC3110-ish format */ { char *bundle = base64_bundle(E, public_modulus); printf("\t#pubkey=%s\n", bundle); pfree(bundle); } printf("\tModulus: 0x%s\n", conv(public_modulus.ptr, public_modulus.len, 16)); printf("\tPublicExponent: 0x%s\n", conv(public_exponent.ptr, public_exponent.len, 16)); if (hex_ckaid != NULL) free(hex_ckaid); if (privkey != NULL) SECKEY_DestroyPrivateKey(privkey); if (pubkey != NULL) SECKEY_DestroyPublicKey(pubkey); lsw_nss_shutdown(LSW_NSS_CLEANUP); } /* * getrandom - get some random bytes from /dev/random (or wherever) * NOTE: This is only used for additional seeding of the NSS RNG */ void getrandom(size_t nbytes, unsigned char *buf) { size_t ndone; int dev; ssize_t got; dev = open(device, 0); if (dev < 0) { fprintf(stderr, "%s: could not open %s (%s)\n", me, device, strerror(errno)); exit(1); } ndone = 0; if (verbose) { fprintf(stderr, "getting %d random seed bytes for NSS from %s...\n", (int) nbytes * BITS_PER_BYTE, device); } while (ndone < nbytes) { got = read(dev, buf + ndone, nbytes - ndone); if (got < 0) { fprintf(stderr, "%s: read error on %s (%s)\n", me, device, strerror(errno)); exit(1); } if (got == 0) { fprintf(stderr, "%s: eof on %s!?!\n", me, device); exit(1); } ndone += got; } close(dev); } /* - conv - convert bits to output in specified datatot format * NOTE: result points into a STATIC buffer */ static const char *conv(const unsigned char *bits, size_t nbytes, int format) { static char convbuf[MAXBITS / 4 + 50]; /* enough for hex */ size_t n; n = datatot(bits, nbytes, format, convbuf, sizeof(convbuf)); if (n == 0) { fprintf(stderr, "%s: can't-happen convert error\n", me); exit(1); } if (n > sizeof(convbuf)) { fprintf(stderr, "%s: can't-happen convert overflow (need %d)\n", me, (int) n); exit(1); } return convbuf; } /* - report - report progress, if indicated */ void report(msg) char *msg; { if (!verbose) return; fprintf(stderr, "%s\n", msg); }
// nsPKCS12Blob::ExportToFile // // Having already loaded the certs, form them into a blob (loading the keys // also), encode the blob, and stuff it into the file. // // TODO: handle slots correctly // mirror "slotToUse" behavior from PSM 1.x // verify the cert array to start off with? // open output file as nsIFileStream object? // set appropriate error codes nsresult nsPKCS12Blob::ExportToFile(nsILocalFile *file, nsIX509Cert **certs, int numCerts) { nsNSSShutDownPreventionLock locker; nsresult rv; SECStatus srv = SECSuccess; SEC_PKCS12ExportContext *ecx = NULL; SEC_PKCS12SafeInfo *certSafe = NULL, *keySafe = NULL; SECItem unicodePw; nsAutoString filePath; int i; nsCOMPtr<nsILocalFile> localFileRef; NS_ASSERTION(mToken, "Need to set the token before exporting"); // init slot bool InformedUserNoSmartcardBackup = false; int numCertsExported = 0; rv = mToken->Login(true); if (NS_FAILED(rv)) goto finish; // get file password (unicode) unicodePw.data = NULL; rv = newPKCS12FilePassword(&unicodePw); if (NS_FAILED(rv)) goto finish; if (unicodePw.data == NULL) { handleError(PIP_PKCS12_USER_CANCELED); return NS_OK; } // what about slotToUse in psm 1.x ??? // create export context ecx = SEC_PKCS12CreateExportContext(NULL, NULL, NULL /*slot*/, NULL); if (!ecx) { srv = SECFailure; goto finish; } // add password integrity srv = SEC_PKCS12AddPasswordIntegrity(ecx, &unicodePw, SEC_OID_SHA1); if (srv) goto finish; #if 0 // count the number of certs to export nrv = mCertArray->Count(&numCerts); if (NS_FAILED(nrv)) goto finish; // loop over the certs for (i=0; i<numCerts; i++) { nsCOMPtr<nsIX509Cert> cert; nrv = mCertArray->GetElementAt(i, getter_AddRefs(cert)); if (NS_FAILED(nrv)) goto finish; #endif for (i=0; i<numCerts; i++) { // nsNSSCertificate *cert = reinterpret_cast<nsNSSCertificate *>(certs[i]); nsNSSCertificate *cert = (nsNSSCertificate *)certs[i]; // get it as a CERTCertificate XXX CERTCertificate *nssCert = NULL; CERTCertificateCleaner nssCertCleaner(nssCert); nssCert = cert->GetCert(); if (!nssCert) { rv = NS_ERROR_FAILURE; goto finish; } // We can only successfully export certs that are on // internal token. Most, if not all, smart card vendors // won't let you extract the private key (in any way // shape or form) from the card. So let's punt if // the cert is not in the internal db. if (nssCert->slot && !PK11_IsInternal(nssCert->slot)) { // we aren't the internal token, see if the key is extractable. SECKEYPrivateKey *privKey=PK11_FindKeyByDERCert(nssCert->slot, nssCert, this); if (privKey) { bool privKeyIsExtractable = isExtractable(privKey); SECKEY_DestroyPrivateKey(privKey); if (!privKeyIsExtractable) { if (!InformedUserNoSmartcardBackup) { InformedUserNoSmartcardBackup = true; handleError(PIP_PKCS12_NOSMARTCARD_EXPORT); } continue; } } } // XXX this is why, to verify the slot is the same // PK11_FindObjectForCert(nssCert, NULL, slot); // create the cert and key safes keySafe = SEC_PKCS12CreateUnencryptedSafe(ecx); if (!SEC_PKCS12IsEncryptionAllowed() || PK11_IsFIPS()) { certSafe = keySafe; } else { certSafe = SEC_PKCS12CreatePasswordPrivSafe(ecx, &unicodePw, SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC); } if (!certSafe || !keySafe) { rv = NS_ERROR_FAILURE; goto finish; } // add the cert and key to the blob srv = SEC_PKCS12AddCertAndKey(ecx, certSafe, NULL, nssCert, CERT_GetDefaultCertDB(), // XXX keySafe, NULL, true, &unicodePw, SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC); if (srv) goto finish; // cert was dup'ed, so release it ++numCertsExported; } if (!numCertsExported) goto finish; // prepare the instance to write to an export file this->mTmpFile = NULL; file->GetPath(filePath); // Use the nsCOMPtr var localFileRef so that // the reference to the nsILocalFile we create gets released as soon as // we're out of scope, ie when this function exits. if (filePath.RFind(".p12", true, -1, 4) < 0) { // We're going to add the .p12 extension to the file name just like // Communicator used to. We create a new nsILocalFile and initialize // it with the new patch. filePath.AppendLiteral(".p12"); localFileRef = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); if (NS_FAILED(rv)) goto finish; localFileRef->InitWithPath(filePath); file = localFileRef; } rv = file->OpenNSPRFileDesc(PR_RDWR|PR_CREATE_FILE|PR_TRUNCATE, 0664, &mTmpFile); if (NS_FAILED(rv) || !this->mTmpFile) goto finish; // encode and write srv = SEC_PKCS12Encode(ecx, write_export_file, this); if (srv) goto finish; handleError(PIP_PKCS12_BACKUP_OK); finish: if (NS_FAILED(rv) || srv != SECSuccess) { handleError(PIP_PKCS12_BACKUP_FAILED); } if (ecx) SEC_PKCS12DestroyExportContext(ecx); if (this->mTmpFile) { PR_Close(this->mTmpFile); this->mTmpFile = NULL; } SECITEM_ZfreeItem(&unicodePw, false); return rv; } /////////////////////////////////////////////////////////////////////// // // private members // /////////////////////////////////////////////////////////////////////// // unicodeToItem // // For the NSS PKCS#12 library, must convert PRUnichars (shorts) to // a buffer of octets. Must handle byte order correctly. // TODO: Is there a mozilla way to do this? In the string lib? void nsPKCS12Blob::unicodeToItem(const PRUnichar *uni, SECItem *item) { int len = 0; while (uni[len++] != 0); SECITEM_AllocItem(NULL, item, sizeof(PRUnichar) * len); #ifdef IS_LITTLE_ENDIAN int i = 0; for (i=0; i<len; i++) { item->data[2*i ] = (unsigned char )(uni[i] << 8); item->data[2*i+1] = (unsigned char )(uni[i]); } #else memcpy(item->data, uni, item->len); #endif }
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; }
void nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert, nsIInterfaceRequestor* ctx, nsCString &nickname) { nickname.Truncate(); nsNSSShutDownPreventionLock locker; nsresult rv; CK_OBJECT_HANDLE keyHandle; CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB(); nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); if (NS_FAILED(rv)) return; nsCAutoString username; char *temp_un = CERT_GetCommonName(&cert->subject); if (temp_un) { username = temp_un; PORT_Free(temp_un); temp_un = nsnull; } nsCAutoString caname; char *temp_ca = CERT_GetOrgName(&cert->issuer); if (temp_ca) { caname = temp_ca; PORT_Free(temp_ca); temp_ca = nsnull; } nsAutoString tmpNickFmt; nssComponent->GetPIPNSSBundleString("nick_template", tmpNickFmt); NS_ConvertUTF16toUTF8 nickFmt(tmpNickFmt); nsCAutoString baseName; char *temp_nn = PR_smprintf(nickFmt.get(), username.get(), caname.get()); if (!temp_nn) { return; } else { baseName = temp_nn; PR_smprintf_free(temp_nn); temp_nn = nsnull; } nickname = baseName; /* * We need to see if the private key exists on a token, if it does * then we need to check for nicknames that already exist on the smart * card. */ PK11SlotInfo *slot = PK11_KeyForCertExists(cert, &keyHandle, ctx); PK11SlotInfoCleaner slotCleaner(slot); if (!slot) return; if (!PK11_IsInternal(slot)) { char *tmp = PR_smprintf("%s:%s", PK11_GetTokenName(slot), baseName.get()); if (!tmp) { nickname.Truncate(); return; } baseName = tmp; PR_smprintf_free(tmp); nickname = baseName; } int count = 1; while (true) { if ( count > 1 ) { char *tmp = PR_smprintf("%s #%d", baseName.get(), count); if (!tmp) { nickname.Truncate(); return; } nickname = tmp; PR_smprintf_free(tmp); } CERTCertificate *dummycert = nsnull; CERTCertificateCleaner dummycertCleaner(dummycert); if (PK11_IsInternal(slot)) { /* look up the nickname to make sure it isn't in use already */ dummycert = CERT_FindCertByNickname(defaultcertdb, nickname.get()); } else { /* * Check the cert against others that already live on the smart * card. */ dummycert = PK11_FindCertFromNickname(nickname.get(), ctx); if (dummycert != NULL) { /* * Make sure the subject names are different. */ if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual) { /* * There is another certificate with the same nickname and * the same subject name on the smart card, so let's use this * nickname. */ CERT_DestroyCertificate(dummycert); dummycert = NULL; } } } if (!dummycert) break; count++; } }
static char * getPin(SVRCOREPinObj *ctx, const char *tokenName, PRBool retry) { SVRCOREFilePinObj *obj = (SVRCOREFilePinObj*)ctx; PK11SlotInfo *slot; int is_internal_token = 0; FILE *pinfile = 0; char *res = 0; /* In really bad situations, where we cannot allocate memory * for a bad PIN list, the entire PIN object is disabled. */ if (obj->disabled) return 0; /* * If the application is retrying the PIN, the one in the file is * probably wrong. It's important that we avoid returning this * PIN to the caller each time, since that will result in disabling * the token. */ { Node *p; for(p = obj->badPinList;p;p = p->next) if (strcmp(p->tokenName, tokenName) == 0) break; if (p) return 0; } /* Mark it as bad (in the hash table) so that we remember * to never return it again. */ if (retry) { Node *ent = 0; do { ent = (Node *)malloc(sizeof (Node)); if (!ent) break; ent->tokenName = strdup(tokenName); if (!ent->tokenName) { free(ent); ent = 0; } } while(0); /* If adding fails, disable the whole object */ if (!ent) { obj->disabled = PR_TRUE; } if (ent) { /* Add to list */ ent->next = obj->badPinList; obj->badPinList = ent; } return 0; } slot = PK11_FindSlotByName((char *)tokenName); if (slot) { is_internal_token = PK11_IsInternal(slot); PK11_FreeSlot(slot); } do { char line[128]; pinfile = fopen(obj->filename, "rt"); if (!pinfile) break; /* Read lines from the file */ while(fgets(line, sizeof line, pinfile)) { char *pin; char *delim; /* Find the ":" */ delim = strchr(line, ':'); if (!delim) continue; /* Terminate name field and skip ";" */ *delim++ = 0; if (strcmp(line, tokenName) == 0 || (is_internal_token && (strcmp(line, "Communicator Certificate DB") == 0 || strcmp(line, "Internal (Software) Token") == 0))) { pin = delim; delim = strchr(pin, '\n'); if (delim) *delim = 0; res = strdup(pin); break; } } /* Clear any sensitive data */ memset(line, 0, sizeof line); } while(0); if (pinfile) fclose(pinfile); return res; }
/* * generate an RSA signature key * * e is fixed at 3, without discussion. That would not be wise if these * keys were to be used for encryption, but for signatures there are some * real speed advantages. * See also: https://www.imperialviolet.org/2012/03/16/rsae.html */ void rsasigkey(int nbits, char *configdir, char *password) { SECStatus rv; PK11RSAGenParams rsaparams = { nbits, (long) E }; secuPWData pwdata = { PW_NONE, NULL }; PK11SlotInfo *slot = NULL; SECKEYPrivateKey *privkey = NULL; SECKEYPublicKey *pubkey = NULL; unsigned char *bundp = NULL; mpz_t n; mpz_t e; size_t bs; char n_str[3 + MAXBITS / 4 + 1]; realtime_t now = realnow(); mpz_init(n); mpz_init(e); if (password == NULL) { pwdata.source = PW_NONE; } else { /* check if passwd == configdir/nsspassword */ size_t cdl = strlen(configdir); size_t pwl = strlen(password); static const char suf[] = "/nsspassword"; if (pwl == cdl + sizeof(suf) - 1 && memeq(password, configdir, cdl) && memeq(password + cdl, suf, sizeof(suf))) pwdata.source = PW_FROMFILE; else pwdata.source = PW_PLAINTEXT; } pwdata.data = password; PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 1); rv = NSS_InitReadWrite(configdir); if (rv != SECSuccess) { fprintf(stderr, "%s: NSS_InitReadWrite(%s) returned %d\n", me, configdir, PR_GetError()); exit(1); } #ifdef FIPS_CHECK if (PK11_IsFIPS() && !FIPSCHECK_verify(NULL, NULL)) { fprintf(stderr, "FIPS HMAC integrity verification test failed.\n"); exit(1); } #endif if (PK11_IsFIPS() && !password) { fprintf(stderr, "%s: On FIPS mode a password is required\n", me); exit(1); } PK11_SetPasswordFunc(GetModulePassword); /* Good for now but someone may want to use a hardware token */ slot = PK11_GetInternalKeySlot(); /* In which case this may be better */ /* slot = PK11_GetBestSlot(CKM_RSA_PKCS_KEY_PAIR_GEN, password ? &pwdata : NULL); */ /* or the user may specify the name of a token. */ #if 0 if (PK11_IsFIPS() || !PK11_IsInternal(slot)) { rv = PK11_Authenticate(slot, PR_FALSE, &pwdata); if (rv != SECSuccess) { fprintf(stderr, "%s: could not authenticate to token '%s'\n", me, PK11_GetTokenName(slot)); return; } } #endif /* 0 */ /* Do some random-number initialization. */ UpdateNSS_RNG(); /* Log in to the token */ if (password) { rv = PK11_Authenticate(slot, PR_FALSE, &pwdata); if (rv != SECSuccess) { fprintf(stderr, "%s: could not authenticate to token '%s'\n", me, PK11_GetTokenName(slot)); return; } } privkey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaparams, &pubkey, PR_TRUE, password ? PR_TRUE : PR_FALSE, &pwdata); /* inTheToken, isSensitive, passwordCallbackFunction */ if (!privkey) { fprintf(stderr, "%s: key pair generation failed: \"%d\"\n", me, PORT_GetError()); return; } /*privkey->wincx = &pwdata;*/ PORT_Assert(pubkey != NULL); fprintf(stderr, "Generated RSA key pair using the NSS database\n"); SECItemToHex(getModulus(pubkey), n_str); assert(!mpz_set_str(n, n_str, 16)); /* and the output */ report("output...\n"); /* deliberate extra newline */ printf("\t# RSA %d bits %s %s", nbits, outputhostname, ctime(&now.real_secs)); /* ctime provides \n */ printf("\t# for signatures only, UNSAFE FOR ENCRYPTION\n"); bundp = bundle(E, n, &bs); printf("\t#pubkey=%s\n", conv(bundp, bs, 's')); /* RFC2537ish format */ printf("\tModulus: %s\n", hexOut(getModulus(pubkey))); printf("\tPublicExponent: %s\n", hexOut(getPublicExponent(pubkey))); SECItem *ckaID = PK11_MakeIDFromPubKey(getModulus(pubkey)); if (ckaID != NULL) { printf("\t# everything after this point is CKA_ID in hex format - not the real values \n"); printf("\tPrivateExponent: %s\n", hexOut(ckaID)); printf("\tPrime1: %s\n", hexOut(ckaID)); printf("\tPrime2: %s\n", hexOut(ckaID)); printf("\tExponent1: %s\n", hexOut(ckaID)); printf("\tExponent2: %s\n", hexOut(ckaID)); printf("\tCoefficient: %s\n", hexOut(ckaID)); printf("\tCKAIDNSS: %s\n", hexOut(ckaID)); SECITEM_FreeItem(ckaID, PR_TRUE); } if (privkey) SECKEY_DestroyPrivateKey(privkey); if (pubkey) SECKEY_DestroyPublicKey(pubkey); (void) NSS_Shutdown(); (void) PR_Cleanup(); }