michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: #include "nspr.h" michael@0: #include "secerr.h" michael@0: #include "secasn1.h" michael@0: #include "seccomon.h" michael@0: #include "pk11func.h" michael@0: #include "certdb.h" michael@0: #include "certt.h" michael@0: #include "cert.h" michael@0: #include "certxutl.h" michael@0: michael@0: #include "nsspki.h" michael@0: #include "pki.h" michael@0: #include "pkit.h" michael@0: #include "pkitm.h" michael@0: #include "pki3hack.h" michael@0: michael@0: michael@0: PRBool michael@0: CERT_MatchNickname(char *name1, char *name2) { michael@0: char *nickname1= NULL; michael@0: char *nickname2 = NULL; michael@0: char *token1; michael@0: char *token2; michael@0: char *token = NULL; michael@0: int len; michael@0: michael@0: /* first deal with the straight comparison */ michael@0: if (PORT_Strcmp(name1, name2) == 0) { michael@0: return PR_TRUE; michael@0: } michael@0: /* we need to handle the case where one name has an explicit token and the other michael@0: * doesn't */ michael@0: token1 = PORT_Strchr(name1,':'); michael@0: token2 = PORT_Strchr(name2,':'); michael@0: if ((token1 && token2) || (!token1 && !token2)) { michael@0: /* either both token names are specified or neither are, not match */ michael@0: return PR_FALSE; michael@0: } michael@0: if (token1) { michael@0: token=name1; michael@0: nickname1=token1; michael@0: nickname2=name2; michael@0: } else { michael@0: token=name2; michael@0: nickname1=token2; michael@0: nickname2=name1; michael@0: } michael@0: len = nickname1-token; michael@0: nickname1++; michael@0: if (PORT_Strcmp(nickname1,nickname2) != 0) { michael@0: return PR_FALSE; michael@0: } michael@0: /* compare the other token with the internal slot here */ michael@0: return PR_TRUE; michael@0: } michael@0: michael@0: /* michael@0: * Find all user certificates that match the given criteria. michael@0: * michael@0: * "handle" - database to search michael@0: * "usage" - certificate usage to match michael@0: * "oneCertPerName" - if set then only return the "best" cert per michael@0: * name michael@0: * "validOnly" - only return certs that are curently valid michael@0: * "proto_win" - window handle passed to pkcs11 michael@0: */ michael@0: CERTCertList * michael@0: CERT_FindUserCertsByUsage(CERTCertDBHandle *handle, michael@0: SECCertUsage usage, michael@0: PRBool oneCertPerName, michael@0: PRBool validOnly, michael@0: void *proto_win) michael@0: { michael@0: CERTCertNicknames *nicknames = NULL; michael@0: char **nnptr; michael@0: int nn; michael@0: CERTCertificate *cert = NULL; michael@0: CERTCertList *certList = NULL; michael@0: SECStatus rv; michael@0: PRTime time; michael@0: CERTCertListNode *node = NULL; michael@0: CERTCertListNode *freenode = NULL; michael@0: int n; michael@0: michael@0: time = PR_Now(); michael@0: michael@0: nicknames = CERT_GetCertNicknames(handle, SEC_CERT_NICKNAMES_USER, michael@0: proto_win); michael@0: michael@0: if ( ( nicknames == NULL ) || ( nicknames->numnicknames == 0 ) ) { michael@0: goto loser; michael@0: } michael@0: michael@0: nnptr = nicknames->nicknames; michael@0: nn = nicknames->numnicknames; michael@0: michael@0: while ( nn > 0 ) { michael@0: cert = NULL; michael@0: /* use the pk11 call so that we pick up any certs on tokens, michael@0: * which may require login michael@0: */ michael@0: if ( proto_win != NULL ) { michael@0: cert = PK11_FindCertFromNickname(*nnptr,proto_win); michael@0: } michael@0: michael@0: /* Sigh, It turns out if the cert is already in the temp db, because michael@0: * it's in the perm db, then the nickname lookup doesn't work. michael@0: * since we already have the cert here, though, than we can just call michael@0: * CERT_CreateSubjectCertList directly. For those cases where we didn't michael@0: * find the cert in pkcs #11 (because we didn't have a password arg, michael@0: * or because the nickname is for a peer, server, or CA cert, then we michael@0: * go look the cert up. michael@0: */ michael@0: if (cert == NULL) { michael@0: cert = CERT_FindCertByNickname(handle,*nnptr); michael@0: } michael@0: michael@0: if ( cert != NULL ) { michael@0: /* collect certs for this nickname, sorting them into the list */ michael@0: certList = CERT_CreateSubjectCertList(certList, handle, michael@0: &cert->derSubject, time, validOnly); michael@0: michael@0: CERT_FilterCertListForUserCerts(certList); michael@0: michael@0: /* drop the extra reference */ michael@0: CERT_DestroyCertificate(cert); michael@0: } michael@0: michael@0: nnptr++; michael@0: nn--; michael@0: } michael@0: michael@0: /* remove certs with incorrect usage */ michael@0: rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE); michael@0: michael@0: if ( rv != SECSuccess ) { michael@0: goto loser; michael@0: } michael@0: michael@0: /* remove any extra certs for each name */ michael@0: if ( oneCertPerName ) { michael@0: PRBool *flags; michael@0: michael@0: nn = nicknames->numnicknames; michael@0: nnptr = nicknames->nicknames; michael@0: michael@0: flags = (PRBool *)PORT_ZAlloc(sizeof(PRBool) * nn); michael@0: if ( flags == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: node = CERT_LIST_HEAD(certList); michael@0: michael@0: /* treverse all certs in the list */ michael@0: while ( !CERT_LIST_END(node, certList) ) { michael@0: michael@0: /* find matching nickname index */ michael@0: for ( n = 0; n < nn; n++ ) { michael@0: if ( CERT_MatchNickname(nnptr[n], node->cert->nickname) ) { michael@0: /* We found a match. If this is the first one, then michael@0: * set the flag and move on to the next cert. If this michael@0: * is not the first one then delete it from the list. michael@0: */ michael@0: if ( flags[n] ) { michael@0: /* We have already seen a cert with this nickname, michael@0: * so delete this one. michael@0: */ michael@0: freenode = node; michael@0: node = CERT_LIST_NEXT(node); michael@0: CERT_RemoveCertListNode(freenode); michael@0: } else { michael@0: /* keep the first cert for each nickname, but set the michael@0: * flag so we know to delete any others with the same michael@0: * nickname. michael@0: */ michael@0: flags[n] = PR_TRUE; michael@0: node = CERT_LIST_NEXT(node); michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: if ( n == nn ) { michael@0: /* if we get here it means that we didn't find a matching michael@0: * nickname, which should not happen. michael@0: */ michael@0: PORT_Assert(0); michael@0: node = CERT_LIST_NEXT(node); michael@0: } michael@0: } michael@0: PORT_Free(flags); michael@0: } michael@0: michael@0: goto done; michael@0: michael@0: loser: michael@0: if ( certList != NULL ) { michael@0: CERT_DestroyCertList(certList); michael@0: certList = NULL; michael@0: } michael@0: michael@0: done: michael@0: if ( nicknames != NULL ) { michael@0: CERT_FreeNicknames(nicknames); michael@0: } michael@0: michael@0: return(certList); michael@0: } michael@0: michael@0: /* michael@0: * Find a user certificate that matchs the given criteria. michael@0: * michael@0: * "handle" - database to search michael@0: * "nickname" - nickname to match michael@0: * "usage" - certificate usage to match michael@0: * "validOnly" - only return certs that are curently valid michael@0: * "proto_win" - window handle passed to pkcs11 michael@0: */ michael@0: CERTCertificate * michael@0: CERT_FindUserCertByUsage(CERTCertDBHandle *handle, michael@0: const char *nickname, michael@0: SECCertUsage usage, michael@0: PRBool validOnly, michael@0: void *proto_win) michael@0: { michael@0: CERTCertificate *cert = NULL; michael@0: CERTCertList *certList = NULL; michael@0: SECStatus rv; michael@0: PRTime time; michael@0: michael@0: time = PR_Now(); michael@0: michael@0: /* use the pk11 call so that we pick up any certs on tokens, michael@0: * which may require login michael@0: */ michael@0: /* XXX - why is this restricted? */ michael@0: if ( proto_win != NULL ) { michael@0: cert = PK11_FindCertFromNickname(nickname,proto_win); michael@0: } michael@0: michael@0: michael@0: /* sigh, There are still problems find smart cards from the temp michael@0: * db. This will get smart cards working again. The real fix michael@0: * is to make sure we can search the temp db by their token nickname. michael@0: */ michael@0: if (cert == NULL) { michael@0: cert = CERT_FindCertByNickname(handle,nickname); michael@0: } michael@0: michael@0: if ( cert != NULL ) { michael@0: unsigned int requiredKeyUsage; michael@0: unsigned int requiredCertType; michael@0: michael@0: rv = CERT_KeyUsageAndTypeForCertUsage(usage, PR_FALSE, michael@0: &requiredKeyUsage, &requiredCertType); michael@0: if ( rv != SECSuccess ) { michael@0: /* drop the extra reference */ michael@0: CERT_DestroyCertificate(cert); michael@0: cert = NULL; michael@0: goto loser; michael@0: } michael@0: /* If we already found the right cert, just return it */ michael@0: if ( (!validOnly || CERT_CheckCertValidTimes(cert, time, PR_FALSE) michael@0: == secCertTimeValid) && michael@0: (CERT_CheckKeyUsage(cert, requiredKeyUsage) == SECSuccess) && michael@0: (cert->nsCertType & requiredCertType) && michael@0: CERT_IsUserCert(cert) ) { michael@0: return(cert); michael@0: } michael@0: michael@0: /* collect certs for this nickname, sorting them into the list */ michael@0: certList = CERT_CreateSubjectCertList(certList, handle, michael@0: &cert->derSubject, time, validOnly); michael@0: michael@0: CERT_FilterCertListForUserCerts(certList); michael@0: michael@0: /* drop the extra reference */ michael@0: CERT_DestroyCertificate(cert); michael@0: cert = NULL; michael@0: } michael@0: michael@0: if ( certList == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: /* remove certs with incorrect usage */ michael@0: rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE); michael@0: michael@0: if ( rv != SECSuccess ) { michael@0: goto loser; michael@0: } michael@0: michael@0: if ( ! CERT_LIST_END(CERT_LIST_HEAD(certList), certList) ) { michael@0: cert = CERT_DupCertificate(CERT_LIST_HEAD(certList)->cert); michael@0: } michael@0: michael@0: loser: michael@0: if ( certList != NULL ) { michael@0: CERT_DestroyCertList(certList); michael@0: } michael@0: michael@0: return(cert); michael@0: } michael@0: michael@0: CERTCertList * michael@0: CERT_MatchUserCert(CERTCertDBHandle *handle, michael@0: SECCertUsage usage, michael@0: int nCANames, char **caNames, michael@0: void *proto_win) michael@0: { michael@0: CERTCertList *certList = NULL; michael@0: SECStatus rv; michael@0: michael@0: certList = CERT_FindUserCertsByUsage(handle, usage, PR_TRUE, PR_TRUE, michael@0: proto_win); michael@0: if ( certList == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: rv = CERT_FilterCertListByCANames(certList, nCANames, caNames, usage); michael@0: if ( rv != SECSuccess ) { michael@0: goto loser; michael@0: } michael@0: michael@0: goto done; michael@0: michael@0: loser: michael@0: if ( certList != NULL ) { michael@0: CERT_DestroyCertList(certList); michael@0: certList = NULL; michael@0: } michael@0: michael@0: done: michael@0: michael@0: return(certList); michael@0: } michael@0: michael@0: michael@0: typedef struct stringNode { michael@0: struct stringNode *next; michael@0: char *string; michael@0: } stringNode; michael@0: michael@0: static PRStatus michael@0: CollectNicknames( NSSCertificate *c, void *data) michael@0: { michael@0: CERTCertNicknames *names; michael@0: PRBool saveit = PR_FALSE; michael@0: stringNode *node; michael@0: int len; michael@0: #ifdef notdef michael@0: NSSTrustDomain *td; michael@0: NSSTrust *trust; michael@0: #endif michael@0: char *stanNickname; michael@0: char *nickname = NULL; michael@0: michael@0: names = (CERTCertNicknames *)data; michael@0: michael@0: stanNickname = nssCertificate_GetNickname(c,NULL); michael@0: michael@0: if ( stanNickname ) { michael@0: nss_ZFreeIf(stanNickname); michael@0: stanNickname = NULL; michael@0: if (names->what == SEC_CERT_NICKNAMES_USER) { michael@0: saveit = NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL); michael@0: } michael@0: #ifdef notdef michael@0: else { michael@0: td = NSSCertificate_GetTrustDomain(c); michael@0: if (!td) { michael@0: return PR_SUCCESS; michael@0: } michael@0: trust = nssTrustDomain_FindTrustForCertificate(td,c); michael@0: michael@0: switch(names->what) { michael@0: case SEC_CERT_NICKNAMES_ALL: michael@0: if ((trust->sslFlags & (CERTDB_VALID_CA|CERTDB_VALID_PEER) ) || michael@0: (trust->emailFlags & (CERTDB_VALID_CA|CERTDB_VALID_PEER) ) || michael@0: (trust->objectSigningFlags & michael@0: (CERTDB_VALID_CA|CERTDB_VALID_PEER))) { michael@0: saveit = PR_TRUE; michael@0: } michael@0: michael@0: break; michael@0: case SEC_CERT_NICKNAMES_SERVER: michael@0: if ( trust->sslFlags & CERTDB_VALID_PEER ) { michael@0: saveit = PR_TRUE; michael@0: } michael@0: michael@0: break; michael@0: case SEC_CERT_NICKNAMES_CA: michael@0: if (((trust->sslFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA)|| michael@0: ((trust->emailFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA) || michael@0: ((trust->objectSigningFlags & CERTDB_VALID_CA ) michael@0: == CERTDB_VALID_CA)) { michael@0: saveit = PR_TRUE; michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: /* traverse the list of collected nicknames and make sure we don't make michael@0: * a duplicate michael@0: */ michael@0: if ( saveit ) { michael@0: nickname = STAN_GetCERTCertificateName(NULL, c); michael@0: /* nickname can only be NULL here if we are having memory michael@0: * alloc problems */ michael@0: if (nickname == NULL) { michael@0: return PR_FAILURE; michael@0: } michael@0: node = (stringNode *)names->head; michael@0: while ( node != NULL ) { michael@0: if ( PORT_Strcmp(nickname, node->string) == 0 ) { michael@0: /* if the string matches, then don't save this one */ michael@0: saveit = PR_FALSE; michael@0: break; michael@0: } michael@0: node = node->next; michael@0: } michael@0: } michael@0: michael@0: if ( saveit ) { michael@0: michael@0: /* allocate the node */ michael@0: node = (stringNode*)PORT_ArenaAlloc(names->arena, sizeof(stringNode)); michael@0: if ( node == NULL ) { michael@0: PORT_Free(nickname); michael@0: return PR_FAILURE; michael@0: } michael@0: michael@0: /* copy the string */ michael@0: len = PORT_Strlen(nickname) + 1; michael@0: node->string = (char*)PORT_ArenaAlloc(names->arena, len); michael@0: if ( node->string == NULL ) { michael@0: PORT_Free(nickname); michael@0: return PR_FAILURE; michael@0: } michael@0: PORT_Memcpy(node->string, nickname, len); michael@0: michael@0: /* link it into the list */ michael@0: node->next = (stringNode *)names->head; michael@0: names->head = (void *)node; michael@0: michael@0: /* bump the count */ michael@0: names->numnicknames++; michael@0: } michael@0: michael@0: if (nickname) PORT_Free(nickname); michael@0: return(PR_SUCCESS); michael@0: } michael@0: michael@0: CERTCertNicknames * michael@0: CERT_GetCertNicknames(CERTCertDBHandle *handle, int what, void *wincx) michael@0: { michael@0: PLArenaPool *arena; michael@0: CERTCertNicknames *names; michael@0: int i; michael@0: stringNode *node; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if ( arena == NULL ) { michael@0: PORT_SetError(SEC_ERROR_NO_MEMORY); michael@0: return(NULL); michael@0: } michael@0: michael@0: names = (CERTCertNicknames *)PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames)); michael@0: if ( names == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: names->arena = arena; michael@0: names->head = NULL; michael@0: names->numnicknames = 0; michael@0: names->nicknames = NULL; michael@0: names->what = what; michael@0: names->totallen = 0; michael@0: michael@0: /* make sure we are logged in */ michael@0: (void) pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, wincx); michael@0: michael@0: NSSTrustDomain_TraverseCertificates(handle, michael@0: CollectNicknames, (void *)names); michael@0: if ( names->numnicknames ) { michael@0: names->nicknames = (char**)PORT_ArenaAlloc(arena, michael@0: names->numnicknames * sizeof(char *)); michael@0: michael@0: if ( names->nicknames == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: node = (stringNode *)names->head; michael@0: michael@0: for ( i = 0; i < names->numnicknames; i++ ) { michael@0: PORT_Assert(node != NULL); michael@0: michael@0: names->nicknames[i] = node->string; michael@0: names->totallen += PORT_Strlen(node->string); michael@0: node = node->next; michael@0: } michael@0: michael@0: PORT_Assert(node == NULL); michael@0: } michael@0: michael@0: return(names); michael@0: michael@0: loser: michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return(NULL); michael@0: } michael@0: michael@0: void michael@0: CERT_FreeNicknames(CERTCertNicknames *nicknames) michael@0: { michael@0: PORT_FreeArena(nicknames->arena, PR_FALSE); michael@0: michael@0: return; michael@0: } michael@0: michael@0: /* [ FROM pcertdb.c ] */ michael@0: michael@0: typedef struct dnameNode { michael@0: struct dnameNode *next; michael@0: SECItem name; michael@0: } dnameNode; michael@0: michael@0: void michael@0: CERT_FreeDistNames(CERTDistNames *names) michael@0: { michael@0: PORT_FreeArena(names->arena, PR_FALSE); michael@0: michael@0: return; michael@0: } michael@0: michael@0: static SECStatus michael@0: CollectDistNames( CERTCertificate *cert, SECItem *k, void *data) michael@0: { michael@0: CERTDistNames *names; michael@0: PRBool saveit = PR_FALSE; michael@0: CERTCertTrust trust; michael@0: dnameNode *node; michael@0: int len; michael@0: michael@0: names = (CERTDistNames *)data; michael@0: michael@0: if ( CERT_GetCertTrust(cert, &trust) == SECSuccess ) { michael@0: /* only collect names of CAs trusted for issuing SSL clients */ michael@0: if ( trust.sslFlags & CERTDB_TRUSTED_CLIENT_CA ) { michael@0: saveit = PR_TRUE; michael@0: } michael@0: } michael@0: michael@0: if ( saveit ) { michael@0: /* allocate the node */ michael@0: node = (dnameNode*)PORT_ArenaAlloc(names->arena, sizeof(dnameNode)); michael@0: if ( node == NULL ) { michael@0: return(SECFailure); michael@0: } michael@0: michael@0: /* copy the name */ michael@0: node->name.len = len = cert->derSubject.len; michael@0: node->name.type = siBuffer; michael@0: node->name.data = (unsigned char*)PORT_ArenaAlloc(names->arena, len); michael@0: if ( node->name.data == NULL ) { michael@0: return(SECFailure); michael@0: } michael@0: PORT_Memcpy(node->name.data, cert->derSubject.data, len); michael@0: michael@0: /* link it into the list */ michael@0: node->next = (dnameNode *)names->head; michael@0: names->head = (void *)node; michael@0: michael@0: /* bump the count */ michael@0: names->nnames++; michael@0: } michael@0: michael@0: return(SECSuccess); michael@0: } michael@0: michael@0: /* michael@0: * Return all of the CAs that are "trusted" for SSL. michael@0: */ michael@0: CERTDistNames * michael@0: CERT_DupDistNames(CERTDistNames *orig) michael@0: { michael@0: PLArenaPool *arena; michael@0: CERTDistNames *names; michael@0: int i; michael@0: SECStatus rv; michael@0: michael@0: /* allocate an arena to use */ michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (arena == NULL) { michael@0: PORT_SetError(SEC_ERROR_NO_MEMORY); michael@0: return(NULL); michael@0: } michael@0: michael@0: /* allocate the header structure */ michael@0: names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames)); michael@0: if (names == NULL) { michael@0: goto loser; michael@0: } michael@0: michael@0: /* initialize the header struct */ michael@0: names->arena = arena; michael@0: names->head = NULL; michael@0: names->nnames = orig->nnames; michael@0: names->names = NULL; michael@0: michael@0: /* construct the array from the list */ michael@0: if (orig->nnames) { michael@0: names->names = (SECItem*)PORT_ArenaNewArray(arena, SECItem, michael@0: orig->nnames); michael@0: if (names->names == NULL) { michael@0: goto loser; michael@0: } michael@0: for (i = 0; i < orig->nnames; i++) { michael@0: rv = SECITEM_CopyItem(arena, &names->names[i], &orig->names[i]); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: } michael@0: } michael@0: return(names); michael@0: michael@0: loser: michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return(NULL); michael@0: } michael@0: michael@0: CERTDistNames * michael@0: CERT_GetSSLCACerts(CERTCertDBHandle *handle) michael@0: { michael@0: PLArenaPool *arena; michael@0: CERTDistNames *names; michael@0: int i; michael@0: SECStatus rv; michael@0: dnameNode *node; michael@0: michael@0: /* allocate an arena to use */ michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if ( arena == NULL ) { michael@0: PORT_SetError(SEC_ERROR_NO_MEMORY); michael@0: return(NULL); michael@0: } michael@0: michael@0: /* allocate the header structure */ michael@0: names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames)); michael@0: if ( names == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: /* initialize the header struct */ michael@0: names->arena = arena; michael@0: names->head = NULL; michael@0: names->nnames = 0; michael@0: names->names = NULL; michael@0: michael@0: /* collect the names from the database */ michael@0: rv = PK11_TraverseSlotCerts(CollectDistNames, (void *)names, NULL); michael@0: if ( rv ) { michael@0: goto loser; michael@0: } michael@0: michael@0: /* construct the array from the list */ michael@0: if ( names->nnames ) { michael@0: names->names = (SECItem*)PORT_ArenaAlloc(arena, names->nnames * sizeof(SECItem)); michael@0: michael@0: if ( names->names == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: node = (dnameNode *)names->head; michael@0: michael@0: for ( i = 0; i < names->nnames; i++ ) { michael@0: PORT_Assert(node != NULL); michael@0: michael@0: names->names[i] = node->name; michael@0: node = node->next; michael@0: } michael@0: michael@0: PORT_Assert(node == NULL); michael@0: } michael@0: michael@0: return(names); michael@0: michael@0: loser: michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return(NULL); michael@0: } michael@0: michael@0: CERTDistNames * michael@0: CERT_DistNamesFromCertList(CERTCertList *certList) michael@0: { michael@0: CERTDistNames * dnames = NULL; michael@0: PLArenaPool * arena; michael@0: CERTCertListNode *node = NULL; michael@0: SECItem * names = NULL; michael@0: int listLen = 0, i = 0; michael@0: michael@0: if (certList == NULL) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return NULL; michael@0: } michael@0: michael@0: node = CERT_LIST_HEAD(certList); michael@0: while ( ! CERT_LIST_END(node, certList) ) { michael@0: listLen += 1; michael@0: node = CERT_LIST_NEXT(node); michael@0: } michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (arena == NULL) goto loser; michael@0: dnames = PORT_ArenaZNew(arena, CERTDistNames); michael@0: if (dnames == NULL) goto loser; michael@0: michael@0: dnames->arena = arena; michael@0: dnames->nnames = listLen; michael@0: dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, listLen); michael@0: if (names == NULL) goto loser; michael@0: michael@0: node = CERT_LIST_HEAD(certList); michael@0: while ( ! CERT_LIST_END(node, certList) ) { michael@0: CERTCertificate *cert = node->cert; michael@0: SECStatus rv = SECITEM_CopyItem(arena, &names[i++], &cert->derSubject); michael@0: if (rv == SECFailure) { michael@0: goto loser; michael@0: } michael@0: node = CERT_LIST_NEXT(node); michael@0: } michael@0: return dnames; michael@0: loser: michael@0: if (arena) { michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: CERTDistNames * michael@0: CERT_DistNamesFromNicknames(CERTCertDBHandle *handle, char **nicknames, michael@0: int nnames) michael@0: { michael@0: CERTDistNames *dnames = NULL; michael@0: PLArenaPool *arena; michael@0: int i, rv; michael@0: SECItem *names = NULL; michael@0: CERTCertificate *cert = NULL; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (arena == NULL) goto loser; michael@0: dnames = PORT_ArenaZNew(arena, CERTDistNames); michael@0: if (dnames == NULL) goto loser; michael@0: michael@0: dnames->arena = arena; michael@0: dnames->nnames = nnames; michael@0: dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, nnames); michael@0: if (names == NULL) goto loser; michael@0: michael@0: for (i = 0; i < nnames; i++) { michael@0: cert = CERT_FindCertByNicknameOrEmailAddr(handle, nicknames[i]); michael@0: if (cert == NULL) goto loser; michael@0: rv = SECITEM_CopyItem(arena, &names[i], &cert->derSubject); michael@0: if (rv == SECFailure) goto loser; michael@0: CERT_DestroyCertificate(cert); michael@0: } michael@0: return dnames; michael@0: michael@0: loser: michael@0: if (cert != NULL) michael@0: CERT_DestroyCertificate(cert); michael@0: if (arena != NULL) michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return NULL; michael@0: } michael@0: michael@0: /* [ from pcertdb.c - calls Ascii to Name ] */ michael@0: /* michael@0: * Lookup a certificate in the database by name michael@0: */ michael@0: CERTCertificate * michael@0: CERT_FindCertByNameString(CERTCertDBHandle *handle, char *nameStr) michael@0: { michael@0: CERTName *name; michael@0: SECItem *nameItem; michael@0: CERTCertificate *cert = NULL; michael@0: PLArenaPool *arena = NULL; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: michael@0: if ( arena == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: name = CERT_AsciiToName(nameStr); michael@0: michael@0: if ( name ) { michael@0: nameItem = SEC_ASN1EncodeItem (arena, NULL, (void *)name, michael@0: CERT_NameTemplate); michael@0: if ( nameItem != NULL ) { michael@0: cert = CERT_FindCertByName(handle, nameItem); michael@0: } michael@0: CERT_DestroyName(name); michael@0: } michael@0: michael@0: loser: michael@0: if ( arena ) { michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: } michael@0: michael@0: return(cert); michael@0: } michael@0: michael@0: /* From certv3.c */ michael@0: michael@0: CERTCrlDistributionPoints * michael@0: CERT_FindCRLDistributionPoints (CERTCertificate *cert) michael@0: { michael@0: SECItem encodedExtenValue; michael@0: SECStatus rv; michael@0: CERTCrlDistributionPoints *dps; michael@0: michael@0: encodedExtenValue.data = NULL; michael@0: encodedExtenValue.len = 0; michael@0: michael@0: rv = cert_FindExtension(cert->extensions, SEC_OID_X509_CRL_DIST_POINTS, michael@0: &encodedExtenValue); michael@0: if ( rv != SECSuccess ) { michael@0: return (NULL); michael@0: } michael@0: michael@0: dps = CERT_DecodeCRLDistributionPoints(cert->arena, &encodedExtenValue); michael@0: michael@0: PORT_Free(encodedExtenValue.data); michael@0: michael@0: return dps; michael@0: } michael@0: michael@0: /* From crl.c */ michael@0: CERTSignedCrl * CERT_ImportCRL michael@0: (CERTCertDBHandle *handle, SECItem *derCRL, char *url, int type, void *wincx) michael@0: { michael@0: CERTSignedCrl* retCrl = NULL; michael@0: PK11SlotInfo* slot = PK11_GetInternalKeySlot(); michael@0: retCrl = PK11_ImportCRL(slot, derCRL, url, type, wincx, michael@0: CRL_IMPORT_DEFAULT_OPTIONS, NULL, CRL_DECODE_DEFAULT_OPTIONS); michael@0: PK11_FreeSlot(slot); michael@0: michael@0: return retCrl; michael@0: } michael@0: michael@0: /* From certdb.c */ michael@0: static SECStatus michael@0: cert_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage, PRBool trusted) michael@0: { michael@0: SECStatus rv; michael@0: SECItem *derCert; michael@0: CERTCertificate *cert = NULL; michael@0: CERTCertificate *newcert = NULL; michael@0: CERTCertDBHandle *handle; michael@0: CERTCertTrust trust; michael@0: PRBool isca; michael@0: char *nickname; michael@0: unsigned int certtype; michael@0: michael@0: handle = CERT_GetDefaultCertDB(); michael@0: michael@0: while (numcerts--) { michael@0: derCert = certs; michael@0: certs++; michael@0: michael@0: /* decode my certificate */ michael@0: /* This use is ok -- only looks at decoded parts, calls NewTemp later */ michael@0: newcert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL); michael@0: if ( newcert == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: if (!trusted) { michael@0: /* make sure that cert is valid */ michael@0: rv = CERT_CertTimesValid(newcert); michael@0: if ( rv == SECFailure ) { michael@0: goto endloop; michael@0: } michael@0: } michael@0: michael@0: /* does it have the CA extension */ michael@0: michael@0: /* michael@0: * Make sure that if this is an intermediate CA in the chain that michael@0: * it was given permission by its signer to be a CA. michael@0: */ michael@0: isca = CERT_IsCACert(newcert, &certtype); michael@0: michael@0: if ( !isca ) { michael@0: if (!trusted) { michael@0: goto endloop; michael@0: } michael@0: trust.sslFlags = CERTDB_VALID_CA; michael@0: trust.emailFlags = CERTDB_VALID_CA; michael@0: trust.objectSigningFlags = CERTDB_VALID_CA; michael@0: } else { michael@0: /* SSL ca's must have the ssl bit set */ michael@0: if ( ( certUsage == certUsageSSLCA ) && michael@0: (( certtype & NS_CERT_TYPE_SSL_CA ) != NS_CERT_TYPE_SSL_CA )) { michael@0: goto endloop; michael@0: } michael@0: michael@0: /* it passed all of the tests, so lets add it to the database */ michael@0: /* mark it as a CA */ michael@0: PORT_Memset((void *)&trust, 0, sizeof(trust)); michael@0: switch ( certUsage ) { michael@0: case certUsageSSLCA: michael@0: trust.sslFlags = CERTDB_VALID_CA; michael@0: break; michael@0: case certUsageUserCertImport: michael@0: if ((certtype & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) { michael@0: trust.sslFlags = CERTDB_VALID_CA; michael@0: } michael@0: if ((certtype & NS_CERT_TYPE_EMAIL_CA) michael@0: == NS_CERT_TYPE_EMAIL_CA ) { michael@0: trust.emailFlags = CERTDB_VALID_CA; michael@0: } michael@0: if ( ( certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA ) == michael@0: NS_CERT_TYPE_OBJECT_SIGNING_CA ) { michael@0: trust.objectSigningFlags = CERTDB_VALID_CA; michael@0: } michael@0: break; michael@0: default: michael@0: PORT_Assert(0); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: cert = CERT_NewTempCertificate(handle, derCert, NULL, michael@0: PR_FALSE, PR_FALSE); michael@0: if ( cert == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: /* if the cert is temp, make it perm; otherwise we're done */ michael@0: if (cert->istemp) { michael@0: /* get a default nickname for it */ michael@0: nickname = CERT_MakeCANickname(cert); michael@0: michael@0: rv = CERT_AddTempCertToPerm(cert, nickname, &trust); michael@0: michael@0: /* free the nickname */ michael@0: if ( nickname ) { michael@0: PORT_Free(nickname); michael@0: } michael@0: } else { michael@0: rv = SECSuccess; michael@0: } michael@0: michael@0: CERT_DestroyCertificate(cert); michael@0: cert = NULL; michael@0: michael@0: if ( rv != SECSuccess ) { michael@0: goto loser; michael@0: } michael@0: michael@0: endloop: michael@0: if ( newcert ) { michael@0: CERT_DestroyCertificate(newcert); michael@0: newcert = NULL; michael@0: } michael@0: michael@0: } michael@0: michael@0: rv = SECSuccess; michael@0: goto done; michael@0: loser: michael@0: rv = SECFailure; michael@0: done: michael@0: michael@0: if ( newcert ) { michael@0: CERT_DestroyCertificate(newcert); michael@0: newcert = NULL; michael@0: } michael@0: michael@0: if ( cert ) { michael@0: CERT_DestroyCertificate(cert); michael@0: cert = NULL; michael@0: } michael@0: michael@0: return(rv); michael@0: } michael@0: michael@0: SECStatus michael@0: CERT_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage) michael@0: { michael@0: return cert_ImportCAChain(certs, numcerts, certUsage, PR_FALSE); michael@0: } michael@0: michael@0: SECStatus michael@0: CERT_ImportCAChainTrusted(SECItem *certs, int numcerts, SECCertUsage certUsage) { michael@0: return cert_ImportCAChain(certs, numcerts, certUsage, PR_TRUE); michael@0: } michael@0: michael@0: /* Moved from certdb.c */ michael@0: /* michael@0: ** CERT_CertChainFromCert michael@0: ** michael@0: ** Construct a CERTCertificateList consisting of the given certificate and all michael@0: ** of the issuer certs until we either get to a self-signed cert or can't find michael@0: ** an issuer. Since we don't know how many certs are in the chain we have to michael@0: ** build a linked list first as we count them. michael@0: */ michael@0: michael@0: typedef struct certNode { michael@0: struct certNode *next; michael@0: CERTCertificate *cert; michael@0: } certNode; michael@0: michael@0: CERTCertificateList * michael@0: CERT_CertChainFromCert(CERTCertificate *cert, SECCertUsage usage, michael@0: PRBool includeRoot) michael@0: { michael@0: CERTCertificateList *chain = NULL; michael@0: NSSCertificate **stanChain; michael@0: NSSCertificate *stanCert; michael@0: PLArenaPool *arena; michael@0: NSSUsage nssUsage; michael@0: int i, len; michael@0: NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); michael@0: NSSCryptoContext *cc = STAN_GetDefaultCryptoContext(); michael@0: michael@0: stanCert = STAN_GetNSSCertificate(cert); michael@0: if (!stanCert) { michael@0: /* error code is set */ michael@0: return NULL; michael@0: } michael@0: nssUsage.anyUsage = PR_FALSE; michael@0: nssUsage.nss3usage = usage; michael@0: nssUsage.nss3lookingForCA = PR_FALSE; michael@0: stanChain = NSSCertificate_BuildChain(stanCert, NULL, &nssUsage, NULL, NULL, michael@0: CERT_MAX_CERT_CHAIN, NULL, NULL, td, cc); michael@0: if (!stanChain) { michael@0: PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); michael@0: return NULL; michael@0: } michael@0: michael@0: len = 0; michael@0: stanCert = stanChain[0]; michael@0: while (stanCert) { michael@0: stanCert = stanChain[++len]; michael@0: } michael@0: michael@0: arena = PORT_NewArena(4096); michael@0: if (arena == NULL) { michael@0: goto loser; michael@0: } michael@0: michael@0: chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, michael@0: sizeof(CERTCertificateList)); michael@0: if (!chain) goto loser; michael@0: chain->certs = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem)); michael@0: if (!chain->certs) goto loser; michael@0: i = 0; michael@0: stanCert = stanChain[i]; michael@0: while (stanCert) { michael@0: SECItem derCert; michael@0: CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert); michael@0: if (!cCert) { michael@0: goto loser; michael@0: } michael@0: derCert.len = (unsigned int)stanCert->encoding.size; michael@0: derCert.data = (unsigned char *)stanCert->encoding.data; michael@0: derCert.type = siBuffer; michael@0: SECITEM_CopyItem(arena, &chain->certs[i], &derCert); michael@0: stanCert = stanChain[++i]; michael@0: if (!stanCert && !cCert->isRoot) { michael@0: /* reached the end of the chain, but the final cert is michael@0: * not a root. Don't discard it. michael@0: */ michael@0: includeRoot = PR_TRUE; michael@0: } michael@0: CERT_DestroyCertificate(cCert); michael@0: } michael@0: if ( !includeRoot && len > 1) { michael@0: chain->len = len - 1; michael@0: } else { michael@0: chain->len = len; michael@0: } michael@0: michael@0: chain->arena = arena; michael@0: nss_ZFreeIf(stanChain); michael@0: return chain; michael@0: loser: michael@0: i = 0; michael@0: stanCert = stanChain[i]; michael@0: while (stanCert) { michael@0: CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert); michael@0: if (cCert) { michael@0: CERT_DestroyCertificate(cCert); michael@0: } michael@0: stanCert = stanChain[++i]; michael@0: } michael@0: nss_ZFreeIf(stanChain); michael@0: if (arena) { michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: /* Builds a CERTCertificateList holding just one DER-encoded cert, namely michael@0: ** the one for the cert passed as an argument. michael@0: */ michael@0: CERTCertificateList * michael@0: CERT_CertListFromCert(CERTCertificate *cert) michael@0: { michael@0: CERTCertificateList *chain = NULL; michael@0: int rv; michael@0: PLArenaPool *arena; michael@0: michael@0: /* arena for SecCertificateList */ michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (arena == NULL) goto no_memory; michael@0: michael@0: /* build the CERTCertificateList */ michael@0: chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, sizeof(CERTCertificateList)); michael@0: if (chain == NULL) goto no_memory; michael@0: chain->certs = (SECItem*)PORT_ArenaAlloc(arena, 1 * sizeof(SECItem)); michael@0: if (chain->certs == NULL) goto no_memory; michael@0: rv = SECITEM_CopyItem(arena, chain->certs, &(cert->derCert)); michael@0: if (rv < 0) goto loser; michael@0: chain->len = 1; michael@0: chain->arena = arena; michael@0: michael@0: return chain; michael@0: michael@0: no_memory: michael@0: PORT_SetError(SEC_ERROR_NO_MEMORY); michael@0: loser: michael@0: if (arena != NULL) { michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: CERTCertificateList * michael@0: CERT_DupCertList(const CERTCertificateList * oldList) michael@0: { michael@0: CERTCertificateList *newList = NULL; michael@0: PLArenaPool *arena = NULL; michael@0: SECItem *newItem; michael@0: SECItem *oldItem; michael@0: int len = oldList->len; michael@0: int rv; michael@0: michael@0: /* arena for SecCertificateList */ michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (arena == NULL) michael@0: goto no_memory; michael@0: michael@0: /* now build the CERTCertificateList */ michael@0: newList = PORT_ArenaNew(arena, CERTCertificateList); michael@0: if (newList == NULL) michael@0: goto no_memory; michael@0: newList->arena = arena; michael@0: newItem = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem)); michael@0: if (newItem == NULL) michael@0: goto no_memory; michael@0: newList->certs = newItem; michael@0: newList->len = len; michael@0: michael@0: for (oldItem = oldList->certs; len > 0; --len, ++newItem, ++oldItem) { michael@0: rv = SECITEM_CopyItem(arena, newItem, oldItem); michael@0: if (rv < 0) michael@0: goto loser; michael@0: } michael@0: return newList; michael@0: michael@0: no_memory: michael@0: PORT_SetError(SEC_ERROR_NO_MEMORY); michael@0: loser: michael@0: if (arena != NULL) { michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: void michael@0: CERT_DestroyCertificateList(CERTCertificateList *list) michael@0: { michael@0: PORT_FreeArena(list->arena, PR_FALSE); michael@0: } michael@0: