/* Called when the server certificate verification fails. This gives us
   the chance to trust the server anyway and add the certificate to the
   local database.  */
static SECStatus
badCertHandler(void *arg, PRFileDesc *sslSocket)
{
  SECStatus secStatus;
  PRErrorCode errorNumber;
  CERTCertificate *serverCert;

  /* By default, don't trust the certificate.  */
  secStatus = SECFailure;

  errorNumber = PR_GetError ();
  if (errorNumber == SEC_ERROR_CA_CERT_INVALID)
    {
      /* The server's certificate is not trusted. Should we trust it? */
      if (trustNewServer_p == NULL)
	return SECFailure; /* Do not trust this server */

      /* Trust it for this session only?  */
      if (strcmp (trustNewServer_p, "session") == 0)
	return SECSuccess;

      /* Trust it permanently?  */
      if (strcmp (trustNewServer_p, "permanent") == 0)
	{
	  /* The user wants to trust this server. Get the server's certificate so
	     and add it to our database.  */
	  serverCert = SSL_PeerCertificate (sslSocket);
	  if (serverCert != NULL)
	    secStatus = trustNewServer (serverCert);
	}
    }

  return secStatus;
}
Example #2
0
/* This invokes the "default" AuthCert handler in libssl.
** The only reason to use this one is that it prints out info as it goes. 
*/
static SECStatus
mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,
		     PRBool isServer)
{
    SECStatus rv;
    CERTCertificate *    peerCert;
    const SECItemArray *csa;

    if (MakeCertOK>=2) {
        return SECSuccess;
    }
    peerCert = SSL_PeerCertificate(fd);

    PRINTF("strsclnt: Subject: %s\nstrsclnt: Issuer : %s\n", 
           peerCert->subjectName, peerCert->issuerName); 
    csa = SSL_PeerStapledOCSPResponses(fd);
    if (csa) {
        PRINTF("Received %d Cert Status items (OCSP stapled data)\n",
               csa->len);
    }
    /* invoke the "default" AuthCert handler. */
    rv = SSL_AuthCertificate(arg, fd, checkSig, isServer);

    PR_ATOMIC_INCREMENT(&certsTested);
    if (rv == SECSuccess) {
	fputs("strsclnt: -- SSL: Server Certificate Validated.\n", stderr);
    }
    CERT_DestroyCertificate(peerCert);
    /* error, if any, will be displayed by the Bad Cert Handler. */
    return rv;  
}
Example #3
0
File: nss.c Project: 0w/moai-dev
/**
 *
 * Check that the Peer certificate's issuer certificate matches the one found
 * by issuer_nickname.  This is not exactly the way OpenSSL and GNU TLS do the
 * issuer check, so we provide comments that mimic the OpenSSL
 * X509_check_issued function (in x509v3/v3_purp.c)
 */
static SECStatus check_issuer_cert(PRFileDesc *sock,
                                   char *issuer_nickname)
{
  CERTCertificate *cert,*cert_issuer,*issuer;
  SECStatus res=SECSuccess;
  void *proto_win = NULL;

  /*
  PRArenaPool   *tmpArena = NULL;
  CERTAuthKeyID *authorityKeyID = NULL;
  SECITEM       *caname = NULL;
  */

  cert = SSL_PeerCertificate(sock);
  cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner);

  proto_win = SSL_RevealPinArg(sock);
  issuer = NULL;
  issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);

  if ((!cert_issuer) || (!issuer))
    res = SECFailure;
  else if (SECITEM_CompareItem(&cert_issuer->derCert,
                               &issuer->derCert)!=SECEqual)
    res = SECFailure;

  CERT_DestroyCertificate(cert);
  CERT_DestroyCertificate(issuer);
  CERT_DestroyCertificate(cert_issuer);
  return res;
}
Example #4
0
static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd) {
    struct tls_connection *conn = arg;
    SECStatus res = SECSuccess;
    PRErrorCode err;
    CERTCertificate *cert;
    char *subject, *issuer;

    err = PR_GetError();
    if (IS_SEC_ERROR(err))
        wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err "
            "%d)", err - SEC_ERROR_BASE);
    else
        wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)",
            err);
    cert = SSL_PeerCertificate(fd);
    subject = CERT_NameToAscii(&cert->subject);
    issuer = CERT_NameToAscii(&cert->issuer);
    wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'",
            subject, issuer);
    CERT_DestroyCertificate(cert);
    PR_Free(subject);
    PR_Free(issuer);
    if (conn->verify_peer)
        res = SECFailure;

    return res;
}
SECStatus TransportLayerDtls::AuthCertificateHook(PRFileDesc *fd,
                                                  PRBool checksig,
                                                  PRBool isServer) {
  CheckThread();
  ScopedCERTCertificate peer_cert;
  peer_cert = SSL_PeerCertificate(fd);


  // We are not set up to take this being called multiple
  // times. Change this if we ever add renegotiation.
  MOZ_ASSERT(!auth_hook_called_);
  if (auth_hook_called_) {
    PR_SetError(PR_UNKNOWN_ERROR, 0);
    return SECFailure;
  }
  auth_hook_called_ = true;

  MOZ_ASSERT(verification_mode_ != VERIFY_UNSET);
  MOZ_ASSERT(peer_cert_ == nullptr);

  switch (verification_mode_) {
    case VERIFY_UNSET:
      // Break out to error exit
      PR_SetError(PR_UNKNOWN_ERROR, 0);
      break;

    case VERIFY_ALLOW_ALL:
      peer_cert_ = peer_cert.forget();
      cert_ok_ = true;
      return SECSuccess;

    case VERIFY_DIGEST:
      {
        MOZ_ASSERT(digests_.size() != 0);
        // Check all the provided digests

        // Checking functions call PR_SetError()
        SECStatus rv = SECFailure;
        for (size_t i = 0; i < digests_.size(); i++) {
          RefPtr<VerificationDigest> digest = digests_[i];
          rv = CheckDigest(digest, peer_cert);

          if (rv != SECSuccess)
            break;
        }

        if (rv == SECSuccess) {
          // Matches all digests, we are good to go
          cert_ok_ = true;
          peer_cert = peer_cert.forget();
          return SECSuccess;
        }
      }
      break;
    default:
      MOZ_CRASH();  // Can't happen
  }

  return SECFailure;
}
Example #6
0
static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
{
  SECStatus result = SECFailure;
  struct connectdata *conn = (struct connectdata *)arg;
  PRErrorCode err = PR_GetError();
  CERTCertificate *cert = NULL;
  char *subject, *subject_cn, *issuer;

  conn->data->set.ssl.certverifyresult=err;
  cert = SSL_PeerCertificate(sock);
  subject = CERT_NameToAscii(&cert->subject);
  subject_cn = CERT_GetCommonName(&cert->subject);
  issuer = CERT_NameToAscii(&cert->issuer);
  CERT_DestroyCertificate(cert);

  switch(err) {
  case SEC_ERROR_CA_CERT_INVALID:
    infof(conn->data, "Issuer certificate is invalid: '%s'\n", issuer);
    break;
  case SEC_ERROR_UNTRUSTED_ISSUER:
    infof(conn->data, "Certificate is signed by an untrusted issuer: '%s'\n",
          issuer);
    break;
  case SSL_ERROR_BAD_CERT_DOMAIN:
    if(conn->data->set.ssl.verifyhost) {
      failf(conn->data, "SSL: certificate subject name '%s' does not match "
            "target host name '%s'", subject_cn, conn->host.dispname);
    }
    else {
      result = SECSuccess;
      infof(conn->data, "warning: SSL: certificate subject name '%s' does not "
            "match target host name '%s'\n", subject_cn, conn->host.dispname);
    }
    break;
  case SEC_ERROR_EXPIRED_CERTIFICATE:
    infof(conn->data, "Remote Certificate has expired.\n");
    break;
  case SEC_ERROR_UNKNOWN_ISSUER:
    infof(conn->data, "Peer's certificate issuer is not recognized: '%s'\n",
          issuer);
    break;
  default:
    infof(conn->data, "Bad certificate received. Subject = '%s', "
          "Issuer = '%s'\n", subject, issuer);
    break;
  }
  if(result == SECSuccess)
    infof(conn->data, "SSL certificate verify ok.\n");
  PR_Free(subject);
  PR_Free(subject_cn);
  PR_Free(issuer);

  return result;
}
Example #7
0
static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
{
  SECStatus success = SECSuccess;
  struct connectdata *conn = (struct connectdata *)arg;
  PRErrorCode err = PR_GetError();
  CERTCertificate *cert = NULL;
  char *subject, *issuer;

  if(conn->data->set.ssl.certverifyresult!=0)
    return success;

  conn->data->set.ssl.certverifyresult=err;
  cert = SSL_PeerCertificate(sock);
  subject = CERT_NameToAscii(&cert->subject);
  issuer = CERT_NameToAscii(&cert->issuer);
  CERT_DestroyCertificate(cert);

  switch(err) {
  case SEC_ERROR_CA_CERT_INVALID:
    infof(conn->data, "Issuer certificate is invalid: '%s'\n", issuer);
    if(conn->data->set.ssl.verifypeer)
      success = SECFailure;
    break;
  case SEC_ERROR_UNTRUSTED_ISSUER:
    if(conn->data->set.ssl.verifypeer)
      success = SECFailure;
    infof(conn->data, "Certificate is signed by an untrusted issuer: '%s'\n",
          issuer);
    break;
  case SSL_ERROR_BAD_CERT_DOMAIN:
    if(conn->data->set.ssl.verifypeer)
      success = SECFailure;
    infof(conn->data, "common name: %s (does not match '%s')\n",
          subject, conn->host.dispname);
    break;
  case SEC_ERROR_EXPIRED_CERTIFICATE:
    if(conn->data->set.ssl.verifypeer)
      success = SECFailure;
    infof(conn->data, "Remote Certificate has expired.\n");
    break;
  default:
    if(conn->data->set.ssl.verifypeer)
      success = SECFailure;
    infof(conn->data, "Bad certificate received. Subject = '%s', "
          "Issuer = '%s'\n", subject, issuer);
    break;
  }
  if(success == SECSuccess)
    infof(conn->data, "SSL certificate verify ok.\n");
  PR_Free(subject);
  PR_Free(issuer);

  return success;
}
Example #8
0
/*
 * Callback from SSL for checking a (possibly) expired
 * certificate the peer presents.
 */
SECStatus
JSSL_ConfirmExpiredPeerCert(void *arg, PRFileDesc *fd, PRBool checkSig,
             PRBool isServer)
{
    SECStatus rv=SECFailure;
    SECCertUsage certUsage;
    CERTCertificate* peerCert=NULL;
    int64 notAfter, notBefore;

    certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;

    peerCert = SSL_PeerCertificate(fd);

    if (peerCert) {
        rv = CERT_GetCertTimes(peerCert, &notBefore, &notAfter);
        if (rv != SECSuccess) goto finish;

        /*
         * Verify the certificate based on it's expiry date. This should
         * always succeed, if the cert is trusted. It doesn't care if
         * the cert has expired.
         */
        rv = CERT_VerifyCert(CERT_GetDefaultCertDB(), peerCert,
                             checkSig, certUsage, 
                             notAfter, NULL /*pinarg*/,
                             NULL /* log */);
    }
    if ( rv != SECSuccess ) goto finish;

    if( ! isServer )  {
        /* This is the client side of an SSL connection.
        * Now check the name field in the cert against the desired hostname.
        * NB: This is our only defense against Man-In-The-Middle (MITM) attacks!
        */
        if( peerCert == NULL ) {
            rv = SECFailure;
        } else {
            char* hostname = NULL;
            hostname = SSL_RevealURL(fd); /* really is a hostname, not a URL */
            if (hostname && hostname[0]) {
                rv = CERT_VerifyCertName(peerCert, hostname);
                PORT_Free(hostname);
            } else {
                rv = SECFailure;
            }
        }
    }

finish:
    if (peerCert!=NULL) CERT_DestroyCertificate(peerCert);
    return rv;
}
Example #9
0
/*
 * Callback from SSL for checking certificate the peer (other end of
 * the socket) presents.
 */
