Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Functions | Variables
nsNSSIOLayer.cpp File Reference
#include "nsNSSComponent.h"
#include "nsNSSIOLayer.h"
#include "nsNSSCallbacks.h"
#include "prlog.h"
#include "prnetdb.h"
#include "nsIPrompt.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsIServiceManager.h"
#include "nsIWebProgressListener.h"
#include "nsIChannel.h"
#include "nsIBadCertListener.h"
#include "nsNSSCertificate.h"
#include "nsIProxyObjectManager.h"
#include "nsProxiedService.h"
#include "nsIDateTimeFormat.h"
#include "nsDateTimeFormatCID.h"
#include "nsIClientAuthDialogs.h"
#include "nsClientAuthRemember.h"
#include "nsXPIDLString.h"
#include "nsReadableUtils.h"
#include "nsVoidArray.h"
#include "nsHashSets.h"
#include "nsCRT.h"
#include "nsPrintfCString.h"
#include "nsAutoLock.h"
#include "nsSSLThread.h"
#include "nsNSSShutDown.h"
#include "nsNSSCertHelper.h"
#include "nsNSSCleaner.h"
#include "ssl.h"
#include "secerr.h"
#include "sslerr.h"
#include "secder.h"
#include "secasn1.h"
#include "certdb.h"
#include "cert.h"
#include "keyhi.h"

Go to the source code of this file.

Classes

struct  CERTCertificateScopeEntry
struct  certCertificateScopeOfUse

Defines

#define HANDSHAKE_TIMEOUT_SECONDS   25
#define DEBUG_DUMP_BUFFER(buf, len)

Functions

 NSSCleanupAutoPtrClass (CERTCertificate, CERT_DestroyCertificate) typedef enum
static SECStatus PR_CALLBACK nsNSS_SSLGetClientAuthData (void *arg, PRFileDesc *socket, CERTDistNames *caNames, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey)
 NS_IMPL_THREADSAFE_ISUPPORTS5 (nsNSSSocketInfo, nsITransportSecurityInfo, nsISSLSocketControl, nsIInterfaceRequestor, nsISSLStatusProvider, nsIClientAuthUserDecision) nsresult nsNSSSocketInfo
static nsresult displayAlert (nsAFlatString &formattedString, nsNSSSocketInfo *infoObject)
static nsresult nsHandleSSLError (nsNSSSocketInfo *socketInfo, PRInt32 err)
static PRStatus PR_CALLBACK nsSSLIOLayerConnect (PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
static PRStatus PR_CALLBACK nsSSLIOLayerClose (PRFileDesc *fd)
static PRBool isNonSSLErrorThatWeAllowToRetry (PRInt32 err, PRBool withInitialCleartext)
static PRBool isTLSIntoleranceError (PRInt32 err, PRBool withInitialCleartext)
static PRBool isClosedConnectionAfterBadCertUIWasShown (PRInt32 bytesTransfered, PRBool wasReading, PRInt32 err, nsNSSSocketInfo::BadCertUIStatusType aBadCertUIStatus)
static PRInt16 PR_CALLBACK nsSSLIOLayerPoll (PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
static PRInt32 PR_CALLBACK nsSSLIOLayerRead (PRFileDesc *fd, void *buf, PRInt32 amount)
static PRInt32 PR_CALLBACK nsSSLIOLayerWrite (PRFileDesc *fd, const void *buf, PRInt32 amount)
static PRIntn _PSM_InvalidInt (void)
static PRInt64 _PSM_InvalidInt64 (void)
static PRStatus _PSM_InvalidStatus (void)
static PRFileDesc_PSM_InvalidDesc (void)
static PRStatus PR_CALLBACK PSMGetsockname (PRFileDesc *fd, PRNetAddr *addr)
static PRStatus PR_CALLBACK PSMGetpeername (PRFileDesc *fd, PRNetAddr *addr)
static PRStatus PR_CALLBACK PSMGetsocketoption (PRFileDesc *fd, PRSocketOptionData *data)
static PRStatus PR_CALLBACK PSMSetsocketoption (PRFileDesc *fd, const PRSocketOptionData *data)
static PRInt32 PR_CALLBACK PSMRecv (PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
static PRInt32 PR_CALLBACK PSMSend (PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
static PRStatus PR_CALLBACK PSMConnectcontinue (PRFileDesc *fd, PRInt16 out_flags)
nsresult nsSSLIOLayerNewSocket (PRInt32 family, const char *host, PRInt32 port, const char *proxyHost, PRInt32 proxyPort, PRFileDesc **fd, nsISupports **info, PRBool forSTARTTLS)
static nsresult addCertToDB (CERTCertificate *peerCert, PRInt16 addType)
static PRBool nsContinueDespiteCertError (nsNSSSocketInfo *infoObject, PRFileDesc *sslSocket, int error, nsNSSCertificate *nssCert)
static SECStatus verifyCertAgain (CERTCertificate *cert, PRFileDesc *sslSocket, nsNSSSocketInfo *infoObject)
SECStatus nsConvertCANamesToStrings (PRArenaPool *arena, char **caNameStrings, CERTDistNames *caNames)
nsresult nsGetUserCertChoice (SSM_UserCertChoice *certChoice)
static PRBool hasExplicitKeyUsageNonRepudiation (CERTCertificate *cert)
static SECStatus nsNSSBadCertHandler (void *arg, PRFileDesc *sslSocket)
static PRFileDescnsSSLIOLayerImportFD (PRFileDesc *fd, nsNSSSocketInfo *infoObject, const char *host)
static nsresult nsSSLIOLayerSetOptions (PRFileDesc *fd, PRBool forSTARTTLS, const char *proxyHost, const char *host, PRInt32 port, nsNSSSocketInfo *infoObject)
nsresult nsSSLIOLayerAddToSocket (PRInt32 family, const char *host, PRInt32 port, const char *proxyHost, PRInt32 proxyPort, PRFileDesc *fd, nsISupports **info, PRBool forSTARTTLS)

Variables

 SSM_UserCertChoice
static const SEC_ASN1Template cert_CertificateScopeEntryTemplate []
static const SEC_ASN1Template cert_CertificateScopeOfUseTemplate []

Class Documentation

struct CERTCertificateScopeEntry

Definition at line 1897 of file nsNSSIOLayer.cpp.

Class Members
CERTGeneralName * constraint
SECItem derConstraint
SECItem derPort
PRIntn port
struct certCertificateScopeOfUse

Definition at line 1904 of file nsNSSIOLayer.cpp.

Collaboration diagram for certCertificateScopeOfUse:
Class Members
CERTCertificateScopeEntry ** entries

Define Documentation

Definition at line 1102 of file nsNSSIOLayer.cpp.

Definition at line 519 of file nsNSSIOLayer.cpp.


Function Documentation

static PRFileDesc* _PSM_InvalidDesc ( void  ) [static]

Definition at line 1383 of file nsNSSIOLayer.cpp.

{
    PR_ASSERT(!"I/O method is invalid");
    PR_SetError(PR_INVALID_METHOD_ERROR, 0);
    return NULL;
}

Here is the caller graph for this function:

static PRIntn _PSM_InvalidInt ( void  ) [static]

Definition at line 1362 of file nsNSSIOLayer.cpp.

{
    PR_ASSERT(!"I/O method is invalid");
    PR_SetError(PR_INVALID_METHOD_ERROR, 0);
    return -1;
}

Here is the caller graph for this function:

static PRInt64 _PSM_InvalidInt64 ( void  ) [static]

Definition at line 1369 of file nsNSSIOLayer.cpp.

{
    PR_ASSERT(!"I/O method is invalid");
    PR_SetError(PR_INVALID_METHOD_ERROR, 0);
    return -1;
}

Here is the caller graph for this function:

static PRStatus _PSM_InvalidStatus ( void  ) [static]

Definition at line 1376 of file nsNSSIOLayer.cpp.

{
    PR_ASSERT(!"I/O method is invalid");
    PR_SetError(PR_INVALID_METHOD_ERROR, 0);
    return PR_FAILURE;
}

Here is the caller graph for this function:

static nsresult addCertToDB ( CERTCertificate *  peerCert,
PRInt16  addType 
) [static]

Definition at line 1580 of file nsNSSIOLayer.cpp.

{
  CERTCertTrust trust;
  SECStatus rv;
  nsresult retVal = NS_ERROR_FAILURE;
  char *nickname;
  
  switch (addType) {
    case nsIBadCertListener::ADD_TRUSTED_PERMANENTLY:
      nickname = nsNSSCertificate::defaultServerNickname(peerCert);
      if (nsnull == nickname)
        break;
      memset((void*)&trust, 0, sizeof(trust));
      rv = CERT_DecodeTrustString(&trust, "P"); 
      if (rv != SECSuccess) {
        return NS_ERROR_FAILURE;
      }
      rv = CERT_AddTempCertToPerm(peerCert, nickname, &trust);
      if (rv == SECSuccess)
        retVal = NS_OK;
      PR_Free(nickname);
      break;
    case nsIBadCertListener::ADD_TRUSTED_FOR_SESSION:
      // XXX We need an API from NSS to do this so 
      //     that we don't have to access the fields 
      //     in the cert directly.
      peerCert->keepSession = PR_TRUE;
      CERTCertTrust *trustPtr;
      if (!peerCert->trust) {
        trustPtr = (CERTCertTrust*)PORT_ArenaZAlloc(peerCert->arena,
                                                    sizeof(CERTCertTrust));
        if (!trustPtr)
          break;

        peerCert->trust = trustPtr;
      } else {
        trustPtr = peerCert->trust;
      }
      rv = CERT_DecodeTrustString(trustPtr, "P");
      if (rv != SECSuccess)
        break;

      retVal = NS_OK;      
      break;
    default:
      PR_ASSERT(!"Invalid value for addType passed to addCertDB");
      break;
  }
  return retVal;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static nsresult displayAlert ( nsAFlatString formattedString,
nsNSSSocketInfo infoObject 
) [static]

Definition at line 546 of file nsNSSIOLayer.cpp.

{
       
       // The interface requestor object may not be safe, so
    // proxy the call to get the nsIPrompt.

     nsCOMPtr<nsIProxyObjectManager> proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID));
     if (!proxyman) 
       return NS_ERROR_FAILURE;
 
     nsCOMPtr<nsIInterfaceRequestor> proxiedCallbacks;
     proxyman->GetProxyForObject(NS_UI_THREAD_EVENTQ,
                                 NS_GET_IID(nsIInterfaceRequestor),
                                 NS_STATIC_CAST(nsIInterfaceRequestor*,infoObject),
                                 PROXY_SYNC,
                                 getter_AddRefs(proxiedCallbacks));

     nsCOMPtr<nsIPrompt> prompt (do_GetInterface(proxiedCallbacks));
  
     if (!prompt)
       return NS_ERROR_NO_INTERFACE;

     nsCOMPtr<nsIPrompt> proxyPrompt;
     // Finally, get a proxy for the nsIPrompt
     proxyman->GetProxyForObject(NS_UI_THREAD_EVENTQ,
                                 NS_GET_IID(nsIPrompt),
                                 prompt,
                                 PROXY_SYNC,
                                 getter_AddRefs(proxyPrompt));
     proxyPrompt->Alert(nsnull, formattedString.get());
     return NS_OK;
     
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool hasExplicitKeyUsageNonRepudiation ( CERTCertificate *  cert) [static]

Definition at line 2224 of file nsNSSIOLayer.cpp.

{
  /* There is no extension, v1 or v2 certificate */
  if (!cert->extensions)
    return PR_FALSE;

  SECStatus srv;
  SECItem keyUsageItem;
  keyUsageItem.data = NULL;

  srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem);
  if (srv == SECFailure)
    return PR_FALSE;

  unsigned char keyUsage = keyUsageItem.data[0];
  PORT_Free (keyUsageItem.data);

  return (keyUsage & KU_NON_REPUDIATION);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool isClosedConnectionAfterBadCertUIWasShown ( PRInt32  bytesTransfered,
PRBool  wasReading,
PRInt32  err,
nsNSSSocketInfo::BadCertUIStatusType  aBadCertUIStatus 
) [static]

Definition at line 1161 of file nsNSSIOLayer.cpp.

{
  if (aBadCertUIStatus != nsNSSSocketInfo::bcuis_not_shown)
  {
    // Bad cert UI was shown for this socket.
    // Server timeout possible.
    // Retry on a simple connection close.

    if (wasReading && 0 == bytesTransfered)
      return PR_TRUE;

    if (0 > bytesTransfered)
    {
      switch (err)
      {
        case PR_CONNECT_RESET_ERROR:
        case PR_END_OF_FILE_ERROR:
          return PR_TRUE;
        default:
          break;
      }
    }
  }

  return PR_FALSE;
}

Here is the caller graph for this function:

static PRBool isNonSSLErrorThatWeAllowToRetry ( PRInt32  err,
PRBool  withInitialCleartext 
) [static]

Definition at line 1106 of file nsNSSIOLayer.cpp.

{
  switch (err)
  {
    case PR_CONNECT_RESET_ERROR:
      if (!withInitialCleartext)
        return PR_TRUE;
      break;
    
    case PR_END_OF_FILE_ERROR:
      return PR_TRUE;
  }

  return PR_FALSE;
}

Here is the caller graph for this function:

static PRBool isTLSIntoleranceError ( PRInt32  err,
PRBool  withInitialCleartext 
) [static]

Definition at line 1123 of file nsNSSIOLayer.cpp.

{
  // This function is supposed to decide, which error codes should
  // be used to conclude server is TLS intolerant.
  // Note this only happens during the initial SSL handshake.
  // 
  // When not using a proxy we'll see a connection reset error.
  // When using a proxy, we'll see an end of file error.
  // In addition check for some error codes where it is reasonable
  // to retry without TLS.

  if (isNonSSLErrorThatWeAllowToRetry(err, withInitialCleartext))
    return PR_TRUE;

  switch (err)
  {
    case SSL_ERROR_BAD_MAC_ALERT:
    case SSL_ERROR_BAD_MAC_READ:
    case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
    case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
    case SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE:
    case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
    case SSL_ERROR_NO_CYPHER_OVERLAP:
    case SSL_ERROR_BAD_SERVER:
    case SSL_ERROR_BAD_BLOCK_PADDING:
    case SSL_ERROR_UNSUPPORTED_VERSION:
    case SSL_ERROR_PROTOCOL_VERSION_ALERT:
    case SSL_ERROR_RX_MALFORMED_FINISHED:
    case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE:
    case SSL_ERROR_DECODE_ERROR_ALERT:
    case SSL_ERROR_RX_UNKNOWN_ALERT:
      return PR_TRUE;
  }
  
  return PR_FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 229 of file nsNSSIOLayer.cpp.

{
  *aHandshakePending = mHandshakePending;
  return NS_OK;
}
static PRBool nsContinueDespiteCertError ( nsNSSSocketInfo infoObject,
PRFileDesc sslSocket,
int  error,
nsNSSCertificate nssCert 
) [static]

Definition at line 1632 of file nsNSSIOLayer.cpp.

{
  PRBool retVal = PR_FALSE;
  nsIBadCertListener *badCertHandler = nsnull;
  PRInt16 addType = nsIBadCertListener::UNINIT_ADD_FLAG;
  nsresult rv;

  if (!nssCert)
    return PR_FALSE;

  // Try to get a nsIBadCertListener implementation from the socket consumer
  // first.  If that fails, fallback to the default UI.
  nsCOMPtr<nsIInterfaceRequestor> callbacks;
  infoObject->GetNotificationCallbacks(getter_AddRefs(callbacks));
  if (callbacks) {
    nsCOMPtr<nsIBadCertListener> handler = do_GetInterface(callbacks);
    if (handler)
      NS_GetProxyForObject(NS_UI_THREAD_EVENTQ,
                           NS_GET_IID(nsIBadCertListener),
                           handler,
                           PROXY_SYNC,
                           (void**)&badCertHandler);
  }
  if (!badCertHandler) {
    rv = getNSSDialogs((void**)&badCertHandler, 
                       NS_GET_IID(nsIBadCertListener),
                       NS_BADCERTLISTENER_CONTRACTID);
    if (NS_FAILED(rv)) 
      return PR_FALSE;
  }
  nsIInterfaceRequestor *csi = NS_STATIC_CAST(nsIInterfaceRequestor*,
                                                 infoObject);
  nsIX509Cert *callBackCert = NS_STATIC_CAST(nsIX509Cert*, nssCert);
  CERTCertificate *peerCert = nssCert->GetCert();
  NS_ASSERTION(peerCert, "Got nsnull cert back from nsNSSCertificate");
  switch (error) {
  case SEC_ERROR_UNKNOWN_ISSUER:
  case SEC_ERROR_CA_CERT_INVALID:
  case SEC_ERROR_UNTRUSTED_ISSUER:
  /* This is a temporay fix for bug# - We are showing a unknown ca dialog,
     when actually the ca cert has expired/not yet valid. We need to change
     this in future - need to define a proper ui for this situation
  */
  case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
    {
      nsPSMUITracker tracker;
      if (tracker.isUIForbidden()) {
        rv = NS_ERROR_NOT_AVAILABLE;
      }
      else {
        rv = badCertHandler->ConfirmUnknownIssuer(csi, callBackCert, &addType, &retVal);
      }
    }
    break;
  case SSL_ERROR_BAD_CERT_DOMAIN:
    {
      nsXPIDLCString url; url.Adopt(SSL_RevealURL(sslSocket));
      NS_ASSERTION(url.get(), "could not find valid URL in ssl socket");
      {
        nsPSMUITracker tracker;
        if (tracker.isUIForbidden()) {
          rv = NS_ERROR_NOT_AVAILABLE;
        }
        else {
        rv = badCertHandler->ConfirmMismatchDomain(csi, url,
                                            callBackCert, &retVal);
        }
      }
      if (NS_SUCCEEDED(rv) && retVal) {
        rv = CERT_AddOKDomainName(peerCert, url);
      }
    }
    break;
  case SEC_ERROR_EXPIRED_CERTIFICATE:
    {
      nsPSMUITracker tracker;
      if (tracker.isUIForbidden()) {
        rv = NS_ERROR_NOT_AVAILABLE;
      }
      else {
        rv = badCertHandler->ConfirmCertExpired(csi, callBackCert, & retVal);
      }
    }
    if (rv == SECSuccess && retVal) {
      // XXX We need an NSS API for this equivalent functionality.
      //     Having to reach inside the cert is evil.
      peerCert->timeOK = PR_TRUE;
    }
    break;
  case SEC_ERROR_CRL_EXPIRED:
    {
      nsXPIDLCString url; url.Adopt(SSL_RevealURL(sslSocket));
      NS_ASSERTION(url, "could not find valid URL in ssl socket");
      {
        nsPSMUITracker tracker;
        if (tracker.isUIForbidden()) {
          rv = NS_ERROR_NOT_AVAILABLE;
        }
        else {
          rv = badCertHandler->NotifyCrlNextupdate(csi, url, callBackCert);
        }
      }
      retVal = PR_FALSE;
    }
    break;
  default:
    nsHandleSSLError(infoObject,error);
    retVal = PR_FALSE;

  }
  if (retVal && addType != nsIBadCertListener::UNINIT_ADD_FLAG) {
    addCertToDB(peerCert, addType);
  }
  NS_RELEASE(badCertHandler);
  CERT_DestroyCertificate(peerCert);
  return NS_FAILED(rv) ? PR_FALSE : retVal;
}

Here is the call graph for this function:

Here is the caller graph for this function:

SECStatus nsConvertCANamesToStrings ( PRArenaPool arena,
char **  caNameStrings,
CERTDistNames *  caNames 
)

Definition at line 1796 of file nsNSSIOLayer.cpp.

{
    SECItem* dername;
    SECStatus rv;
    int headerlen;
    uint32 contentlen;
    SECItem newitem;
    int n;
    char* namestring;

    for (n = 0; n < caNames->nnames; n++) {
        newitem.data = NULL;
        dername = &caNames->names[n];

        rv = DER_Lengths(dername, &headerlen, &contentlen);

        if (rv != SECSuccess) {
            goto loser;
        }

        if (headerlen + contentlen != dername->len) {
            /* This must be from an enterprise 2.x server, which sent
             * incorrectly formatted der without the outer wrapper of
             * type and length.  Fix it up by adding the top level
             * header.
             */
            if (dername->len <= 127) {
                newitem.data = (unsigned char *) PR_Malloc(dername->len + 2);
                if (newitem.data == NULL) {
                    goto loser;
                }
                newitem.data[0] = (unsigned char)0x30;
                newitem.data[1] = (unsigned char)dername->len;
                (void)memcpy(&newitem.data[2], dername->data, dername->len);
            }
            else if (dername->len <= 255) {
                newitem.data = (unsigned char *) PR_Malloc(dername->len + 3);
                if (newitem.data == NULL) {
                    goto loser;
                }
                newitem.data[0] = (unsigned char)0x30;
                newitem.data[1] = (unsigned char)0x81;
                newitem.data[2] = (unsigned char)dername->len;
                (void)memcpy(&newitem.data[3], dername->data, dername->len);
            }
            else {
                /* greater than 256, better be less than 64k */
                newitem.data = (unsigned char *) PR_Malloc(dername->len + 4);
                if (newitem.data == NULL) {
                    goto loser;
                }
                newitem.data[0] = (unsigned char)0x30;
                newitem.data[1] = (unsigned char)0x82;
                newitem.data[2] = (unsigned char)((dername->len >> 8) & 0xff);
                newitem.data[3] = (unsigned char)(dername->len & 0xff);
                memcpy(&newitem.data[4], dername->data, dername->len);
            }
            dername = &newitem;
        }

        namestring = CERT_DerNameToAscii(dername);
        if (namestring == NULL) {
            /* XXX - keep going until we fail to convert the name */
            caNameStrings[n] = "";
        }
        else {
            caNameStrings[n] = PORT_ArenaStrdup(arena, namestring);
            PR_Free(namestring);
            if (caNameStrings[n] == NULL) {
                goto loser;
            }
        }

        if (newitem.data != NULL) {
            PR_Free(newitem.data);
        }
    }

    return SECSuccess;
loser:
    if (newitem.data != NULL) {
        PR_Free(newitem.data);
    }
    return SECFailure;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 2191 of file nsNSSIOLayer.cpp.

{
       char *mode=NULL;
       nsresult ret;

       NS_ENSURE_ARG_POINTER(certChoice);

       nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);

       ret = pref->GetCharPref("security.default_personal_cert", &mode);
       if (NS_FAILED(ret)) {
              goto loser;
       }

    if (PL_strcmp(mode, "Select Automatically") == 0) {
              *certChoice = AUTO;
       }
    else if (PL_strcmp(mode, "Ask Every Time") == 0) {
        *certChoice = ASK;
    }
    else {
      // Most likely we see a nickname from a migrated cert.
      // We do not currently support that, ask the user which cert to use.
                *certChoice = ASK;
       }

loser:
       if (mode) {
              nsMemory::Free(mode);
       }
       return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static nsresult nsHandleSSLError ( nsNSSSocketInfo socketInfo,
PRInt32  err 
) [static]

Definition at line 581 of file nsNSSIOLayer.cpp.

{
  if (socketInfo->GetCanceled()) {
    // If the socket has been flagged as canceled,
    // the code who did was responsible for showing
    // an error message (if desired).
    return NS_OK;
  }

  nsresult rv;
  NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
  if (NS_FAILED(rv))
    return rv;

  char buf[80];
  PR_snprintf(buf, 80, "%ld", err);
  NS_ConvertASCIItoUCS2 errorCode(buf);

  nsXPIDLCString hostName;
  socketInfo->GetHostName(getter_Copies(hostName));
  NS_ConvertASCIItoUCS2 hostNameU(hostName);

  NS_DEFINE_CID(StringBundleServiceCID,  NS_STRINGBUNDLESERVICE_CID);
  nsCOMPtr<nsIStringBundleService> service = 
                              do_GetService(StringBundleServiceCID, &rv);
  nsCOMPtr<nsIStringBundle> brandBundle;
  service->CreateBundle("chrome://branding/locale/brand.properties",
                        getter_AddRefs(brandBundle));
  nsXPIDLString brandShortName;
  brandBundle->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
                                 getter_Copies(brandShortName));
    
  const PRUnichar *params[2];
  nsAutoString formattedString;

  switch (err) {
  case SSL_ERROR_SSL_DISABLED:
    params[0] = brandShortName.get();
    params[1] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("SSL_Disabled",
                                                params, 2, formattedString);
    break;
  case SSL_ERROR_SSL2_DISABLED:
    params[0] = brandShortName.get();
    params[1] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("SSL2_Disabled",
                                                params, 2, formattedString);
    break;
  case SSL_ERROR_EXPORT_ONLY_SERVER:
  case SSL_ERROR_US_ONLY_SERVER:
  case SSL_ERROR_NO_CYPHER_OVERLAP:
  case SSL_ERROR_UNSUPPORTED_VERSION:
  case SSL_ERROR_UNKNOWN_CIPHER_SUITE:
  case SSL_ERROR_NO_CIPHERS_SUPPORTED:
  case SSL_ERROR_FORTEZZA_PQG:
    params[0] = brandShortName.get();
    params[1] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("SSL_NoMatchingCiphers",
                                                params, 2, formattedString);
                                                  
    break;

  //Clients Cert Rejected
  case SSL_ERROR_REVOKED_CERT_ALERT :
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("UsersCertRevoked",
                                                params, 1, formattedString);
    break;

  case SSL_ERROR_EXPIRED_CERT_ALERT:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("UsersCertExpired",
                                                params, 1, formattedString);
    break;

  case SSL_ERROR_BAD_CERT_ALERT:
  case SSL_ERROR_UNSUPPORTED_CERT_ALERT:
  case SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT:
    params[0] = hostNameU.get();
    params[1] = errorCode.get();
    nssComponent->PIPBundleFormatStringFromName("UsersCertRejected",
                                                params, 2, formattedString);
    break;

  //Errors related to Peers Certificate
  case SEC_ERROR_CRL_EXPIRED:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("CRLExpired", 
                                                params, 1, formattedString);
    break;

  case SEC_ERROR_CRL_NOT_YET_VALID:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("CRLNotYetValid", 
                                                params, 1, formattedString);
    break;

  case SEC_ERROR_CRL_INVALID:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("CRLSNotValid", 
                                                params, 1, formattedString);
    break;

  case SEC_ERROR_CRL_BAD_SIGNATURE:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("CRLSigNotValid", 
                                                params, 1, formattedString);
    break;

  case SEC_ERROR_OCSP_MALFORMED_REQUEST:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("OCSPMalformedRequest", 
                                             params, 1, formattedString);
    break;

  case SEC_ERROR_OCSP_REQUEST_NEEDS_SIG:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("OCSPRequestNeedsSig", 
                                             params, 1, formattedString);
    break;

  case SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("OCSPUnauthorizedReq", 
                                             params, 1, formattedString);
    break;

  case SEC_ERROR_OCSP_SERVER_ERROR:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("OCSPServerError", 
                                             params, 1, formattedString);
    break;

  case SEC_ERROR_OCSP_TRY_SERVER_LATER:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("OCSPTryServerLater", 
                                             params, 1, formattedString);
    break;
  
  case SEC_ERROR_OCSP_FUTURE_RESPONSE:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("OCSPFutureResponse", 
                                             params, 1, formattedString);
    break;

  case SEC_ERROR_OCSP_OLD_RESPONSE:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("OCSPOldResponse", 
                                             params, 1, formattedString);
    break;

  case SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE:
  case SEC_ERROR_OCSP_BAD_HTTP_RESPONSE:
  case SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS:
  case SEC_ERROR_OCSP_MALFORMED_RESPONSE:
    params[0] = hostNameU.get();
    params[1] = errorCode.get();
    nssComponent->PIPBundleFormatStringFromName("OCSPCorruptedResponse", 
                                             params, 2, formattedString);
    break;

  case SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("OCSPUnauthorizedResponse", 
                                             params, 1, formattedString);
    break;
    
  case SEC_ERROR_OCSP_UNKNOWN_CERT:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("OCSPUnknownCert", 
                                             params, 1, formattedString);
    break;


  case SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("OCSPNoDefaultResponder", 
                                             params, 1, formattedString);
    break;
  
  case PR_DIRECTORY_LOOKUP_ERROR:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("OCSPDirLookup", 
                                             params, 1, formattedString);
    break;

  case SEC_ERROR_REVOKED_CERTIFICATE:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("PeersCertRevoked", 
                                             params, 1, formattedString);
    break;

  case SEC_ERROR_UNTRUSTED_CERT:
    params[0] = hostNameU.get();
         nssComponent->PIPBundleFormatStringFromName("PeersCertUntrusted", 
                                            params, 1, formattedString);
         break;

  case SSL_ERROR_BAD_CERT_DOMAIN:
    params[0] = hostNameU.get();
         nssComponent->PIPBundleFormatStringFromName("PeersCertWrongDomain", 
                                            params, 1, formattedString);
         break;

  case SEC_ERROR_EXPIRED_CERTIFICATE:
    params[0] = hostNameU.get();
         nssComponent->PIPBundleFormatStringFromName("PeersCertExpired", 
                                            params, 1, formattedString);
         break;

  case SEC_ERROR_BAD_SIGNATURE:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("PeersCertBadSignature", 
                                                params, 1, formattedString);
    break;

  //A generic error handler for peer cert
  case SEC_ERROR_UNKNOWN_CERT:
  case SEC_ERROR_BAD_KEY:
  case SEC_ERROR_CERT_USAGES_INVALID:
  case SEC_ERROR_INADEQUATE_KEY_USAGE:
  case SEC_ERROR_INADEQUATE_CERT_TYPE:
  case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:
  case SEC_ERROR_CERT_NOT_VALID:
  case SEC_ERROR_CERT_ADDR_MISMATCH:
  case SSL_ERROR_BAD_CERTIFICATE:
  case SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE:
  case SSL_ERROR_WRONG_CERTIFICATE:
  case SSL_ERROR_CERT_KEA_MISMATCH:
  case SEC_ERROR_EXTENSION_VALUE_INVALID :
  case SEC_ERROR_EXTENSION_NOT_FOUND:
  case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
    params[0] = hostNameU.get();
    params[1] = errorCode.get();
    nssComponent->PIPBundleFormatStringFromName("PeersCertNoGood", 
                                               params, 2, formattedString);
         break;

  case SSL_ERROR_BAD_MAC_READ:
    params[0] = brandShortName.get();
    nssComponent->PIPBundleFormatStringFromName("BadMac",
                                                params, 1, formattedString);
    break;

  case SSL_ERROR_BAD_MAC_ALERT:
    params[0] = hostNameU.get();
    nssComponent->PIPBundleFormatStringFromName("BadMac",
                                                params, 1, formattedString);
    break;

  //Connection Reset by peer
  case SSL_ERROR_CLOSE_NOTIFY_ALERT:
  case SSL_ERROR_SOCKET_WRITE_FAILURE:
    params[0] = hostNameU.get();
    params[1] = errorCode.get();
    nssComponent->PIPBundleFormatStringFromName("PeerResetConnection",
                                                params, 2, formattedString);
    break;

  //Connection reset by host
  case SEC_ERROR_USER_CANCELLED:
  case SEC_ERROR_MESSAGE_SEND_ABORTED:
    nssComponent->GetPIPNSSBundleString("HostResetConnection", formattedString);
    break;

  //Bad password
  case SEC_ERROR_BAD_PASSWORD:
  case SEC_ERROR_RETRY_PASSWORD:
    nssComponent->GetPIPNSSBundleString("BadPassword", formattedString);
    break;

  //Bad Database
  case SEC_ERROR_BAD_DATABASE:
  case SEC_ERROR_NO_KEY:
  case SEC_ERROR_CERT_NO_RESPONSE:
    params[0] = errorCode.get();
    nssComponent->PIPBundleFormatStringFromName("BadDatabase",
                                                params, 1, formattedString);
    break;

  //Malformed or unxepected data or message was received from server
  case SSL_ERROR_BAD_SERVER:
  case SSL_ERROR_BAD_BLOCK_PADDING:
  case SSL_ERROR_RX_RECORD_TOO_LONG:
  case SSL_ERROR_TX_RECORD_TOO_LONG:
  case SSL_ERROR_RX_MALFORMED_HELLO_REQUEST:
  case SSL_ERROR_RX_MALFORMED_SERVER_HELLO:
  case SSL_ERROR_RX_MALFORMED_CERTIFICATE:
  case SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH:
  case SSL_ERROR_RX_MALFORMED_CERT_REQUEST:
  case SSL_ERROR_RX_MALFORMED_HELLO_DONE:
  case SSL_ERROR_RX_MALFORMED_FINISHED:
  case SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER:
  case SSL_ERROR_RX_MALFORMED_ALERT:
  case SSL_ERROR_RX_MALFORMED_HANDSHAKE:
  case SSL_ERROR_RX_MALFORMED_APPLICATION_DATA:
  case SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST:
  case SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO:
  case SSL_ERROR_RX_UNEXPECTED_CERTIFICATE:
  case SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH:
  case SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST:
  case SSL_ERROR_RX_UNEXPECTED_HELLO_DONE:
  case SSL_ERROR_RX_UNEXPECTED_FINISHED:
  case SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER:
  case SSL_ERROR_RX_UNEXPECTED_ALERT:
  case SSL_ERROR_RX_UNEXPECTED_HANDSHAKE:
  case SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA:
  case SSL_ERROR_RX_UNKNOWN_RECORD_TYPE:
  case SSL_ERROR_RX_UNKNOWN_HANDSHAKE:
  case SSL_ERROR_RX_UNKNOWN_ALERT:
    params[0] = hostNameU.get();
    params[1] = errorCode.get();
    nssComponent->PIPBundleFormatStringFromName("BadServer",
                                                params, 2, formattedString);
    break;

  //Alert for Malformed or unexpected data or message recieved by server
  case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
  case SSL_ERROR_DECOMPRESSION_FAILURE_ALERT:
  case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
  case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
    params[0] = hostNameU.get();
    params[1] = errorCode.get();
    nssComponent->PIPBundleFormatStringFromName("BadClient",
                                                params, 2, formattedString);
    break;

  case SEC_ERROR_REUSED_ISSUER_AND_SERIAL:
    nssComponent->GetPIPNSSBundleString("HostReusedIssuerSerial", formattedString);
    break;

  default:
    params[0] = hostNameU.get();
    params[1] = errorCode.get(); 
    nssComponent->PIPBundleFormatStringFromName("SSLGenericError",
                                                params, 2, formattedString);
      
  }

  {
    nsPSMUITracker tracker;
    if (tracker.isUIForbidden()) {
      rv = NS_ERROR_NOT_AVAILABLE;
    }
    else {
      rv = displayAlert(formattedString, socketInfo);
    }
  }
  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

SECStatus nsNSS_SSLGetClientAuthData ( void arg,
PRFileDesc socket,
CERTDistNames *  caNames,
CERTCertificate **  pRetCert,
SECKEYPrivateKey **  pRetKey 
) [static]

Definition at line 2259 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;
  void* wincx = NULL;
  SECStatus ret = SECFailure;
  nsNSSSocketInfo* info = NULL;
  PRArenaPool* arena = NULL;
  char** caNameStrings;
  CERTCertificate* cert = NULL;
  SECKEYPrivateKey* privKey = NULL;
  CERTCertList* certList = NULL;
  CERTCertListNode* node;
  CERTCertNicknames* nicknames = NULL;
  char* extracted = NULL;
  PRIntn keyError = 0; /* used for private key retrieval error */
  SSM_UserCertChoice certChoice;
  PRUint32 NumberOfCerts = 0;
       
  /* do some argument checking */
  if (socket == NULL || caNames == NULL || pRetCert == NULL ||
      pRetKey == NULL) {
    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    return SECFailure;
  }

  /* get PKCS11 pin argument */
  wincx = SSL_RevealPinArg(socket);
  if (wincx == NULL) {
    return SECFailure;
  }

  /* get the socket info */
  info = (nsNSSSocketInfo*)socket->higher->secret;

  /* create caNameStrings */
  arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  if (arena == NULL) {
    goto loser;
  }

  caNameStrings = (char**)PORT_ArenaAlloc(arena, 
                                          sizeof(char*)*(caNames->nnames));
  if (caNameStrings == NULL) {
    goto loser;
  }


  ret = nsConvertCANamesToStrings(arena, caNameStrings, caNames);
  if (ret != SECSuccess) {
    goto loser;
  }

  /* get the preference */
  if (NS_FAILED(nsGetUserCertChoice(&certChoice))) {
    goto loser;
  }

  /* find valid user cert and key pair */ 
  if (certChoice == AUTO) {
    /* automatically find the right cert */

    /* find all user certs that are valid and for SSL */
    certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), 
                                         certUsageSSLClient, PR_FALSE,
                                         PR_TRUE, wincx);
    if (certList == NULL) {
      goto noCert;
    }

    /* filter the list to those issued by CAs supported by the server */
    ret = CERT_FilterCertListByCANames(certList, caNames->nnames,
                                       caNameStrings, certUsageSSLClient);
    if (ret != SECSuccess) {
      goto noCert;
    }

    /* make sure the list is not empty */
    node = CERT_LIST_HEAD(certList);
    if (CERT_LIST_END(node, certList)) {
      goto noCert;
    }

    CERTCertificate* low_prio_nonrep_cert = NULL;
    CERTCertificateCleaner low_prio_cleaner(low_prio_nonrep_cert);

    /* loop through the list until we find a cert with a key */
    while (!CERT_LIST_END(node, certList)) {
      /* if the certificate has restriction and we do not satisfy it
       * we do not use it
       */
#if 0         /* XXX This must be re-enabled */
      if (!CERT_MatchesScopeOfUse(node->cert, info->GetHostName,
                                  info->GetHostIP, info->GetHostPort)) {
          node = CERT_LIST_NEXT(node);
          continue;
      }
#endif

      privKey = PK11_FindKeyByAnyCert(node->cert, wincx);
      if (privKey != NULL) {
        if (hasExplicitKeyUsageNonRepudiation(node->cert)) {
          SECKEY_DestroyPrivateKey(privKey);
          privKey = NULL;
          // Not a prefered cert
          if (!low_prio_nonrep_cert) // did not yet find a low prio cert
            low_prio_nonrep_cert = CERT_DupCertificate(node->cert);
        }
        else {
          // this is a good cert to present
          cert = CERT_DupCertificate(node->cert);
          break;
        }
      }
      keyError = PR_GetError();
      if (keyError == SEC_ERROR_BAD_PASSWORD) {
          /* problem with password: bail */
          goto loser;
      }

      node = CERT_LIST_NEXT(node);
    }

    if (!cert && low_prio_nonrep_cert) {
      cert = low_prio_nonrep_cert;
      low_prio_nonrep_cert = NULL; // take it away from the cleaner
      privKey = PK11_FindKeyByAnyCert(cert, wincx);
    }

    if (cert == NULL) {
        goto noCert;
    }
  }
  else { // Not Auto => ask
    /* Get the SSL Certificate */
    CERTCertificate* serverCert = NULL;
    CERTCertificateCleaner serverCertCleaner(serverCert);
    serverCert = SSL_PeerCertificate(socket);
    if (serverCert == NULL) {
      /* couldn't get the server cert: what do I do? */
      goto loser;
    }

    nsXPIDLCString hostname;
    info->GetHostName(getter_Copies(hostname));

    nsresult rv;
    NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
    nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
    nsRefPtr<nsClientAuthRememberService> cars;
    if (nssComponent) {
      nssComponent->GetClientAuthRememberService(getter_AddRefs(cars));
    }

    PRBool hasRemembered = PR_FALSE;
    nsCString rememberedNickname;
    if (cars) {
      PRBool found;
      nsresult rv = cars->HasRememberedDecision(hostname, 
                                                serverCert,
                                                rememberedNickname, &found);
      if (NS_SUCCEEDED(rv) && found) {
        hasRemembered = PR_TRUE;
      }
    }

    PRBool canceled = PR_FALSE;

if (hasRemembered)
{
  if (rememberedNickname.IsEmpty())
    canceled = PR_TRUE;
  else {
    char *const_nickname = const_cast<char*>(rememberedNickname.get());
    cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), const_nickname);
  }
}
else
{
    /* user selects a cert to present */
    nsIClientAuthDialogs *dialogs = NULL;
    PRInt32 selectedIndex = -1;
    PRUnichar **certNicknameList = NULL;
    PRUnichar **certDetailsList = NULL;

    /* find all user certs that are for SSL */
    /* note that we are allowing expired certs in this list */
    certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), 
                                         certUsageSSLClient, PR_FALSE, 
                                         PR_FALSE, wincx);
    if (certList == NULL) {
      goto noCert;
    }

    if (caNames->nnames != 0) {
      /* filter the list to those issued by CAs supported by the 
       * server 
       */
      ret = CERT_FilterCertListByCANames(certList, caNames->nnames, 
                                        caNameStrings, 
                                        certUsageSSLClient);
      if (ret != SECSuccess) {
        goto loser;
      }
    }

    if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
      /* list is empty - no matching certs */
      goto noCert;
    }

    /* filter it further for hostname restriction */
    node = CERT_LIST_HEAD(certList);
    while (!CERT_LIST_END(node, certList)) {
      ++NumberOfCerts;
#if 0 /* XXX Fix this */
      if (!CERT_MatchesScopeOfUse(node->cert, conn->hostName,
                                  conn->hostIP, conn->port)) {
        CERTCertListNode* removed = node;
        node = CERT_LIST_NEXT(removed);
        CERT_RemoveCertListNode(removed);
      }
      else {
        node = CERT_LIST_NEXT(node);
      }
#endif
      node = CERT_LIST_NEXT(node);
    }
    if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
      goto noCert;
    }

    nicknames = getNSSCertNicknamesFromCertList(certList);

    if (nicknames == NULL) {
      goto loser;
    }

    NS_ASSERTION(nicknames->numnicknames == NumberOfCerts, "nicknames->numnicknames != NumberOfCerts");

    /* Get CN and O of the subject and O of the issuer */
    char *ccn = CERT_GetCommonName(&serverCert->subject);
    NS_ConvertUTF8toUCS2 cn(ccn);
    if (ccn) PORT_Free(ccn);

    char *corg = CERT_GetOrgName(&serverCert->subject);
    NS_ConvertUTF8toUCS2 org(corg);
    if (corg) PORT_Free(corg);

    char *cissuer = CERT_GetOrgName(&serverCert->issuer);
    NS_ConvertUTF8toUCS2 issuer(cissuer);
    if (cissuer) PORT_Free(cissuer);

    certNicknameList = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nicknames->numnicknames);
    if (!certNicknameList)
      goto loser;
    certDetailsList = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nicknames->numnicknames);
    if (!certDetailsList) {
      nsMemory::Free(certNicknameList);
      goto loser;
    }

    PRInt32 CertsToUse;
    for (CertsToUse = 0, node = CERT_LIST_HEAD(certList);
         !CERT_LIST_END(node, certList) && CertsToUse < nicknames->numnicknames;
         node = CERT_LIST_NEXT(node)
        )
    {
      nsRefPtr<nsNSSCertificate> tempCert = new nsNSSCertificate(node->cert);

      if (!tempCert)
        continue;
      
      NS_ConvertUTF8toUTF16 i_nickname(nicknames->nicknames[CertsToUse]);
      nsAutoString nickWithSerial, details;
      
      if (NS_FAILED(tempCert->FormatUIStrings(i_nickname, nickWithSerial, details)))
        continue;

      if (hasExplicitKeyUsageNonRepudiation(node->cert))
        nickWithSerial.Append(NS_LITERAL_STRING(" [NR]"));

      certNicknameList[CertsToUse] = ToNewUnicode(nickWithSerial);
      if (!certNicknameList[CertsToUse])
        continue;
      certDetailsList[CertsToUse] = ToNewUnicode(details);
      if (!certDetailsList[CertsToUse]) {
        nsMemory::Free(certNicknameList[CertsToUse]);
        continue;
      }

      ++CertsToUse;
    }

    /* Throw up the client auth dialog and get back the index of the selected cert */
    rv = getNSSDialogs((void**)&dialogs, 
                       NS_GET_IID(nsIClientAuthDialogs),
                       NS_CLIENTAUTHDIALOGS_CONTRACTID);

    if (NS_FAILED(rv)) {
      NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
      NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
      goto loser;
    }

    {
      nsPSMUITracker tracker;
      if (tracker.isUIForbidden()) {
        rv = NS_ERROR_NOT_AVAILABLE;
      }
      else {
        rv = dialogs->ChooseCertificate(info, cn.get(), org.get(), issuer.get(), 
          (const PRUnichar**)certNicknameList, (const PRUnichar**)certDetailsList,
          CertsToUse, &selectedIndex, &canceled);
      }
    }

    NS_RELEASE(dialogs);
    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
    
    if (NS_FAILED(rv)) goto loser;

    // even if the user has canceled, we want to remember that, to avoid repeating prompts
    PRBool wantRemember = PR_FALSE;
    info->GetRememberClientAuthCertificate(&wantRemember);

    int i;
    if (!canceled)
    for (i = 0, node = CERT_LIST_HEAD(certList);
         !CERT_LIST_END(node, certList);
         ++i, node = CERT_LIST_NEXT(node)) {

      if (i == selectedIndex) {
        cert = CERT_DupCertificate(node->cert);
        break;
      }
    }

    if (cars && wantRemember) {
      cars->RememberDecision(hostname, 
                             serverCert, 
                             canceled ? 0 : cert);
    }
}

    if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }

    if (cert == NULL) {
      goto loser;
    }

    /* go get the private key */
    privKey = PK11_FindKeyByAnyCert(cert, wincx);
    if (privKey == NULL) {
      keyError = PR_GetError();
      if (keyError == SEC_ERROR_BAD_PASSWORD) {
          /* problem with password: bail */
          goto loser;
      }
      else {
          goto noCert;
      }
    }
  }
  goto done;

