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