SECStatus
JSSL_DefaultCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig,
             PRBool isServer)
{
    char *          hostname = NULL;
    SECStatus         rv    = SECFailure;
    SECCertUsage      certUsage;
    CERTCertificate   *peerCert=NULL;

    certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
 

    /* SSL_PeerCertificate() returns a shallow copy of the cert, so we
       must destroy it before we exit this function */

    peerCert   = SSL_PeerCertificate(fd);

    if (peerCert) {
        rv = CERT_VerifyCertNow(CERT_GetDefaultCertDB(), peerCert,
                checkSig, certUsage, NULL /*pinarg*/);
    }

    /* if we're a server, then we don't need to check the CN of the
       certificate, so we can just return whatever returncode we
       have now
     */

    if ( rv != SECSuccess || isServer )  {
        if (peerCert) CERT_DestroyCertificate(peerCert);
            return (int)rv;
        }

    /* cert is OK.  This is the client side of an SSL connection.
     * Now check the name field in the cert against the desired hostname.
     * NB: This is our only defense against Man-In-The-Middle (MITM) attacks!
     */
    hostname = SSL_RevealURL(fd);    /* really is a hostname, not a URL */
    if (hostname && hostname[0]) {
        rv = CERT_VerifyCertName(peerCert, hostname);
        PORT_Free(hostname); 
    } else
        rv = SECFailure;

    if (peerCert) CERT_DestroyCertificate(peerCert);
    return rv;
}
Example #10
0
static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
{
  SSLChannelInfo channel;
  SSLCipherSuiteInfo suite;
  CERTCertificate *cert;
  char *subject, *issuer, *common_name;
  PRExplodedTime printableTime;
  char timeString[256];
  PRTime notBefore, notAfter;

  if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
     SECSuccess && channel.length == sizeof channel &&
     channel.cipherSuite) {
    if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
                              &suite, sizeof suite) == SECSuccess) {
      infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
    }
  }

  infof(conn->data, "Server certificate:\n");

  cert = SSL_PeerCertificate(sock);
  subject = CERT_NameToAscii(&cert->subject);
  issuer = CERT_NameToAscii(&cert->issuer);
  common_name = CERT_GetCommonName(&cert->subject);
  infof(conn->data, "\tsubject: %s\n", subject);

  CERT_GetCertTimes(cert, &notBefore, &notAfter);
  PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
  PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
  infof(conn->data, "\tstart date: %s\n", timeString);
  PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
  PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
  infof(conn->data, "\texpire date: %s\n", timeString);
  infof(conn->data, "\tcommon name: %s\n", common_name);
  infof(conn->data, "\tissuer: %s\n", issuer);

  PR_Free(subject);
  PR_Free(issuer);
  PR_Free(common_name);

  CERT_DestroyCertificate(cert);

  return;
}
Example #11
0
File: nss.c Project: flashfoxter/sx
static int cert_from_sessioninfo(sxc_client_t *sx, const struct curl_tlssessioninfo *info, CERTCertificate **cert)
{
    if (info->backend != CURLSSLBACKEND_NSS) {
        curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
        sxi_seterr(sx, SXE_ECURL, "SSL backend mismatch: NSS expected, got %d (curl %s)",
                   info->backend, data->ssl_version ? data->ssl_version : "N/A");
        return -1;
    }
    PRFileDesc *desc = info->internals;
    if(!desc) {
        SXDEBUG("NULL PRFileDesc context");
        return -EAGAIN;
    }
    *cert = SSL_PeerCertificate(desc);
    if (!*cert) {
        PRInt32 err = PR_GetError();
        SXDEBUG("Unable to retrieve certificate for cluster: %s",
                PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
        return -EAGAIN;
    }
    return 0;
}
Example #12
0
static GList *
ssl_nss_get_peer_certificates(PRFileDesc *socket, PurpleSslConnection * gsc)
{
	CERTCertificate *curcert;
	CERTCertificate *issuerCert;
	PurpleCertificate * newcrt;

	/* List of Certificate instances to return */
	GList * peer_certs = NULL;
	int count;
	int64 now = PR_Now();

	curcert = SSL_PeerCertificate(socket);
	if (curcert == NULL) {
		purple_debug_error("nss", "could not DupCertificate\n");
		return NULL;
	}

	for (count = 0 ; count < CERT_MAX_CERT_CHAIN ; count++) {
		purple_debug_info("nss", "subject=%s issuer=%s\n", curcert->subjectName,
						  curcert->issuerName  ? curcert->issuerName : "(null)");
		newcrt = x509_import_from_nss(curcert);
		peer_certs = g_list_append(peer_certs, newcrt);

		if (curcert->isRoot) {
			break;
		}
		issuerCert = CERT_FindCertIssuer(curcert, now, certUsageSSLServer);
		if (!issuerCert) {
			purple_debug_error("nss", "partial certificate chain\n");
			break;
		}
		CERT_DestroyCertificate(curcert);
		curcert = issuerCert;
	}
	CERT_DestroyCertificate(curcert);

	return peer_certs;
}
std::string SslSocket::getClientAuthId() const
{
    std::string authId;
    CERTCertificate* cert = SSL_PeerCertificate(nssSocket);
    if (cert) {
        char *cn = CERT_GetCommonName(&(cert->subject));
        if (cn) {
            authId = std::string(cn);
            /*
             * The NSS function CERT_GetDomainComponentName only returns
             * the last component of the domain name, so we have to parse
             * the subject manually to extract the full domain.
             */
            std::string domain = getDomainFromSubject(cert->subjectName);
            if (!domain.empty()) {
                authId += DOMAIN_SEPARATOR;
                authId += domain;
            }
        }
        CERT_DestroyCertificate(cert);
    }
    return authId;
}
Example #14
0
static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
{
  SSLChannelInfo channel;
  SSLCipherSuiteInfo suite;
  CERTCertificate *cert;

  if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
     SECSuccess && channel.length == sizeof channel &&
     channel.cipherSuite) {
    if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
                              &suite, sizeof suite) == SECSuccess) {
      infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
    }
  }

  infof(conn->data, "Server certificate:\n");

  cert = SSL_PeerCertificate(sock);
  display_cert_info(conn->data, cert);
  CERT_DestroyCertificate(cert);

  return;
}
Example #15
0
static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
{
  struct connectdata *conn = (struct connectdata *)arg;
  struct SessionHandle *data = conn->data;
  PRErrorCode err = PR_GetError();
  CERTCertificate *cert;

  /* remember the cert verification result */
  data->set.ssl.certverifyresult = err;

  if(err == SSL_ERROR_BAD_CERT_DOMAIN && !data->set.ssl.verifyhost)
    /* we are asked not to verify the host name */
    return SECSuccess;

  /* print only info about the cert, the error is printed off the callback */
  cert = SSL_PeerCertificate(sock);
  if(cert) {
    infof(data, "Server certificate:\n");
    display_cert_info(data, cert);
    CERT_DestroyCertificate(cert);
  }

  return SECFailure;
}
Example #16
0
static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
{
  SSLChannelInfo channel;
  SSLCipherSuiteInfo suite;
  CERTCertificate *cert;
  CERTCertificate *cert2;
  CERTCertificate *cert3;
  PRTime now;
  int i;

  if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
     SECSuccess && channel.length == sizeof channel &&
     channel.cipherSuite) {
    if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
                              &suite, sizeof suite) == SECSuccess) {
      infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
    }
  }

  cert = SSL_PeerCertificate(sock);

  if(cert) {
    infof(conn->data, "Server certificate:\n");

    if(!conn->data->set.ssl.certinfo) {
      display_cert_info(conn->data, cert);
      CERT_DestroyCertificate(cert);
    }
    else {
      /* Count certificates in chain. */
      now = PR_Now();
      i = 1;
      if(!cert->isRoot) {
        cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
        while(cert2) {
          i++;
          if(cert2->isRoot) {
            CERT_DestroyCertificate(cert2);
            break;
          }
          cert3 = CERT_FindCertIssuer(cert2, now, certUsageSSLCA);
          CERT_DestroyCertificate(cert2);
          cert2 = cert3;
        }
      }
      Curl_ssl_init_certinfo(conn->data, i);
      for(i = 0; cert; cert = cert2) {
        Curl_extract_certinfo(conn, i++, (char *)cert->derCert.data,
                              (char *)cert->derCert.data + cert->derCert.len);
        if(cert->isRoot) {
          CERT_DestroyCertificate(cert);
          break;
        }
        cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
        CERT_DestroyCertificate(cert);
      }
    }
  }

  return;
}
Example #17
0
void PR_CALLBACK HandshakeCallback(PRFileDesc* fd, void* client_data) {
  nsNSSShutDownPreventionLock locker;
  PRInt32 sslStatus;
  char* signer = nsnull;
  char* cipherName = nsnull;
  PRInt32 keyLength;
  nsresult rv;
  PRInt32 encryptBits;

  if (SECSuccess != SSL_SecurityStatus(fd, &sslStatus, &cipherName, &keyLength,
                                       &encryptBits, &signer, nsnull)) {
    return;
  }

  PRInt32 secStatus;
  if (sslStatus == SSL_SECURITY_STATUS_OFF)
    secStatus = nsIWebProgressListener::STATE_IS_BROKEN;
  else if (encryptBits >= 90)
    secStatus = (nsIWebProgressListener::STATE_IS_SECURE |
                 nsIWebProgressListener::STATE_SECURE_HIGH);
  else
    secStatus = (nsIWebProgressListener::STATE_IS_SECURE |
                 nsIWebProgressListener::STATE_SECURE_LOW);

  CERTCertificate *peerCert = SSL_PeerCertificate(fd);
  const char* caName = nsnull; // caName is a pointer only, no ownership
  char* certOrgName = CERT_GetOrgName(&peerCert->issuer);
  CERT_DestroyCertificate(peerCert);
  caName = certOrgName ? certOrgName : signer;

  const char* verisignName = "Verisign, Inc.";
  // If the CA name is RSA Data Security, then change the name to the real
  // name of the company i.e. VeriSign, Inc.
  if (nsCRT::strcmp((const char*)caName, "RSA Data Security, Inc.") == 0) {
    caName = verisignName;
  }

  nsAutoString shortDesc;
  const PRUnichar* formatStrings[1] = { ToNewUnicode(NS_ConvertUTF8toUTF16(caName)) };
  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  if (NS_SUCCEEDED(rv)) {
    rv = nssComponent->PIPBundleFormatStringFromName("SignedBy",
                                                   formatStrings, 1,
                                                   shortDesc);

    nsMemory::Free(const_cast<PRUnichar*>(formatStrings[0]));

    nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
    infoObject->SetSecurityState(secStatus);
    infoObject->SetShortSecurityDescription(shortDesc.get());

    /* Set the SSL Status information */
    nsRefPtr<nsSSLStatus> status = infoObject->SSLStatus();
    if (!status) {
      status = new nsSSLStatus();
      infoObject->SetSSLStatus(status);
    }

    CERTCertificate *serverCert = SSL_PeerCertificate(fd);
    if (serverCert) {
      nsRefPtr<nsNSSCertificate> nssc = new nsNSSCertificate(serverCert);
      CERT_DestroyCertificate(serverCert);
      serverCert = nsnull;

      nsCOMPtr<nsIX509Cert> prevcert;
      infoObject->GetPreviousCert(getter_AddRefs(prevcert));

      PRBool equals_previous = PR_FALSE;
      if (prevcert) {
        nsresult rv = nssc->Equals(prevcert, &equals_previous);
        if (NS_FAILED(rv)) {
          equals_previous = PR_FALSE;
        }
      }

      if (equals_previous) {
        PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
               ("HandshakeCallback using PREV cert %p\n", prevcert.get()));
        infoObject->SetCert(prevcert);
        status->mServerCert = prevcert;
      }
      else {
        if (status->mServerCert) {
          PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
                 ("HandshakeCallback KEEPING cert %p\n", status->mServerCert.get()));
          infoObject->SetCert(status->mServerCert);
        }
        else {
          PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
                 ("HandshakeCallback using NEW cert %p\n", nssc.get()));
          infoObject->SetCert(nssc);
          status->mServerCert = nssc;
        }
      }
    }

    status->mHaveKeyLengthAndCipher = PR_TRUE;
    status->mKeyLength = keyLength;
    status->mSecretKeyLength = encryptBits;
    status->mCipherName.Adopt(cipherName);
  }

  PR_FREEIF(certOrgName);
  PR_Free(signer);
}
Example #18
0
SECStatus PR_CALLBACK AuthCertificateCallback(void* client_data, PRFileDesc* fd,
                                              PRBool checksig, PRBool isServer) {
  nsNSSShutDownPreventionLock locker;

  // first the default action
  SECStatus rv = SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer);

  // We want to remember the CA certs in the temp db, so that the application can find the
  // complete chain at any time it might need it.
  // But we keep only those CA certs in the temp db, that we didn't already know.
  
  CERTCertificate *serverCert = SSL_PeerCertificate(fd);
  CERTCertificateCleaner serverCertCleaner(serverCert);

  if (serverCert) {
    nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
    nsRefPtr<nsSSLStatus> status = infoObject->SSLStatus();
    nsRefPtr<nsNSSCertificate> nsc;

    if (!status || !status->mServerCert) {
      nsc = new nsNSSCertificate(serverCert);
    }

    if (SECSuccess == rv) {
      if (nsc) {
        PRBool dummyIsEV;
        nsc->GetIsExtendedValidation(&dummyIsEV); // the nsc object will cache the status
      }
    
      CERTCertList *certList = CERT_GetCertChainFromCert(serverCert, PR_Now(), certUsageSSLCA);

      nsCOMPtr<nsINSSComponent> nssComponent;
      
      for (CERTCertListNode *node = CERT_LIST_HEAD(certList);
           !CERT_LIST_END(node, certList);
           node = CERT_LIST_NEXT(node)) {

        if (node->cert->slot) {
          // This cert was found on a token, no need to remember it in the temp db.
          continue;
        }

        if (node->cert->isperm) {
          // We don't need to remember certs already stored in perm db.
          continue;
        }
        
        if (node->cert == serverCert) {
          // We don't want to remember the server cert, 
          // the code that cares for displaying page info does this already.
          continue;
        }

        // We have found a signer cert that we want to remember.
        nsCAutoString nickname;
        nickname = nsNSSCertificate::defaultServerNickname(node->cert);
        if (!nickname.IsEmpty()) {
          PK11SlotInfo *slot = PK11_GetInternalKeySlot();
          if (slot) {
            PK11_ImportCert(slot, node->cert, CK_INVALID_HANDLE, 
                            const_cast<char*>(nickname.get()), PR_FALSE);
            PK11_FreeSlot(slot);
          }
        }
      }

      CERT_DestroyCertList(certList);
    }

    // The connection may get terminated, for example, if the server requires
    // a client cert. Let's provide a minimal SSLStatus
    // to the caller that contains at least the cert and its status.
    if (!status) {
      status = new nsSSLStatus();
      infoObject->SetSSLStatus(status);
    }
    if (status && !status->mServerCert) {
      status->mServerCert = nsc;
      PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
             ("AuthCertificateCallback setting NEW cert %p\n", status->mServerCert.get()));
    }
  }

  return rv;
}
// Extracts whatever information we need out of fd (using SSL_*) and passes it
// to SSLServerCertVerificationJob::Dispatch. SSLServerCertVerificationJob should
// never do anything with fd except logging.
SECStatus
AuthCertificateHook(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
{
    // Runs on the socket transport thread

    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
           ("[%p] starting AuthCertificateHook\n", fd));

    // Modern libssl always passes PR_TRUE for checkSig, and we have no means of
    // doing verification without checking signatures.
    NS_ASSERTION(checkSig, "AuthCertificateHook: checkSig unexpectedly false");

    // PSM never causes libssl to call this function with PR_TRUE for isServer,
    // and many things in PSM assume that we are a client.
    NS_ASSERTION(!isServer, "AuthCertificateHook: isServer unexpectedly true");

    nsNSSSocketInfo *socketInfo = static_cast<nsNSSSocketInfo*>(arg);

    if (socketInfo) {
        // This is the first callback during full handshakes.
        socketInfo->SetFirstServerHelloReceived();
    }

    CERTCertificate *serverCert = SSL_PeerCertificate(fd);
    CERTCertificateCleaner serverCertCleaner(serverCert);

    if (!checkSig || isServer || !socketInfo || !serverCert) {
        PR_SetError(PR_INVALID_STATE_ERROR, 0);
        return SECFailure;
    }

    if (BlockServerCertChangeForSpdy(socketInfo, serverCert) != SECSuccess)
        return SECFailure;

    bool onSTSThread;
    nsresult nrv;
    nsCOMPtr<nsIEventTarget> sts
        = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
    if (NS_SUCCEEDED(nrv)) {
        nrv = sts->IsOnCurrentThread(&onSTSThread);
    }

    if (NS_FAILED(nrv)) {
        NS_ERROR("Could not get STS service or IsOnCurrentThread failed");
        PR_SetError(PR_UNKNOWN_ERROR, 0);
        return SECFailure;
    }

    if (onSTSThread) {
        // We *must* do certificate verification on a background thread because
        // we need the socket transport thread to be free for our OCSP requests,
        // and we *want* to do certificate verification on a background thread
        // because of the performance benefits of doing so.
        socketInfo->SetCertVerificationWaiting();
        SECStatus rv = SSLServerCertVerificationJob::Dispatch(
                           static_cast<const void *>(fd), socketInfo, serverCert);
        return rv;
    }

    // We can't do certificate verification on a background thread, because the
    // thread doing the network I/O may not interrupt its network I/O on receipt
    // of our SSLServerCertVerificationResult event, and/or it might not even be
    // a non-blocking socket.
    SECStatus rv = AuthCertificate(socketInfo, serverCert);
    if (rv == SECSuccess) {
        return SECSuccess;
    }

    PRErrorCode error = PR_GetError();
    if (error != 0) {
        nsRefPtr<CertErrorRunnable> runnable = CreateCertErrorRunnable(
                error, socketInfo, serverCert,
                static_cast<const void *>(fd));
        if (!runnable) {
            // CreateCertErrorRunnable sets a new error code when it fails
            error = PR_GetError();
        } else {
            // We have to return SECSuccess or SECFailure based on the result of the
            // override processing, so we must block this thread waiting for it. The
            // CertErrorRunnable will NOT dispatch the result at all, since we passed
            // false for CreateCertErrorRunnable's async parameter
            nrv = runnable->DispatchToMainThreadAndWait();
            if (NS_FAILED(nrv)) {
                NS_ERROR("Failed to dispatch CertErrorRunnable");
                PR_SetError(PR_INVALID_STATE_ERROR, 0);
                return SECFailure;
            }

            if (!runnable->mResult) {
                NS_ERROR("CertErrorRunnable did not set result");
                PR_SetError(PR_INVALID_STATE_ERROR, 0);
                return SECFailure;
            }

            if (runnable->mResult->mErrorCode == 0) {
                return SECSuccess; // cert error override occurred.
            }

            // We must call SetCanceled here to set the error message type
            // in case it isn't PlainErrorMessage, which is what we would
            // default to if we just called
            // PR_SetError(runnable->mResult->mErrorCode, 0) and returned
            // SECFailure without doing this.
            socketInfo->SetCanceled(runnable->mResult->mErrorCode,
                                    runnable->mResult->mErrorMessageType);
            error = runnable->mResult->mErrorCode;
        }
    }

    if (error == 0) {
        NS_ERROR("error code not set");
        error = PR_UNKNOWN_ERROR;
    }

    PR_SetError(error, 0);
    return SECFailure;
}
Example #20
0
JNIEXPORT jobject JNICALL
Java_org_mozilla_jss_ssl_SSLSocket_getStatus
    (JNIEnv *env, jobject self)
{
    SECStatus secstatus;
    JSSL_SocketData *sock=NULL;
    int on;
    char *cipher=NULL;
    jobject cipherString;
    jint keySize;
    jint secretKeySize;
    char *issuer=NULL;
    jobject issuerString;
    char *subject=NULL;
    jobject subjectString;
    jobject statusObj = NULL;
    jclass statusClass;
    jmethodID statusCons;
    CERTCertificate *peerCert=NULL;
    jobject peerCertObj = NULL;
    char *serialNum = NULL;
    jobject serialNumObj = NULL;

    /* get the fd */
    if( JSSL_getSockData(env, self, &sock) != PR_SUCCESS) {
        /* exception was thrown */
        goto finish;
    }


    /* get the status */
    secstatus = SSL_SecurityStatus( sock->fd,
                                    &on,
                                    &cipher,
                                    (int*)&keySize,
                                    (int*)&secretKeySize,
                                    &issuer,
                                    &subject);

    if(secstatus != SECSuccess) {
        JSSL_throwSSLSocketException(env,
            "Failed to retrieve socket security status");
        goto finish;
    }

    /*
     * get the peer certificate
     */
    peerCert = SSL_PeerCertificate(sock->fd);
    if( peerCert != NULL ) {
        /* the peer cert might be null, for example if this is the server
         * side and the client didn't auth. */

        serialNum = CERT_Hexify(&peerCert->serialNumber, PR_FALSE /*do_colon*/);
        PR_ASSERT(serialNum != NULL);
        serialNumObj = (*env)->NewStringUTF(env, serialNum);
        if( serialNumObj == NULL ) {
            goto finish;
        }

        /* this call will wipe out peerCert */
        peerCertObj = JSS_PK11_wrapCert(env, &peerCert);
        if( peerCertObj == NULL) {
            goto finish;
        }
    }

    /*
     * convert char*s to Java Strings
     */
    cipherString = issuerString = subjectString = NULL;
    if( cipher != NULL ) cipherString = (*env)->NewStringUTF(env, cipher);
    if( issuer != NULL ) issuerString = (*env)->NewStringUTF(env, issuer);
    if( subject != NULL ) subjectString = (*env)->NewStringUTF(env, subject);

    /*
     * package the status into a new SSLSecurityStatus object
     */
    statusClass = (*env)->FindClass(env, SSL_SECURITY_STATUS_CLASS_NAME);
    PR_ASSERT(statusClass != NULL);
    if( statusClass == NULL ) {
        /* exception was thrown */
        goto finish;
    }
    statusCons = (*env)->GetMethodID(env, statusClass,
                            SSL_SECURITY_STATUS_CONSTRUCTOR_NAME,
                            SSL_SECURITY_STATUS_CONSTRUCTOR_SIG);
    PR_ASSERT(statusCons != NULL);
    if(statusCons == NULL ) {
        /* exception was thrown */
        goto finish;
    }
    statusObj = (*env)->NewObject(env, statusClass, statusCons,
            on, cipherString, keySize, secretKeySize, issuerString,
            subjectString, serialNumObj, peerCertObj);
        

finish:
    if( cipher != NULL ) {
        PR_Free(cipher);
    }
    if( issuer != NULL ) {
        PORT_Free(issuer);
    }
    if ( subject != NULL) {
        PORT_Free(subject);
    }
    if( peerCert != NULL ) {
        CERT_DestroyCertificate(peerCert);
    }
    if( serialNum != NULL ) {
        PR_Free(serialNum);
    }

    EXCEPTION_CHECK(env, sock)
    return statusObj;
}
Example #21
0
/*
 * Callback from SSL for checking a (possibly) expired
 * certificate the peer presents.
 *
 * obj - a jobject -> instance of a class implementing 
 *       the SSLCertificateApprovalCallback interface
 */