noCert:
loser:
  if (ret == SECSuccess) {
    ret = SECFailure;
  }
  if (cert != NULL) {
    CERT_DestroyCertificate(cert);
    cert = NULL;
  }
done:
  if (extracted != NULL) {
    PR_Free(extracted);
  }
  if (nicknames != NULL) {
    CERT_FreeNicknames(nicknames);
  }
  if (certList != NULL) {
    CERT_DestroyCertList(certList);
  }
  if (arena != NULL) {
    PORT_FreeArena(arena, PR_FALSE);
  }

  *pRetCert = cert;
  *pRetKey = privKey;

  return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus nsNSSBadCertHandler ( void arg,
PRFileDesc sslSocket 
) [static]

Definition at line 2658 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;
  SECStatus rv = SECFailure;
  int error;
  nsNSSSocketInfo* infoObject = (nsNSSSocketInfo *)arg;
  CERTCertificate *peerCert;
  nsNSSCertificate *nssCert;

  error = PR_GetError();
  peerCert = SSL_PeerCertificate(sslSocket);
  nssCert = new nsNSSCertificate(peerCert);
  if (!nssCert) {
    return SECFailure;
  } 
  NS_ADDREF(nssCert);
  infoObject->SetBadCertUIStatus(nsNSSSocketInfo::bcuis_active);
  while (rv != SECSuccess) {
     //Func nsContinueDespiteCertError does the same set of checks as func.
     //nsCertErrorNeedsDialog. So, removing call to nsCertErrorNeedsDialog
     if (!nsContinueDespiteCertError(infoObject, sslSocket, 
                                    error, nssCert)) {
      break;
    }
    rv = verifyCertAgain(peerCert, sslSocket, infoObject);
       error = PR_GetError();
  }
  infoObject->SetBadCertUIStatus(nsNSSSocketInfo::bcuis_was_shown);
  NS_RELEASE(nssCert);
  CERT_DestroyCertificate(peerCert); 
  if (rv != SECSuccess) {
    // if the cert is bad, we don't want to connect
    infoObject->SetCanceled(PR_TRUE);
  }
  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

