SECStatus __CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname, CERTCertTrust *trust) { NSSUTF8 *stanNick; PK11SlotInfo *slot; NSSToken *internal; NSSCryptoContext *context; nssCryptokiObject *permInstance; NSSCertificate *c = STAN_GetNSSCertificate(cert); nssCertificateStoreTrace lockTrace = { NULL, NULL, PR_FALSE, PR_FALSE }; nssCertificateStoreTrace unlockTrace = { NULL, NULL, PR_FALSE, PR_FALSE }; SECStatus rv; PRStatus ret; if (c == NULL) { CERT_MapStanError(); return SECFailure; } context = c->object.cryptoContext; if (!context) { PORT_SetError(SEC_ERROR_ADDING_CERT); return SECFailure; /* wasn't a temp cert */ } stanNick = nssCertificate_GetNickname(c, NULL); if (stanNick && nickname && strcmp(nickname, stanNick) != 0) { /* different: take the new nickname */ cert->nickname = NULL; nss_ZFreeIf(stanNick); stanNick = NULL; } if (!stanNick && nickname) { /* Either there was no nickname yet, or we have a new nickname */ stanNick = nssUTF8_Duplicate((NSSUTF8 *)nickname, NULL); } /* else: old stanNick is identical to new nickname */ /* Delete the temp instance */ nssCertificateStore_Lock(context->certStore, &lockTrace); nssCertificateStore_RemoveCertLOCKED(context->certStore, c); nssCertificateStore_Unlock(context->certStore, &lockTrace, &unlockTrace); c->object.cryptoContext = NULL; /* Import the perm instance onto the internal token */ slot = PK11_GetInternalKeySlot(); internal = PK11Slot_GetNSSToken(slot); permInstance = nssToken_ImportCertificate( internal, NULL, NSSCertificateType_PKIX, &c->id, stanNick, &c->encoding, &c->issuer, &c->subject, &c->serial, cert->emailAddr, PR_TRUE); nss_ZFreeIf(stanNick); stanNick = NULL; PK11_FreeSlot(slot); if (!permInstance) { if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) { PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL); } return SECFailure; } nssPKIObject_AddInstance(&c->object, permInstance); nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1); /* reset the CERTCertificate fields */ cert->nssCertificate = NULL; cert = STAN_GetCERTCertificateOrRelease(c); /* should return same pointer */ if (!cert) { CERT_MapStanError(); return SECFailure; } CERT_LockCertTempPerm(cert); cert->istemp = PR_FALSE; cert->isperm = PR_TRUE; CERT_UnlockCertTempPerm(cert); if (!trust) { return SECSuccess; } ret = STAN_ChangeCertTrust(cert, trust); rv = SECSuccess; if (ret != PR_SUCCESS) { rv = SECFailure; CERT_MapStanError(); } return rv; }
CERTCertificate * CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert, char *nickname, PRBool isperm, PRBool copyDER) { NSSCertificate *c; CERTCertificate *cc; NSSCertificate *tempCert = NULL; nssPKIObject *pkio; NSSCryptoContext *gCC = STAN_GetDefaultCryptoContext(); NSSTrustDomain *gTD = STAN_GetDefaultTrustDomain(); if (!isperm) { NSSDER encoding; NSSITEM_FROM_SECITEM(&encoding, derCert); /* First, see if it is already a temp cert */ c = NSSCryptoContext_FindCertificateByEncodedCertificate(gCC, &encoding); if (!c) { /* Then, see if it is already a perm cert */ c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle, &encoding); } if (c) { /* actually, that search ends up going by issuer/serial, * so it is still possible to return a cert with the same * issuer/serial but a different encoding, and we're * going to reject that */ if (!nssItem_Equal(&c->encoding, &encoding, NULL)) { nssCertificate_Destroy(c); PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL); cc = NULL; } else { cc = STAN_GetCERTCertificateOrRelease(c); if (cc == NULL) { CERT_MapStanError(); } } return cc; } } pkio = nssPKIObject_Create(NULL, NULL, gTD, gCC, nssPKIMonitor); if (!pkio) { CERT_MapStanError(); return NULL; } c = nss_ZNEW(pkio->arena, NSSCertificate); if (!c) { CERT_MapStanError(); nssPKIObject_Destroy(pkio); return NULL; } c->object = *pkio; if (copyDER) { nssItem_Create(c->object.arena, &c->encoding, derCert->len, derCert->data); } else { NSSITEM_FROM_SECITEM(&c->encoding, derCert); } /* Forces a decoding of the cert in order to obtain the parts used * below */ /* 'c' is not adopted here, if we fail loser frees what has been * allocated so far for 'c' */ cc = STAN_GetCERTCertificate(c); if (!cc) { CERT_MapStanError(); goto loser; } nssItem_Create(c->object.arena, &c->issuer, cc->derIssuer.len, cc->derIssuer.data); nssItem_Create(c->object.arena, &c->subject, cc->derSubject.len, cc->derSubject.data); if (PR_TRUE) { /* CERTCertificate stores serial numbers decoded. I need the DER * here. sigh. */ SECItem derSerial = { 0 }; CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial); if (!derSerial.data) goto loser; nssItem_Create(c->object.arena, &c->serial, derSerial.len, derSerial.data); PORT_Free(derSerial.data); } if (nickname) { c->object.tempName = nssUTF8_Create(c->object.arena, nssStringType_UTF8String, (NSSUTF8 *)nickname, PORT_Strlen(nickname)); } if (cc->emailAddr && cc->emailAddr[0]) { c->email = nssUTF8_Create( c->object.arena, nssStringType_PrintableString, (NSSUTF8 *)cc->emailAddr, PORT_Strlen(cc->emailAddr)); } tempCert = NSSCryptoContext_FindOrImportCertificate(gCC, c); if (!tempCert) { CERT_MapStanError(); goto loser; } /* destroy our copy */ NSSCertificate_Destroy(c); /* and use the stored entry */ c = tempCert; cc = STAN_GetCERTCertificateOrRelease(c); if (!cc) { /* STAN_GetCERTCertificateOrRelease destroys c on failure. */ CERT_MapStanError(); return NULL; } CERT_LockCertTempPerm(cc); cc->istemp = PR_TRUE; cc->isperm = PR_FALSE; CERT_UnlockCertTempPerm(cc); return cc; loser: /* Perhaps this should be nssCertificate_Destroy(c) */ nssPKIObject_Destroy(&c->object); return NULL; }
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_IsInternalKeySlot(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) { /* chicken and egg issue: * * c->issuer and c->serial are empty at this point, but * nssTrustDomain_FindTrustForCertificate use them to look up * up the trust object, so we point them to cc->derIssuer and * cc->serialNumber. * * Our caller will fill these in with proper arena copies when we * return. */ c->issuer.data = cc->derIssuer.data; c->issuer.size = cc->derIssuer.len; c->serial.data = cc->serialNumber.data; c->serial.size = cc->serialNumber.len; nssTrust = nssTrustDomain_FindTrustForCertificate(context->td, 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 */ CERT_LockCertTrust(cc); cc->trust = trust; CERT_UnlockCertTrust(cc); } 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 */ CERT_LockCertTrust(cc); cc->trust = trust; CERT_UnlockCertTrust(cc); } } if (instance) { 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 */ CERT_LockCertTempPerm(cc); cc->istemp = PR_FALSE; /* CERT_NewTemp will override this */ cc->isperm = PR_TRUE; /* by default */ CERT_UnlockCertTempPerm(cc); /* 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_ATOMIC_SET((PRInt32 *)&cc->nsCertType, nsCertType); } }