SECStatus
JSSL_JavaCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig,
             PRBool isServer)
{
    CERTCertificate *peerCert=NULL;
    CERTVerifyLog log;
    JNIEnv *env;
    jobject validityStatus;
    jmethodID addReasonMethod;
    int certUsage;
    int checkcn_rv;
    jmethodID approveMethod;
    jboolean result;
    char *hostname=NULL;
    SECStatus retval = SECFailure;
    SECStatus verificationResult;

    PR_ASSERT(arg != NULL);
    PR_ASSERT(fd != NULL);

    /* initialize logging structures */
    log.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    if( log.arena == NULL ) return SECFailure;
    log.head = NULL;
    log.tail = NULL;
    log.count = 0;

    /* get the JNI environment */
    if((*JSS_javaVM)->AttachCurrentThread(JSS_javaVM, (void**)&env, NULL) != 0){
        PR_ASSERT(PR_FALSE);
        goto finish;
    }

    /* First, get a handle on the cert that the peer presented */
    peerCert = SSL_PeerCertificate(fd);
    
    /* if peer didn't present a cert, why am I called? */
    if (peerCert == NULL) goto finish;

    certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;

    /* 
     * verify it against current time - (can't use
     * CERT_VerifyCertNow() since it doesn't allow passing of
     * logging parameter)
     */

    verificationResult = CERT_VerifyCert(   CERT_GetDefaultCertDB(),
                            peerCert,
                            checkSig,
                            certUsage,
                            PR_Now(),
                            NULL /*pinarg*/,
                            &log);

    if (verificationResult == SECSuccess && log.count > 0) {
        verificationResult = SECFailure;
    }

    /*
     * Verify the domain name of the cert.
     */
    hostname = SSL_RevealURL(fd);    /* really is a hostname, not a URL */
    if (hostname && hostname[0]) {
        checkcn_rv = CERT_VerifyCertName(peerCert, hostname);
        PORT_Free(hostname);
    } else {
        checkcn_rv = SECFailure;
    }
    if (checkcn_rv != SECSuccess) {
        addToVerifyLog(env, &log,peerCert,SSL_ERROR_BAD_CERT_DOMAIN,0);
        if((*env)->ExceptionOccurred(env) != NULL) goto finish;
        verificationResult = SECFailure;
    }

    /*
     * create a new ValidityStatus object
     */
    {
        jclass clazz;
        jmethodID cons;

        clazz = (*env)->FindClass(env, SSLCERT_APP_CB_VALIDITY_STATUS_CLASS);
        if( clazz == NULL ) goto finish;

        cons = (*env)->GetMethodID(env, clazz,
                        PLAIN_CONSTRUCTOR, PLAIN_CONSTRUCTOR_SIG);
        if( cons == NULL ) goto finish;

        validityStatus = (*env)->NewObject(env, clazz, cons);
        if( validityStatus == NULL ) {
            goto finish;
        }

        /* get the addReason methodID while we're at it */
        addReasonMethod = (*env)->GetMethodID(env, clazz,
            SSLCERT_APP_CB_VALIDITY_STATUS_ADD_REASON_NAME,
            SSLCERT_APP_CB_VALIDITY_STATUS_ADD_REASON_SIG);
        if( addReasonMethod == NULL ) {
            goto finish;
        }
    }
    
    /*
     * Load up the ValidityStatus object with all the reasons for failure
     */
    if (verificationResult == SECFailure)  {
        CERTVerifyLogNode *node;
        int error;
        CERTCertificate *errorcert=NULL;
        int depth;
        jobject ninjacert;

        node = log.head;
        while (node) {
            error = node->error;
            errorcert = node->cert;
            node->cert = NULL;
            depth = node->depth;

            ninjacert = JSS_PK11_wrapCert(env,&errorcert);
            (*env)->CallVoidMethod(env, validityStatus, addReasonMethod,
                error,
                ninjacert,
                depth
                );

            node = node->next;
        }
    }

    /*
     * Call the approval callback
     */
    {
        jobject approvalCallbackObj;
        jclass approvalCallbackClass;
        jobject peerninjacert;

        approvalCallbackObj = (jobject) arg;

        approvalCallbackClass = (*env)->GetObjectClass(env,approvalCallbackObj);
        approveMethod = (*env)->GetMethodID(
            env,
            approvalCallbackClass,
            SSLCERT_APP_CB_APPROVE_NAME,
            SSLCERT_APP_CB_APPROVE_SIG);
        if( approveMethod == NULL ) {
            PR_ASSERT(PR_FALSE);
            goto finish;
        }

        peerninjacert = JSS_PK11_wrapCert(env,&peerCert);
        if( peerninjacert == NULL) {
            PR_ASSERT(PR_FALSE);
            goto finish;
        }
        result = (*env)->CallBooleanMethod(env, approvalCallbackObj,
            approveMethod, peerninjacert, validityStatus);
        if( result == JNI_TRUE ) {
            retval = SECSuccess;
        }
    }

finish:
    if( peerCert != NULL ) {
        CERT_DestroyCertificate(peerCert);
    }
    PORT_FreeArena(log.arena, PR_FALSE);
    return retval;
}
// Extracts whatever information we need out of fd (using SSL_*) and passes it
// to SSLServerCertVerificationJob::Dispatch. SSLServerCertVerificationJob should
// never do anything with fd except logging.
SECStatus
AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig, PRBool isServer)
{
  RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
  if (!certVerifier) {
    PR_SetError(SEC_ERROR_NOT_INITIALIZED, 0);
    return SECFailure;
  }

  // Runs on the socket transport thread

  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
         ("[%p] starting AuthCertificateHook\n", fd));

  // Modern libssl always passes PR_TRUE for checkSig, and we have no means of
  // doing verification without checking signatures.
  NS_ASSERTION(checkSig, "AuthCertificateHook: checkSig unexpectedly false");

  // PSM never causes libssl to call this function with PR_TRUE for isServer,
  // and many things in PSM assume that we are a client.
  NS_ASSERTION(!isServer, "AuthCertificateHook: isServer unexpectedly true");

  nsNSSSocketInfo* socketInfo = static_cast<nsNSSSocketInfo*>(arg);

  ScopedCERTCertificate serverCert(SSL_PeerCertificate(fd));

  if (!checkSig || isServer || !socketInfo || !serverCert) {
      PR_SetError(PR_INVALID_STATE_ERROR, 0);
      return SECFailure;
  }

  socketInfo->SetFullHandshake();

  // This value of "now" is used both here for OCSP stapling and later
  // when calling CreateCertErrorRunnable.
  PRTime now = PR_Now();

  if (BlockServerCertChangeForSpdy(socketInfo, serverCert) != SECSuccess)
    return SECFailure;

  bool onSTSThread;
  nsresult nrv;
  nsCOMPtr<nsIEventTarget> sts
    = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
  if (NS_SUCCEEDED(nrv)) {
    nrv = sts->IsOnCurrentThread(&onSTSThread);
  }

  if (NS_FAILED(nrv)) {
    NS_ERROR("Could not get STS service or IsOnCurrentThread failed");
    PR_SetError(PR_UNKNOWN_ERROR, 0);
    return SECFailure;
  }

  // SSL_PeerStapledOCSPResponses will never return a non-empty response if
  // OCSP stapling wasn't enabled because libssl wouldn't have let the server
  // return a stapled OCSP response.
  // We don't own these pointers.
  const SECItemArray* csa = SSL_PeerStapledOCSPResponses(fd);
  SECItem* stapledOCSPResponse = nullptr;
  // we currently only support single stapled responses
  if (csa && csa->len == 1) {
    stapledOCSPResponse = &csa->items[0];
  }

  uint32_t providerFlags = 0;
  socketInfo->GetProviderFlags(&providerFlags);

  if (onSTSThread) {

    // We *must* do certificate verification on a background thread because
    // we need the socket transport thread to be free for our OCSP requests,
    // and we *want* to do certificate verification on a background thread
    // because of the performance benefits of doing so.
    socketInfo->SetCertVerificationWaiting();
    SECStatus rv = SSLServerCertVerificationJob::Dispatch(
                     certVerifier, static_cast<const void*>(fd), socketInfo,
                     serverCert, stapledOCSPResponse, providerFlags, now);
    return rv;
  }

  // We can't do certificate verification on a background thread, because the
  // thread doing the network I/O may not interrupt its network I/O on receipt
  // of our SSLServerCertVerificationResult event, and/or it might not even be
  // a non-blocking socket.

  SECStatus rv = AuthCertificate(*certVerifier, socketInfo, serverCert,
                                 stapledOCSPResponse, providerFlags, now);
  if (rv == SECSuccess) {
    Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1);
    return SECSuccess;
  }

  PRErrorCode error = PR_GetError();
  if (error != 0) {
    RefPtr<CertErrorRunnable> runnable(
        CreateCertErrorRunnable(*certVerifier, error, socketInfo, serverCert,
                                static_cast<const void*>(fd), providerFlags,
                                now));
    if (!runnable) {
      // CreateCertErrorRunnable sets a new error code when it fails
      error = PR_GetError();
    } else {
      // We have to return SECSuccess or SECFailure based on the result of the
      // override processing, so we must block this thread waiting for it. The
      // CertErrorRunnable will NOT dispatch the result at all, since we passed
      // false for CreateCertErrorRunnable's async parameter
      nrv = runnable->DispatchToMainThreadAndWait();
      if (NS_FAILED(nrv)) {
        NS_ERROR("Failed to dispatch CertErrorRunnable");
        PR_SetError(PR_INVALID_STATE_ERROR, 0);
        return SECFailure;
      }

      if (!runnable->mResult) {
        NS_ERROR("CertErrorRunnable did not set result");
        PR_SetError(PR_INVALID_STATE_ERROR, 0);
        return SECFailure;
      }

      if (runnable->mResult->mErrorCode == 0) {
        return SECSuccess; // cert error override occurred.
      }

      // We must call SetCanceled here to set the error message type
      // in case it isn't PlainErrorMessage, which is what we would
      // default to if we just called
      // PR_SetError(runnable->mResult->mErrorCode, 0) and returned
      // SECFailure without doing this.
      socketInfo->SetCanceled(runnable->mResult->mErrorCode,
                              runnable->mResult->mErrorMessageType);
      error = runnable->mResult->mErrorCode;
    }
  }

  if (error == 0) {
    NS_ERROR("error code not set");
    error = PR_UNKNOWN_ERROR;
  }

  PR_SetError(error, 0);
  return SECFailure;
}
Example #23
0
/* Function: SECStatus myAuthCertificate()
 *
 * Purpose: This function is our custom certificate authentication handler.
 * 
 * Note: This implementation is essentially the same as the default 
 *       SSL_AuthCertificate().
 */