NSSCleanupAutoPtrClass ( CERTCertificate  ,
CERT_DestroyCertificate   
)

Definition at line 95 of file nsNSSIOLayer.cpp.

nsresult nsSSLIOLayerAddToSocket ( PRInt32  family,
const char *  host,
PRInt32  port,
const char *  proxyHost,
PRInt32  proxyPort,
PRFileDesc fd,
nsISupports **  info,
PRBool  forSTARTTLS 
)

Definition at line 2791 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;
  PRFileDesc* layer = nsnull;
  nsresult rv;

  nsNSSSocketInfo* infoObject = new nsNSSSocketInfo();
  if (!infoObject) return NS_ERROR_FAILURE;
  
  NS_ADDREF(infoObject);
  infoObject->SetForSTARTTLS(forSTARTTLS);
  infoObject->SetHostName(host);
  infoObject->SetPort(port);

  PRFileDesc *sslSock = nsSSLIOLayerImportFD(fd, infoObject, host);
  if (!sslSock) {
    NS_ASSERTION(PR_FALSE, "NSS: Error importing socket");
    goto loser;
  }

  infoObject->SetFileDescPtr(sslSock);

  rv = nsSSLIOLayerSetOptions(sslSock, forSTARTTLS, proxyHost, host, port,
                              infoObject);

  if (NS_FAILED(rv))
    goto loser;

  /* Now, layer ourselves on top of the SSL socket... */
  layer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
                               &nsSSLIOLayerHelpers::nsSSLIOLayerMethods);
  if (!layer)
    goto loser;
  
  layer->secret = (PRFilePrivate*) infoObject;
  rv = PR_PushIOLayer(sslSock, PR_GetLayersIdentity(sslSock), layer);
  
  if (NS_FAILED(rv)) {
    goto loser;
  }
  
  nsNSSShutDownList::trackSSLSocketCreate();

  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Socket set up\n", (void*)sslSock));
  infoObject->QueryInterface(NS_GET_IID(nsISupports), (void**) (info));

  // We are going use a clear connection first //
  if (forSTARTTLS || proxyHost) {
    infoObject->SetHandshakePending(PR_FALSE);
  }

  return NS_OK;
 loser:
  NS_IF_RELEASE(infoObject);
  if (layer) {
    layer->dtor(layer);
  }
  return NS_ERROR_FAILURE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRStatus PR_CALLBACK nsSSLIOLayerClose ( PRFileDesc fd) [static]

