certvfy.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:42k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. #include "nspr.h"
  34. #include "secerr.h"
  35. #include "secport.h"
  36. #include "seccomon.h"
  37. #include "secoid.h"
  38. #include "sslerr.h"
  39. #include "genname.h"
  40. #include "keyhi.h"
  41. #include "cert.h"
  42. #include "certdb.h"
  43. #include "cryptohi.h"
  44. #define PENDING_SLOP (24L*60L*60L)
  45. /*
  46.  * WARNING - this function is depricated, and will go away in the near future.
  47.  * It has been superseded by CERT_CheckCertValidTimes().
  48.  *
  49.  * Check the validity times of a certificate
  50.  */
  51. SECStatus
  52. CERT_CertTimesValid(CERTCertificate *c)
  53. {
  54.     int64 now, notBefore, notAfter, pendingSlop;
  55.     SECStatus rv;
  56.     
  57.     /* if cert is already marked OK, then don't bother to check */
  58.     if ( c->timeOK ) {
  59. return(SECSuccess);
  60.     }
  61.     
  62.     /* get current UTC time */
  63.     now = PR_Now();
  64.     rv = CERT_GetCertTimes(c, &notBefore, &notAfter);
  65.     
  66.     if (rv) {
  67. return(SECFailure);
  68.     }
  69.     
  70.     LL_I2L(pendingSlop, PENDING_SLOP);
  71.     LL_SUB(notBefore, notBefore, pendingSlop);
  72.     if (LL_CMP(now, <, notBefore) || LL_CMP(now, >, notAfter)) {
  73. PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE);
  74. return(SECFailure);
  75.     }
  76.     return(SECSuccess);
  77. }
  78. /*
  79.  * verify the signature of a signed data object with the given certificate
  80.  */
  81. SECStatus
  82. CERT_VerifySignedData(CERTSignedData *sd, CERTCertificate *cert,
  83.       int64 t, void *wincx)
  84. {
  85.     SECItem sig;
  86.     SECKEYPublicKey *pubKey = 0;
  87.     SECStatus rv;
  88.     SECCertTimeValidity validity;
  89.     SECOidTag algid;
  90.     /* check the certificate's validity */
  91.     validity = CERT_CheckCertValidTimes(cert, t, PR_FALSE);
  92.     if ( validity != secCertTimeValid ) {
  93. return(SECFailure);
  94.     }
  95.     /* get cert's public key */
  96.     pubKey = CERT_ExtractPublicKey(cert);
  97.     if ( !pubKey ) {
  98. return(SECFailure);
  99.     }
  100.     
  101.     /* check the signature */
  102.     sig = sd->signature;
  103.     DER_ConvertBitString(&sig);
  104.     algid = SECOID_GetAlgorithmTag(&sd->signatureAlgorithm);
  105.     rv = VFY_VerifyData(sd->data.data, sd->data.len, pubKey, &sig,
  106. algid, wincx);
  107.     SECKEY_DestroyPublicKey(pubKey);
  108.     if ( rv ) {
  109. return(SECFailure);
  110.     }
  111.     return(SECSuccess);
  112. }
  113. /*
  114.  * This must only be called on a cert that is known to have an issuer
  115.  * with an invalid time
  116.  */
  117. CERTCertificate *
  118. CERT_FindExpiredIssuer(CERTCertDBHandle *handle, CERTCertificate *cert)
  119. {
  120.     CERTCertificate *issuerCert = NULL;
  121.     CERTCertificate *subjectCert;
  122.     int              count;
  123.     SECStatus        rv;
  124.     SECComparison    rvCompare;
  125.     
  126.     subjectCert = CERT_DupCertificate(cert);
  127.     if ( subjectCert == NULL ) {
  128. goto loser;
  129.     }
  130.     
  131.     for ( count = 0; count < CERT_MAX_CERT_CHAIN; count++ ) {
  132. /* find the certificate of the issuer */
  133. issuerCert = CERT_FindCertByName(handle, &subjectCert->derIssuer);
  134.     
  135. if ( ! issuerCert ) {
  136.     goto loser;
  137. }
  138. rv = CERT_CertTimesValid(issuerCert);
  139. if ( rv == SECFailure ) {
  140.     /* this is the invalid issuer */
  141.     CERT_DestroyCertificate(subjectCert);
  142.     return(issuerCert);
  143. }
  144. /* make sure that the issuer is not self signed.  If it is, then
  145.  * stop here to prevent looping.
  146.  */
  147. rvCompare = SECITEM_CompareItem(&issuerCert->derSubject,
  148.  &issuerCert->derIssuer);
  149. if (rvCompare == SECEqual) {
  150.     PORT_Assert(0); /* No expired issuer! */
  151.     goto loser;
  152. }
  153. CERT_DestroyCertificate(subjectCert);
  154. subjectCert = issuerCert;
  155.     }
  156. loser:
  157.     if ( issuerCert ) {
  158. CERT_DestroyCertificate(issuerCert);
  159.     }
  160.     
  161.     if ( subjectCert ) {
  162. CERT_DestroyCertificate(subjectCert);
  163.     }
  164.     
  165.     return(NULL);
  166. }
  167. /* Software FORTEZZA installation hack. The software fortezza installer does
  168.  * not have access to the krl and cert.db file. Accept FORTEZZA Certs without
  169.  * KRL's in this case. 
  170.  */
  171. static int dont_use_krl = 0;
  172. /* not a public exposed function... */
  173. void sec_SetCheckKRLState(int value) { dont_use_krl = value; }
  174. SECStatus
  175. SEC_CheckKRL(CERTCertDBHandle *handle,SECKEYPublicKey *key,
  176.      CERTCertificate *rootCert, int64 t, void * wincx)
  177. {
  178.     CERTSignedCrl *crl = NULL;
  179.     SECStatus rv = SECFailure;
  180.     SECStatus rv2;
  181.     CERTCrlEntry **crlEntry;
  182.     SECCertTimeValidity validity;
  183.     CERTCertificate *issuerCert = NULL;
  184.     if (dont_use_krl) return SECSuccess;
  185.     /* first look up the KRL */
  186.     crl = SEC_FindCrlByName(handle,&rootCert->derSubject, SEC_KRL_TYPE);
  187.     if (crl == NULL) {
  188. PORT_SetError(SEC_ERROR_NO_KRL);
  189. goto done;
  190.     }
  191.     /* get the issuing certificate */
  192.     issuerCert = CERT_FindCertByName(handle, &crl->crl.derName);
  193.     if (issuerCert == NULL) {
  194.         PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);
  195.         goto done;
  196.     }
  197.     /* now verify the KRL signature */
  198.     rv2 = CERT_VerifySignedData(&crl->signatureWrap, issuerCert, t, wincx);
  199.     if (rv2 != SECSuccess) {
  200. PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);
  201.      goto done;
  202.     }
  203.     /* Verify the date validity of the KRL */
  204.     validity = SEC_CheckCrlTimes(&crl->crl, t);
  205.     if (validity == secCertTimeExpired) {
  206. PORT_SetError(SEC_ERROR_KRL_EXPIRED);
  207. goto done;
  208.     }
  209.     /* now make sure the key in this cert is still valid */
  210.     if (key->keyType != fortezzaKey) {
  211. PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
  212. goto done; /* This should be an assert? */
  213.     }
  214.     /* now make sure the key is not on the revocation list */
  215.     for (crlEntry = crl->crl.entries; crlEntry && *crlEntry; crlEntry++) {
  216. if (PORT_Memcmp((*crlEntry)->serialNumber.data,
  217. key->u.fortezza.KMID,
  218.     (*crlEntry)->serialNumber.len) == 0) {
  219.     PORT_SetError(SEC_ERROR_REVOKED_KEY);
  220.     goto done;
  221. }
  222.     }
  223.     rv = SECSuccess;
  224. done:
  225.     if (issuerCert) CERT_DestroyCertificate(issuerCert);
  226.     if (crl) SEC_DestroyCrl(crl);
  227.     return rv;
  228. }
  229. SECStatus
  230. SEC_CheckCRL(CERTCertDBHandle *handle,CERTCertificate *cert,
  231.      CERTCertificate *caCert, int64 t, void * wincx)
  232. {
  233.     CERTSignedCrl *crl = NULL;
  234.     SECStatus rv = SECSuccess;
  235.     CERTCrlEntry **crlEntry;
  236.     SECCertTimeValidity validity;
  237.     /* first look up the CRL */
  238.     crl = SEC_FindCrlByName(handle,&caCert->derSubject, SEC_CRL_TYPE);
  239.     if (crl == NULL) {
  240. /* XXX for now no CRL is ok */
  241. goto done;
  242.     }
  243.     /* now verify the CRL signature */
  244.     rv = CERT_VerifySignedData(&crl->signatureWrap, caCert, t, wincx);
  245.     if (rv != SECSuccess) {
  246. PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
  247.         rv = SECWouldBlock; /* Soft error, ask the user */
  248.      goto done;
  249.     }
  250.     /* Verify the date validity of the KRL */
  251.     validity = SEC_CheckCrlTimes(&crl->crl,t);
  252.     if (validity == secCertTimeExpired) {
  253. PORT_SetError(SEC_ERROR_CRL_EXPIRED);
  254.         rv = SECWouldBlock; /* Soft error, ask the user */
  255.     } else if (validity == secCertTimeNotValidYet) {
  256. PORT_SetError(SEC_ERROR_CRL_NOT_YET_VALID);
  257. rv = SECWouldBlock; /* Soft error, ask the user */
  258.     }
  259.     /* now make sure the key is not on the revocation list */
  260.     for (crlEntry = crl->crl.entries; crlEntry && *crlEntry; crlEntry++) {
  261. if (SECITEM_CompareItem(&(*crlEntry)->serialNumber,&cert->serialNumber) == SECEqual) {
  262.     PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
  263.     rv = SECFailure; /* cert is revoked */
  264.     goto done;
  265. }
  266.     }
  267. done:
  268.     if (crl) SEC_DestroyCrl(crl);
  269.     return rv;
  270. }
  271. /*
  272.  * Find the issuer of a cert.  Use the authorityKeyID if it exists.
  273.  */
  274. CERTCertificate *
  275. CERT_FindCertIssuer(CERTCertificate *cert, int64 validTime, SECCertUsage usage)
  276. {
  277.     CERTAuthKeyID *   authorityKeyID = NULL;  
  278.     CERTCertificate * issuerCert     = NULL;
  279.     SECItem *         caName;
  280.     PRArenaPool       *tmpArena = NULL;
  281.     SECItem           issuerCertKey;
  282.     SECStatus         rv;
  283.     tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  284.     
  285.     if ( !tmpArena ) {
  286. goto loser;
  287.     }
  288.     authorityKeyID = CERT_FindAuthKeyIDExten(tmpArena,cert);
  289.     if ( authorityKeyID != NULL ) {
  290. /* has the authority key ID extension */
  291. if ( authorityKeyID->keyID.data != NULL ) {
  292.     /* extension contains a key ID, so lookup based on it */
  293.     issuerCert = CERT_FindCertByKeyID(cert->dbhandle, &cert->derIssuer,
  294.       &authorityKeyID->keyID);
  295.     if ( issuerCert == NULL ) {
  296. PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);
  297. goto loser;
  298.     }
  299.     
  300. } else if ( authorityKeyID->authCertIssuer != NULL ) {
  301.     /* no key ID, so try issuer and serial number */
  302.     caName = (SECItem*)CERT_GetGeneralNameByType(authorityKeyID->authCertIssuer,
  303.          certDirectoryName, PR_TRUE);
  304.     /*
  305.      * caName is NULL when the authCertIssuer field is not
  306.      * being used, or other name form is used instead.
  307.      * If the directoryName format and serialNumber fields are
  308.      * used, we use them to find the CA cert.
  309.      * Note:
  310.      * By the time it gets here, we known for sure that if the
  311.      * authCertIssuer exists, then the authCertSerialNumber
  312.      * must also exists (CERT_DecodeAuthKeyID() ensures this).
  313.      * We don't need to check again. 
  314.      */
  315.     if (caName != NULL) {
  316. rv = CERT_KeyFromIssuerAndSN(tmpArena, caName,
  317.      &authorityKeyID->authCertSerialNumber,
  318.      &issuerCertKey);
  319. if ( rv == SECSuccess ) {
  320.     issuerCert = CERT_FindCertByKey(cert->dbhandle,
  321.     &issuerCertKey);
  322. }
  323. if ( issuerCert == NULL ) {
  324.     PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);
  325.     goto loser;
  326. }
  327.     }
  328. }
  329.     }
  330.     if ( issuerCert == NULL ) {
  331. /* if there is not authorityKeyID, then try to find the issuer */
  332. /* find a valid CA cert with correct usage */
  333. issuerCert = CERT_FindMatchingCert(cert->dbhandle,
  334.    &cert->derIssuer,
  335.    certOwnerCA, usage, PR_TRUE,
  336.    validTime, PR_TRUE);
  337. /* if that fails, then fall back to grabbing any cert with right name*/
  338. if ( issuerCert == NULL ) {
  339.     issuerCert = CERT_FindCertByName(cert->dbhandle, &cert->derIssuer);
  340.     if ( issuerCert == NULL ) {
  341. PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);
  342.     }
  343. }
  344.     }
  345. loser:
  346.     if (tmpArena != NULL) {
  347. PORT_FreeArena(tmpArena, PR_FALSE);
  348. tmpArena = NULL;
  349.     }
  350.     return(issuerCert);
  351. }
  352. /*
  353.  * return required trust flags for various cert usages for CAs
  354.  */
  355. SECStatus
  356. CERT_TrustFlagsForCACertUsage(SECCertUsage usage,
  357.       unsigned int *retFlags,
  358.       SECTrustType *retTrustType)
  359. {
  360.     unsigned int requiredFlags;
  361.     SECTrustType trustType;
  362.     switch ( usage ) {
  363.       case certUsageSSLClient:
  364. requiredFlags = CERTDB_TRUSTED_CLIENT_CA;
  365. trustType = trustSSL;
  366.         break;
  367.       case certUsageSSLServer:
  368.       case certUsageSSLCA:
  369. requiredFlags = CERTDB_TRUSTED_CA;
  370. trustType = trustSSL;
  371.         break;
  372.       case certUsageSSLServerWithStepUp:
  373. requiredFlags = CERTDB_TRUSTED_CA | CERTDB_GOVT_APPROVED_CA;
  374. trustType = trustSSL;
  375.         break;
  376.       case certUsageEmailSigner:
  377.       case certUsageEmailRecipient:
  378. requiredFlags = CERTDB_TRUSTED_CA;
  379. trustType = trustEmail;
  380. break;
  381.       case certUsageObjectSigner:
  382. requiredFlags = CERTDB_TRUSTED_CA;
  383. trustType = trustObjectSigning;
  384. break;
  385.       case certUsageVerifyCA:
  386.       case certUsageAnyCA:
  387.       case certUsageStatusResponder:
  388. requiredFlags = CERTDB_TRUSTED_CA;
  389. trustType = trustTypeNone;
  390. break;
  391.       default:
  392. PORT_Assert(0);
  393. goto loser;
  394.     }
  395.     if ( retFlags != NULL ) {
  396. *retFlags = requiredFlags;
  397.     }
  398.     if ( retTrustType != NULL ) {
  399. *retTrustType = trustType;
  400.     }
  401.     
  402.     return(SECSuccess);
  403. loser:
  404.     return(SECFailure);
  405. }
  406. static void
  407. AddToVerifyLog(CERTVerifyLog *log, CERTCertificate *cert, unsigned long error,
  408.        unsigned int depth, void *arg)
  409. {
  410.     CERTVerifyLogNode *node, *tnode;
  411.     PORT_Assert(log != NULL);
  412.     
  413.     node = (CERTVerifyLogNode *)PORT_ArenaAlloc(log->arena,
  414. sizeof(CERTVerifyLogNode));
  415.     if ( node != NULL ) {
  416. node->cert = CERT_DupCertificate(cert);
  417. node->error = error;
  418. node->depth = depth;
  419. node->arg = arg;
  420. if ( log->tail == NULL ) {
  421.     /* empty list */
  422.     log->head = log->tail = node;
  423.     node->prev = NULL;
  424.     node->next = NULL;
  425. } else if ( depth >= log->tail->depth ) {
  426.     /* add to tail */
  427.     node->prev = log->tail;
  428.     log->tail->next = node;
  429.     log->tail = node;
  430.     node->next = NULL;
  431. } else if ( depth < log->head->depth ) {
  432.     /* add at head */
  433.     node->prev = NULL;
  434.     node->next = log->head;
  435.     log->head->prev = node;
  436.     log->head = node;
  437. } else {
  438.     /* add in middle */
  439.     tnode = log->tail;
  440.     while ( tnode != NULL ) {
  441. if ( depth >= tnode->depth ) {
  442.     /* insert after tnode */
  443.     node->prev = tnode;
  444.     node->next = tnode->next;
  445.     tnode->next->prev = node;
  446.     tnode->next = node;
  447.     break;
  448. }
  449. tnode = tnode->prev;
  450.     }
  451. }
  452. log->count++;
  453.     }
  454.     return;
  455. }
  456. #define EXIT_IF_NOT_LOGGING(log) 
  457.     if ( log == NULL ) { 
  458. goto loser; 
  459.     }
  460. #define LOG_ERROR_OR_EXIT(log,cert,depth,arg) 
  461.     if ( log != NULL ) { 
  462. AddToVerifyLog(log, cert, PORT_GetError(), depth, (void *)arg); 
  463.     } else { 
  464. goto loser; 
  465.     }
  466. #define LOG_ERROR(log,cert,depth,arg) 
  467.     if ( log != NULL ) { 
  468. AddToVerifyLog(log, cert, PORT_GetError(), depth, (void *)arg); 
  469.     }
  470. SECStatus
  471. CERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
  472.      PRBool checkSig, SECCertUsage certUsage, int64 t,
  473.      void *wincx, CERTVerifyLog *log)
  474. {
  475.     SECTrustType trustType;
  476.     CERTBasicConstraints basicConstraint;
  477.     CERTCertificate *issuerCert = NULL;
  478.     CERTCertificate *subjectCert = NULL;
  479.     CERTCertificate *badCert = NULL;
  480.     PRBool isca;
  481.     PRBool isFortezzaV1 = PR_FALSE;
  482.     SECStatus rv;
  483.     SECComparison rvCompare;
  484.     SECStatus rvFinal = SECSuccess;
  485.     int count;
  486.     int currentPathLen = -1;
  487.     int flags;
  488.     unsigned int caCertType;
  489.     unsigned int requiredCAKeyUsage;
  490.     unsigned int requiredFlags;
  491.     PRArenaPool *arena = NULL;
  492.     CERTGeneralName *namesList = NULL;
  493.     CERTGeneralName *subjectNameList = NULL;
  494.     SECItem *namesIndex = NULL;
  495.     int namesIndexLen = 10;
  496.     int namesCount = 0;
  497.     enum { cbd_None, cbd_User, cbd_CA } last_type = cbd_None;
  498.     SECKEYPublicKey *key;
  499.     if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE,
  500.  &requiredCAKeyUsage,
  501.  &caCertType)
  502. != SECSuccess ) {
  503. PORT_Assert(0);
  504. EXIT_IF_NOT_LOGGING(log);
  505. requiredCAKeyUsage = 0;
  506. caCertType = 0;
  507.     }
  508.     switch ( certUsage ) {
  509.       case certUsageSSLClient:
  510.       case certUsageSSLServer:
  511.       case certUsageSSLCA:
  512.       case certUsageSSLServerWithStepUp:
  513.       case certUsageEmailSigner:
  514.       case certUsageEmailRecipient:
  515.       case certUsageObjectSigner:
  516.       case certUsageVerifyCA:
  517.       case certUsageStatusResponder:
  518. if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags,
  519.    &trustType) != SECSuccess ) {
  520.     PORT_Assert(0);
  521.     EXIT_IF_NOT_LOGGING(log);
  522.     requiredFlags = 0;
  523.     trustType = trustSSL;
  524. }
  525. break;
  526.       default:
  527. PORT_Assert(0);
  528. EXIT_IF_NOT_LOGGING(log);
  529. requiredFlags = 0;
  530. trustType = trustSSL;/* This used to be 0, but we need something
  531.       * that matches the enumeration type.
  532.       */
  533. caCertType = 0;
  534.     }
  535.     
  536.     subjectCert = CERT_DupCertificate(cert);
  537.     if ( subjectCert == NULL ) {
  538. goto loser;
  539.     }
  540.     /* determine if the cert is fortezza. Getting the key is an easy
  541.      * way to determine it, especially since we need to get the privillege
  542.      * from the key anyway.
  543.      */
  544.     key = CERT_ExtractPublicKey(cert);
  545.     if (key != NULL) {
  546. isFortezzaV1 = (PRBool)(key->keyType == fortezzaKey);
  547. /* find out what type of cert we are starting with */
  548. if (isFortezzaV1) {
  549.     unsigned char priv = 0;;
  550.     rv = SEC_CheckKRL(handle, key, NULL, t, wincx);
  551.     if (rv == SECFailure) {
  552. /**** PORT_SetError is already set by SEC_CheckKRL **/
  553. SECKEY_DestroyPublicKey(key);
  554. /**** Bob - should we log and continue when logging? **/
  555. LOG_ERROR(log,subjectCert,0,0);
  556. goto loser;
  557.     }                
  558.     if (key->u.fortezza.DSSpriviledge.len > 0) {
  559. priv = key->u.fortezza.DSSpriviledge.data[0];
  560.     }
  561.     last_type = (priv & 0x30) ? cbd_CA : cbd_User;
  562. }
  563. SECKEY_DestroyPublicKey(key);
  564.     }
  565.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  566.     if (arena == NULL) {
  567. goto loser;
  568.     }
  569.     namesIndex = (SECItem *) PORT_ZAlloc(sizeof(SECItem) * namesIndexLen);
  570.     if (namesIndex == NULL) {
  571. goto loser;
  572.     }
  573.     for ( count = 0; count < CERT_MAX_CERT_CHAIN; count++ ) {
  574. int subjectNameListLen;
  575. int i;
  576. /* Construct a list of names for the current and all previous certifcates 
  577.    to be verified against the name constraints extension of the issuer
  578.    certificate. */
  579. subjectNameList = CERT_GetCertificateNames(subjectCert, arena);
  580. subjectNameListLen = CERT_GetNamesLength(subjectNameList);
  581. for (i = 0; i < subjectNameListLen; i++) {
  582.     if (namesIndexLen < namesCount + i) {
  583. namesIndexLen = namesIndexLen * 2;
  584. namesIndex = (SECItem *) PORT_Realloc(namesIndex, namesIndexLen * 
  585.        sizeof(SECItem));
  586. if (namesIndex == NULL) {
  587.     goto loser;
  588. }
  589.     }
  590.     rv = SECITEM_CopyItem(arena, &(namesIndex[namesCount + i]), &(subjectCert->derSubject));
  591. }
  592. namesCount += subjectNameListLen;
  593. namesList = cert_CombineNamesLists(namesList, subjectNameList);
  594. /* find the certificate of the issuer */
  595. issuerCert = CERT_FindCertIssuer(subjectCert, t, certUsage);
  596. if ( ! issuerCert ) {
  597.     PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
  598.     LOG_ERROR(log,subjectCert,count,0);
  599.     goto loser;
  600. }
  601. /* verify the signature on the cert */
  602. if ( checkSig ) {
  603.     rv = CERT_VerifySignedData(&subjectCert->signatureWrap,
  604.        issuerCert, t, wincx);
  605.     
  606.     if ( rv != SECSuccess ) {
  607. if ( PORT_GetError() == SEC_ERROR_EXPIRED_CERTIFICATE ) {
  608.     PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
  609.     LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
  610. } else {
  611.     PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
  612.     LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
  613. }
  614.     }
  615. }
  616. /*
  617.  * XXX - fortezza may need error logging stuff added
  618.  */
  619. if (isFortezzaV1) {
  620.     unsigned char priv = 0;
  621.     /* read the key */
  622.     key = CERT_ExtractPublicKey(issuerCert);
  623.     /* Cant' get Key? fail. */
  624.     if (key == NULL) {
  625.      PORT_SetError(SEC_ERROR_BAD_KEY);
  626. LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
  627. goto fortezzaDone;
  628.     }
  629.     /* if the issuer is not an old fortezza cert, we bail */
  630.     if (key->keyType != fortezzaKey) {
  631.      SECKEY_DestroyPublicKey(key);
  632. /* CA Cert not fortezza */
  633.      PORT_SetError(SEC_ERROR_NOT_FORTEZZA_ISSUER);
  634. LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
  635. goto fortezzaDone;
  636.     }
  637.     /* get the privilege mask */
  638.     if (key->u.fortezza.DSSpriviledge.len > 0) {
  639. priv = key->u.fortezza.DSSpriviledge.data[0];
  640.     }
  641.     /*
  642.      * make sure the CA's keys are OK
  643.      */
  644.             
  645.     rv = SEC_CheckKRL(handle, key, NULL, t, wincx);
  646.     if (rv != SECSuccess) {
  647.      SECKEY_DestroyPublicKey(key);
  648. LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
  649. goto fortezzaDone;
  650. /** fall through looking for more stuff **/
  651.     } else {
  652.         SECKEY_DestroyPublicKey(key);
  653.     }
  654.     switch (last_type) {
  655.       case cbd_User:
  656. /* first check for subordination */
  657. /*rv = FortezzaSubordinateCheck(cert,issuerCert);*/
  658. rv = SECSuccess;
  659. /* now check for issuer privilege */
  660. if ((rv != SECSuccess) || ((priv & 0x10) == 0)) {
  661.     /* bail */
  662.     PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
  663.     LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
  664. }
  665. break;
  666.       case cbd_CA:
  667.       case cbd_None:
  668. if ((priv & 0x20) == 0) {
  669.     /* bail */
  670.     PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
  671.     LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
  672. }
  673. break;
  674.       default:
  675. /* bail */ /* shouldn't ever happen */
  676.      PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
  677. LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
  678.     }
  679. fortezzaDone:
  680.     last_type =  cbd_CA;
  681. }
  682. /* If the basicConstraint extension is included in an immediate CA
  683.  * certificate, make sure that the isCA flag is on.  If the
  684.  * pathLenConstraint component exists, it must be greater than the
  685.  * number of CA certificates we have seen so far.  If the extension
  686.  * is omitted, we will assume that this is a CA certificate with
  687.  * an unlimited pathLenConstraint (since it already passes the
  688.  * netscape-cert-type extension checking).
  689.  *
  690.  * In the fortezza (V1) case, we've already checked the CA bits
  691.  * in the key, so we're presumed to be a CA; however we really don't
  692.  * want to bypass Basic constraint or netscape extension parsing.
  693.          * 
  694.          * In Fortezza V2, basicConstraint will be set for every CA,PCA,PAA
  695.  */
  696. rv = CERT_FindBasicConstraintExten(issuerCert, &basicConstraint);
  697. if ( rv != SECSuccess ) {
  698.     if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {
  699. LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
  700.     } else {
  701. currentPathLen = CERT_UNLIMITED_PATH_CONSTRAINT;
  702.     }
  703.     /* no basic constraints found, if we're fortezza, CA bit is already
  704.      * verified (isca = PR_TRUE). otherwise, we aren't (yet) a ca
  705.      * isca = PR_FALSE */
  706.     isca = isFortezzaV1;
  707. } else  {
  708.     if ( basicConstraint.isCA == PR_FALSE ) {
  709. PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
  710. LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
  711.     }
  712.     
  713.     /* make sure that the path len constraint is properly set.
  714.      */
  715.     if ( basicConstraint.pathLenConstraint ==
  716. CERT_UNLIMITED_PATH_CONSTRAINT ) {
  717. currentPathLen = CERT_UNLIMITED_PATH_CONSTRAINT;
  718.     } else if ( currentPathLen == CERT_UNLIMITED_PATH_CONSTRAINT ) {
  719. /* error if the previous CA's path length constraint is
  720.  * unlimited but its CA's path is not.
  721.  */
  722. PORT_SetError (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID);
  723. LOG_ERROR_OR_EXIT(log,issuerCert,count+1,basicConstraint.pathLenConstraint);
  724.     } else if (basicConstraint.pathLenConstraint > currentPathLen) {
  725. currentPathLen = basicConstraint.pathLenConstraint;
  726.     } else {
  727. PORT_SetError (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID);
  728. LOG_ERROR_OR_EXIT(log,issuerCert,count+1,basicConstraint.pathLenConstraint);
  729.     }
  730.     isca = PR_TRUE;
  731. }
  732. /* XXX - the error logging may need to go down into CRL stuff at some
  733.  * point
  734.  */
  735. /* check revoked list (issuer) */
  736. rv = SEC_CheckCRL(handle, subjectCert, issuerCert, t, wincx);
  737. if (rv == SECFailure) {
  738.     LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
  739. } else if (rv == SECWouldBlock) {
  740.     /* We found something fishy, so we intend to issue an
  741.      * error to the user, but the user may wish to continue
  742.      * processing, in which case we better make sure nothing
  743.      * worse has happened... so keep cranking the loop */
  744.     rvFinal = SECFailure;
  745.     LOG_ERROR(log,subjectCert,count,0);
  746. }
  747. if ( issuerCert->trust ) {
  748.     /*
  749.      * check the trust parms of the issuer
  750.      */
  751.     if ( certUsage == certUsageVerifyCA ) {
  752. if ( subjectCert->nsCertType & NS_CERT_TYPE_EMAIL_CA ) {
  753.     trustType = trustEmail;
  754. } else if ( subjectCert->nsCertType & NS_CERT_TYPE_SSL_CA ) {
  755.     trustType = trustSSL;
  756. } else {
  757.     trustType = trustObjectSigning;
  758. }
  759.     }
  760.     
  761.     flags = SEC_GET_TRUST_FLAGS(issuerCert->trust, trustType);
  762.     
  763.     if ( (flags & CERTDB_VALID_CA) ||
  764.  (certUsage == certUsageStatusResponder)) {
  765. if ( ( flags & requiredFlags ) == requiredFlags ||
  766.      certUsage == certUsageStatusResponder ) {
  767.     /* we found a trusted one, so return */
  768.     rv = rvFinal; 
  769.     goto done;
  770. }
  771.     }
  772. }
  773. /*
  774.  * Make sure that if this is an intermediate CA in the chain that
  775.  * it was given permission by its signer to be a CA.
  776.  */
  777. if ( isca ) {
  778.     /*
  779.      * if basicConstraints says it is a ca, then we check the
  780.      * nsCertType.  If the nsCertType has any CA bits set, then
  781.      * it must have the right one.
  782.      */
  783.     if ( issuerCert->nsCertType & NS_CERT_TYPE_CA ) {
  784. if ( issuerCert->nsCertType & caCertType ) {
  785.     isca = PR_TRUE;
  786. } else {
  787.     isca = PR_FALSE;
  788. }
  789.     }
  790. } else {
  791.     if ( issuerCert->nsCertType & caCertType ) {
  792. isca = PR_TRUE;
  793.     } else {
  794. isca = PR_FALSE;
  795.     }
  796. }
  797. if (  !isca  ) {
  798.     PORT_SetError(SEC_ERROR_CA_CERT_INVALID);
  799.     LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
  800. }
  801.     
  802. /* make sure key usage allows cert signing */
  803. if (CERT_CheckKeyUsage(issuerCert, requiredCAKeyUsage) != SECSuccess) {
  804.     PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
  805.     LOG_ERROR_OR_EXIT(log,issuerCert,count+1,requiredCAKeyUsage);
  806. }
  807. /* make sure that the entire chain is within the name space of the current issuer
  808.  * certificate.
  809.  */
  810. badCert = CERT_CompareNameSpace(issuerCert, namesList, namesIndex, arena, handle);
  811. if (badCert != NULL) {
  812.     PORT_SetError(SEC_ERROR_CERT_NOT_IN_NAME_SPACE);
  813.             LOG_ERROR_OR_EXIT(log, badCert, count + 1, 0);
  814.     goto loser;
  815. }
  816. /* make sure that the issuer is not self signed.  If it is, then
  817.  * stop here to prevent looping.
  818.  */
  819. rvCompare = SECITEM_CompareItem(&issuerCert->derSubject,
  820.  &issuerCert->derIssuer);
  821. if (rvCompare == SECEqual) {
  822.     PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
  823.     LOG_ERROR(log, issuerCert, count+1, 0);
  824.     goto loser;
  825. }
  826. CERT_DestroyCertificate(subjectCert);
  827. subjectCert = issuerCert;
  828.     }
  829.     subjectCert = NULL;
  830.     PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
  831.     LOG_ERROR(log,issuerCert,count,0);
  832. loser:
  833.     rv = SECFailure;
  834. done:
  835.     if (namesIndex != NULL) {
  836. PORT_Free(namesIndex);
  837.     }
  838.     if ( issuerCert ) {
  839. CERT_DestroyCertificate(issuerCert);
  840.     }
  841.     
  842.     if ( subjectCert ) {
  843. CERT_DestroyCertificate(subjectCert);
  844.     }
  845.     if ( arena != NULL ) {
  846. PORT_FreeArena(arena, PR_FALSE);
  847.     }
  848.     return rv;
  849. }
  850. /*
  851.  * verify a certificate by checking if its valid and that we
  852.  * trust the issuer.
  853.  * Note that this routine does not verify the signature of the certificate.
  854.  */
  855. SECStatus
  856. CERT_VerifyCert(CERTCertDBHandle *handle, CERTCertificate *cert,
  857. PRBool checkSig, SECCertUsage certUsage, int64 t,
  858. void *wincx, CERTVerifyLog *log)
  859. {
  860.     SECStatus rv;
  861.     unsigned int requiredKeyUsage;
  862.     unsigned int requiredCertType;
  863.     unsigned int flags;
  864.     unsigned int certType;
  865.     PRBool       allowOverride;
  866.     SECCertTimeValidity validity;
  867.     CERTStatusConfig *statusConfig;
  868.     
  869.     /* check if this cert is in the Evil list */
  870.     rv = CERT_CheckForEvilCert(cert);
  871.     if ( rv != SECSuccess ) {
  872. PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
  873. LOG_ERROR_OR_EXIT(log,cert,0,0);
  874.     }
  875.     
  876.     /* make sure that the cert is valid at time t */
  877.     allowOverride = (PRBool)((certUsage == certUsageSSLServer) ||
  878.                              (certUsage == certUsageSSLServerWithStepUp));
  879.     validity = CERT_CheckCertValidTimes(cert, t, allowOverride);
  880.     if ( validity != secCertTimeValid ) {
  881. LOG_ERROR_OR_EXIT(log,cert,0,validity);
  882.     }
  883.     /* check key usage and netscape cert type */
  884.     CERT_GetCertType(cert);
  885.     certType = cert->nsCertType;
  886.     switch ( certUsage ) {
  887.       case certUsageSSLClient:
  888.       case certUsageSSLServer:
  889.       case certUsageSSLServerWithStepUp:
  890.       case certUsageSSLCA:
  891.       case certUsageEmailSigner:
  892.       case certUsageEmailRecipient:
  893.       case certUsageObjectSigner:
  894.       case certUsageStatusResponder:
  895. rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE,
  896.       &requiredKeyUsage,
  897.       &requiredCertType);
  898. if ( rv != SECSuccess ) {
  899.     PORT_Assert(0);
  900.     EXIT_IF_NOT_LOGGING(log);
  901.     requiredKeyUsage = 0;
  902.     requiredCertType = 0;
  903. }
  904. break;
  905.       case certUsageVerifyCA:
  906. requiredKeyUsage = KU_KEY_CERT_SIGN;
  907. requiredCertType = NS_CERT_TYPE_CA;
  908. if ( ! ( certType & NS_CERT_TYPE_CA ) ) {
  909.     certType |= NS_CERT_TYPE_CA;
  910. }
  911. break;
  912.       default:
  913. PORT_Assert(0);
  914. EXIT_IF_NOT_LOGGING(log);
  915. requiredKeyUsage = 0;
  916. requiredCertType = 0;
  917.     }
  918.     if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) {
  919. PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
  920. LOG_ERROR_OR_EXIT(log,cert,0,requiredKeyUsage);
  921.     }
  922.     if ( !( certType & requiredCertType ) ) {
  923. PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
  924. LOG_ERROR_OR_EXIT(log,cert,0,requiredCertType);
  925.     }
  926.     /* check trust flags to see if this cert is directly trusted */
  927.     if ( cert->trust ) { /* the cert is in the DB */
  928. switch ( certUsage ) {
  929.   case certUsageSSLClient:
  930.   case certUsageSSLServer:
  931.     flags = cert->trust->sslFlags;
  932.     
  933.     /* is the cert directly trusted or not trusted ? */
  934.     if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
  935. if ( flags & CERTDB_TRUSTED ) { /* trust this cert */
  936.     goto winner;
  937. } else { /* don't trust this cert */
  938.     PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
  939.     LOG_ERROR_OR_EXIT(log,cert,0,flags);
  940. }
  941.     }
  942.     break;
  943.   case certUsageSSLServerWithStepUp:
  944.     /* XXX - step up certs can't be directly trusted */
  945.     break;
  946.   case certUsageSSLCA:
  947.     break;
  948.   case certUsageEmailSigner:
  949.   case certUsageEmailRecipient:
  950.     flags = cert->trust->emailFlags;
  951.     
  952.     /* is the cert directly trusted or not trusted ? */
  953.     if ( ( flags & ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) ==
  954. ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) {
  955. goto winner;
  956.     }
  957.     break;
  958.   case certUsageObjectSigner:
  959.     flags = cert->trust->objectSigningFlags;
  960.     /* is the cert directly trusted or not trusted ? */
  961.     if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
  962. if ( flags & CERTDB_TRUSTED ) { /* trust this cert */
  963.     goto winner;
  964. } else { /* don't trust this cert */
  965.     PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
  966.     LOG_ERROR_OR_EXIT(log,cert,0,flags);
  967. }
  968.     }
  969.     break;
  970.   case certUsageVerifyCA:
  971.   case certUsageStatusResponder:
  972.     flags = cert->trust->sslFlags;
  973.     /* is the cert directly trusted or not trusted ? */
  974.     if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
  975. ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
  976. goto winner;
  977.     }
  978.     flags = cert->trust->emailFlags;
  979.     /* is the cert directly trusted or not trusted ? */
  980.     if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
  981. ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
  982. goto winner;
  983.     }
  984.     flags = cert->trust->objectSigningFlags;
  985.     /* is the cert directly trusted or not trusted ? */
  986.     if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
  987. ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
  988. goto winner;
  989.     }
  990.     break;
  991.   case certUsageAnyCA:
  992.   case certUsageProtectedObjectSigner:
  993.   case certUsageUserCertImport:
  994.     /* XXX to make the compiler happy.  Should these be
  995.      * explicitly handled?
  996.      */
  997.     break;
  998. }
  999.     }
  1000.     rv = CERT_VerifyCertChain(handle, cert, checkSig, certUsage,
  1001.       t, wincx, log);
  1002.     if (rv != SECSuccess) {
  1003. EXIT_IF_NOT_LOGGING(log);
  1004.     }
  1005.     /*
  1006.      * Check revocation status, but only if the cert we are checking
  1007.      * is not a status reponder itself.  We only do this in the case
  1008.      * where we checked the cert chain (above); explicit trust "wins"
  1009.      * (avoids status checking, just as it avoids CRL checking, which
  1010.      * is all done inside VerifyCertChain) by bypassing this code.
  1011.      */
  1012.     statusConfig = CERT_GetStatusConfig(handle);
  1013.     if (certUsage != certUsageStatusResponder && statusConfig != NULL) {
  1014. if (statusConfig->statusChecker != NULL) {
  1015.     rv = (* statusConfig->statusChecker)(handle, cert,
  1016.  t, wincx);
  1017.     if (rv != SECSuccess) {
  1018. LOG_ERROR_OR_EXIT(log,cert,0,0);
  1019.     }
  1020. }
  1021.     }
  1022. winner:
  1023.     return(SECSuccess);
  1024. loser:
  1025.     rv = SECFailure;
  1026.     
  1027.     return(rv);
  1028. }
  1029. /*
  1030.  * verify a certificate by checking if its valid and that we
  1031.  * trust the issuer.  Verify time against now.
  1032.  */
  1033. SECStatus
  1034. CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert,
  1035.    PRBool checkSig, SECCertUsage certUsage, void *wincx)
  1036. {
  1037.     return(CERT_VerifyCert(handle, cert, checkSig, 
  1038.    certUsage, PR_Now(), wincx, NULL));
  1039. }
  1040. /* [ FROM pcertdb.c ] */
  1041. /*
  1042.  * Supported usage values and types:
  1043.  * certUsageSSLClient
  1044.  * certUsageSSLServer
  1045.  * certUsageSSLServerWithStepUp
  1046.  * certUsageEmailSigner
  1047.  * certUsageEmailRecipient
  1048.  * certUsageObjectSigner
  1049.  */
  1050. CERTCertificate *
  1051. CERT_FindMatchingCert(CERTCertDBHandle *handle, SECItem *derName,
  1052.       CERTCertOwner owner, SECCertUsage usage,
  1053.       PRBool preferTrusted, int64 validTime, PRBool validOnly)
  1054. {
  1055.     CERTCertList *certList = NULL;
  1056.     CERTCertificate *cert = NULL;
  1057.     unsigned int requiredTrustFlags;
  1058.     SECTrustType requiredTrustType;
  1059.     unsigned int flags;
  1060.     
  1061.     PRBool lookingForCA = PR_FALSE;
  1062.     SECStatus rv;
  1063.     CERTCertListNode *node;
  1064.     CERTCertificate *saveUntrustedCA = NULL;
  1065.     
  1066.     /* if preferTrusted is set, must be a CA cert */
  1067.     PORT_Assert( ! ( preferTrusted && ( owner != certOwnerCA ) ) );
  1068.     
  1069.     if ( owner == certOwnerCA ) {
  1070. lookingForCA = PR_TRUE;
  1071. if ( preferTrusted ) {
  1072.     rv = CERT_TrustFlagsForCACertUsage(usage, &requiredTrustFlags,
  1073.        &requiredTrustType);
  1074.     if ( rv != SECSuccess ) {
  1075. goto loser;
  1076.     }
  1077.     requiredTrustFlags |= CERTDB_VALID_CA;
  1078. }
  1079.     }
  1080.     certList = CERT_CreateSubjectCertList(NULL, handle, derName, validTime,
  1081.   validOnly);
  1082.     if ( certList != NULL ) {
  1083. rv = CERT_FilterCertListByUsage(certList, usage, lookingForCA);
  1084. if ( rv != SECSuccess ) {
  1085.     goto loser;
  1086. }
  1087. node = CERT_LIST_HEAD(certList);
  1088. while ( !CERT_LIST_END(node, certList) ) {
  1089.     cert = node->cert;
  1090.     /* looking for a trusted CA cert */
  1091.     if ( ( owner == certOwnerCA ) && preferTrusted &&
  1092. ( requiredTrustType != trustTypeNone ) ) {
  1093. if ( cert->trust == NULL ) {
  1094.     flags = 0;
  1095. } else {
  1096.     flags = SEC_GET_TRUST_FLAGS(cert->trust, requiredTrustType);
  1097. }
  1098. if ( ( flags & requiredTrustFlags ) != requiredTrustFlags ) {
  1099.     /* cert is not trusted */
  1100.     /* if this is the first cert to get this far, then save
  1101.      * it, so we can use it if we can't find a trusted one
  1102.      */
  1103.     if ( saveUntrustedCA == NULL ) {
  1104. saveUntrustedCA = cert;
  1105.     }
  1106.     goto endloop;
  1107. }
  1108.     }
  1109.     /* if we got this far, then this cert meets all criteria */
  1110.     break;
  1111.     
  1112. endloop:
  1113.     node = CERT_LIST_NEXT(node);
  1114.     cert = NULL;
  1115. }
  1116. /* use the saved one if we have it */
  1117. if ( cert == NULL ) {
  1118.     cert = saveUntrustedCA;
  1119. }
  1120. /* if we found one then bump the ref count before freeing the list */
  1121. if ( cert != NULL ) {
  1122.     /* bump the ref count */
  1123.     cert = CERT_DupCertificate(cert);
  1124. }
  1125. CERT_DestroyCertList(certList);
  1126.     }
  1127.     return(cert);
  1128. loser:
  1129.     if ( certList != NULL ) {
  1130. CERT_DestroyCertList(certList);
  1131.     }
  1132.     return(NULL);
  1133. }
  1134. /* [ From certdb.c ] */
  1135. /*
  1136.  * Filter a list of certificates, removing those certs that do not have
  1137.  * one of the named CA certs somewhere in their cert chain.
  1138.  *
  1139.  * "certList" - the list of certificates to filter
  1140.  * "nCANames" - number of CA names
  1141.  * "caNames" - array of CA names in string(rfc 1485) form
  1142.  * "usage" - what use the certs are for, this is used when
  1143.  * selecting CA certs
  1144.  */
  1145. SECStatus
  1146. CERT_FilterCertListByCANames(CERTCertList *certList, int nCANames,
  1147.      char **caNames, SECCertUsage usage)
  1148. {
  1149.     CERTCertificate *issuerCert = NULL;
  1150.     CERTCertificate *subjectCert;
  1151.     CERTCertListNode *node, *freenode;
  1152.     CERTCertificate *cert;
  1153.     int n;
  1154.     char **names;
  1155.     PRBool found;
  1156.     int64 time;
  1157.     
  1158.     if ( nCANames <= 0 ) {
  1159. return(SECSuccess);
  1160.     }
  1161.     time = PR_Now();
  1162.     
  1163.     node = CERT_LIST_HEAD(certList);
  1164.     
  1165.     while ( ! CERT_LIST_END(node, certList) ) {
  1166. cert = node->cert;
  1167. subjectCert = CERT_DupCertificate(cert);
  1168. /* traverse the CA certs for this cert */
  1169. found = PR_FALSE;
  1170. while ( subjectCert != NULL ) {
  1171.     n = nCANames;
  1172.     names = caNames;
  1173.    
  1174.             if (subjectCert->issuerName != NULL) { 
  1175.         while ( n > 0 ) {
  1176.     if ( PORT_Strcmp(*names, subjectCert->issuerName) == 0 ) {
  1177.         found = PR_TRUE;
  1178.         break;
  1179.     }
  1180.     n--;
  1181.     names++;
  1182.                 }
  1183.     }
  1184.     if ( found ) {
  1185. break;
  1186.     }
  1187.     
  1188.     issuerCert = CERT_FindCertIssuer(subjectCert, time, usage);
  1189.     if ( issuerCert == subjectCert ) {
  1190. CERT_DestroyCertificate(issuerCert);
  1191. issuerCert = NULL;
  1192. break;
  1193.     }
  1194.     CERT_DestroyCertificate(subjectCert);
  1195.     subjectCert = issuerCert;
  1196. }
  1197. CERT_DestroyCertificate(subjectCert);
  1198. if ( !found ) {
  1199.     /* CA was not found, so remove this cert from the list */
  1200.     freenode = node;
  1201.     node = CERT_LIST_NEXT(node);
  1202.     CERT_RemoveCertListNode(freenode);
  1203. } else {
  1204.     /* CA was found, so leave it in the list */
  1205.     node = CERT_LIST_NEXT(node);
  1206. }
  1207.     }
  1208.     
  1209.     return(SECSuccess);
  1210. }
  1211. /*
  1212.  * Given a certificate, return a string containing the nickname, and possibly
  1213.  * one of the validity strings, based on the current validity state of the
  1214.  * certificate.
  1215.  *
  1216.  * "arena" - arena to allocate returned string from.  If NULL, then heap
  1217.  * is used.
  1218.  * "cert" - the cert to get nickname from
  1219.  * "expiredString" - the string to append to the nickname if the cert is
  1220.  * expired.
  1221.  * "notYetGoodString" - the string to append to the nickname if the cert is
  1222.  * not yet good.
  1223.  */
  1224. char *
  1225. CERT_GetCertNicknameWithValidity(PRArenaPool *arena, CERTCertificate *cert,
  1226.  char *expiredString, char *notYetGoodString)
  1227. {
  1228.     SECCertTimeValidity validity;
  1229.     char *nickname, *tmpstr;
  1230.     
  1231.     validity = CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE);
  1232.     /* if the cert is good, then just use the nickname directly */
  1233.     if ( validity == secCertTimeValid ) {
  1234. if ( arena == NULL ) {
  1235.     nickname = PORT_Strdup(cert->nickname);
  1236. } else {
  1237.     nickname = PORT_ArenaStrdup(arena, cert->nickname);
  1238. }
  1239. if ( nickname == NULL ) {
  1240.     goto loser;
  1241. }
  1242.     } else {
  1243.     
  1244. /* if the cert is not valid, then tack one of the strings on the
  1245.  * end
  1246.  */
  1247. if ( validity == secCertTimeExpired ) {
  1248.     tmpstr = PR_smprintf("%s%s", cert->nickname,
  1249.  expiredString);
  1250. } else {
  1251.     /* not yet valid */
  1252.     tmpstr = PR_smprintf("%s%s", cert->nickname,
  1253.  notYetGoodString);
  1254. }
  1255. if ( tmpstr == NULL ) {
  1256.     goto loser;
  1257. }
  1258. if ( arena ) {
  1259.     /* copy the string into the arena and free the malloc'd one */
  1260.     nickname = PORT_ArenaStrdup(arena, tmpstr);
  1261.     PORT_Free(tmpstr);
  1262. } else {
  1263.     nickname = tmpstr;
  1264. }
  1265. if ( nickname == NULL ) {
  1266.     goto loser;
  1267. }
  1268.     }    
  1269.     return(nickname);
  1270. loser:
  1271.     return(NULL);
  1272. }
  1273. /*
  1274.  * Collect the nicknames from all certs in a CertList.  If the cert is not
  1275.  * valid, append a string to that nickname.
  1276.  *
  1277.  * "certList" - the list of certificates
  1278.  * "expiredString" - the string to append to the nickname of any expired cert
  1279.  * "notYetGoodString" - the string to append to the nickname of any cert
  1280.  * that is not yet valid
  1281.  */
  1282. CERTCertNicknames *
  1283. CERT_NicknameStringsFromCertList(CERTCertList *certList, char *expiredString,
  1284.  char *notYetGoodString)
  1285. {
  1286.     CERTCertNicknames *names;
  1287.     PRArenaPool *arena;
  1288.     CERTCertListNode *node;
  1289.     char **nn;
  1290.     
  1291.     /* allocate an arena */
  1292.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1293.     if ( arena == NULL ) {
  1294. return(NULL);
  1295.     }
  1296.     
  1297.     /* allocate the structure */
  1298.     names = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
  1299.     if ( names == NULL ) {
  1300. goto loser;
  1301.     }
  1302.     /* init the structure */
  1303.     names->arena = arena;
  1304.     names->head = NULL;
  1305.     names->numnicknames = 0;
  1306.     names->nicknames = NULL;
  1307.     names->totallen = 0;
  1308.     /* count the certs in the list */
  1309.     node = CERT_LIST_HEAD(certList);
  1310.     while ( ! CERT_LIST_END(node, certList) ) {
  1311. names->numnicknames++;
  1312. node = CERT_LIST_NEXT(node);
  1313.     }
  1314.     
  1315.     /* allocate nicknames array */
  1316.     names->nicknames = PORT_ArenaAlloc(arena,
  1317.        sizeof(char *) * names->numnicknames);
  1318.     if ( names->nicknames == NULL ) {
  1319. goto loser;
  1320.     }
  1321.     /* just in case printf can't deal with null strings */
  1322.     if (expiredString == NULL ) {
  1323. expiredString = "";
  1324.     }
  1325.     if ( notYetGoodString == NULL ) {
  1326. notYetGoodString = "";
  1327.     }
  1328.     
  1329.     /* traverse the list of certs and collect the nicknames */
  1330.     nn = names->nicknames;
  1331.     node = CERT_LIST_HEAD(certList);
  1332.     while ( ! CERT_LIST_END(node, certList) ) {
  1333. *nn = CERT_GetCertNicknameWithValidity(arena, node->cert,
  1334.        expiredString,
  1335.        notYetGoodString);
  1336. if ( *nn == NULL ) {
  1337.     goto loser;
  1338. }
  1339. names->totallen += PORT_Strlen(*nn);
  1340. nn++;
  1341. node = CERT_LIST_NEXT(node);
  1342.     }
  1343.     return(names);
  1344. loser:
  1345.     PORT_FreeArena(arena, PR_FALSE);
  1346.     return(NULL);
  1347. }
  1348. /*
  1349.  * Extract the nickname from a nickmake string that may have either
  1350.  * expiredString or notYetGoodString appended.
  1351.  *
  1352.  * Args:
  1353.  * "namestring" - the string containing the nickname, and possibly
  1354.  * one of the validity label strings
  1355.  * "expiredString" - the expired validity label string
  1356.  * "notYetGoodString" - the not yet good validity label string
  1357.  *
  1358.  * Returns the raw nickname
  1359.  */
  1360. char *
  1361. CERT_ExtractNicknameString(char *namestring, char *expiredString,
  1362.    char *notYetGoodString)
  1363. {
  1364.     int explen, nyglen, namelen;
  1365.     int retlen;
  1366.     char *retstr;
  1367.     
  1368.     namelen = PORT_Strlen(namestring);
  1369.     explen = PORT_Strlen(expiredString);
  1370.     nyglen = PORT_Strlen(notYetGoodString);
  1371.     
  1372.     if ( namelen > explen ) {
  1373. if ( PORT_Strcmp(expiredString, &namestring[namelen-explen]) == 0 ) {
  1374.     retlen = namelen - explen;
  1375.     retstr = (char *)PORT_Alloc(retlen+1);
  1376.     if ( retstr == NULL ) {
  1377. goto loser;
  1378.     }
  1379.     
  1380.     PORT_Memcpy(retstr, namestring, retlen);
  1381.     retstr[retlen] = '';
  1382.     goto done;
  1383. }
  1384.     }
  1385.     if ( namelen > nyglen ) {
  1386. if ( PORT_Strcmp(notYetGoodString, &namestring[namelen-nyglen]) == 0) {
  1387.     retlen = namelen - nyglen;
  1388.     retstr = (char *)PORT_Alloc(retlen+1);
  1389.     if ( retstr == NULL ) {
  1390. goto loser;
  1391.     }
  1392.     
  1393.     PORT_Memcpy(retstr, namestring, retlen);
  1394.     retstr[retlen] = '';
  1395.     goto done;
  1396. }
  1397.     }
  1398.     /* if name string is shorter than either invalid string, then it must
  1399.      * be a raw nickname
  1400.      */
  1401.     retstr = PORT_Strdup(namestring);
  1402.     
  1403. done:
  1404.     return(retstr);
  1405. loser:
  1406.     return(NULL);
  1407. }
  1408. CERTCertList *
  1409. CERT_GetCertChainFromCert(CERTCertificate *cert, int64 time, SECCertUsage usage)
  1410. {
  1411.     CERTCertList *chain;
  1412.     if (cert != NULL) {
  1413. chain = CERT_NewCertList();
  1414. cert = CERT_DupCertificate(cert);
  1415. while (SECITEM_CompareItem(&cert->derIssuer, &cert->derSubject) 
  1416.        != SECEqual) {
  1417.     CERT_AddCertToListTail(chain, cert);
  1418.     cert = CERT_FindCertIssuer(cert, time, usage);
  1419. }
  1420. CERT_AddCertToListTail(chain, cert);
  1421. return chain;
  1422.     }
  1423.     return NULL;
  1424. }