security/nss/lib/certhigh/certhigh.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     4 #include "nspr.h"
     5 #include "secerr.h"
     6 #include "secasn1.h"
     7 #include "seccomon.h"
     8 #include "pk11func.h"
     9 #include "certdb.h"
    10 #include "certt.h"
    11 #include "cert.h"
    12 #include "certxutl.h"
    14 #include "nsspki.h"
    15 #include "pki.h"
    16 #include "pkit.h"
    17 #include "pkitm.h"
    18 #include "pki3hack.h"
    21 PRBool
    22 CERT_MatchNickname(char *name1, char *name2) {
    23     char *nickname1= NULL;
    24     char *nickname2 = NULL;
    25     char *token1;
    26     char *token2;
    27     char *token = NULL;
    28     int len;
    30     /* first deal with the straight comparison */
    31     if (PORT_Strcmp(name1, name2) == 0) {
    32 	return PR_TRUE;
    33     }
    34     /* we need to handle the case where one name has an explicit token and the other
    35      * doesn't */
    36     token1 = PORT_Strchr(name1,':');
    37     token2 = PORT_Strchr(name2,':');
    38     if ((token1 && token2) || (!token1 && !token2)) {
    39 	/* either both token names are specified or neither are, not match */
    40 	return PR_FALSE;
    41     }
    42     if (token1) {
    43 	token=name1;
    44 	nickname1=token1;
    45 	nickname2=name2;
    46     } else {
    47 	token=name2;
    48 	nickname1=token2;
    49 	nickname2=name1;
    50     }
    51     len = nickname1-token;
    52     nickname1++;
    53     if (PORT_Strcmp(nickname1,nickname2) != 0) {
    54 	return PR_FALSE;
    55     }
    56     /* compare the other token with the internal slot here */
    57     return PR_TRUE;
    58 }
    60 /*
    61  * Find all user certificates that match the given criteria.
    62  * 
    63  *	"handle" - database to search
    64  *	"usage" - certificate usage to match
    65  *	"oneCertPerName" - if set then only return the "best" cert per
    66  *			name
    67  *	"validOnly" - only return certs that are curently valid
    68  *	"proto_win" - window handle passed to pkcs11
    69  */
    70 CERTCertList *
    71 CERT_FindUserCertsByUsage(CERTCertDBHandle *handle,
    72 			  SECCertUsage usage,
    73 			  PRBool oneCertPerName,
    74 			  PRBool validOnly,
    75 			  void *proto_win)
    76 {
    77     CERTCertNicknames *nicknames = NULL;
    78     char **nnptr;
    79     int nn;
    80     CERTCertificate *cert = NULL;
    81     CERTCertList *certList = NULL;
    82     SECStatus rv;
    83     PRTime time;
    84     CERTCertListNode *node = NULL;
    85     CERTCertListNode *freenode = NULL;
    86     int n;
    88     time = PR_Now();
    90     nicknames = CERT_GetCertNicknames(handle, SEC_CERT_NICKNAMES_USER,
    91 				      proto_win);
    93     if ( ( nicknames == NULL ) || ( nicknames->numnicknames == 0 ) ) {
    94 	goto loser;
    95     }
    97     nnptr = nicknames->nicknames;
    98     nn = nicknames->numnicknames;
   100     while ( nn > 0 ) {
   101 	cert = NULL;
   102 	/* use the pk11 call so that we pick up any certs on tokens,
   103 	 * which may require login
   104 	 */
   105 	if ( proto_win != NULL ) {
   106 	    cert = PK11_FindCertFromNickname(*nnptr,proto_win);
   107 	}
   109 	/* Sigh, It turns out if the cert is already in the temp db, because
   110 	 * it's in the perm db, then the nickname lookup doesn't work.
   111 	 * since we already have the cert here, though, than we can just call
   112 	 * CERT_CreateSubjectCertList directly. For those cases where we didn't
   113 	 * find the cert in pkcs #11 (because we didn't have a password arg,
   114 	 * or because the nickname is for a peer, server, or CA cert, then we
   115 	 * go look the cert up.
   116 	 */
   117 	if (cert == NULL) { 
   118 	    cert = CERT_FindCertByNickname(handle,*nnptr);
   119 	}
   121 	if ( cert != NULL ) {
   122 	   /* collect certs for this nickname, sorting them into the list */
   123 	    certList = CERT_CreateSubjectCertList(certList, handle, 
   124 				&cert->derSubject, time, validOnly);
   126 	    CERT_FilterCertListForUserCerts(certList);
   128 	    /* drop the extra reference */
   129 	    CERT_DestroyCertificate(cert);
   130 	}
   132 	nnptr++;
   133 	nn--;
   134     }
   136     /* remove certs with incorrect usage */
   137     rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE);
   139     if ( rv != SECSuccess ) {
   140 	goto loser;
   141     }
   143     /* remove any extra certs for each name */
   144     if ( oneCertPerName ) {
   145 	PRBool *flags;
   147 	nn = nicknames->numnicknames;
   148 	nnptr = nicknames->nicknames;
   150 	flags = (PRBool *)PORT_ZAlloc(sizeof(PRBool) * nn);
   151 	if ( flags == NULL ) {
   152 	    goto loser;
   153 	}
   155 	node = CERT_LIST_HEAD(certList);
   157 	/* treverse all certs in the list */
   158 	while ( !CERT_LIST_END(node, certList) ) {
   160 	    /* find matching nickname index */
   161 	    for ( n = 0; n < nn; n++ ) {
   162 		if ( CERT_MatchNickname(nnptr[n], node->cert->nickname) ) {
   163 		    /* We found a match.  If this is the first one, then
   164 		     * set the flag and move on to the next cert.  If this
   165 		     * is not the first one then delete it from the list.
   166 		     */
   167 		    if ( flags[n] ) {
   168 			/* We have already seen a cert with this nickname,
   169 			 * so delete this one.
   170 			 */
   171 			freenode = node;
   172 			node = CERT_LIST_NEXT(node);
   173 			CERT_RemoveCertListNode(freenode);
   174 		    } else {
   175 			/* keep the first cert for each nickname, but set the
   176 			 * flag so we know to delete any others with the same
   177 			 * nickname.
   178 			 */
   179 			flags[n] = PR_TRUE;
   180 			node = CERT_LIST_NEXT(node);
   181 		    }
   182 		    break;
   183 		}
   184 	    }
   185 	    if ( n == nn ) {
   186 		/* if we get here it means that we didn't find a matching
   187 		 * nickname, which should not happen.
   188 		 */
   189 		PORT_Assert(0);
   190 		node = CERT_LIST_NEXT(node);
   191 	    }
   192 	}
   193 	PORT_Free(flags);
   194     }
   196     goto done;
   198 loser:
   199     if ( certList != NULL ) {
   200 	CERT_DestroyCertList(certList);
   201 	certList = NULL;
   202     }
   204 done:
   205     if ( nicknames != NULL ) {
   206 	CERT_FreeNicknames(nicknames);
   207     }
   209     return(certList);
   210 }
   212 /*
   213  * Find a user certificate that matchs the given criteria.
   214  * 
   215  *	"handle" - database to search
   216  *	"nickname" - nickname to match
   217  *	"usage" - certificate usage to match
   218  *	"validOnly" - only return certs that are curently valid
   219  *	"proto_win" - window handle passed to pkcs11
   220  */
   221 CERTCertificate *
   222 CERT_FindUserCertByUsage(CERTCertDBHandle *handle,
   223 			 const char *nickname,
   224 			 SECCertUsage usage,
   225 			 PRBool validOnly,
   226 			 void *proto_win)
   227 {
   228     CERTCertificate *cert = NULL;
   229     CERTCertList *certList = NULL;
   230     SECStatus rv;
   231     PRTime time;
   233     time = PR_Now();
   235     /* use the pk11 call so that we pick up any certs on tokens,
   236      * which may require login
   237      */
   238     /* XXX - why is this restricted? */
   239     if ( proto_win != NULL ) {
   240 	cert = PK11_FindCertFromNickname(nickname,proto_win);
   241     }
   244     /* sigh, There are still problems find smart cards from the temp
   245      * db. This will get smart cards working again. The real fix
   246      * is to make sure we can search the temp db by their token nickname.
   247      */
   248     if (cert == NULL) {
   249 	cert = CERT_FindCertByNickname(handle,nickname);
   250     }
   252     if ( cert != NULL ) {
   253 	unsigned int requiredKeyUsage;
   254 	unsigned int requiredCertType;
   256 	rv = CERT_KeyUsageAndTypeForCertUsage(usage, PR_FALSE,
   257 					&requiredKeyUsage, &requiredCertType);
   258 	if ( rv != SECSuccess ) {
   259 	    /* drop the extra reference */
   260 	    CERT_DestroyCertificate(cert);
   261 	    cert = NULL;
   262 	    goto loser;
   263 	}
   264 	/* If we already found the right cert, just return it */
   265 	if ( (!validOnly || CERT_CheckCertValidTimes(cert, time, PR_FALSE)
   266 	      == secCertTimeValid) &&
   267 	     (CERT_CheckKeyUsage(cert, requiredKeyUsage) == SECSuccess) &&
   268 	     (cert->nsCertType & requiredCertType) &&
   269 	      CERT_IsUserCert(cert) ) {
   270 	    return(cert);
   271 	}
   273  	/* collect certs for this nickname, sorting them into the list */
   274 	certList = CERT_CreateSubjectCertList(certList, handle, 
   275 					&cert->derSubject, time, validOnly);
   277 	CERT_FilterCertListForUserCerts(certList);
   279 	/* drop the extra reference */
   280 	CERT_DestroyCertificate(cert);
   281 	cert = NULL;
   282     }
   284     if ( certList == NULL ) {
   285 	goto loser;
   286     }
   288     /* remove certs with incorrect usage */
   289     rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE);
   291     if ( rv != SECSuccess ) {
   292 	goto loser;
   293     }
   295     if ( ! CERT_LIST_END(CERT_LIST_HEAD(certList), certList) ) {
   296 	cert = CERT_DupCertificate(CERT_LIST_HEAD(certList)->cert);
   297     }
   299 loser:
   300     if ( certList != NULL ) {
   301 	CERT_DestroyCertList(certList);
   302     }
   304     return(cert);
   305 }
   307 CERTCertList *
   308 CERT_MatchUserCert(CERTCertDBHandle *handle,
   309 		   SECCertUsage usage,
   310 		   int nCANames, char **caNames,
   311 		   void *proto_win)
   312 {
   313     CERTCertList *certList = NULL;
   314     SECStatus rv;
   316     certList = CERT_FindUserCertsByUsage(handle, usage, PR_TRUE, PR_TRUE,
   317 					 proto_win);
   318     if ( certList == NULL ) {
   319 	goto loser;
   320     }
   322     rv = CERT_FilterCertListByCANames(certList, nCANames, caNames, usage);
   323     if ( rv != SECSuccess ) {
   324 	goto loser;
   325     }
   327     goto done;
   329 loser:
   330     if ( certList != NULL ) {
   331 	CERT_DestroyCertList(certList);
   332 	certList = NULL;
   333     }
   335 done:
   337     return(certList);
   338 }
   341 typedef struct stringNode {
   342     struct stringNode *next;
   343     char *string;
   344 } stringNode;
   346 static PRStatus
   347 CollectNicknames( NSSCertificate *c, void *data)
   348 {
   349     CERTCertNicknames *names;
   350     PRBool saveit = PR_FALSE;
   351     stringNode *node;
   352     int len;
   353 #ifdef notdef
   354     NSSTrustDomain *td;
   355     NSSTrust *trust;
   356 #endif
   357     char *stanNickname;
   358     char *nickname = NULL;
   360     names = (CERTCertNicknames *)data;
   362     stanNickname = nssCertificate_GetNickname(c,NULL);
   364     if ( stanNickname ) {
   365         nss_ZFreeIf(stanNickname);
   366         stanNickname = NULL;
   367 	if (names->what == SEC_CERT_NICKNAMES_USER) {
   368 	    saveit = NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL);
   369 	}
   370 #ifdef notdef
   371 	  else {
   372 	    td = NSSCertificate_GetTrustDomain(c);
   373 	    if (!td) {
   374 		return PR_SUCCESS;
   375 	    }
   376 	    trust = nssTrustDomain_FindTrustForCertificate(td,c);
   378 	    switch(names->what) {
   379 	     case SEC_CERT_NICKNAMES_ALL:
   380 		if ((trust->sslFlags & (CERTDB_VALID_CA|CERTDB_VALID_PEER) ) ||
   381 		 (trust->emailFlags & (CERTDB_VALID_CA|CERTDB_VALID_PEER) ) ||
   382 		 (trust->objectSigningFlags & 
   383 					(CERTDB_VALID_CA|CERTDB_VALID_PEER))) {
   384 		    saveit = PR_TRUE;
   385 		}
   387 		break;
   388 	     case SEC_CERT_NICKNAMES_SERVER:
   389 		if ( trust->sslFlags & CERTDB_VALID_PEER ) {
   390 		    saveit = PR_TRUE;
   391 		}
   393 		break;
   394 	     case SEC_CERT_NICKNAMES_CA:
   395 		if (((trust->sslFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA)||
   396 		 ((trust->emailFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA) ||
   397 		 ((trust->objectSigningFlags & CERTDB_VALID_CA ) 
   398 							== CERTDB_VALID_CA)) {
   399 		    saveit = PR_TRUE;
   400 		}
   401 		break;
   402 	    }
   403 	}
   404 #endif
   405     }
   407     /* traverse the list of collected nicknames and make sure we don't make
   408      * a duplicate
   409      */
   410     if ( saveit ) {
   411 	nickname = STAN_GetCERTCertificateName(NULL, c);
   412 	/* nickname can only be NULL here if we are having memory 
   413 	 * alloc problems */
   414 	if (nickname == NULL) {
   415 	    return PR_FAILURE;
   416 	}
   417 	node = (stringNode *)names->head;
   418 	while ( node != NULL ) {
   419 	    if ( PORT_Strcmp(nickname, node->string) == 0 ) { 
   420 		/* if the string matches, then don't save this one */
   421 		saveit = PR_FALSE;
   422 		break;
   423 	    }
   424 	    node = node->next;
   425 	}
   426     }
   428     if ( saveit ) {
   430 	/* allocate the node */
   431 	node = (stringNode*)PORT_ArenaAlloc(names->arena, sizeof(stringNode));
   432 	if ( node == NULL ) {
   433 	    PORT_Free(nickname);
   434 	    return PR_FAILURE;
   435 	}
   437 	/* copy the string */
   438 	len = PORT_Strlen(nickname) + 1;
   439 	node->string = (char*)PORT_ArenaAlloc(names->arena, len);
   440 	if ( node->string == NULL ) {
   441 	    PORT_Free(nickname);
   442 	    return PR_FAILURE;
   443 	}
   444 	PORT_Memcpy(node->string, nickname, len);
   446 	/* link it into the list */
   447 	node->next = (stringNode *)names->head;
   448 	names->head = (void *)node;
   450 	/* bump the count */
   451 	names->numnicknames++;
   452     }
   454     if (nickname) PORT_Free(nickname);
   455     return(PR_SUCCESS);
   456 }
   458 CERTCertNicknames *
   459 CERT_GetCertNicknames(CERTCertDBHandle *handle, int what, void *wincx)
   460 {
   461     PLArenaPool *arena;
   462     CERTCertNicknames *names;
   463     int i;
   464     stringNode *node;
   466     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   467     if ( arena == NULL ) {
   468 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   469 	return(NULL);
   470     }
   472     names = (CERTCertNicknames *)PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
   473     if ( names == NULL ) {
   474 	goto loser;
   475     }
   477     names->arena = arena;
   478     names->head = NULL;
   479     names->numnicknames = 0;
   480     names->nicknames = NULL;
   481     names->what = what;
   482     names->totallen = 0;
   484     /* make sure we are logged in */
   485     (void) pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, wincx);
   487     NSSTrustDomain_TraverseCertificates(handle,
   488 					    CollectNicknames, (void *)names);
   489     if ( names->numnicknames ) {
   490 	names->nicknames = (char**)PORT_ArenaAlloc(arena,
   491 					 names->numnicknames * sizeof(char *));
   493 	if ( names->nicknames == NULL ) {
   494 	    goto loser;
   495 	}
   497 	node = (stringNode *)names->head;
   499 	for ( i = 0; i < names->numnicknames; i++ ) {
   500 	    PORT_Assert(node != NULL);
   502 	    names->nicknames[i] = node->string;
   503 	    names->totallen += PORT_Strlen(node->string);
   504 	    node = node->next;
   505 	}
   507 	PORT_Assert(node == NULL);
   508     }
   510     return(names);
   512 loser:
   513     PORT_FreeArena(arena, PR_FALSE);
   514     return(NULL);
   515 }
   517 void
   518 CERT_FreeNicknames(CERTCertNicknames *nicknames)
   519 {
   520     PORT_FreeArena(nicknames->arena, PR_FALSE);
   522     return;
   523 }
   525 /* [ FROM pcertdb.c ] */
   527 typedef struct dnameNode {
   528     struct dnameNode *next;
   529     SECItem name;
   530 } dnameNode;
   532 void
   533 CERT_FreeDistNames(CERTDistNames *names)
   534 {
   535     PORT_FreeArena(names->arena, PR_FALSE);
   537     return;
   538 }
   540 static SECStatus
   541 CollectDistNames( CERTCertificate *cert, SECItem *k, void *data)
   542 {
   543     CERTDistNames *names;
   544     PRBool saveit = PR_FALSE;
   545     CERTCertTrust trust;
   546     dnameNode *node;
   547     int len;
   549     names = (CERTDistNames *)data;
   551     if ( CERT_GetCertTrust(cert, &trust) == SECSuccess ) {
   552 	/* only collect names of CAs trusted for issuing SSL clients */
   553 	if (  trust.sslFlags &  CERTDB_TRUSTED_CLIENT_CA )  {
   554 	    saveit = PR_TRUE;
   555 	}
   556     }
   558     if ( saveit ) {
   559 	/* allocate the node */
   560 	node = (dnameNode*)PORT_ArenaAlloc(names->arena, sizeof(dnameNode));
   561 	if ( node == NULL ) {
   562 	    return(SECFailure);
   563 	}
   565 	/* copy the name */
   566 	node->name.len = len = cert->derSubject.len;
   567 	node->name.type = siBuffer;
   568 	node->name.data = (unsigned char*)PORT_ArenaAlloc(names->arena, len);
   569 	if ( node->name.data == NULL ) {
   570 	    return(SECFailure);
   571 	}
   572 	PORT_Memcpy(node->name.data, cert->derSubject.data, len);
   574 	/* link it into the list */
   575 	node->next = (dnameNode *)names->head;
   576 	names->head = (void *)node;
   578 	/* bump the count */
   579 	names->nnames++;
   580     }
   582     return(SECSuccess);
   583 }
   585 /*
   586  * Return all of the CAs that are "trusted" for SSL.
   587  */
   588 CERTDistNames *
   589 CERT_DupDistNames(CERTDistNames *orig)
   590 {
   591     PLArenaPool *arena;
   592     CERTDistNames *names;
   593     int i;
   594     SECStatus rv;
   596     /* allocate an arena to use */
   597     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   598     if (arena == NULL) {
   599 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   600 	return(NULL);
   601     }
   603     /* allocate the header structure */
   604     names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames));
   605     if (names == NULL) {
   606 	goto loser;
   607     }
   609     /* initialize the header struct */
   610     names->arena = arena;
   611     names->head = NULL;
   612     names->nnames = orig->nnames;
   613     names->names = NULL;
   615     /* construct the array from the list */
   616     if (orig->nnames) {
   617 	names->names = (SECItem*)PORT_ArenaNewArray(arena, SECItem,
   618                                                     orig->nnames);
   619 	if (names->names == NULL) {
   620 	    goto loser;
   621 	}
   622 	for (i = 0; i < orig->nnames; i++) {
   623             rv = SECITEM_CopyItem(arena, &names->names[i], &orig->names[i]);
   624             if (rv != SECSuccess) {
   625                 goto loser;
   626             }
   627         }
   628     }
   629     return(names);
   631 loser:
   632     PORT_FreeArena(arena, PR_FALSE);
   633     return(NULL);
   634 }
   636 CERTDistNames *
   637 CERT_GetSSLCACerts(CERTCertDBHandle *handle)
   638 {
   639     PLArenaPool *arena;
   640     CERTDistNames *names;
   641     int i;
   642     SECStatus rv;
   643     dnameNode *node;
   645     /* allocate an arena to use */
   646     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   647     if ( arena == NULL ) {
   648 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   649 	return(NULL);
   650     }
   652     /* allocate the header structure */
   653     names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames));
   654     if ( names == NULL ) {
   655 	goto loser;
   656     }
   658     /* initialize the header struct */
   659     names->arena = arena;
   660     names->head = NULL;
   661     names->nnames = 0;
   662     names->names = NULL;
   664     /* collect the names from the database */
   665     rv = PK11_TraverseSlotCerts(CollectDistNames, (void *)names, NULL);
   666     if ( rv ) {
   667 	goto loser;
   668     }
   670     /* construct the array from the list */
   671     if ( names->nnames ) {
   672 	names->names = (SECItem*)PORT_ArenaAlloc(arena, names->nnames * sizeof(SECItem));
   674 	if ( names->names == NULL ) {
   675 	    goto loser;
   676 	}
   678 	node = (dnameNode *)names->head;
   680 	for ( i = 0; i < names->nnames; i++ ) {
   681 	    PORT_Assert(node != NULL);
   683 	    names->names[i] = node->name;
   684 	    node = node->next;
   685 	}
   687 	PORT_Assert(node == NULL);
   688     }
   690     return(names);
   692 loser:
   693     PORT_FreeArena(arena, PR_FALSE);
   694     return(NULL);
   695 }
   697 CERTDistNames *
   698 CERT_DistNamesFromCertList(CERTCertList *certList)
   699 {
   700     CERTDistNames *   dnames = NULL;
   701     PLArenaPool *     arena;
   702     CERTCertListNode *node = NULL;
   703     SECItem *         names = NULL;
   704     int               listLen = 0, i = 0;
   706     if (certList == NULL) {
   707         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   708         return NULL;
   709     }
   711     node = CERT_LIST_HEAD(certList);
   712     while ( ! CERT_LIST_END(node, certList) ) {
   713         listLen += 1;
   714         node = CERT_LIST_NEXT(node);
   715     }
   717     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   718     if (arena == NULL) goto loser;
   719     dnames = PORT_ArenaZNew(arena, CERTDistNames);
   720     if (dnames == NULL) goto loser;
   722     dnames->arena = arena;
   723     dnames->nnames = listLen;
   724     dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, listLen);
   725     if (names == NULL) goto loser;
   727     node = CERT_LIST_HEAD(certList);
   728     while ( ! CERT_LIST_END(node, certList) ) {
   729         CERTCertificate *cert = node->cert;
   730         SECStatus rv = SECITEM_CopyItem(arena, &names[i++], &cert->derSubject);
   731         if (rv == SECFailure) {
   732             goto loser;
   733         }
   734         node = CERT_LIST_NEXT(node);
   735     }
   736     return dnames;
   737 loser:
   738     if (arena) {
   739         PORT_FreeArena(arena, PR_FALSE);
   740     }
   741     return NULL;
   742 }
   744 CERTDistNames *
   745 CERT_DistNamesFromNicknames(CERTCertDBHandle *handle, char **nicknames,
   746 			   int nnames)
   747 {
   748     CERTDistNames *dnames = NULL;
   749     PLArenaPool *arena;
   750     int i, rv;
   751     SECItem *names = NULL;
   752     CERTCertificate *cert = NULL;
   754     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   755     if (arena == NULL) goto loser;
   756     dnames = PORT_ArenaZNew(arena, CERTDistNames);
   757     if (dnames == NULL) goto loser;
   759     dnames->arena = arena;
   760     dnames->nnames = nnames;
   761     dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, nnames);
   762     if (names == NULL) goto loser;
   764     for (i = 0; i < nnames; i++) {
   765 	cert = CERT_FindCertByNicknameOrEmailAddr(handle, nicknames[i]);
   766 	if (cert == NULL) goto loser;
   767 	rv = SECITEM_CopyItem(arena, &names[i], &cert->derSubject);
   768 	if (rv == SECFailure) goto loser;
   769 	CERT_DestroyCertificate(cert);
   770     }
   771     return dnames;
   773 loser:
   774     if (cert != NULL)
   775 	CERT_DestroyCertificate(cert);
   776     if (arena != NULL)
   777 	PORT_FreeArena(arena, PR_FALSE);
   778     return NULL;
   779 }
   781 /* [ from pcertdb.c - calls Ascii to Name ] */
   782 /*
   783  * Lookup a certificate in the database by name
   784  */
   785 CERTCertificate *
   786 CERT_FindCertByNameString(CERTCertDBHandle *handle, char *nameStr)
   787 {
   788     CERTName *name;
   789     SECItem *nameItem;
   790     CERTCertificate *cert = NULL;
   791     PLArenaPool *arena = NULL;
   793     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   795     if ( arena == NULL ) {
   796 	goto loser;
   797     }
   799     name = CERT_AsciiToName(nameStr);
   801     if ( name ) {
   802 	nameItem = SEC_ASN1EncodeItem (arena, NULL, (void *)name,
   803 				       CERT_NameTemplate);
   804 	if ( nameItem != NULL ) {
   805             cert = CERT_FindCertByName(handle, nameItem);
   806 	}
   807 	CERT_DestroyName(name);
   808     }
   810 loser:
   811     if ( arena ) {
   812 	PORT_FreeArena(arena, PR_FALSE);
   813     }
   815     return(cert);
   816 }
   818 /* From certv3.c */
   820 CERTCrlDistributionPoints *
   821 CERT_FindCRLDistributionPoints (CERTCertificate *cert)
   822 {
   823     SECItem encodedExtenValue;
   824     SECStatus rv;
   825     CERTCrlDistributionPoints *dps;
   827     encodedExtenValue.data = NULL;
   828     encodedExtenValue.len = 0;
   830     rv = cert_FindExtension(cert->extensions, SEC_OID_X509_CRL_DIST_POINTS,
   831 			    &encodedExtenValue);
   832     if ( rv != SECSuccess ) {
   833 	return (NULL);
   834     }
   836     dps = CERT_DecodeCRLDistributionPoints(cert->arena, &encodedExtenValue);
   838     PORT_Free(encodedExtenValue.data);
   840     return dps;
   841 }
   843 /* From crl.c */
   844 CERTSignedCrl * CERT_ImportCRL
   845    (CERTCertDBHandle *handle, SECItem *derCRL, char *url, int type, void *wincx)
   846 {
   847     CERTSignedCrl* retCrl = NULL;
   848     PK11SlotInfo* slot = PK11_GetInternalKeySlot();
   849     retCrl = PK11_ImportCRL(slot, derCRL, url, type, wincx,
   850         CRL_IMPORT_DEFAULT_OPTIONS, NULL, CRL_DECODE_DEFAULT_OPTIONS);
   851     PK11_FreeSlot(slot);
   853     return retCrl;
   854 }
   856 /* From certdb.c */
   857 static SECStatus
   858 cert_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage, PRBool trusted)
   859 {
   860     SECStatus rv;
   861     SECItem *derCert;
   862     CERTCertificate *cert = NULL;
   863     CERTCertificate *newcert = NULL;
   864     CERTCertDBHandle *handle;
   865     CERTCertTrust trust;
   866     PRBool isca;
   867     char *nickname;
   868     unsigned int certtype;
   870     handle = CERT_GetDefaultCertDB();
   872     while (numcerts--) {
   873 	derCert = certs;
   874 	certs++;
   876 	/* decode my certificate */
   877 	/* This use is ok -- only looks at decoded parts, calls NewTemp later */
   878 	newcert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
   879 	if ( newcert == NULL ) {
   880 	    goto loser;
   881 	}
   883 	if (!trusted) {
   884 	    /* make sure that cert is valid */
   885 	    rv = CERT_CertTimesValid(newcert);
   886 	    if ( rv == SECFailure ) {
   887 		goto endloop;
   888 	    }
   889 	}
   891 	/* does it have the CA extension */
   893 	/*
   894 	 * Make sure that if this is an intermediate CA in the chain that
   895 	 * it was given permission by its signer to be a CA.
   896 	 */
   897 	isca = CERT_IsCACert(newcert, &certtype);
   899 	if ( !isca ) {
   900 	    if (!trusted) {
   901 		goto endloop;
   902 	    }
   903 	    trust.sslFlags = CERTDB_VALID_CA;
   904 	    trust.emailFlags = CERTDB_VALID_CA;
   905 	    trust.objectSigningFlags = CERTDB_VALID_CA;
   906 	} else {
   907 	    /* SSL ca's must have the ssl bit set */
   908 	    if ( ( certUsage == certUsageSSLCA ) &&
   909 		(( certtype & NS_CERT_TYPE_SSL_CA ) != NS_CERT_TYPE_SSL_CA )) {
   910 		goto endloop;
   911 	    }
   913 	    /* it passed all of the tests, so lets add it to the database */
   914 	    /* mark it as a CA */
   915 	    PORT_Memset((void *)&trust, 0, sizeof(trust));
   916 	    switch ( certUsage ) {
   917 	      case certUsageSSLCA:
   918 		trust.sslFlags = CERTDB_VALID_CA;
   919 		break;
   920 	      case certUsageUserCertImport:
   921 		if ((certtype & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) {
   922 		    trust.sslFlags = CERTDB_VALID_CA;
   923 		}
   924 		if ((certtype & NS_CERT_TYPE_EMAIL_CA) 
   925 						== NS_CERT_TYPE_EMAIL_CA ) {
   926 		    trust.emailFlags = CERTDB_VALID_CA;
   927 		}
   928 		if ( ( certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA ) ==
   929 					NS_CERT_TYPE_OBJECT_SIGNING_CA ) {
   930 		     trust.objectSigningFlags = CERTDB_VALID_CA;
   931 		}
   932 		break;
   933 	      default:
   934 		PORT_Assert(0);
   935 		break;
   936 	    }
   937 	}
   939 	cert = CERT_NewTempCertificate(handle, derCert, NULL, 
   940 							PR_FALSE, PR_FALSE);
   941 	if ( cert == NULL ) {
   942 	    goto loser;
   943 	}
   945 	/* if the cert is temp, make it perm; otherwise we're done */
   946 	if (cert->istemp) {
   947 	    /* get a default nickname for it */
   948 	    nickname = CERT_MakeCANickname(cert);
   950 	    rv = CERT_AddTempCertToPerm(cert, nickname, &trust);
   952 	    /* free the nickname */
   953 	    if ( nickname ) {
   954 		PORT_Free(nickname);
   955 	    }
   956 	} else {
   957 	    rv = SECSuccess;
   958 	}
   960 	CERT_DestroyCertificate(cert);
   961 	cert = NULL;
   963 	if ( rv != SECSuccess ) {
   964 	    goto loser;
   965 	}
   967 endloop:
   968 	if ( newcert ) {
   969 	    CERT_DestroyCertificate(newcert);
   970 	    newcert = NULL;
   971 	}
   973     }
   975     rv = SECSuccess;
   976     goto done;
   977 loser:
   978     rv = SECFailure;
   979 done:
   981     if ( newcert ) {
   982 	CERT_DestroyCertificate(newcert);
   983 	newcert = NULL;
   984     }
   986     if ( cert ) {
   987 	CERT_DestroyCertificate(cert);
   988 	cert = NULL;
   989     }
   991     return(rv);
   992 }
   994 SECStatus
   995 CERT_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage)
   996 {
   997     return cert_ImportCAChain(certs, numcerts, certUsage, PR_FALSE);
   998 }
  1000 SECStatus
  1001 CERT_ImportCAChainTrusted(SECItem *certs, int numcerts, SECCertUsage certUsage) {
  1002     return cert_ImportCAChain(certs, numcerts, certUsage, PR_TRUE);
  1005 /* Moved from certdb.c */
  1006 /*
  1007 ** CERT_CertChainFromCert
  1008 **
  1009 ** Construct a CERTCertificateList consisting of the given certificate and all
  1010 ** of the issuer certs until we either get to a self-signed cert or can't find
  1011 ** an issuer.  Since we don't know how many certs are in the chain we have to
  1012 ** build a linked list first as we count them.
  1013 */
  1015 typedef struct certNode {
  1016     struct certNode *next;
  1017     CERTCertificate *cert;
  1018 } certNode;
  1020 CERTCertificateList *
  1021 CERT_CertChainFromCert(CERTCertificate *cert, SECCertUsage usage,
  1022 		       PRBool includeRoot)
  1024     CERTCertificateList *chain = NULL;
  1025     NSSCertificate **stanChain;
  1026     NSSCertificate *stanCert;
  1027     PLArenaPool *arena;
  1028     NSSUsage nssUsage;
  1029     int i, len;
  1030     NSSTrustDomain *td   = STAN_GetDefaultTrustDomain();
  1031     NSSCryptoContext *cc = STAN_GetDefaultCryptoContext();
  1033     stanCert = STAN_GetNSSCertificate(cert);
  1034     if (!stanCert) {
  1035         /* error code is set */
  1036         return NULL;
  1038     nssUsage.anyUsage = PR_FALSE;
  1039     nssUsage.nss3usage = usage;
  1040     nssUsage.nss3lookingForCA = PR_FALSE;
  1041     stanChain = NSSCertificate_BuildChain(stanCert, NULL, &nssUsage, NULL, NULL,
  1042 					  CERT_MAX_CERT_CHAIN, NULL, NULL, td, cc);
  1043     if (!stanChain) {
  1044 	PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
  1045 	return NULL;
  1048     len = 0;
  1049     stanCert = stanChain[0];
  1050     while (stanCert) {
  1051 	stanCert = stanChain[++len];
  1054     arena = PORT_NewArena(4096);
  1055     if (arena == NULL) {
  1056 	goto loser;
  1059     chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, 
  1060                                                  sizeof(CERTCertificateList));
  1061     if (!chain) goto loser;
  1062     chain->certs = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem));
  1063     if (!chain->certs) goto loser;
  1064     i = 0;
  1065     stanCert = stanChain[i];
  1066     while (stanCert) {
  1067 	SECItem derCert;
  1068 	CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert);
  1069 	if (!cCert) {
  1070 	    goto loser;
  1072 	derCert.len = (unsigned int)stanCert->encoding.size;
  1073 	derCert.data = (unsigned char *)stanCert->encoding.data;
  1074 	derCert.type = siBuffer;
  1075 	SECITEM_CopyItem(arena, &chain->certs[i], &derCert);
  1076 	stanCert = stanChain[++i];
  1077 	if (!stanCert && !cCert->isRoot) {
  1078 	    /* reached the end of the chain, but the final cert is
  1079 	     * not a root.  Don't discard it.
  1080 	     */
  1081 	    includeRoot = PR_TRUE;
  1083 	CERT_DestroyCertificate(cCert);
  1085     if ( !includeRoot && len > 1) {
  1086 	chain->len = len - 1;
  1087     } else {
  1088 	chain->len = len;
  1091     chain->arena = arena;
  1092     nss_ZFreeIf(stanChain);
  1093     return chain;
  1094 loser:
  1095     i = 0;
  1096     stanCert = stanChain[i];
  1097     while (stanCert) {
  1098 	CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert);
  1099 	if (cCert) {
  1100 	    CERT_DestroyCertificate(cCert);
  1102 	stanCert = stanChain[++i];
  1104     nss_ZFreeIf(stanChain);
  1105     if (arena) {
  1106 	PORT_FreeArena(arena, PR_FALSE);
  1108     return NULL;
  1111 /* Builds a CERTCertificateList holding just one DER-encoded cert, namely
  1112 ** the one for the cert passed as an argument.
  1113 */
  1114 CERTCertificateList *
  1115 CERT_CertListFromCert(CERTCertificate *cert)
  1117     CERTCertificateList *chain = NULL;
  1118     int rv;
  1119     PLArenaPool *arena;
  1121     /* arena for SecCertificateList */
  1122     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1123     if (arena == NULL) goto no_memory;
  1125     /* build the CERTCertificateList */
  1126     chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, sizeof(CERTCertificateList));
  1127     if (chain == NULL) goto no_memory;
  1128     chain->certs = (SECItem*)PORT_ArenaAlloc(arena, 1 * sizeof(SECItem));
  1129     if (chain->certs == NULL) goto no_memory;
  1130     rv = SECITEM_CopyItem(arena, chain->certs, &(cert->derCert));
  1131     if (rv < 0) goto loser;
  1132     chain->len = 1;
  1133     chain->arena = arena;
  1135     return chain;
  1137 no_memory:
  1138     PORT_SetError(SEC_ERROR_NO_MEMORY);
  1139 loser:
  1140     if (arena != NULL) {
  1141 	PORT_FreeArena(arena, PR_FALSE);
  1143     return NULL;
  1146 CERTCertificateList *
  1147 CERT_DupCertList(const CERTCertificateList * oldList)
  1149     CERTCertificateList *newList = NULL;
  1150     PLArenaPool         *arena   = NULL;
  1151     SECItem             *newItem;
  1152     SECItem             *oldItem;
  1153     int                 len      = oldList->len;
  1154     int                 rv;
  1156     /* arena for SecCertificateList */
  1157     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1158     if (arena == NULL) 
  1159 	goto no_memory;
  1161     /* now build the CERTCertificateList */
  1162     newList = PORT_ArenaNew(arena, CERTCertificateList);
  1163     if (newList == NULL) 
  1164 	goto no_memory;
  1165     newList->arena = arena;
  1166     newItem = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem));
  1167     if (newItem == NULL) 
  1168 	goto no_memory;
  1169     newList->certs = newItem;
  1170     newList->len   = len;
  1172     for (oldItem = oldList->certs; len > 0; --len, ++newItem, ++oldItem) {
  1173 	rv = SECITEM_CopyItem(arena, newItem, oldItem);
  1174 	if (rv < 0) 
  1175 	    goto loser;
  1177     return newList;
  1179 no_memory:
  1180     PORT_SetError(SEC_ERROR_NO_MEMORY);
  1181 loser:
  1182     if (arena != NULL) {
  1183 	PORT_FreeArena(arena, PR_FALSE);
  1185     return NULL;
  1188 void
  1189 CERT_DestroyCertificateList(CERTCertificateList *list)
  1191     PORT_FreeArena(list->arena, PR_FALSE);

mercurial