Definition at line 1013 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;
  if (!fd)
    return PR_FAILURE;

  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Shutting down socket\n", (void*)fd));
  
  nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
  NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");

  return nsSSLThread::requestClose(socketInfo);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRStatus PR_CALLBACK nsSSLIOLayerConnect ( PRFileDesc fd,
const PRNetAddr addr,
PRIntervalTime  timeout 
) [static]

Definition at line 935 of file nsNSSIOLayer.cpp.

{
  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] connecting SSL socket\n", (void*)fd));
  nsNSSShutDownPreventionLock locker;
  if (!fd || !fd->lower)
    return PR_FAILURE;
  
  PRStatus status = PR_SUCCESS;

#if defined(XP_BEOS)
  // Due to BeOS net_server's lack of support for nonblocking sockets,
  // we must execute this entire connect as a blocking operation - bug 70217
 
  PRSocketOptionData sockopt;
  sockopt.option = PR_SockOpt_Nonblocking;
  PR_GetSocketOption(fd, &sockopt);
  PRBool oldBlockVal = sockopt.value.non_blocking;
  sockopt.option = PR_SockOpt_Nonblocking;
  sockopt.value.non_blocking = PR_FALSE;
  PR_SetSocketOption(fd, &sockopt);
#endif
  
  status = fd->lower->methods->connect(fd->lower, addr, 
#if defined(XP_BEOS)  // bug 70217
                                       PR_INTERVAL_NO_TIMEOUT);
#else
                                       timeout);
#endif
  if (status != PR_SUCCESS) {
    PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("[%p] Lower layer connect error: %d\n",
                                      (void*)fd, PR_GetError()));
#if defined(XP_BEOS)  // bug 70217
    goto loser;
#else
    return status;
#endif
  }
  
  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Connect\n", (void*)fd));

#if defined(XP_BEOS)  // bug 70217
 loser:
  // We put the Nonblocking bit back to the value it was when 
  // we entered this function.
  NS_ASSERTION(sockopt.option == PR_SockOpt_Nonblocking,
               "sockopt.option was re-set to an unexpected value");
  sockopt.value.non_blocking = oldBlockVal;
  PR_SetSocketOption(fd, &sockopt);
#endif

  return status;
}

Here is the caller graph for this function:

static PRFileDesc* nsSSLIOLayerImportFD ( PRFileDesc fd,
nsNSSSocketInfo infoObject,
const char *  host 
) [static]

Definition at line 2696 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;
  PRFileDesc* sslSock = SSL_ImportFD(nsnull, fd);
  if (!sslSock) {
    NS_ASSERTION(PR_FALSE, "NSS: Error importing socket");
    return nsnull;
  }
  SSL_SetPKCS11PinArg(sslSock, (nsIInterfaceRequestor*)infoObject);
  SSL_HandshakeCallback(sslSock, HandshakeCallback, infoObject);
  SSL_GetClientAuthDataHook(sslSock, 
                            (SSLGetClientAuthData)nsNSS_SSLGetClientAuthData,
                            infoObject);
  SSL_AuthCertificateHook(sslSock, AuthCertificateCallback, 0);

  PRInt32 ret = SSL_SetURL(sslSock, host);
  if (ret == -1) {
    NS_ASSERTION(PR_FALSE, "NSS: Error setting server name");
    goto loser;
  }
  return sslSock;
loser:
  if (sslSock) {
    PR_Close(sslSock);
  }
  return nsnull;
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult nsSSLIOLayerNewSocket ( PRInt32  family,
const char *  host,
PRInt32  port,
const char *  proxyHost,
PRInt32  proxyPort,
PRFileDesc **  fd,
nsISupports **  info,
PRBool  forSTARTTLS 
)

Definition at line 1555 of file nsNSSIOLayer.cpp.

{

  PRFileDesc* sock = PR_OpenTCPSocket(family);
  if (!sock) return NS_ERROR_OUT_OF_MEMORY;

  nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxyHost, proxyPort,
                                        sock, info, forSTARTTLS);
  if (NS_FAILED(rv)) {
    PR_Close(sock);
    return rv;
  }

  *fd = sock;
  return NS_OK;
}

Here is the call graph for this function:

static PRInt16 PR_CALLBACK nsSSLIOLayerPoll ( PRFileDesc fd,
PRInt16  in_flags,
PRInt16 out_flags 
) [static]

Definition at line 1299 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;

  if (!out_flags)
  {
    NS_WARNING("nsSSLIOLayerPoll called with null out_flags");
    return 0;
  }

  *out_flags = 0;

  if (!fd)
  {
    NS_WARNING("nsSSLIOLayerPoll called with null fd");
    return 0;
  }

  nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
  NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");

  return nsSSLThread::requestPoll(socketInfo, in_flags, out_flags);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 PR_CALLBACK nsSSLIOLayerRead ( PRFileDesc fd,
void buf,
PRInt32  amount 
) [static]

Definition at line 1324 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;
  if (!fd || !fd->lower) {
    return PR_FAILURE;
  }

  nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
  NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");

  return nsSSLThread::requestRead(socketInfo, buf, amount);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static nsresult nsSSLIOLayerSetOptions ( PRFileDesc fd,
PRBool  forSTARTTLS,
const char *  proxyHost,
const char *  host,
PRInt32  port,
nsNSSSocketInfo infoObject 
) [static]

Definition at line 2727 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;
  if (forSTARTTLS || proxyHost) {
    if (SECSuccess != SSL_OptionSet(fd, SSL_SECURITY, PR_FALSE)) {
      return NS_ERROR_FAILURE;
    }
    infoObject->SetHasCleartextPhase(PR_TRUE);
  }

  if (forSTARTTLS) {
    if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_SSL2, PR_FALSE)) {
      return NS_ERROR_FAILURE;
    }
    if (SECSuccess != SSL_OptionSet(fd, SSL_V2_COMPATIBLE_HELLO, PR_FALSE)) {
      return NS_ERROR_FAILURE;
    }
  }

  // Let's see if we're trying to connect to a site we know is
  // TLS intolerant.
  nsCAutoString key;
  key = nsDependentCString(host) + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);

  if (nsSSLIOLayerHelpers::isKnownAsIntolerantSite(key)) {
    if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_TLS, PR_FALSE))
      return NS_ERROR_FAILURE;

    infoObject->SetAllowTLSIntoleranceTimeout(PR_FALSE);
      
    // We assume that protocols that use the STARTTLS mechanism should support
    // modern hellos. For other protocols, if we suspect a site 
    // does not support TLS, let's also use V2 hellos.
    // One advantage of this approach, if a site only supports the older
    // hellos, it is more likely that we will get a reasonable error code
    // on our single retry attempt.
    
    if (!forSTARTTLS &&
        SECSuccess != SSL_OptionSet(fd, SSL_V2_COMPATIBLE_HELLO, PR_TRUE))
      return NS_ERROR_FAILURE;
  }

  if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE)) {
    return NS_ERROR_FAILURE;
  }
  if (SECSuccess != SSL_BadCertHook(fd, (SSLBadCertHandler) nsNSSBadCertHandler,
                                    infoObject)) {
    return NS_ERROR_FAILURE;
  }

  // Set the Peer ID so that SSL proxy connections work properly.
  char *peerId = PR_smprintf("%s:%d", host, port);
  if (SECSuccess != SSL_SetSockPeerID(fd, peerId)) {
    PR_smprintf_free(peerId);
    return NS_ERROR_FAILURE;
  }

  PR_smprintf_free(peerId);
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 PR_CALLBACK nsSSLIOLayerWrite ( PRFileDesc fd,
const void buf,
PRInt32  amount 
) [static]

Definition at line 1338 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;
  if (!fd || !fd->lower) {
    return PR_FAILURE;
  }

#ifdef DEBUG_SSL_VERBOSE
  DEBUG_DUMP_BUFFER((unsigned char*)buf, amount);
#endif
  nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
  NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");

  return nsSSLThread::requestWrite(socketInfo, buf, amount);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRStatus PR_CALLBACK PSMConnectcontinue ( PRFileDesc fd,
PRInt16  out_flags 
) [static]

Definition at line 1475 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;
  if (!fd || !fd->lower) {
    return PR_FAILURE;
  }

  nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
  NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");

  return nsSSLThread::requestConnectcontinue(socketInfo, out_flags);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRStatus PR_CALLBACK PSMGetpeername ( PRFileDesc fd,
PRNetAddr addr 
) [static]

Definition at line 1403 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;
  if (!fd || !fd->lower) {
    return PR_FAILURE;
  }

  nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
  NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");

  return nsSSLThread::requestGetpeername(socketInfo, addr);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRStatus PR_CALLBACK PSMGetsocketoption ( PRFileDesc fd,
PRSocketOptionData data 
) [static]

Definition at line 1416 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;
  if (!fd || !fd->lower) {
    return PR_FAILURE;
  }

  nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
  NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");

  return nsSSLThread::requestGetsocketoption(socketInfo, data);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRStatus PR_CALLBACK PSMGetsockname ( PRFileDesc fd,
PRNetAddr addr 
) [static]

Definition at line 1390 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;
  if (!fd || !fd->lower) {
    return PR_FAILURE;
  }

  nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
  NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");

  return nsSSLThread::requestGetsockname(socketInfo, addr);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 PR_CALLBACK PSMRecv ( PRFileDesc fd,
void buf,
PRInt32  amount,
PRIntn  flags,
PRIntervalTime  timeout 
) [static]

Definition at line 1444 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;
  if (!fd || !fd->lower) {
    PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
    return -1;
  }

  nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
  NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");

  if (flags == PR_MSG_PEEK) {
    return nsSSLThread::requestRecvMsgPeek(socketInfo, buf, amount, flags, timeout);
  }

  return fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 PR_CALLBACK PSMSend ( PRFileDesc fd,
const void buf,
PRInt32  amount,
PRIntn  flags,
PRIntervalTime  timeout 
) [static]

Definition at line 1463 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;
  if (!fd || !fd->lower) {
    PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
    return -1;
  }

  return fd->lower->methods->send(fd->lower, buf, amount, flags, timeout);
}

Here is the caller graph for this function:

Definition at line 1430 of file nsNSSIOLayer.cpp.

{
  nsNSSShutDownPreventionLock locker;
  if (!fd || !fd->lower) {
    return PR_FAILURE;
  }

  nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
  NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");

  return nsSSLThread::requestSetsocketoption(socketInfo, data);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus verifyCertAgain ( CERTCertificate *  cert,
PRFileDesc sslSocket,
nsNSSSocketInfo infoObject 
) [static]

Definition at line 1754 of file nsNSSIOLayer.cpp.

{
  SECStatus rv;

  // If we get here, the user has accepted the cert so
  // far, so we don't check the signature again.
  rv = CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert,
                          PR_FALSE, certificateUsageSSLServer,
                          (void*)infoObject, NULL);

  if (rv != SECSuccess) {
    return rv;
  }
  
  // Check the name field against the desired hostname.
  char *hostname = SSL_RevealURL(sslSocket); 
  if (hostname && hostname[0]) {
    rv = CERT_VerifyCertName(cert, hostname);
  } else {
    rv = SECFailure;
  }

  if (rv != SECSuccess) {
    PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0);
  }
  PR_FREEIF(hostname);
  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Initial value:

Definition at line 1909 of file nsNSSIOLayer.cpp.

Initial value:

Definition at line 1919 of file nsNSSIOLayer.cpp.

Definition at line 98 of file nsNSSIOLayer.cpp.