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