Blame nss/lib/certhigh/certhigh.c

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