SECStatus 
myAuthCertificate(void *arg, PRFileDesc *socket, 
                  PRBool checksig, PRBool isServer) 
{

    SECCertificateUsage certUsage;
    CERTCertificate *   cert;
    void *              pinArg;
    char *              hostName;
    SECStatus           secStatus;

    if (!arg || !socket) {
	errWarn("myAuthCertificate");
	return SECFailure;
    }

    /* Define how the cert is being used based upon the isServer flag. */

    certUsage = isServer ? certificateUsageSSLClient : certificateUsageSSLServer;

    cert = SSL_PeerCertificate(socket);
	
    pinArg = SSL_RevealPinArg(socket);
    
    if (dumpChain == PR_TRUE) {
        dumpCertChain(cert, certUsage);
    }

    secStatus = CERT_VerifyCertificateNow((CERTCertDBHandle *)arg,
				   cert,
				   checksig,
				   certUsage,
				   pinArg,
                                   NULL);

    /* If this is a server, we're finished. */
    if (isServer || secStatus != SECSuccess) {
	SECU_printCertProblems(stderr, (CERTCertDBHandle *)arg, cert, 
			  checksig, certUsage, pinArg, PR_FALSE);
	CERT_DestroyCertificate(cert);
	return secStatus;
    }

    /* Certificate is OK.  Since this is the client side of an SSL
     * connection, we need to verify that the name field in the cert
     * matches the desired hostname.  This is our defense against
     * man-in-the-middle attacks.
     */

    /* SSL_RevealURL returns a hostName, not an URL. */
    hostName = SSL_RevealURL(socket);

    if (hostName && hostName[0]) {
	secStatus = CERT_VerifyCertName(cert, hostName);
    } else {
	PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0);
	secStatus = SECFailure;
    }

    if (hostName)
	PR_Free(hostName);

    CERT_DestroyCertificate(cert);
    return secStatus;
}