andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: andre@0: #include "prtime.h" andre@0: andre@0: #include "cert.h" andre@0: #include "certi.h" andre@0: #include "certdb.h" andre@0: #include "secitem.h" andre@0: #include "secder.h" andre@0: andre@0: /* Call to PK11_FreeSlot below */ andre@0: andre@0: #include "secasn1.h" andre@0: #include "secerr.h" andre@0: #include "nssilock.h" andre@0: #include "prmon.h" andre@0: #include "base64.h" andre@0: #include "sechash.h" andre@0: #include "plhash.h" andre@0: #include "pk11func.h" /* sigh */ andre@0: andre@0: #include "nsspki.h" andre@0: #include "pki.h" andre@0: #include "pkim.h" andre@0: #include "pki3hack.h" andre@0: #include "ckhelper.h" andre@0: #include "base.h" andre@0: #include "pkistore.h" andre@0: #include "dev3hack.h" andre@0: #include "dev.h" andre@0: andre@0: PRBool andre@0: SEC_CertNicknameConflict(const char *nickname, const SECItem *derSubject, andre@0: CERTCertDBHandle *handle) andre@0: { andre@0: CERTCertificate *cert; andre@0: PRBool conflict = PR_FALSE; andre@0: andre@0: cert=CERT_FindCertByNickname(handle, nickname); andre@0: andre@0: if (!cert) { andre@0: return conflict; andre@0: } andre@0: andre@0: conflict = !SECITEM_ItemsAreEqual(derSubject,&cert->derSubject); andre@0: CERT_DestroyCertificate(cert); andre@0: return conflict; andre@0: } andre@0: andre@0: SECStatus andre@0: SEC_DeletePermCertificate(CERTCertificate *cert) andre@0: { andre@0: PRStatus nssrv; andre@0: NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); andre@0: NSSCertificate *c = STAN_GetNSSCertificate(cert); andre@0: CERTCertTrust *certTrust; andre@0: andre@0: if (c == NULL) { andre@0: /* error code is set */ andre@0: return SECFailure; andre@0: } andre@0: andre@0: certTrust = nssTrust_GetCERTCertTrustForCert(c, cert); andre@0: if (certTrust) { andre@0: NSSTrust *nssTrust = nssTrustDomain_FindTrustForCertificate(td, c); andre@0: if (nssTrust) { andre@0: nssrv = STAN_DeleteCertTrustMatchingSlot(c); andre@0: if (nssrv != PR_SUCCESS) { andre@0: CERT_MapStanError(); andre@0: } andre@0: /* This call always returns PR_SUCCESS! */ andre@0: (void) nssTrust_Destroy(nssTrust); andre@0: } andre@0: } andre@0: andre@0: /* get rid of the token instances */ andre@0: nssrv = NSSCertificate_DeleteStoredObject(c, NULL); andre@0: andre@0: /* get rid of the cache entry */ andre@0: nssTrustDomain_LockCertCache(td); andre@0: nssTrustDomain_RemoveCertFromCacheLOCKED(td, c); andre@0: nssTrustDomain_UnlockCertCache(td); andre@0: andre@0: return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; andre@0: } andre@0: andre@0: SECStatus andre@0: CERT_GetCertTrust(const CERTCertificate *cert, CERTCertTrust *trust) andre@0: { andre@0: SECStatus rv; andre@0: CERT_LockCertTrust(cert); andre@0: if ( cert->trust == NULL ) { andre@0: rv = SECFailure; andre@0: } else { andre@0: *trust = *cert->trust; andre@0: rv = SECSuccess; andre@0: } andre@0: CERT_UnlockCertTrust(cert); andre@0: return(rv); andre@0: } andre@0: andre@0: extern const NSSError NSS_ERROR_NO_ERROR; andre@0: extern const NSSError NSS_ERROR_INTERNAL_ERROR; andre@0: extern const NSSError NSS_ERROR_NO_MEMORY; andre@0: extern const NSSError NSS_ERROR_INVALID_POINTER; andre@0: extern const NSSError NSS_ERROR_INVALID_ARENA; andre@0: extern const NSSError NSS_ERROR_INVALID_ARENA_MARK; andre@0: extern const NSSError NSS_ERROR_DUPLICATE_POINTER; andre@0: extern const NSSError NSS_ERROR_POINTER_NOT_REGISTERED; andre@0: extern const NSSError NSS_ERROR_TRACKER_NOT_EMPTY; andre@0: extern const NSSError NSS_ERROR_TRACKER_NOT_INITIALIZED; andre@0: extern const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD; andre@0: extern const NSSError NSS_ERROR_VALUE_TOO_LARGE; andre@0: extern const NSSError NSS_ERROR_UNSUPPORTED_TYPE; andre@0: extern const NSSError NSS_ERROR_BUFFER_TOO_SHORT; andre@0: extern const NSSError NSS_ERROR_INVALID_ATOB_CONTEXT; andre@0: extern const NSSError NSS_ERROR_INVALID_BASE64; andre@0: extern const NSSError NSS_ERROR_INVALID_BTOA_CONTEXT; andre@0: extern const NSSError NSS_ERROR_INVALID_ITEM; andre@0: extern const NSSError NSS_ERROR_INVALID_STRING; andre@0: extern const NSSError NSS_ERROR_INVALID_ASN1ENCODER; andre@0: extern const NSSError NSS_ERROR_INVALID_ASN1DECODER; andre@0: extern const NSSError NSS_ERROR_INVALID_BER; andre@0: extern const NSSError NSS_ERROR_INVALID_ATAV; andre@0: extern const NSSError NSS_ERROR_INVALID_ARGUMENT; andre@0: extern const NSSError NSS_ERROR_INVALID_UTF8; andre@0: extern const NSSError NSS_ERROR_INVALID_NSSOID; andre@0: extern const NSSError NSS_ERROR_UNKNOWN_ATTRIBUTE; andre@0: extern const NSSError NSS_ERROR_NOT_FOUND; andre@0: extern const NSSError NSS_ERROR_INVALID_PASSWORD; andre@0: extern const NSSError NSS_ERROR_USER_CANCELED; andre@0: extern const NSSError NSS_ERROR_MAXIMUM_FOUND; andre@0: extern const NSSError NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND; andre@0: extern const NSSError NSS_ERROR_CERTIFICATE_IN_CACHE; andre@0: extern const NSSError NSS_ERROR_HASH_COLLISION; andre@0: extern const NSSError NSS_ERROR_DEVICE_ERROR; andre@0: extern const NSSError NSS_ERROR_INVALID_CERTIFICATE; andre@0: extern const NSSError NSS_ERROR_BUSY; andre@0: extern const NSSError NSS_ERROR_ALREADY_INITIALIZED; andre@0: extern const NSSError NSS_ERROR_PKCS11; andre@0: andre@0: andre@0: /* Look at the stan error stack and map it to NSS 3 errors */ andre@0: #define STAN_MAP_ERROR(x,y) \ andre@0: else if (error == (x)) { \ andre@0: secError = y; \ andre@0: } \ andre@0: andre@0: /* andre@0: * map Stan errors into NSS errors andre@0: * This function examines the stan error stack and automatically sets andre@0: * PORT_SetError(); to the appropriate SEC_ERROR value. andre@0: */ andre@0: void andre@0: CERT_MapStanError() andre@0: { andre@0: PRInt32 *errorStack; andre@0: NSSError error, prevError; andre@0: int secError; andre@0: int i; andre@0: andre@0: error = 0; andre@0: andre@0: errorStack = NSS_GetErrorStack(); andre@0: if (errorStack == 0) { andre@0: PORT_SetError(0); andre@0: return; andre@0: } andre@0: error = prevError = CKR_GENERAL_ERROR; andre@0: /* get the 'top 2' error codes from the stack */ andre@0: for (i=0; errorStack[i]; i++) { andre@0: prevError = error; andre@0: error = errorStack[i]; andre@0: } andre@0: if (error == NSS_ERROR_PKCS11) { andre@0: /* map it */ andre@0: secError = PK11_MapError(prevError); andre@0: } andre@0: STAN_MAP_ERROR(NSS_ERROR_NO_ERROR, 0) andre@0: STAN_MAP_ERROR(NSS_ERROR_NO_MEMORY, SEC_ERROR_NO_MEMORY) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_BASE64, SEC_ERROR_BAD_DATA) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_BER, SEC_ERROR_BAD_DER) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_ATAV, SEC_ERROR_INVALID_AVA) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_PASSWORD,SEC_ERROR_BAD_PASSWORD) andre@0: STAN_MAP_ERROR(NSS_ERROR_BUSY, SEC_ERROR_BUSY) andre@0: STAN_MAP_ERROR(NSS_ERROR_DEVICE_ERROR, SEC_ERROR_IO) andre@0: STAN_MAP_ERROR(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND, andre@0: SEC_ERROR_UNKNOWN_ISSUER) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_CERTIFICATE, SEC_ERROR_CERT_NOT_VALID) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_UTF8, SEC_ERROR_BAD_DATA) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_NSSOID, SEC_ERROR_BAD_DATA) andre@0: andre@0: /* these are library failure for lack of a better error code */ andre@0: STAN_MAP_ERROR(NSS_ERROR_NOT_FOUND, SEC_ERROR_LIBRARY_FAILURE) andre@0: STAN_MAP_ERROR(NSS_ERROR_CERTIFICATE_IN_CACHE, andre@0: SEC_ERROR_LIBRARY_FAILURE) andre@0: STAN_MAP_ERROR(NSS_ERROR_MAXIMUM_FOUND, SEC_ERROR_LIBRARY_FAILURE) andre@0: STAN_MAP_ERROR(NSS_ERROR_USER_CANCELED, SEC_ERROR_LIBRARY_FAILURE) andre@0: STAN_MAP_ERROR(NSS_ERROR_TRACKER_NOT_INITIALIZED, andre@0: SEC_ERROR_LIBRARY_FAILURE) andre@0: STAN_MAP_ERROR(NSS_ERROR_ALREADY_INITIALIZED, SEC_ERROR_LIBRARY_FAILURE) andre@0: STAN_MAP_ERROR(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD, andre@0: SEC_ERROR_LIBRARY_FAILURE) andre@0: STAN_MAP_ERROR(NSS_ERROR_HASH_COLLISION, SEC_ERROR_LIBRARY_FAILURE) andre@0: andre@0: STAN_MAP_ERROR(NSS_ERROR_INTERNAL_ERROR, SEC_ERROR_LIBRARY_FAILURE) andre@0: andre@0: /* these are all invalid arguments */ andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_ARGUMENT, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_POINTER, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_ARENA, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_ARENA_MARK, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_DUPLICATE_POINTER, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_POINTER_NOT_REGISTERED, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_TRACKER_NOT_EMPTY, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_VALUE_TOO_LARGE, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_UNSUPPORTED_TYPE, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_BUFFER_TOO_SHORT, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_ATOB_CONTEXT, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_BTOA_CONTEXT, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_ITEM, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_STRING, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_ASN1ENCODER, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_INVALID_ASN1DECODER, SEC_ERROR_INVALID_ARGS) andre@0: STAN_MAP_ERROR(NSS_ERROR_UNKNOWN_ATTRIBUTE, SEC_ERROR_INVALID_ARGS) andre@0: else { andre@0: secError = SEC_ERROR_LIBRARY_FAILURE; andre@0: } andre@0: PORT_SetError(secError); andre@0: } andre@0: andre@0: andre@0: andre@0: SECStatus andre@0: CERT_ChangeCertTrust(CERTCertDBHandle *handle, CERTCertificate *cert, andre@0: CERTCertTrust *trust) andre@0: { andre@0: SECStatus rv = SECSuccess; andre@0: PRStatus ret; andre@0: andre@0: ret = STAN_ChangeCertTrust(cert, trust); andre@0: if (ret != PR_SUCCESS) { andre@0: rv = SECFailure; andre@0: CERT_MapStanError(); andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: extern const NSSError NSS_ERROR_INVALID_CERTIFICATE; andre@0: andre@0: SECStatus andre@0: __CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname, andre@0: CERTCertTrust *trust) andre@0: { andre@0: NSSUTF8 *stanNick; andre@0: PK11SlotInfo *slot; andre@0: NSSToken *internal; andre@0: NSSCryptoContext *context; andre@0: nssCryptokiObject *permInstance; andre@0: NSSCertificate *c = STAN_GetNSSCertificate(cert); andre@0: nssCertificateStoreTrace lockTrace = {NULL, NULL, PR_FALSE, PR_FALSE}; andre@0: nssCertificateStoreTrace unlockTrace = {NULL, NULL, PR_FALSE, PR_FALSE}; andre@0: SECStatus rv; andre@0: PRStatus ret; andre@0: andre@0: if (c == NULL) { andre@0: CERT_MapStanError(); andre@0: return SECFailure; andre@0: } andre@0: andre@0: context = c->object.cryptoContext; andre@0: if (!context) { andre@0: PORT_SetError(SEC_ERROR_ADDING_CERT); andre@0: return SECFailure; /* wasn't a temp cert */ andre@0: } andre@0: stanNick = nssCertificate_GetNickname(c, NULL); andre@0: if (stanNick && nickname && strcmp(nickname, stanNick) != 0) { andre@0: /* different: take the new nickname */ andre@0: cert->nickname = NULL; andre@0: nss_ZFreeIf(stanNick); andre@0: stanNick = NULL; andre@0: } andre@0: if (!stanNick && nickname) { andre@0: /* Either there was no nickname yet, or we have a new nickname */ andre@0: stanNick = nssUTF8_Duplicate((NSSUTF8 *)nickname, NULL); andre@0: } /* else: old stanNick is identical to new nickname */ andre@0: /* Delete the temp instance */ andre@0: nssCertificateStore_Lock(context->certStore, &lockTrace); andre@0: nssCertificateStore_RemoveCertLOCKED(context->certStore, c); andre@0: nssCertificateStore_Unlock(context->certStore, &lockTrace, &unlockTrace); andre@0: c->object.cryptoContext = NULL; andre@0: /* Import the perm instance onto the internal token */ andre@0: slot = PK11_GetInternalKeySlot(); andre@0: internal = PK11Slot_GetNSSToken(slot); andre@0: permInstance = nssToken_ImportCertificate(internal, NULL, andre@0: NSSCertificateType_PKIX, andre@0: &c->id, andre@0: stanNick, andre@0: &c->encoding, andre@0: &c->issuer, andre@0: &c->subject, andre@0: &c->serial, andre@0: cert->emailAddr, andre@0: PR_TRUE); andre@0: nss_ZFreeIf(stanNick); andre@0: stanNick = NULL; andre@0: PK11_FreeSlot(slot); andre@0: if (!permInstance) { andre@0: if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) { andre@0: PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL); andre@0: } andre@0: return SECFailure; andre@0: } andre@0: nssPKIObject_AddInstance(&c->object, permInstance); andre@0: nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1); andre@0: /* reset the CERTCertificate fields */ andre@0: cert->nssCertificate = NULL; andre@0: cert = STAN_GetCERTCertificateOrRelease(c); /* should return same pointer */ andre@0: if (!cert) { andre@0: CERT_MapStanError(); andre@0: return SECFailure; andre@0: } andre@0: cert->istemp = PR_FALSE; andre@0: cert->isperm = PR_TRUE; andre@0: if (!trust) { andre@0: return SECSuccess; andre@0: } andre@0: ret = STAN_ChangeCertTrust(cert, trust); andre@0: rv = SECSuccess; andre@0: if (ret != PR_SUCCESS) { andre@0: rv = SECFailure; andre@0: CERT_MapStanError(); andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: SECStatus andre@0: CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname, andre@0: CERTCertTrust *trust) andre@0: { andre@0: return __CERT_AddTempCertToPerm(cert, nickname, trust); andre@0: } andre@0: andre@0: CERTCertificate * andre@0: CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert, andre@0: char *nickname, PRBool isperm, PRBool copyDER) andre@0: { andre@0: NSSCertificate *c; andre@0: CERTCertificate *cc; andre@0: NSSCertificate *tempCert = NULL; andre@0: nssPKIObject *pkio; andre@0: NSSCryptoContext *gCC = STAN_GetDefaultCryptoContext(); andre@0: NSSTrustDomain *gTD = STAN_GetDefaultTrustDomain(); andre@0: if (!isperm) { andre@0: NSSDER encoding; andre@0: NSSITEM_FROM_SECITEM(&encoding, derCert); andre@0: /* First, see if it is already a temp cert */ andre@0: c = NSSCryptoContext_FindCertificateByEncodedCertificate(gCC, andre@0: &encoding); andre@0: if (!c) { andre@0: /* Then, see if it is already a perm cert */ andre@0: c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle, andre@0: &encoding); andre@0: } andre@0: if (c) { andre@0: /* actually, that search ends up going by issuer/serial, andre@0: * so it is still possible to return a cert with the same andre@0: * issuer/serial but a different encoding, and we're andre@0: * going to reject that andre@0: */ andre@0: if (!nssItem_Equal(&c->encoding, &encoding, NULL)) { andre@0: nssCertificate_Destroy(c); andre@0: PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL); andre@0: cc = NULL; andre@0: } else { andre@0: cc = STAN_GetCERTCertificateOrRelease(c); andre@0: if (cc == NULL) { andre@0: CERT_MapStanError(); andre@0: } andre@0: } andre@0: return cc; andre@0: } andre@0: } andre@0: pkio = nssPKIObject_Create(NULL, NULL, gTD, gCC, nssPKIMonitor); andre@0: if (!pkio) { andre@0: CERT_MapStanError(); andre@0: return NULL; andre@0: } andre@0: c = nss_ZNEW(pkio->arena, NSSCertificate); andre@0: if (!c) { andre@0: CERT_MapStanError(); andre@0: nssPKIObject_Destroy(pkio); andre@0: return NULL; andre@0: } andre@0: c->object = *pkio; andre@0: if (copyDER) { andre@0: nssItem_Create(c->object.arena, &c->encoding, andre@0: derCert->len, derCert->data); andre@0: } else { andre@0: NSSITEM_FROM_SECITEM(&c->encoding, derCert); andre@0: } andre@0: /* Forces a decoding of the cert in order to obtain the parts used andre@0: * below andre@0: */ andre@0: /* 'c' is not adopted here, if we fail loser frees what has been andre@0: * allocated so far for 'c' */ andre@0: cc = STAN_GetCERTCertificate(c); andre@0: if (!cc) { andre@0: CERT_MapStanError(); andre@0: goto loser; andre@0: } andre@0: nssItem_Create(c->object.arena, andre@0: &c->issuer, cc->derIssuer.len, cc->derIssuer.data); andre@0: nssItem_Create(c->object.arena, andre@0: &c->subject, cc->derSubject.len, cc->derSubject.data); andre@0: if (PR_TRUE) { andre@0: /* CERTCertificate stores serial numbers decoded. I need the DER andre@0: * here. sigh. andre@0: */ andre@0: SECItem derSerial = { 0 }; andre@0: CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial); andre@0: if (!derSerial.data) goto loser; andre@0: nssItem_Create(c->object.arena, &c->serial, derSerial.len, derSerial.data); andre@0: PORT_Free(derSerial.data); andre@0: } andre@0: if (nickname) { andre@0: c->object.tempName = nssUTF8_Create(c->object.arena, andre@0: nssStringType_UTF8String, andre@0: (NSSUTF8 *)nickname, andre@0: PORT_Strlen(nickname)); andre@0: } andre@0: if (cc->emailAddr && cc->emailAddr[0]) { andre@0: c->email = nssUTF8_Create(c->object.arena, andre@0: nssStringType_PrintableString, andre@0: (NSSUTF8 *)cc->emailAddr, andre@0: PORT_Strlen(cc->emailAddr)); andre@0: } andre@0: andre@0: tempCert = NSSCryptoContext_FindOrImportCertificate(gCC, c); andre@0: if (!tempCert) { andre@0: CERT_MapStanError(); andre@0: goto loser; andre@0: } andre@0: /* destroy our copy */ andre@0: NSSCertificate_Destroy(c); andre@0: /* and use the stored entry */ andre@0: c = tempCert; andre@0: cc = STAN_GetCERTCertificateOrRelease(c); andre@0: if (!cc) { andre@0: /* STAN_GetCERTCertificateOrRelease destroys c on failure. */ andre@0: CERT_MapStanError(); andre@0: return NULL; andre@0: } andre@0: andre@0: cc->istemp = PR_TRUE; andre@0: cc->isperm = PR_FALSE; andre@0: return cc; andre@0: loser: andre@0: /* Perhaps this should be nssCertificate_Destroy(c) */ andre@0: nssPKIObject_Destroy(&c->object); andre@0: return NULL; andre@0: } andre@0: andre@0: /* This symbol is exported for backward compatibility. */ andre@0: CERTCertificate * andre@0: __CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert, andre@0: char *nickname, PRBool isperm, PRBool copyDER) andre@0: { andre@0: return CERT_NewTempCertificate(handle, derCert, nickname, andre@0: isperm, copyDER); andre@0: } andre@0: andre@0: /* maybe all the wincx's should be some const for internal token login? */ andre@0: CERTCertificate * andre@0: CERT_FindCertByIssuerAndSN(CERTCertDBHandle *handle, CERTIssuerAndSN *issuerAndSN) andre@0: { andre@0: PK11SlotInfo *slot; andre@0: CERTCertificate *cert; andre@0: andre@0: cert = PK11_FindCertByIssuerAndSN(&slot,issuerAndSN,NULL); andre@0: if (cert && slot) { andre@0: PK11_FreeSlot(slot); andre@0: } andre@0: andre@0: return cert; andre@0: } andre@0: andre@0: static NSSCertificate * andre@0: get_best_temp_or_perm(NSSCertificate *ct, NSSCertificate *cp) andre@0: { andre@0: NSSUsage usage; andre@0: NSSCertificate *arr[3]; andre@0: if (!ct) { andre@0: return nssCertificate_AddRef(cp); andre@0: } else if (!cp) { andre@0: return nssCertificate_AddRef(ct); andre@0: } andre@0: arr[0] = ct; andre@0: arr[1] = cp; andre@0: arr[2] = NULL; andre@0: usage.anyUsage = PR_TRUE; andre@0: return nssCertificateArray_FindBestCertificate(arr, NULL, &usage, NULL); andre@0: } andre@0: andre@0: CERTCertificate * andre@0: CERT_FindCertByName(CERTCertDBHandle *handle, SECItem *name) andre@0: { andre@0: NSSCertificate *cp, *ct, *c; andre@0: NSSDER subject; andre@0: NSSUsage usage; andre@0: NSSCryptoContext *cc; andre@0: NSSITEM_FROM_SECITEM(&subject, name); andre@0: usage.anyUsage = PR_TRUE; andre@0: cc = STAN_GetDefaultCryptoContext(); andre@0: ct = NSSCryptoContext_FindBestCertificateBySubject(cc, &subject, andre@0: NULL, &usage, NULL); andre@0: cp = NSSTrustDomain_FindBestCertificateBySubject(handle, &subject, andre@0: NULL, &usage, NULL); andre@0: c = get_best_temp_or_perm(ct, cp); andre@0: if (ct) { andre@0: CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); andre@0: } andre@0: if (cp) { andre@0: CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(cp)); andre@0: } andre@0: return c ? STAN_GetCERTCertificateOrRelease(c) : NULL; andre@0: } andre@0: andre@0: CERTCertificate * andre@0: CERT_FindCertByKeyID(CERTCertDBHandle *handle, SECItem *name, SECItem *keyID) andre@0: { andre@0: CERTCertList *list; andre@0: CERTCertificate *cert = NULL; andre@0: CERTCertListNode *node, *head; andre@0: andre@0: list = CERT_CreateSubjectCertList(NULL,handle,name,0,PR_FALSE); andre@0: if (list == NULL) return NULL; andre@0: andre@0: node = head = CERT_LIST_HEAD(list); andre@0: if (head) { andre@0: do { andre@0: if (node->cert && andre@0: SECITEM_ItemsAreEqual(&node->cert->subjectKeyID, keyID) ) { andre@0: cert = CERT_DupCertificate(node->cert); andre@0: goto done; andre@0: } andre@0: node = CERT_LIST_NEXT(node); andre@0: } while (node && head != node); andre@0: } andre@0: PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); andre@0: done: andre@0: if (list) { andre@0: CERT_DestroyCertList(list); andre@0: } andre@0: return cert; andre@0: } andre@0: andre@0: CERTCertificate * andre@0: CERT_FindCertByNickname(CERTCertDBHandle *handle, const char *nickname) andre@0: { andre@0: NSSCryptoContext *cc; andre@0: NSSCertificate *c, *ct; andre@0: CERTCertificate *cert; andre@0: NSSUsage usage; andre@0: usage.anyUsage = PR_TRUE; andre@0: cc = STAN_GetDefaultCryptoContext(); andre@0: ct = NSSCryptoContext_FindBestCertificateByNickname(cc, nickname, andre@0: NULL, &usage, NULL); andre@0: cert = PK11_FindCertFromNickname(nickname, NULL); andre@0: c = NULL; andre@0: if (cert) { andre@0: c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert)); andre@0: CERT_DestroyCertificate(cert); andre@0: if (ct) { andre@0: CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); andre@0: } andre@0: } else { andre@0: c = ct; andre@0: } andre@0: return c ? STAN_GetCERTCertificateOrRelease(c) : NULL; andre@0: } andre@0: andre@0: CERTCertificate * andre@0: CERT_FindCertByDERCert(CERTCertDBHandle *handle, SECItem *derCert) andre@0: { andre@0: NSSCryptoContext *cc; andre@0: NSSCertificate *c; andre@0: NSSDER encoding; andre@0: NSSITEM_FROM_SECITEM(&encoding, derCert); andre@0: cc = STAN_GetDefaultCryptoContext(); andre@0: c = NSSCryptoContext_FindCertificateByEncodedCertificate(cc, &encoding); andre@0: if (!c) { andre@0: c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle, andre@0: &encoding); andre@0: if (!c) return NULL; andre@0: } andre@0: return STAN_GetCERTCertificateOrRelease(c); andre@0: } andre@0: andre@0: static CERTCertificate * andre@0: common_FindCertByNicknameOrEmailAddrForUsage(CERTCertDBHandle *handle, andre@0: const char *name, andre@0: PRBool anyUsage, andre@0: SECCertUsage lookingForUsage) andre@0: { andre@0: NSSCryptoContext *cc; andre@0: NSSCertificate *c, *ct; andre@0: CERTCertificate *cert = NULL; andre@0: NSSUsage usage; andre@0: CERTCertList *certlist; andre@0: andre@0: if (NULL == name) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: andre@0: usage.anyUsage = anyUsage; andre@0: andre@0: if (!anyUsage) { andre@0: usage.nss3lookingForCA = PR_FALSE; andre@0: usage.nss3usage = lookingForUsage; andre@0: } andre@0: andre@0: cc = STAN_GetDefaultCryptoContext(); andre@0: ct = NSSCryptoContext_FindBestCertificateByNickname(cc, name, andre@0: NULL, &usage, NULL); andre@0: if (!ct && PORT_Strchr(name, '@') != NULL) { andre@0: char* lowercaseName = CERT_FixupEmailAddr(name); andre@0: if (lowercaseName) { andre@0: ct = NSSCryptoContext_FindBestCertificateByEmail(cc, lowercaseName, andre@0: NULL, &usage, NULL); andre@0: PORT_Free(lowercaseName); andre@0: } andre@0: } andre@0: andre@0: if (anyUsage) { andre@0: cert = PK11_FindCertFromNickname(name, NULL); andre@0: } andre@0: else { andre@0: if (ct) { andre@0: /* Does ct really have the required usage? */ andre@0: nssDecodedCert *dc; andre@0: dc = nssCertificate_GetDecoding(ct); andre@0: if (!dc->matchUsage(dc, &usage)) { andre@0: CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); andre@0: ct = NULL; andre@0: } andre@0: } andre@0: andre@0: certlist = PK11_FindCertsFromNickname(name, NULL); andre@0: if (certlist) { andre@0: SECStatus rv = CERT_FilterCertListByUsage(certlist, andre@0: lookingForUsage, andre@0: PR_FALSE); andre@0: if (SECSuccess == rv && andre@0: !CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist)) { andre@0: cert = CERT_DupCertificate(CERT_LIST_HEAD(certlist)->cert); andre@0: } andre@0: CERT_DestroyCertList(certlist); andre@0: } andre@0: } andre@0: andre@0: if (cert) { andre@0: c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert)); andre@0: CERT_DestroyCertificate(cert); andre@0: if (ct) { andre@0: CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); andre@0: } andre@0: } else { andre@0: c = ct; andre@0: } andre@0: return c ? STAN_GetCERTCertificateOrRelease(c) : NULL; andre@0: } andre@0: andre@0: CERTCertificate * andre@0: CERT_FindCertByNicknameOrEmailAddr(CERTCertDBHandle *handle, const char *name) andre@0: { andre@0: return common_FindCertByNicknameOrEmailAddrForUsage(handle, name, andre@0: PR_TRUE, 0); andre@0: } andre@0: andre@0: CERTCertificate * andre@0: CERT_FindCertByNicknameOrEmailAddrForUsage(CERTCertDBHandle *handle, andre@0: const char *name, andre@0: SECCertUsage lookingForUsage) andre@0: { andre@0: return common_FindCertByNicknameOrEmailAddrForUsage(handle, name, andre@0: PR_FALSE, andre@0: lookingForUsage); andre@0: } andre@0: andre@0: static void andre@0: add_to_subject_list(CERTCertList *certList, CERTCertificate *cert, andre@0: PRBool validOnly, PRTime sorttime) andre@0: { andre@0: SECStatus secrv; andre@0: if (!validOnly || andre@0: CERT_CheckCertValidTimes(cert, sorttime, PR_FALSE) andre@0: == secCertTimeValid) { andre@0: secrv = CERT_AddCertToListSorted(certList, cert, andre@0: CERT_SortCBValidity, andre@0: (void *)&sorttime); andre@0: if (secrv != SECSuccess) { andre@0: CERT_DestroyCertificate(cert); andre@0: } andre@0: } else { andre@0: CERT_DestroyCertificate(cert); andre@0: } andre@0: } andre@0: andre@0: CERTCertList * andre@0: CERT_CreateSubjectCertList(CERTCertList *certList, CERTCertDBHandle *handle, andre@0: const SECItem *name, PRTime sorttime, andre@0: PRBool validOnly) andre@0: { andre@0: NSSCryptoContext *cc; andre@0: NSSCertificate **tSubjectCerts, **pSubjectCerts; andre@0: NSSCertificate **ci; andre@0: CERTCertificate *cert; andre@0: NSSDER subject; andre@0: PRBool myList = PR_FALSE; andre@0: cc = STAN_GetDefaultCryptoContext(); andre@0: NSSITEM_FROM_SECITEM(&subject, name); andre@0: /* Collect both temp and perm certs for the subject */ andre@0: tSubjectCerts = NSSCryptoContext_FindCertificatesBySubject(cc, andre@0: &subject, andre@0: NULL, andre@0: 0, andre@0: NULL); andre@0: pSubjectCerts = NSSTrustDomain_FindCertificatesBySubject(handle, andre@0: &subject, andre@0: NULL, andre@0: 0, andre@0: NULL); andre@0: if (!tSubjectCerts && !pSubjectCerts) { andre@0: return NULL; andre@0: } andre@0: if (certList == NULL) { andre@0: certList = CERT_NewCertList(); andre@0: myList = PR_TRUE; andre@0: if (!certList) goto loser; andre@0: } andre@0: /* Iterate over the matching temp certs. Add them to the list */ andre@0: ci = tSubjectCerts; andre@0: while (ci && *ci) { andre@0: cert = STAN_GetCERTCertificateOrRelease(*ci); andre@0: /* *ci may be invalid at this point, don't reference it again */ andre@0: if (cert) { andre@0: /* NOTE: add_to_subject_list adopts the incoming cert. */ andre@0: add_to_subject_list(certList, cert, validOnly, sorttime); andre@0: } andre@0: ci++; andre@0: } andre@0: /* Iterate over the matching perm certs. Add them to the list */ andre@0: ci = pSubjectCerts; andre@0: while (ci && *ci) { andre@0: cert = STAN_GetCERTCertificateOrRelease(*ci); andre@0: /* *ci may be invalid at this point, don't reference it again */ andre@0: if (cert) { andre@0: /* NOTE: add_to_subject_list adopts the incoming cert. */ andre@0: add_to_subject_list(certList, cert, validOnly, sorttime); andre@0: } andre@0: ci++; andre@0: } andre@0: /* all the references have been adopted or freed at this point, just andre@0: * free the arrays now */ andre@0: nss_ZFreeIf(tSubjectCerts); andre@0: nss_ZFreeIf(pSubjectCerts); andre@0: return certList; andre@0: loser: andre@0: /* need to free the references in tSubjectCerts and pSubjectCerts! */ andre@0: nssCertificateArray_Destroy(tSubjectCerts); andre@0: nssCertificateArray_Destroy(pSubjectCerts); andre@0: if (myList && certList != NULL) { andre@0: CERT_DestroyCertList(certList); andre@0: } andre@0: return NULL; andre@0: } andre@0: andre@0: void andre@0: CERT_DestroyCertificate(CERTCertificate *cert) andre@0: { andre@0: if ( cert ) { andre@0: /* don't use STAN_GetNSSCertificate because we don't want to andre@0: * go to the trouble of translating the CERTCertificate into andre@0: * an NSSCertificate just to destroy it. If it hasn't been done andre@0: * yet, don't do it at all. andre@0: */ andre@0: NSSCertificate *tmp = cert->nssCertificate; andre@0: if (tmp) { andre@0: /* delete the NSSCertificate */ andre@0: NSSCertificate_Destroy(tmp); andre@0: } else if (cert->arena) { andre@0: PORT_FreeArena(cert->arena, PR_FALSE); andre@0: } andre@0: } andre@0: return; andre@0: } andre@0: andre@0: int andre@0: CERT_GetDBContentVersion(CERTCertDBHandle *handle) andre@0: { andre@0: /* should read the DB content version from the pkcs #11 device */ andre@0: return 0; andre@0: } andre@0: andre@0: SECStatus andre@0: certdb_SaveSingleProfile(CERTCertificate *cert, const char *emailAddr, andre@0: SECItem *emailProfile, SECItem *profileTime) andre@0: { andre@0: PRTime oldtime; andre@0: PRTime newtime; andre@0: SECStatus rv = SECFailure; andre@0: PRBool saveit; andre@0: SECItem oldprof, oldproftime; andre@0: SECItem *oldProfile = NULL; andre@0: SECItem *oldProfileTime = NULL; andre@0: PK11SlotInfo *slot = NULL; andre@0: NSSCertificate *c; andre@0: NSSCryptoContext *cc; andre@0: nssSMIMEProfile *stanProfile = NULL; andre@0: PRBool freeOldProfile = PR_FALSE; andre@0: andre@0: c = STAN_GetNSSCertificate(cert); andre@0: if (!c) return SECFailure; andre@0: cc = c->object.cryptoContext; andre@0: if (cc != NULL) { andre@0: stanProfile = nssCryptoContext_FindSMIMEProfileForCertificate(cc, c); andre@0: if (stanProfile) { andre@0: PORT_Assert(stanProfile->profileData); andre@0: SECITEM_FROM_NSSITEM(&oldprof, stanProfile->profileData); andre@0: oldProfile = &oldprof; andre@0: SECITEM_FROM_NSSITEM(&oldproftime, stanProfile->profileTime); andre@0: oldProfileTime = &oldproftime; andre@0: } andre@0: } else { andre@0: oldProfile = PK11_FindSMimeProfile(&slot, (char *)emailAddr, andre@0: &cert->derSubject, &oldProfileTime); andre@0: freeOldProfile = PR_TRUE; andre@0: } andre@0: andre@0: saveit = PR_FALSE; andre@0: andre@0: /* both profileTime and emailProfile have to exist or not exist */ andre@0: if ( emailProfile == NULL ) { andre@0: profileTime = NULL; andre@0: } else if ( profileTime == NULL ) { andre@0: emailProfile = NULL; andre@0: } andre@0: andre@0: if ( oldProfileTime == NULL ) { andre@0: saveit = PR_TRUE; andre@0: } else { andre@0: /* there was already a profile for this email addr */ andre@0: if ( profileTime ) { andre@0: /* we have an old and new profile - save whichever is more recent*/ andre@0: if ( oldProfileTime->len == 0 ) { andre@0: /* always replace if old entry doesn't have a time */ andre@0: oldtime = LL_MININT; andre@0: } else { andre@0: rv = DER_UTCTimeToTime(&oldtime, oldProfileTime); andre@0: if ( rv != SECSuccess ) { andre@0: goto loser; andre@0: } andre@0: } andre@0: andre@0: rv = DER_UTCTimeToTime(&newtime, profileTime); andre@0: if ( rv != SECSuccess ) { andre@0: goto loser; andre@0: } andre@0: andre@0: if ( LL_CMP(newtime, >, oldtime ) ) { andre@0: /* this is a newer profile, save it and cert */ andre@0: saveit = PR_TRUE; andre@0: } andre@0: } else { andre@0: saveit = PR_TRUE; andre@0: } andre@0: } andre@0: andre@0: andre@0: if (saveit) { andre@0: if (cc) { andre@0: if (stanProfile) { andre@0: /* stanProfile is already stored in the crypto context, andre@0: * overwrite the data andre@0: */ andre@0: NSSArena *arena = stanProfile->object.arena; andre@0: stanProfile->profileTime = nssItem_Create(arena, andre@0: NULL, andre@0: profileTime->len, andre@0: profileTime->data); andre@0: stanProfile->profileData = nssItem_Create(arena, andre@0: NULL, andre@0: emailProfile->len, andre@0: emailProfile->data); andre@0: } else if (profileTime && emailProfile) { andre@0: PRStatus nssrv; andre@0: NSSItem profTime, profData; andre@0: NSSITEM_FROM_SECITEM(&profTime, profileTime); andre@0: NSSITEM_FROM_SECITEM(&profData, emailProfile); andre@0: stanProfile = nssSMIMEProfile_Create(c, &profTime, &profData); andre@0: if (!stanProfile) goto loser; andre@0: nssrv = nssCryptoContext_ImportSMIMEProfile(cc, stanProfile); andre@0: rv = (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; andre@0: } andre@0: } else { andre@0: rv = PK11_SaveSMimeProfile(slot, (char *)emailAddr, andre@0: &cert->derSubject, emailProfile, profileTime); andre@0: } andre@0: } else { andre@0: rv = SECSuccess; andre@0: } andre@0: andre@0: loser: andre@0: if (oldProfile && freeOldProfile) { andre@0: SECITEM_FreeItem(oldProfile,PR_TRUE); andre@0: } andre@0: if (oldProfileTime && freeOldProfile) { andre@0: SECITEM_FreeItem(oldProfileTime,PR_TRUE); andre@0: } andre@0: if (stanProfile) { andre@0: nssSMIMEProfile_Destroy(stanProfile); andre@0: } andre@0: if (slot) { andre@0: PK11_FreeSlot(slot); andre@0: } andre@0: andre@0: return(rv); andre@0: } andre@0: andre@0: /* andre@0: * andre@0: * Manage S/MIME profiles andre@0: * andre@0: */ andre@0: andre@0: SECStatus andre@0: CERT_SaveSMimeProfile(CERTCertificate *cert, SECItem *emailProfile, andre@0: SECItem *profileTime) andre@0: { andre@0: const char *emailAddr; andre@0: SECStatus rv; andre@0: andre@0: if (!cert) { andre@0: return SECFailure; andre@0: } andre@0: andre@0: if (cert->slot && !PK11_IsInternal(cert->slot)) { andre@0: /* this cert comes from an external source, we need to add it andre@0: to the cert db before creating an S/MIME profile */ andre@0: PK11SlotInfo* internalslot = PK11_GetInternalKeySlot(); andre@0: if (!internalslot) { andre@0: return SECFailure; andre@0: } andre@0: rv = PK11_ImportCert(internalslot, cert, andre@0: CK_INVALID_HANDLE, NULL, PR_FALSE); andre@0: andre@0: PK11_FreeSlot(internalslot); andre@0: if (rv != SECSuccess ) { andre@0: return SECFailure; andre@0: } andre@0: } andre@0: andre@0: if (cert->slot && cert->isperm && CERT_IsUserCert(cert) && andre@0: (!emailProfile || !emailProfile->len)) { andre@0: /* Don't clobber emailProfile for user certs. */ andre@0: return SECSuccess; andre@0: } andre@0: andre@0: for (emailAddr = CERT_GetFirstEmailAddress(cert); emailAddr != NULL; andre@0: emailAddr = CERT_GetNextEmailAddress(cert,emailAddr)) { andre@0: rv = certdb_SaveSingleProfile(cert,emailAddr,emailProfile,profileTime); andre@0: if (rv != SECSuccess) { andre@0: return SECFailure; andre@0: } andre@0: } andre@0: return SECSuccess; andre@0: andre@0: } andre@0: andre@0: andre@0: SECItem * andre@0: CERT_FindSMimeProfile(CERTCertificate *cert) andre@0: { andre@0: PK11SlotInfo *slot = NULL; andre@0: NSSCertificate *c; andre@0: NSSCryptoContext *cc; andre@0: SECItem *rvItem = NULL; andre@0: andre@0: if (!cert || !cert->emailAddr || !cert->emailAddr[0]) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: c = STAN_GetNSSCertificate(cert); andre@0: if (!c) return NULL; andre@0: cc = c->object.cryptoContext; andre@0: if (cc != NULL) { andre@0: nssSMIMEProfile *stanProfile; andre@0: stanProfile = nssCryptoContext_FindSMIMEProfileForCertificate(cc, c); andre@0: if (stanProfile) { andre@0: rvItem = SECITEM_AllocItem(NULL, NULL, andre@0: stanProfile->profileData->size); andre@0: if (rvItem) { andre@0: rvItem->data = stanProfile->profileData->data; andre@0: } andre@0: nssSMIMEProfile_Destroy(stanProfile); andre@0: } andre@0: return rvItem; andre@0: } andre@0: rvItem = andre@0: PK11_FindSMimeProfile(&slot, cert->emailAddr, &cert->derSubject, NULL); andre@0: if (slot) { andre@0: PK11_FreeSlot(slot); andre@0: } andre@0: return rvItem; andre@0: } andre@0: andre@0: /* andre@0: * deprecated functions that are now just stubs. andre@0: */ andre@0: /* andre@0: * Close the database andre@0: */ andre@0: void andre@0: __CERT_ClosePermCertDB(CERTCertDBHandle *handle) andre@0: { andre@0: PORT_Assert("CERT_ClosePermCertDB is Deprecated" == NULL); andre@0: return; andre@0: } andre@0: andre@0: SECStatus andre@0: CERT_OpenCertDBFilename(CERTCertDBHandle *handle, char *certdbname, andre@0: PRBool readOnly) andre@0: { andre@0: PORT_Assert("CERT_OpenCertDBFilename is Deprecated" == NULL); andre@0: PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); andre@0: return SECFailure; andre@0: } andre@0: andre@0: SECItem * andre@0: SECKEY_HashPassword(char *pw, SECItem *salt) andre@0: { andre@0: PORT_Assert("SECKEY_HashPassword is Deprecated" == NULL); andre@0: PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); andre@0: return NULL; andre@0: } andre@0: andre@0: SECStatus andre@0: __CERT_TraversePermCertsForSubject(CERTCertDBHandle *handle, andre@0: SECItem *derSubject, andre@0: void *cb, void *cbarg) andre@0: { andre@0: PORT_Assert("CERT_TraversePermCertsForSubject is Deprecated" == NULL); andre@0: PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); andre@0: return SECFailure; andre@0: } andre@0: andre@0: andre@0: SECStatus andre@0: __CERT_TraversePermCertsForNickname(CERTCertDBHandle *handle, char *nickname, andre@0: void *cb, void *cbarg) andre@0: { andre@0: PORT_Assert("CERT_TraversePermCertsForNickname is Deprecated" == NULL); andre@0: PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); andre@0: return SECFailure; andre@0: } andre@0: andre@0: andre@0: