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

CA认证

开发平台:

WINDOWS

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /*
  3.  * The contents of this file are subject to the Mozilla Public
  4.  * License Version 1.1 (the "License"); you may not use this file
  5.  * except in compliance with the License. You may obtain a copy of
  6.  * the License at http://www.mozilla.org/MPL/
  7.  * 
  8.  * Software distributed under the License is distributed on an "AS
  9.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10.  * implied. See the License for the specific language governing
  11.  * rights and limitations under the License.
  12.  * 
  13.  * The Original Code is the Netscape security libraries.
  14.  * 
  15.  * The Initial Developer of the Original Code is Netscape
  16.  * Communications Corporation.  Portions created by Netscape are 
  17.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  18.  * Rights Reserved.
  19.  * 
  20.  * Contributor(s):
  21.  * 
  22.  * Alternatively, the contents of this file may be used under the
  23.  * terms of the GNU General Public License Version 2 or later (the
  24.  * "GPL"), in which case the provisions of the GPL are applicable 
  25.  * instead of those above.  If you wish to allow use of your 
  26.  * version of this file only under the terms of the GPL and not to
  27.  * allow others to use your version of this file under the MPL,
  28.  * indicate your decision by deleting the provisions above and
  29.  * replace them with the notice and other provisions required by
  30.  * the GPL.  If you do not delete the provisions above, a recipient
  31.  * may use your version of this file under either the MPL or the
  32.  * GPL.
  33.  */
  34. #include "sslconn.h"
  35. #include "ctrlconn.h"
  36. #include "sslerror.h"
  37. #include "serv.h"
  38. #include "servimpl.h"
  39. #include "sslskst.h"
  40. #include "ssmerrs.h"
  41. #include "ssldlgs.h"
  42. #include "collectn.h"
  43. #include "prefs.h"
  44. /* NSS headers */
  45. #include "seccomon.h"
  46. #include "keyt.h"
  47. #include "cert.h"
  48. #include "secasn1.h"
  49. #include "genname.h"
  50. /* Shorthand macros for inherited classes */
  51. #define SSMRESOURCE(sslconn) (&(sslconn)->super.super.super)
  52. #define SSMCONNECTION(sslconn) (&(sslconn)->super.super)
  53. #define SSMDATACONNECTION(sslconn) (&(sslconn)->super)
  54. #define SSMCONTROLCONNECTION(sslconn) ((SSMControlConnection*)(sslconn->super.super.m_parent))
  55. /* SSM_UserCertChoice: enum for cert choice info */
  56. typedef enum {ASK, AUTO} SSM_UserCertChoice;
  57. /* persistent cert choice object we will use here */
  58. static SSM_UserCertChoice certChoice;
  59. /* strings for marking invalid user cert nicknames */
  60. #define NICKNAME_EXPIRED_STRING " (expired)"
  61. #define NICKNAME_NOT_YET_VALID_STRING " (not yet valid)"
  62. /* private function prototypes */
  63. void SSMSSLDataConnection_InitializeUIInfo(SSMSSLUIInfo* info);
  64. void SSMSSLDataConnection_DestroyUIInfo(SSMSSLUIInfo* info);
  65. SSMStatus SSMSSLDataConnection_UpdateSecurityStatus(SSMSSLDataConnection* conn);
  66. SECStatus SSM_SetupSSLSocket(PRFileDesc* socket, PRFileDesc** sslsocket,
  67.                              CERTCertDBHandle* handle, char* hostname,
  68.                              void* wincx);
  69. SSMStatus SSM_GetSSLSocket(SSMSSLDataConnection* conn);
  70. void SSM_SSLDataServiceThread(void* arg);
  71. SSMStatus SSM_SetUserCertChoice(SSMSSLDataConnection* conn);
  72. SECStatus SSM_ConvertCANamesToStrings(PRArenaPool* arena, char** caNameStrings,
  73.                                       CERTDistNames* caNames);
  74. SSMStatus ssm_client_auth_prepare_nicknames(SSMSSLDataConnection* conn,
  75.                                             CERTCertNicknames* nicknames);
  76. PRBool SSM_SSLErrorNeedsDialog(int error);
  77. SECStatus SSM_SSLMakeBadServerCertDialog(int error, 
  78.                                          CERTCertificate* cert,
  79.                                          SSMSSLDataConnection* conn);
  80. SECStatus SSM_SSLVerifyServerCert(CERTCertDBHandle* handle,
  81.                                   CERTCertificate* cert, PRBool checkSig, 
  82.                                   SSMSSLDataConnection* conn);
  83. PRStatus SSMSSLDataConnection_TLSStepUp(SSMSSLDataConnection* conn);
  84. /* callback functions */
  85. SECStatus SSM_SSLAuthCertificate(void* arg, PRFileDesc* socket,
  86.                                  PRBool checkSig, PRBool isServer);
  87. SECStatus SSM_SSLBadCertHandler(void* arg, PRFileDesc* socket);
  88. SECStatus SSM_SSLGetClientAuthData(void* arg,
  89.                                    PRFileDesc* socket,
  90.    struct CERTDistNamesStr* caNames,
  91.    struct CERTCertificateStr** pRetCert,
  92.    struct SECKEYPrivateKeyStr** pRetKey);
  93. void SSM_SSLHandshakeCallback(PRFileDesc* socket, void* clientData);
  94. /* implementations */
  95. /* class functions */
  96. SSMStatus SSMSSLDataConnection_Create(void* arg, 
  97.                                      SSMControlConnection* ctrlconn,
  98.                                      SSMResource** res)
  99. {
  100.     SSMStatus rv = PR_SUCCESS;
  101.     SSMSSLDataConnection* conn;
  102. /* check arguments */
  103. if (arg == NULL || res == NULL) {
  104. goto loser;
  105. }
  106.     *res = NULL; /* in case we fail */
  107.     
  108.     conn = (SSMSSLDataConnection*)PR_CALLOC(sizeof(SSMSSLDataConnection));
  109.     if (!conn) {
  110. goto loser;
  111. }
  112.     rv = SSMSSLDataConnection_Init(conn, (SSMInfoSSL*)arg, 
  113.                                    SSM_RESTYPE_SSL_DATA_CONNECTION);
  114.     if (rv != PR_SUCCESS) {
  115. goto loser;
  116. }
  117.     SSMSSLDataConnection_Invariant(conn);
  118.     
  119.     *res = &conn->super.super.super;
  120.     return PR_SUCCESS;
  121. loser:
  122.     if (rv == PR_SUCCESS) {
  123. rv = PR_FAILURE;
  124. }
  125.     if (conn) {
  126. SSM_ShutdownResource(SSMRESOURCE(conn), rv);
  127.         SSM_FreeResource(SSMRESOURCE(conn));
  128.     }
  129.         
  130.     return rv;
  131. }
  132. SSMStatus SSMSSLDataConnection_Shutdown(SSMResource* arg, SSMStatus status)
  133. {
  134.     SSMStatus rv;
  135.     SSMSSLDataConnection* conn = (SSMSSLDataConnection*)arg;
  136. PRBool firstTime = PR_TRUE;
  137.     /* ### sjlee: firstTime doesn't seem to be set anywhere */
  138.     
  139. /* check argument */
  140. if (arg == NULL) {
  141. return PR_FAILURE;
  142. }
  143.     /*SSMSSLDataConnection_Invariant(conn); -- this could have been called from loser */
  144.     SSM_LockResource(arg);
  145.     /* shut down base class */
  146.     rv = SSMDataConnection_Shutdown(arg, status);
  147. if (firstTime) {
  148. SSM_DEBUG("First time shutting down SSL connection.n");
  149. }
  150.     /* If service threads are done, close the SSL socket */
  151.     if (SSMRESOURCE(conn)->m_threadCount == 0) {
  152.         if (conn->socketSSL) {
  153. SSM_DEBUG("Closing SSL socket with linger.n");
  154.             rv = PR_Close(conn->socketSSL);
  155.             conn->socketSSL = NULL;
  156.             SSM_DEBUG("Closed SSL socket (rv == %d).n", rv);
  157.         }
  158.     }
  159.     SSM_UnlockResource(arg);
  160. if (!firstTime) {
  161. rv = (SSMStatus)SSM_ERR_ALREADY_SHUT_DOWN;
  162. }
  163.     return rv;
  164. }
  165. SSMStatus SSMSSLDataConnection_Init(SSMSSLDataConnection* conn, 
  166.    SSMInfoSSL* info, SSMResourceType type)
  167. {
  168.     SSMStatus rv = PR_SUCCESS;
  169.     SSMControlConnection* parent;
  170.  
  171.   /* check arguments */
  172. if (conn == NULL || info == NULL) {
  173. goto loser;
  174. }
  175.     /* fill in the information we got from the request packet */
  176. parent = info->parent;
  177.     rv = SSMDataConnection_Init(SSMDATACONNECTION(conn), parent, type);
  178.     if (rv != PR_SUCCESS) {
  179. goto loser;
  180. }
  181.     conn->isTLS = info->isTLS;
  182.     conn->port = info->port;
  183.     conn->hostIP = info->hostIP;
  184.     conn->hostName = info->hostName;
  185.     /* Initialize UI info */
  186.     SSMSSLDataConnection_InitializeUIInfo(&conn->m_UIInfo);
  187.     if (conn->isTLS) {
  188.         conn->isSecure = PR_FALSE;
  189.         /* Create the step-up FD so that the control connection
  190.            can wake us up */
  191.         conn->stepUpFD = PR_NewPollableEvent();
  192.         if (conn->stepUpFD == NULL)
  193.             goto loser;
  194.     }
  195.     else {
  196.         conn->isSecure = PR_TRUE;
  197.         conn->forceHandshake = info->forceHandshake;
  198.         /* Save the client context */
  199.         SSMRESOURCE(conn)->m_clientContext = info->clientContext;
  200.     }
  201.     /* Spawn the data service thread */
  202.     SSM_DEBUG("Creating SSL data service thread.  Getting ref on SSL "
  203.               "connection.n");
  204.     /*
  205.      * This reference is for the socket status.  The client needs to tell
  206.      * us when to get rid of it.
  207.      */
  208.     SSM_GetResourceReference(SSMRESOURCE(conn));
  209.     SSMDATACONNECTION(conn)->m_dataServiceThread =
  210.         SSM_CreateThread(SSMRESOURCE(conn), SSM_SSLDataServiceThread);
  211.     if (SSMDATACONNECTION(conn)->m_dataServiceThread == NULL) {
  212.         goto loser;
  213.     }
  214.     conn->m_statusFetched = PR_FALSE;
  215.     return PR_SUCCESS;
  216. loser:
  217.     if (rv == PR_SUCCESS) {
  218. rv = PR_FAILURE;
  219. }
  220.     return rv;
  221. }
  222. SSMStatus SSMSSLDataConnection_Destroy(SSMResource* res, PRBool doFree)
  223. {
  224.     SSMSSLDataConnection* conn = (SSMSSLDataConnection*)res;
  225. if (res == NULL) {
  226. return PR_FAILURE;
  227. }
  228.     /* We should be shut down. */
  229.     PR_ASSERT(res->m_threadCount == 0);
  230.     /* Destroy our fields. */
  231.     PR_FREEIF(conn->hostIP);
  232.     PR_FREEIF(conn->hostName);
  233.     /* Destroy UI info. */
  234.     SSMSSLDataConnection_DestroyUIInfo(&conn->m_UIInfo);
  235.     /* Destroy step-up FD if we still have one. */
  236.     if (conn->stepUpFD)
  237.         PR_DestroyPollableEvent(conn->stepUpFD);
  238.     /* Destroy superclass fields. */
  239.     SSMDataConnection_Destroy(SSMRESOURCE(conn), PR_FALSE);
  240.     /* Destroy the socket status if it's there. */
  241.     if (conn->m_sockStat) {
  242.         SSM_FreeResource(&conn->m_sockStat->super);
  243.     }
  244.     /* Free the connection object if asked. */
  245.     if (doFree) {
  246.         PR_DELETE(conn);
  247. }
  248.     return PR_SUCCESS;
  249. }
  250. void SSMSSLDataConnection_Invariant(SSMSSLDataConnection* conn)
  251. {
  252.     SSMDataConnection_Invariant(SSMDATACONNECTION(conn));
  253.     SSM_LockResource(SSMRESOURCE(conn));
  254.     PR_ASSERT(SSM_IsAKindOf(SSMRESOURCE(conn), 
  255.                             SSM_RESTYPE_SSL_DATA_CONNECTION));
  256.     SSM_UnlockResource(SSMRESOURCE(conn));
  257. }
  258. SSMStatus SSMSSLDataConnection_GetAttrIDs(SSMResource* res,
  259.  SSMAttributeID** ids, PRIntn* count)
  260. {
  261.     SSMStatus rv;
  262. if (res == NULL || ids == NULL || count == NULL) {
  263. goto loser;
  264. }
  265.     rv = SSMDataConnection_GetAttrIDs(res, ids, count);
  266.     if (rv != PR_SUCCESS) {
  267.         goto loser;
  268. }
  269.     *ids = (SSMAttributeID *) PR_REALLOC(*ids, (*count + 2)*sizeof(SSMAttributeID));
  270.     if (!*ids) {
  271. goto loser;
  272. }
  273.     (*ids)[*count++] = SSM_FID_SSLDATA_SOCKET_STATUS;
  274.     (*ids)[*count++] = SSM_FID_SSLDATA_DISCARD_SOCKET_STATUS;
  275.     goto done;
  276. loser:
  277.     if (rv == PR_SUCCESS) {
  278. rv = PR_FAILURE;
  279. }
  280. done:
  281.     return rv;
  282. }
  283. SSMStatus SSMSSLDataConnection_SetAttr(SSMResource * res,
  284.                                        SSMResourceAttrType attrType,
  285.                                        SSMAttributeValue *value)
  286. {
  287.     SSMStatus rv = SSM_FAILURE;
  288.     SSMSSLDataConnection *conn = (SSMSSLDataConnection*)res;
  289.     if (!SSM_IsAKindOf(res, SSM_RESTYPE_SSL_DATA_CONNECTION)) {
  290.         return SSM_FAILURE;
  291.     }
  292.     switch (attrType) {
  293.     case SSM_FID_SSLDATA_DISCARD_SOCKET_STATUS:
  294.         /*
  295.          * Just release the reference we were holding onto.
  296.          */
  297.         if (!conn->m_statusFetched) {
  298.             SSM_FreeResource(res);
  299.             conn->m_statusFetched = PR_TRUE;
  300.         }
  301.         rv = SSM_SUCCESS;
  302.         break;
  303.     default:
  304.         break;
  305.     }
  306.     return rv;
  307. }
  308. SSMStatus SSMSSLDataConnection_GetAttr(SSMResource *res, SSMAttributeID attrID,
  309.                                        SSMResourceAttrType attrType,
  310.                                        SSMAttributeValue *value)
  311. {
  312.     SSMSSLDataConnection* conn = (SSMSSLDataConnection*)res;
  313.     SSMStatus rv = PR_SUCCESS;
  314. if (res == NULL || value == NULL) {
  315. goto loser;
  316. }
  317.     /* see what it is */
  318.     switch(attrID) {
  319.     case SSM_FID_SSLDATA_SOCKET_STATUS:
  320.         /* if the socket status does not exist at this time (which
  321.          * is very unlikely usually), we will wait until the handshake
  322.          * callback creates it
  323.          */
  324.         SSM_LockResource(SSMRESOURCE(conn));
  325.         while (conn->m_sockStat == NULL || 
  326.                conn->m_sockStat->m_cipherName == NULL) {
  327.             SSM_DEBUG("Oops, the security status has not been updated.  Waiting...n");
  328.             SSM_WaitResource(SSMRESOURCE(conn), PR_INTERVAL_NO_TIMEOUT);
  329.         }
  330.         if (conn->m_sockStat == NULL) {
  331.             SSM_DEBUG("No socket status on dead socket.n");
  332.             SSM_UnlockResource(SSMRESOURCE(conn));
  333.             goto loser;
  334.         }
  335.         /* We have a socket status object, return its resource ID. */
  336.         value->u.rid = conn->m_sockStat->super.m_id;
  337.         value->type = SSM_RID_ATTRIBUTE;
  338.         SSM_UnlockResource(SSMRESOURCE(conn));
  339.         /*
  340.         if (conn->m_sockStat) {
  341.         }
  342.         else {
  343.             rv = SSM_ERR_ATTRIBUTE_MISSING;
  344.             goto loser;
  345.         }
  346.         */
  347. break;
  348.     case SSM_FID_SSLDATA_ERROR_VALUE:
  349.         value->type = SSM_NUMERIC_ATTRIBUTE;
  350.         SSM_LockResource(SSMRESOURCE(conn));
  351.         value->u.numeric = conn->m_error;
  352.         SSM_DEBUG("Reported error: %ldn", conn->m_error);
  353.         SSM_UnlockResource(SSMRESOURCE(conn));
  354.         break;
  355.     default:
  356.         rv = SSMConnection_GetAttr(res, attrID, attrType, value);
  357.         if (rv != PR_SUCCESS) {
  358. goto loser;
  359. }
  360.     }
  361.     goto done;
  362. loser:
  363.     value->type = SSM_NO_ATTRIBUTE;
  364.     if (rv == PR_SUCCESS) {
  365. rv = PR_FAILURE;
  366. }
  367. done:
  368.     return rv;
  369. }
  370. /*
  371.  * Function: SSMStatus SSMSSLDataConnection_PickleSecurityStatus()
  372.  * Purpose: fills in information on security status (pickled socket status
  373.  *          and the security level) on PickleSecurityStatus request
  374.  *
  375.  * Arguments and return values:
  376.  * - conn: SSL connection object
  377.  * - len: length of the pickled data
  378.  * - blob: pickled data
  379.  * - securityLevel: security level
  380.  * - returns: PR_SUCCESS if successful; error code otherwise
  381.  *
  382.  * Note: Note that this is not really a pickle class function.  This is
  383.  *       specially designed to handle security status requests efficiently.
  384.  */
  385. SSMStatus SSMSSLDataConnection_PickleSecurityStatus(SSMSSLDataConnection* conn,
  386.                                                    PRIntn* len, void** blob,
  387.                                                    PRIntn* securityLevel)
  388. {
  389.     SSMStatus rv = PR_SUCCESS;
  390.     PR_ASSERT(conn != NULL);
  391.     /* in case of failure */
  392.     *len = 0;
  393.     *blob = NULL;
  394.     *securityLevel = 0;
  395.     /* the connection may not be secure yet in case of proxy connections:
  396.      * we should just return and indicate no security if that's the case
  397.      */
  398.     if (!conn->isSecure) {
  399.         return rv;
  400.     }
  401.     /* if the socket status does not exist at this time (which is usually
  402.      * very unlikely), we will wait until the handshake callback creates it
  403.      */
  404.     SSM_LockResource(SSMRESOURCE(conn));
  405.     if (conn->m_sockStat == NULL ||
  406.         conn->m_sockStat->m_cipherName == NULL) {
  407.         SSM_DEBUG("Oops, the security status has not been updated.  "
  408.                   "Waiting...n");
  409.         SSM_WaitResource(SSMRESOURCE(conn), PR_TicksPerSecond());
  410.     }
  411.     if (conn->m_sockStat == NULL) {
  412.         SSM_DEBUG("No socket status on dead socket.n");
  413.         SSM_UnlockResource(SSMRESOURCE(conn));
  414.         rv = PR_FAILURE;
  415.         goto loser;
  416.     }
  417.     /* it's probably OK to unlock it here */
  418.     SSM_UnlockResource(SSMRESOURCE(conn));
  419.     /* we have a socket status object. */
  420.     rv = SSMSSLSocketStatus_Pickle(&conn->m_sockStat->super, len, blob);
  421.     if (rv != PR_SUCCESS) {
  422.         SSM_DEBUG("Failed to pickle the socket status.n");
  423.         goto loser;
  424.     }
  425.     /* get the security level */
  426.     *securityLevel = conn->m_sockStat->m_level;
  427.     /*
  428.      * The client retrieved the socket status, so we can release our
  429.      * refernce now.
  430.      */
  431.     if (!conn->m_statusFetched) {
  432.         SSM_FreeResource(SSMRESOURCE(conn));
  433.         conn->m_statusFetched = PR_TRUE;
  434.     }
  435.  loser:
  436.     return rv;
  437. }
  438. /*
  439.  * Function: SSMStatus SSMSSLDataConnection_FormSubmitHandler()
  440.  * Purpose: handles any UI form submission that has an SSMSSLDataConnection
  441.  *          object as target
  442.  * Expected request:
  443.  * - command: "formsubmit_handler"
  444.  * - baseRef: "formsubmit_dosubmit_js"
  445.  * - target: an SSMSSLDataConnection object
  446.  * - formName: "cert_selection" | "bad_server_cert"
  447.  * Arguments and return values
  448.  * - res: SSMSSLDataConnection object
  449.  * - req: the HTTPRequest object to be processed
  450.  * - returns: SSM_SUCCESS if successful; error otherwise
  451.  *
  452.  * Note: add more handling helper functions if there are other form
  453.  *       submission scenarios
  454.  */
  455. SSMStatus SSMSSLDataConnection_FormSubmitHandler(SSMResource* res,
  456.                                                  HTTPRequest* req)
  457. {
  458.     SSMStatus rv;
  459.     char* tmpStr = NULL;
  460.     SSMSSLDataConnection* conn;
  461.     conn = (SSMSSLDataConnection*)res;
  462.     
  463.     /* make sure you got the right baseRef */
  464.     rv = SSM_HTTPParamValue(req, "baseRef", &tmpStr);
  465.     if (rv != SSM_SUCCESS ||
  466.         PL_strcmp(tmpStr, "windowclose_doclose_js") != 0) {
  467.         goto loser;
  468.     }
  469.     /* differentiate among different form submission events by looking up
  470.      * formName, and dispatch the request to the appropriate handler 
  471.      */
  472.     /* cleaning up (unlocking monitors, etc.) is handled by individual
  473.      * handlers, so just go to done
  474.      */
  475.     if (res->m_formName == NULL) {
  476.         goto loser;
  477.     }
  478.     if (PL_strcmp(res->m_formName, "cert_selection") == 0) {
  479.         rv = SSM_ClientAuthCertSelectionButtonHandler(req);
  480.         goto done;
  481.     }
  482.     else if (PL_strcmp(res->m_formName, "bad_server_cert") == 0) {
  483.         /* server auth failure other than unknown issuer case */
  484.         rv = SSM_ServerAuthFailureButtonHandler(req);
  485.         goto done;
  486.     }
  487.     else {
  488.         /* unknown form name; abort */
  489.         SSM_DEBUG("don't know how to handle this form.n");
  490.         goto loser;
  491.     }
  492. loser:
  493.     if (rv == SSM_SUCCESS) {
  494.         rv = SSM_FAILURE;
  495.     }
  496.     SSM_LockResource(req->target);
  497.     conn->m_UIInfo.chosen = -1;
  498.     conn->m_UIInfo.trustBadServerCert = BSCA_NO;
  499.     conn->m_UIInfo.UICompleted = PR_TRUE;
  500.     SSM_NotifyResource(req->target);
  501.     SSM_UnlockResource(req->target);
  502. done:
  503.     return rv;
  504. }
  505. void SSMSSLDataConnection_InitializeUIInfo(SSMSSLUIInfo* info)
  506. {
  507.     info->UICompleted = PR_FALSE;
  508.     info->numFilteredCerts = 0;
  509.     info->certNicknames = NULL;
  510.     info->chosen = -1;    /* negative value denotes no cert was chosen */
  511.     info->trustBadServerCert = BSCA_NO;
  512. }
  513. void SSMSSLDataConnection_DestroyUIInfo(SSMSSLUIInfo* info)
  514. {
  515.     int i;
  516.     if (info->numFilteredCerts != 0) {
  517.         for (i = 0; i < info->numFilteredCerts; i++) {
  518.             PR_FREEIF(info->certNicknames[i]);
  519.         }
  520.         PR_FREEIF(info->certNicknames);
  521.     }
  522. }
  523. SSMStatus SSMSSLDataConnection_UpdateSecurityStatus(SSMSSLDataConnection* conn)
  524. {
  525.     SSMStatus rv = PR_SUCCESS;
  526. PR_ASSERT(conn != NULL);
  527. SSM_LockResource(SSMRESOURCE(conn));
  528.     if (conn->m_sockStat == NULL) {
  529.         /* socket status has not been created.  The security status will
  530.          * be properly populated by creating the socket status.
  531.          */
  532.         SSMResourceID statRID;
  533.         SSM_CreateResource(SSM_RESTYPE_SSL_SOCKET_STATUS, conn->socketSSL, 
  534.                            SSMRESOURCE(conn)->m_connection, &statRID, 
  535.                            (SSMResource**)&conn->m_sockStat);
  536. conn->m_sockStat->m_error = conn->m_sslServerError;
  537.         /*
  538.          * Just in case someone's waiting on the resource.
  539.          */
  540.         SSM_LockResource(SSMRESOURCE(conn));
  541.         SSM_NotifyResource(SSMRESOURCE(conn));
  542.         SSM_UnlockResource(SSMRESOURCE(conn));
  543.     }
  544.     else {
  545.         /* just update the values */
  546.         rv = SSMSSLSocketStatus_UpdateSecurityStatus(conn->m_sockStat, 
  547.                                                      conn->socketSSL);
  548.         if (rv != PR_SUCCESS) {
  549.             goto loser;
  550.         }
  551.     }
  552. loser:
  553.     /* in case we fail to update the security status, we still notify
  554.      * because we don't want to quit just because this failed...
  555.      */
  556.     SSM_NotifyResource(SSMRESOURCE(conn));
  557.     /* notify SSMSSLDataConnection_GetAttr() for the socket RID */
  558. SSM_UnlockResource(SSMRESOURCE(conn));
  559.     return rv;
  560. }
  561. /* updates the error code in case of an exception: returns the current
  562.  * error code (0 if no error) 
  563.  */
  564. static 
  565. SSMStatus SSMSSLDataConnection_UpdateErrorCode(SSMSSLDataConnection* conn)
  566. {
  567.     PR_ASSERT(conn != NULL);
  568.     SSM_LockResource(SSMRESOURCE(conn));
  569.     if (conn->m_error == 0) {
  570.         /* update the error code only if it is not already set:
  571.          * otherwise preserve the initial error code
  572.          */
  573.         PRInt32 rv;
  574.         rv = PR_GetError();
  575.         if (rv != SEC_ERROR_LIBRARY_FAILURE) {
  576.             /* XXX sometimes NSS reports this error even when connection
  577.              *     terminates normally: will escape this error here so that
  578.              *     this is not reported erroneously
  579.              */
  580.             conn->m_error = rv;
  581.         }
  582.     }
  583.     SSM_UnlockResource(SSMRESOURCE(conn));
  584.     return conn->m_error;
  585. }
  586. /* functions for setting up and configuring SSL connection */
  587. SECStatus SSM_SetupSSLSocket(PRFileDesc* socket, PRFileDesc** sslsocket,
  588.                              CERTCertDBHandle* handle, char* hostname,
  589.                              void* wincx)
  590. {
  591.     SECStatus rv = SECFailure;
  592.     /* check arguments */
  593.     if ((socket == NULL) || (sslsocket == NULL) || (handle == NULL) || 
  594.         (hostname == NULL) || (wincx == NULL)) {
  595.         goto loser;
  596.     }
  597.     *sslsocket = NULL;
  598.    /* import the socket into SSL layer */
  599.     *sslsocket = SSL_ImportFD(NULL, socket);
  600.     if (*sslsocket == NULL) {
  601.         goto loser;
  602.     }
  603.   
  604.    /* set some SSL settings for the socket */
  605.     rv = SSL_Enable(*sslsocket, SSL_SECURITY, PR_TRUE);
  606.     if (rv != SECSuccess) {
  607. goto loser;
  608. }
  609.    rv = SSL_Enable(*sslsocket, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
  610.     if (rv != SECSuccess) {
  611. goto loser;
  612. }
  613. rv = SSL_Enable(*sslsocket, SSL_ENABLE_FDX, PR_TRUE);
  614.     if (rv != SECSuccess) {
  615. goto loser;
  616. }
  617.    /* set callbacks */
  618.    /* client authentication */
  619.    rv = SSL_GetClientAuthDataHook(*sslsocket, 
  620.                                    (SSLGetClientAuthData)SSM_SSLGetClientAuthData, 
  621.                                    NULL) == 0 ? SECSuccess : SECFailure;
  622.     if (rv  != SECSuccess) {
  623. goto loser;
  624. }
  625.   
  626.    /* server cert authentication */
  627. rv = SSL_AuthCertificateHook(*sslsocket,
  628.                                  (SSLAuthCertificate)SSM_SSLAuthCertificate,
  629.                                  (void*)handle) == 0 ? SECSuccess : SECFailure;
  630.     if (rv != SECSuccess) {
  631. goto loser;
  632. }
  633.   
  634.    rv = SSL_BadCertHook(*sslsocket, (SSLBadCertHandler)SSM_SSLBadCertHandler, 
  635.                          wincx) == 0 ? SECSuccess : SECFailure;
  636.     if (rv != SECSuccess) {
  637.    goto loser;
  638. }
  639.     rv = SSL_HandshakeCallback(*sslsocket, 
  640.                                (SSLHandshakeCallback)SSM_SSLHandshakeCallback,
  641.                                wincx) == 0 ? SECSuccess : SECFailure;
  642.     if (rv != SECSuccess) {
  643.         goto loser;
  644.     }
  645.     SSM_DEBUG("setting PKCS11 pin arg.n");
  646.     rv = SSL_SetPKCS11PinArg(*sslsocket, wincx) == 0 ? SECSuccess : SECFailure;
  647.     if (rv != SECSuccess) {
  648.         goto loser;
  649.     }
  650.     /* prepare against man-in-the-middle attacks */
  651.     rv = SSL_SetURL(*sslsocket, hostname) == 0 ? SECSuccess : SECFailure;
  652.     if (rv != SECSuccess) {
  653.         goto loser;
  654.     }
  655.    return rv;
  656. loser:
  657. if (*sslsocket == NULL) {
  658. /* aborted before SSL_ImportFD() */
  659. if (socket != NULL) {
  660. PR_Close(socket);
  661. }
  662. }
  663. else {
  664. PR_Close(*sslsocket);
  665.         *sslsocket = NULL;
  666. }
  667. return rv;
  668. }
  669. SSMStatus SSM_GetSSLSocket(SSMSSLDataConnection* conn)
  670. {
  671.     SECStatus secstatus = SECSuccess;
  672.     PRStatus prstatus = PR_SUCCESS;
  673.     PRFileDesc* socket = NULL;
  674.     PRSocketOptionData sockdata;
  675.     SSMControlConnection* ctrlconn;
  676.     PRNetAddr addr;
  677.     PRHostEnt hostentry;
  678.     char buffer[256];
  679.     SSM_DEBUG("SSM_GetSSLSocket entered.n");
  680. /* check argument first */
  681. if (conn == NULL) {
  682. return PR_FAILURE;
  683. }
  684.     /* Enter SSL lock. We will release once connection is set up. 
  685.      * If GetSecurityStatus request comes in before we are done, it'll spin 
  686.      * on the SSL lock. (This lock is not used anyplace else.)
  687.      */
  688.   
  689.     /*PR_EnterMonitor(conn->sslLock);*/
  690.     /* set up SSL secure socket */
  691.     SSM_DEBUG("setting up secure socket.n");
  692.     socket = PR_NewTCPSocket();
  693.     if (socket == NULL) {
  694.         goto loser;
  695.     }
  696.     /* make the socket blocking - default on some platforms is non-blocking */
  697.     sockdata.option = PR_SockOpt_Nonblocking;
  698.     sockdata.value.non_blocking = PR_FALSE;
  699.     if (PR_SetSocketOption(socket, &sockdata) != PR_SUCCESS) {
  700.         goto loser;
  701.     }
  702.     if (!conn->isTLS) {
  703.         /* set up SSL secure socket */
  704.         SSM_DEBUG("setting up secure socket.n");
  705.         ctrlconn = SSMCONTROLCONNECTION(conn);
  706.         secstatus = SSM_SetupSSLSocket(socket, &conn->socketSSL,
  707.                                        ctrlconn->m_certdb, conn->hostName, 
  708.                                        (void*)conn);
  709.         if (secstatus != SECSuccess) {
  710.             goto loser;
  711.         }
  712.     }
  713.     else {
  714.         /* do not need to create a secure socket here */
  715.         conn->socketSSL = socket;
  716.     }
  717.     /* prepare and setup network connection */
  718.     SSM_DEBUG("preparing and setting up network connection.n");
  719.     if (PR_StringToNetAddr(conn->hostIP, &addr) != PR_SUCCESS) {
  720.         PRIntn hostIndex;
  721.         prstatus = PR_GetHostByName(conn->hostName, buffer, 256, &hostentry);
  722. if (prstatus != PR_SUCCESS) {
  723.     goto loser;
  724. }
  725.   
  726. SSM_DEBUG("SSL server port: %d / host: %s n", conn->port, 
  727.   conn->hostName);
  728. do {
  729.     hostIndex = PR_EnumerateHostEnt(0, &hostentry, 
  730.     (PRUint16) conn->port, &addr);
  731.     if (hostIndex < 0) {
  732.         goto loser;
  733.     }
  734. } while (PR_Connect(conn->socketSSL, &addr, PR_INTERVAL_NO_TIMEOUT) != PR_SUCCESS
  735.  && hostIndex > 0);
  736. SSM_DEBUG("Connected to target.n");
  737.     } else {
  738.         if (PR_InitializeNetAddr(PR_IpAddrNull, (PRUint16)conn->port, &addr) != PR_SUCCESS) {
  739.     goto loser;
  740. }
  741. if (PR_Connect(conn->socketSSL, &addr, PR_INTERVAL_NO_TIMEOUT) != PR_SUCCESS) {
  742.   goto loser;
  743. }
  744. SSM_DEBUG("SSL server port: %d / host: %sn", conn->port, 
  745.   conn->hostName);
  746. SSM_DEBUG("connected using hostIP: %sn", conn->hostIP);
  747.     }
  748. #ifdef _HACK_
  749.     /* ### mwelch Fix for NSPR20 connect problem under 95/NT. */
  750.     PR_Sleep(PR_INTERVAL_NO_WAIT);
  751. #endif
  752.     /* established SSL connection, ready to send data */
  753.     if (!conn->isTLS && conn->forceHandshake) {
  754.         /* if the client wants a forced handshake (e.g. SSL/IMAP), 
  755.          * do it here 
  756.          */
  757.         SSM_DEBUG("forcing handshake.n");
  758.         secstatus = (SSL_ForceHandshake(conn->socketSSL) == 0)? SECSuccess:SECFailure;
  759.         if (secstatus != SECSuccess) {
  760.             goto loser;
  761.         }
  762.     }
  763.     /*
  764. if (conn->m_sockStat) {
  765.         SSM_FreeResource(&conn->m_sockStat->super);
  766. }
  767.     SSM_CreateResource(SSM_RESTYPE_SSL_SOCKET_STATUS, conn->socketSSL, 
  768.                        SSMRESOURCE(conn)->m_connection, &statRID, 
  769.                        (SSMResource**)&conn->m_sockStat);
  770.     */
  771. /* check everything is hunky-dorey */
  772.     /* SSMSSLSocketStatus_Invariant(conn->m_sockStat); */
  773.     /* end of the block */
  774.     /* release SSL lock. SSL connection is established. */
  775.     /*PR_Notify(conn->sslLock);
  776.       PR_ExitMonitor(conn->sslLock);*/
  777.     SSM_DEBUG("returning OK.n");
  778.     return prstatus;
  779. loser:
  780.     (void)SSMSSLDataConnection_UpdateErrorCode(conn);
  781.     SSM_LockResource(SSMRESOURCE(conn));
  782.     SSM_DEBUG("error %d (%s), exiting abnormally.n", conn->m_error, 
  783.               SSL_Strerror(conn->m_error));
  784.     SSM_UnlockResource(SSMRESOURCE(conn));
  785.     return PR_FAILURE;
  786. }
  787. /* 
  788.  * Function: PRStatus SSMSSLDataConnection_TLSStepUp()
  789.  * Purpose: "step up" the connection and set up an SSL socket for the 
  790.  *          underlying TCP socket
  791.  * Arguments and return values:
  792.  * - conn: TLS connection object to be manipulated
  793.  * - returns: PR_SUCCESS if successful; PR_FAILURE otherwise
  794.  *
  795.  * Notes: SSL handshakes are not done here; it is performed when the first
  796.  *        read/write operation is done on the secure socket
  797.  *        This function must be called while the underlying resource is
  798.  *        locked
  799.  */
  800. static PRStatus SSMSSLDataConnection_TLSStepUp(SSMSSLDataConnection* conn)
  801. {
  802.     PRFileDesc* socket = conn->socketSSL;
  803.     PRFileDesc* sslsocket = NULL;
  804.     PR_ASSERT(conn->isTLS == PR_TRUE);
  805.     if (conn->isSecure == PR_TRUE) {
  806.         /* socket is already secure */
  807.         return PR_SUCCESS;
  808.     }
  809.     SSM_DEBUG("Setting up secure socket for this TLS connection.n");
  810.     if (SSM_SetupSSLSocket(socket, &sslsocket,
  811.                            SSMCONTROLCONNECTION(conn)->m_certdb, 
  812.                            conn->hostName, (void*)conn) != SECSuccess) {
  813.         goto loser;
  814.     }
  815.     SSM_DEBUG("Resetting handshake.n");
  816.     if (SSL_ResetHandshake(sslsocket, PR_FALSE) != SECSuccess) {
  817.         goto loser;
  818.     }
  819.     /* XXX it is important that the SSL handshake does not take place here
  820.      *     because that would create a deadlock on this thread
  821.      */
  822.     SSM_DEBUG("We now have a secure socket.n");
  823.     /* secure socket is established */
  824.     conn->socketSSL = sslsocket;
  825.     conn->isSecure = PR_TRUE;
  826.     return PR_SUCCESS;
  827. loser:
  828.     (void)SSMSSLDataConnection_UpdateErrorCode(conn);
  829.     if (sslsocket == NULL) {
  830.         if (socket != NULL) {
  831.             PR_Close(socket);
  832.         }
  833.     }
  834.     else {
  835.         PR_Close(sslsocket);
  836.     }
  837.     return PR_FAILURE;
  838. }
  839. /* thread function */
  840. /* SSL connection is serviced by the data service thread that works on
  841.  * the client data socket and the SSL socket.
  842.  * 
  843.  * Our poll descriptor array contains the client data socket and the SSL 
  844.  * target socket in this order.
  845.  */
  846. #define SSL_PDS 3
  847. #define READSSL_CHUNKSIZE 16384
  848. void SSM_SSLDataServiceThread(void* arg)
  849. {
  850.     SSMStatus rv = PR_SUCCESS;
  851.     SSMSSLDataConnection* conn = NULL;
  852.     PRPollDesc pds[SSL_PDS];
  853.     PRIntn nSockets = 0;
  854.     PRInt32 nReady;
  855.     int i;
  856.     PRIntn read = 0;
  857.     PRIntn sent = 0;
  858.     char *outbound = NULL;
  859.     char *inbound = NULL;
  860.     PRIntn oBufSize;
  861.     
  862.     SSM_RegisterNewThread("ssl data", (SSMResource *) arg);
  863.     conn = (SSMSSLDataConnection*)arg;
  864.     SSM_DEBUG("initializing.n");
  865.     if (arg == NULL) {
  866.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  867.         goto loser;
  868.     }
  869.     SSMDATACONNECTION(conn)->m_dataServiceThread = PR_GetCurrentThread();
  870. /* initialize xfer buffers */
  871. outbound = (char *) PR_CALLOC(READSSL_CHUNKSIZE+1);
  872. if (outbound == NULL)
  873. goto loser;
  874. inbound = (char *) PR_CALLOC(READSSL_CHUNKSIZE+1);
  875. if (inbound == NULL)
  876. goto loser;
  877.     /* initialize the poll descriptors */
  878.     for (i = 0; i < SSL_PDS; i++) {
  879.         pds[i].fd = NULL;
  880.     }
  881.     /* set up sockets */
  882.     /* set up the client data socket */
  883.     rv = SSMDataConnection_SetupClientSocket(SSMDATACONNECTION(conn));
  884.     if (rv != PR_SUCCESS) {
  885.         goto loser;
  886.     }
  887.     /* save the client data socket in the array */
  888.     pds[0].fd = SSMDATACONNECTION(conn)->m_clientSocket;
  889.     pds[0].in_flags = PR_POLL_READ;
  890.     nSockets++;
  891.     /* set up the SSL socket */
  892.     rv = SSM_GetSSLSocket(conn);
  893.     if (rv != PR_SUCCESS) {
  894.         goto loser;
  895.     }
  896.     /* save the SSL socket in the array */
  897.     pds[1].fd = conn->socketSSL;
  898.     pds[1].in_flags = PR_POLL_READ;
  899.     nSockets++;
  900.     if (conn->isTLS) {
  901.         /* SSL/SMTP connections usually require a large outbound buffer */
  902.         oBufSize = READSSL_CHUNKSIZE;
  903.         /* Add step-up FD to the list of FDs until we've been asked to
  904.            encrypt */
  905.         pds[2].fd = conn->stepUpFD;
  906.         pds[2].in_flags = PR_POLL_READ;
  907.         nSockets++;
  908.     }
  909.     else {
  910.         oBufSize = LINESIZE;
  911.     }
  912.     /* spinning mode.  Exchange data between the client socket and the SSL
  913.      * socket.
  914.      */
  915.     while ((nSockets > 0) && 
  916.            (SSM_Count(SSMDATACONNECTION(conn)->m_shutdownQ) == 0)) {
  917.         /* XXX Nova-specific: Nova does not handle active close from the
  918.          *     server properly in case of keep-alive connections: what
  919.          *     happens is that although we perform a shutdown on the client
  920.          *     socket, Nova never sends us a close.  If the SSL socket is 
  921.          *     removed, we might as well close the client socket by hand.
  922.          */
  923.         /* if the outbound connection is shut down and there is no data
  924.          * pending in the client socket, perhaps the client is acting up
  925.          */
  926.         if (pds[1].fd == NULL) {
  927.             /* don't block in polling */
  928.             nReady = PR_Poll(pds, SSL_PDS, PR_INTERVAL_NO_WAIT);
  929.             if (nReady <= 0) {
  930.                 /* either error or the client socket is blocked.  Bail. */
  931.                 rv = SSMSSLDataConnection_UpdateErrorCode(conn);
  932.                 if (SSMDATACONNECTION(conn)->m_clientSocket != NULL) {
  933.                     PR_Shutdown(SSMDATACONNECTION(conn)->m_clientSocket,
  934.                                 PR_SHUTDOWN_SEND);
  935.                 }
  936.                 nSockets--;
  937.                 if (nSockets > 1)
  938.                     {
  939.                         /* 
  940.                            We were waiting for notification to step up,
  941.                            but that notification won't happen. So,
  942.                            remove stepUpFD from the list as well.
  943.                         */
  944.                         pds[2].fd = NULL;
  945.                         nSockets = 1;
  946.                     }
  947.                 break;    /* go to loser; */
  948.             }
  949.         }
  950.         SSM_DEBUG("Polling sockets for pending data.n");
  951.         /* poll sockets for pending data */
  952. #if 0
  953.         if (conn->isTLS == PR_TRUE) {
  954.             /* we require the lock for this operation and do a non-blocking
  955.              * poll in case of TLS because we want to yield to the step-up 
  956.              * operation
  957.              */
  958.             SSM_LockResource(SSMRESOURCE(conn));
  959.             nReady = PR_Poll(pds, SSL_PDS, PR_INTERVAL_NO_WAIT);
  960.             SSM_UnlockResource(SSMRESOURCE(conn));
  961.             if (nReady == 0) {
  962.                 continue;
  963.             }
  964.         }
  965.         else {
  966. #endif
  967.             /* Poll for however many sockets we're interested in. */
  968.             nReady = PR_Poll(pds, nSockets, PR_INTERVAL_NO_TIMEOUT);
  969. #if 0
  970.         }
  971. #endif
  972.         if (nReady < 0) {
  973.             rv = SSMSSLDataConnection_UpdateErrorCode(conn);
  974.             goto loser;
  975.         }
  976.         /* Wind down from SSL_PDS because the pollable event
  977.            takes priority over the I/O sockets. */
  978.         for (i = (SSL_PDS-1); i >= 0; i--) {
  979.             if (pds[i].fd == NULL) {
  980.                 continue;
  981.             }
  982.             /* check sockets for data */
  983.             if (pds[i].out_flags & (PR_POLL_READ | PR_POLL_EXCEPT)) {
  984.                 if (pds[i].fd == SSMDATACONNECTION(conn)->m_clientSocket) {
  985.                     /* got data at the client socket */
  986.                     SSM_DEBUG("Attempting to read %ld bytes from client "
  987.                               "socket.n", oBufSize);
  988.                     read = PR_Recv(SSMDATACONNECTION(conn)->m_clientSocket,
  989.                                    outbound, oBufSize, 0,
  990.                                    PR_INTERVAL_NO_TIMEOUT);
  991.                     
  992.                     if (read <= 0) {
  993.                         if (read < 0) {
  994.                             /* Got an error */
  995.                             rv = SSMSSLDataConnection_UpdateErrorCode(conn);
  996.                             SSM_DEBUG("Error receiving data over client "
  997.                                       "socket, status == %ldn", (long)rv);
  998.                         }
  999.                         else {
  1000.                             /* We got an EOF */
  1001.                             SSM_DEBUG("Got EOF at client socket.n");
  1002.                             rv = PR_SUCCESS;
  1003.                         }
  1004.                         if (conn->socketSSL != NULL) {
  1005.                             SSM_DEBUG("Shutting down the target socket.n");
  1006.                             PR_Shutdown(conn->socketSSL, PR_SHUTDOWN_SEND);
  1007.                         }
  1008.                         /* remove the socket from the array */
  1009.                         pds[i].fd = NULL;
  1010.                         nSockets--;
  1011.                     }
  1012.                     else {
  1013.                         SSM_DEBUG("data: <%s>n" "Send the data to the "
  1014.                                   "target.n", outbound);
  1015.                         sent = PR_Send(conn->socketSSL, outbound, read, 0,
  1016.                                        PR_INTERVAL_NO_TIMEOUT);
  1017.                         if (sent != read) {
  1018.                          SSM_DEBUG("Couldn't send all data to the target socket (sent: %d read: %d)n",
  1019.                          sent, read);
  1020.                             rv = SSMSSLDataConnection_UpdateErrorCode(conn);
  1021.                             
  1022.                             if (SSMDATACONNECTION(conn)->m_clientSocket != 
  1023. NULL) {
  1024.                                 SSM_DEBUG("Shutting down the client socket.n");
  1025.                                 PR_Shutdown(SSMDATACONNECTION(conn)->m_clientSocket, 
  1026.     PR_SHUTDOWN_SEND);
  1027.                             }
  1028.                             /* remove the socket from the array */
  1029.                             pds[i].fd = NULL;
  1030.                             nSockets--;
  1031.                         }
  1032.                     }
  1033.                 }
  1034.                 else if (pds[i].fd == conn->socketSSL) {
  1035.                     /* got data at the SSL socket */
  1036.                     SSM_DEBUG("Reading data from target socket.n");
  1037.                     read = PR_Recv(conn->socketSSL, inbound, READSSL_CHUNKSIZE,
  1038.                                    0, PR_INTERVAL_NO_TIMEOUT);
  1039.                     if (read <= 0) {
  1040.                         if (read < 0) {
  1041.                             /* Got error */
  1042.                             rv = SSMSSLDataConnection_UpdateErrorCode(conn);
  1043.                             SSM_DEBUG("Error receiving data from target "
  1044.                                       "socket, status = %ldn", rv);
  1045.                         }
  1046.                         else {
  1047.                             /* We got an EOF */
  1048.                             SSM_DEBUG("Got EOF at target socket.n");
  1049.                             rv = PR_SUCCESS;
  1050.                         }
  1051.                         if (SSMDATACONNECTION(conn)->m_clientSocket != NULL) {
  1052.     SSM_DEBUG("Shutting down the client socket.n");
  1053.                             PR_Shutdown(SSMDATACONNECTION(conn)->m_clientSocket, 
  1054.                                         PR_SHUTDOWN_SEND);
  1055.                         }
  1056.                         /* remove the socket from the array */
  1057.                         pds[i].fd = NULL;
  1058.                         nSockets--;
  1059.                     }
  1060.                     else {
  1061.                         /* Got data, write it to the client socket */
  1062.                         SSM_DEBUG("Writing to client socket.n");
  1063. #if 0
  1064.                         SSM_DumpBuffer(inbound, read);
  1065. #endif
  1066.                         sent = PR_Send(SSMDATACONNECTION(conn)->m_clientSocket,
  1067.                                        inbound, read, 0, 
  1068.                                        PR_INTERVAL_NO_TIMEOUT);
  1069.                         if (sent != read) {
  1070.                             rv = SSMSSLDataConnection_UpdateErrorCode(conn);
  1071.                             if (conn->socketSSL != NULL) {
  1072.         SSM_DEBUG("Shutting down the target socket.n");
  1073.                                 PR_Shutdown(conn->socketSSL, PR_SHUTDOWN_SEND);
  1074.                             }
  1075.                             /* remove the socket from the array */
  1076.                             pds[i].fd = NULL;
  1077.                             nSockets--;
  1078.                         }
  1079.                         SSM_DEBUG("Wrote %ld bytes.n", sent);
  1080.                     }
  1081.                 }
  1082.                 else if (pds[i].fd == conn->stepUpFD)
  1083.                 {
  1084.                     /* We've been told to enable TLS on this connection.
  1085.                        Clear the event, step up, and reconfigure sockets. */
  1086.                     PRFileDesc *stepUpFD = conn->stepUpFD;
  1087.                     /* Make sure the control connection has settled */
  1088.                     SSM_LockResource(SSMRESOURCE(conn));
  1089.                     if ((pds[i].out_flags & PR_POLL_READ) != 0)
  1090.                         /* it's readable, so it should return immediately */
  1091.                         PR_WaitForPollableEvent(stepUpFD);
  1092.                     /* Step up to encryption. */
  1093.                     rv = SSMSSLDataConnection_TLSStepUp(conn);
  1094.                     conn->m_error = rv; /* tell the control connection */
  1095.                     /* Remove the step-up fd */
  1096.                     conn->stepUpFD = NULL;
  1097.                     pds[i].fd = NULL;
  1098.                     nSockets--;
  1099.                     PR_DestroyPollableEvent(stepUpFD);
  1100.                     /* Notify ourselves to wake up the control connection */
  1101.                     SSM_NotifyResource(SSMRESOURCE(conn));
  1102.                     SSM_UnlockResource(SSMRESOURCE(conn));
  1103.                 }
  1104.             }
  1105.         }    /* end of for loop */
  1106.     }    /* end of while loop */
  1107. loser:
  1108.     SSM_DEBUG("** Closing, return value %ld. **n", rv);
  1109.     if (conn != NULL) {
  1110.        SSM_ShutdownResource(SSMRESOURCE(conn), rv);
  1111.         SSM_FreeResource(SSMRESOURCE(conn));
  1112.     }
  1113.     if (outbound != NULL) {
  1114.         PR_Free(outbound);
  1115.     }
  1116.     if (inbound != NULL) {
  1117.         PR_Free(inbound);
  1118.     }
  1119.     SSM_DEBUG("SSL data service thread terminated.n");
  1120. }
  1121. /* callback functions and auxilliary functions */
  1122. /*
  1123.  * Function: SECStatus SSM_SSLAuthCertificate()
  1124.  * Purpose: this callback function is used to authenticate certificates
  1125.  * received from the remote end of an SSL connection.
  1126.  *
  1127.  * Arguments and return values
  1128.  * - arg: certDB handle (cannot be NULL)
  1129.  * - socket: SSL socket
  1130.  * - checkSig: whether to check the signature (usually should be PR_TRUE)
  1131.  * - isServer: whether we are an SSL server (expect PR_FALSE since Cartman is
  1132.  *    an SSL client)
  1133.  * - returns: SECSuccess if successful; error code otherwise
  1134.  *
  1135.  * ### sjlee: this is essentially a wrapper over the default SSL callback
  1136.  *   function.  It provides minimal argument checking to the default
  1137.  *   callback.  When we're confident that the default will do the
  1138.  *   job, we might want to drop this...
  1139.  */
  1140. SECStatus SSM_SSLAuthCertificate(void* arg, PRFileDesc* socket, 
  1141.  PRBool checkSig, PRBool isServer)
  1142. {
  1143. SSM_DEBUG("checking server cert.n");
  1144. /* check arguments */
  1145. if (arg == NULL || socket == NULL || isServer) {
  1146.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1147.         return SECFailure;
  1148. }
  1149. /* call the default callback */
  1150. return (SECStatus) SSL_AuthCertificate(arg, socket, checkSig, isServer);
  1151. }
  1152. /*
  1153.  * Function: SECStatus SSM_SSLBadCertHandler()
  1154.  * Purpose: this callback function is used to handle a situation in which 
  1155.  * server certificate verification has failed.
  1156.  *
  1157.  * Arguments and return values
  1158.  * - arg: the SSL data connection
  1159.  * - socket: SSL socket
  1160.  * - returns: SECSuccess if the case is handled and it is authorized to
  1161.  *   continue connection; otherwise SECFailure
  1162.  */
  1163. SECStatus SSM_SSLBadCertHandler(void* arg, PRFileDesc* socket)
  1164. {
  1165. int error;
  1166.     SSMSSLDataConnection* conn;
  1167.     CERTCertificate* cert = NULL;
  1168.     SECStatus rv = SECFailure;
  1169.     if (socket == NULL || arg == NULL) {
  1170.         return SECFailure;
  1171.     }
  1172.     conn = (SSMSSLDataConnection*)arg;
  1173.     if (!(SSMCONTROLCONNECTION(conn)->m_doesUI)) {
  1174.         /* UI-less application.  We choose to reject the server cert. */
  1175.         goto loser;
  1176.     }
  1177.     cert = SSL_PeerCertificate(conn->socketSSL);
  1178.     if (cert == NULL) {
  1179.         goto loser;
  1180.     }
  1181.     while (rv != SECSuccess) {
  1182.         error = PR_GetError(); /* first of all, get error code */
  1183.         SSM_DEBUG("Got a bad server cert: error %d (%s).n", error, 
  1184.                   SSL_Strerror(error));
  1185. /* Save error for socket status */
  1186. conn->m_sslServerError = error;
  1187.         if (!SSM_SSLErrorNeedsDialog(error)) {
  1188.             SSM_DEBUG("Exiting abnormally...n");
  1189.             break;
  1190.         }
  1191.         if (SSM_SSLMakeBadServerCertDialog(error, cert, conn) != SECSuccess) {
  1192.             break;
  1193.         }
  1194.         /* check the server cert again for more errors */
  1195.         rv = SSM_DoubleCheckServerCert(cert, conn);
  1196.     }
  1197. loser:
  1198.     if (rv != SECSuccess) {
  1199.         (void)SSMSSLDataConnection_UpdateErrorCode(conn);
  1200.     }
  1201.     if (cert != NULL) {
  1202.         CERT_DestroyCertificate(cert);
  1203.     }
  1204.     return rv;
  1205. }
  1206. /*
  1207.  * structs and ASN1 templates for the limited scope-of-use extension
  1208.  *
  1209.  * CertificateScopeEntry ::= SEQUENCE {
  1210.  *     name GeneralName, -- pattern, as for NameConstraints
  1211.  *     portNumber INTEGER OPTIONAL }
  1212.  *
  1213.  * CertificateScopeOfUse ::= SEQUENCE OF CertificateScopeEntry
  1214.  */
  1215. /*
  1216.  * CERTCertificateScopeEntry: struct for scope entry that can be consumed by
  1217.  *                            the code
  1218.  * certCertificateScopeOfUse: struct that represents the decoded extension data
  1219.  */
  1220. typedef struct {
  1221.     SECItem derConstraint;
  1222.     SECItem derPort;
  1223.     CERTGeneralName* constraint; /* decoded constraint */
  1224.     PRIntn port; /* decoded port number */
  1225. } CERTCertificateScopeEntry;
  1226. typedef struct {
  1227.     CERTCertificateScopeEntry** entries;
  1228. } certCertificateScopeOfUse;
  1229. /* corresponding ASN1 templates */
  1230. static const SEC_ASN1Template cert_CertificateScopeEntryTemplate[] = {
  1231.     { SEC_ASN1_SEQUENCE, 
  1232.       0, NULL, sizeof(CERTCertificateScopeEntry) },
  1233.     { SEC_ASN1_ANY,
  1234.       offsetof(CERTCertificateScopeEntry, derConstraint) },
  1235.     { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER,
  1236.       offsetof(CERTCertificateScopeEntry, derPort) },
  1237.     { 0 }
  1238. };
  1239. static const SEC_ASN1Template cert_CertificateScopeOfUseTemplate[] = {
  1240.     { SEC_ASN1_SEQUENCE_OF, 0, cert_CertificateScopeEntryTemplate }
  1241. };
  1242. /* 
  1243.  * decodes the extension data and create CERTCertificateScopeEntry that can
  1244.  * be consumed by the code
  1245.  */
  1246. static
  1247. SECStatus cert_DecodeScopeOfUseEntries(PRArenaPool* arena, SECItem* extData,
  1248.                                        CERTCertificateScopeEntry*** entries,
  1249.                                        int* numEntries)
  1250. {
  1251.     certCertificateScopeOfUse* scope = NULL;
  1252.     SECStatus rv = SECSuccess;
  1253.     int i;
  1254.     *entries = NULL; /* in case of failure */
  1255.     *numEntries = 0; /* ditto */
  1256.     scope = (certCertificateScopeOfUse*)
  1257.         PORT_ArenaZAlloc(arena, sizeof(certCertificateScopeOfUse));
  1258.     if (scope == NULL) {
  1259.         goto loser;
  1260.     }
  1261.     rv = SEC_ASN1DecodeItem(arena, (void*)scope, 
  1262.                             cert_CertificateScopeOfUseTemplate, extData);
  1263.     if (rv != SECSuccess) {
  1264.         goto loser;
  1265.     }
  1266.     *entries = scope->entries;
  1267.     PR_ASSERT(*entries != NULL);
  1268.     /* first, let's count 'em. */
  1269.     for (i = 0; (*entries)[i] != NULL; i++) ;
  1270.     *numEntries = i;
  1271.     /* convert certCertificateScopeEntry sequence into what we can readily
  1272.      * use
  1273.      */
  1274.     for (i = 0; i < *numEntries; i++) {
  1275.         (*entries)[i]->constraint = 
  1276.             cert_DecodeGeneralName(arena, &((*entries)[i]->derConstraint), 
  1277.                                    NULL);
  1278.         if ((*entries)[i]->derPort.data != NULL) {
  1279.             (*entries)[i]->port = 
  1280.                 (int)DER_GetInteger(&((*entries)[i]->derPort));
  1281.         }
  1282.         else {
  1283.             (*entries)[i]->port = 0;
  1284.         }
  1285.     }
  1286.     goto done;
  1287. loser:
  1288.     if (rv == SECSuccess) {
  1289.         rv = SECFailure;
  1290.     }
  1291. done:
  1292.     return rv;
  1293. }
  1294. static SECStatus cert_DecodeCertIPAddress(SECItem* genname, 
  1295.                                           PRUint32* constraint, PRUint32* mask)
  1296. {
  1297.     /* in case of failure */
  1298.     *constraint = 0;
  1299.     *mask = 0;
  1300.     PR_ASSERT(genname->data != NULL);
  1301.     if (genname->data == NULL) {
  1302.         return SECFailure;
  1303.     }
  1304.     if (genname->len != 8) {
  1305.         /* the length must be 4 byte IP address with 4 byte subnet mask */
  1306.         return SECFailure;
  1307.     }
  1308.     /* get them in the right order */
  1309.     *constraint = PR_ntohl((PRUint32)(*genname->data));
  1310.     *mask = PR_ntohl((PRUint32)(*(genname->data + 4)));
  1311.     return SECSuccess;
  1312. }
  1313. static char* _str_to_lower(char* string)
  1314. {
  1315. #ifdef XP_WIN
  1316.     return _strlwr(string);
  1317. #else
  1318.     int i;
  1319.     for (i = 0; string[i] != ''; i++) {
  1320.         string[i] = tolower(string[i]);
  1321.     }
  1322.     return string;
  1323. #endif
  1324. }
  1325. /*
  1326.  * Sees if the client certificate has a restriction in presenting the cert
  1327.  * to the host: returns PR_TRUE if there is no restriction or if the hostname
  1328.  * (and the port) satisfies the restriction, or PR_FALSE if the hostname (and
  1329.  * the port) does not satisfy the restriction
  1330.  */
  1331. static PRBool CERT_MatchesScopeOfUse(CERTCertificate* cert, char* hostname,
  1332.                                      char* hostIP, PRIntn port)
  1333. {
  1334.     PRBool rv = PR_TRUE; /* whether the cert can be presented */
  1335.     SECStatus srv;
  1336.     SECItem extData;
  1337.     PRArenaPool* arena = NULL;
  1338.     CERTCertificateScopeEntry** entries = NULL;
  1339.     /* arrays of decoded scope entries */
  1340.     int numEntries = 0;
  1341.     int i;
  1342.     char* hostLower = NULL;
  1343.     PRUint32 hostIPAddr = 0;
  1344.     PR_ASSERT((cert != NULL) && (hostname != NULL) && (hostIP != NULL));
  1345.     /* find cert extension */
  1346.     srv = CERT_FindCertExtension(cert, SEC_OID_NS_CERT_EXT_SCOPE_OF_USE,
  1347.                                  &extData);
  1348.     if (srv != SECSuccess) {
  1349.         /* most of the time, this means the extension was not found: also,
  1350.          * since this is not a critical extension (as of now) we may simply
  1351.          * return PR_TRUE
  1352.          */
  1353.         goto done;
  1354.     }
  1355.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1356.     if (arena == NULL) {
  1357.         goto done;
  1358.     }
  1359.     /* decode the scope of use entries into pairs of GeneralNames and
  1360.      * an optional port numbers
  1361.      */
  1362.     srv = cert_DecodeScopeOfUseEntries(arena, &extData, &entries, &numEntries);
  1363.     if (srv != SECSuccess) {
  1364.         /* XXX What should we do when we failed to decode the extension?  This
  1365.          *     may mean either the extension was malformed or some (unlikely)
  1366.          *     fatal error on our part: my argument is that if the extension 
  1367.          *     was malformed the extension "disqualifies" as a valid 
  1368.          *     constraint and we may present the cert
  1369.          */
  1370.         goto done;
  1371.     }
  1372.     /* loop over these structures */
  1373.     for (i = 0; i < numEntries; i++) {
  1374.         /* determine whether the GeneralName is a DNS pattern, an IP address 
  1375.          * constraint, or else
  1376.          */
  1377.         CERTGeneralName* genname = entries[i]->constraint;
  1378.         /* if constraint is NULL, don't bother looking */
  1379.         if (genname == NULL) {
  1380.             /* this is not a failure: just continue */
  1381.             continue;
  1382.         }
  1383.         switch (genname->type) {
  1384.         case certDNSName: {
  1385.             /* we have a DNS name constraint; we should use only the host name
  1386.              * information
  1387.              */
  1388.             char* pattern = NULL;
  1389.             char* substring = NULL;
  1390.             /* null-terminate the string */
  1391.             genname->name.other.data[genname->name.other.len] = '';
  1392.             pattern = _str_to_lower(genname->name.other.data);
  1393.             if (hostLower == NULL) {
  1394.                 /* so that it's done only if necessary and only once */
  1395.                 hostLower = _str_to_lower(PL_strdup(hostname));
  1396.             }
  1397.             /* the hostname satisfies the constraint */
  1398.             if (((substring = strstr(hostLower, pattern)) != NULL) &&
  1399.                 /* the hostname contains the pattern */
  1400.                 (strlen(substring) == strlen(pattern)) &&
  1401.                 /* the hostname ends with the pattern */
  1402.                 ((substring == hostLower) || (*(substring-1) == '.'))) {
  1403.                 /* the hostname either is identical to the pattern or
  1404.                  * belongs to a subdomain
  1405.                  */
  1406.                 rv = PR_TRUE;
  1407.             }
  1408.             else {
  1409.                 rv = PR_FALSE;
  1410.             }
  1411.             /* clean up strings if necessary */
  1412.             break;
  1413.         }
  1414.         case certIPAddress: {
  1415.             PRUint32 constraint;
  1416.             PRUint32 mask;
  1417.             PRNetAddr addr;
  1418.             
  1419.             if (hostIPAddr == 0) {
  1420.                 /* so that it's done only if necessary and only once */
  1421.                 PR_StringToNetAddr(hostIP, &addr);
  1422.                 hostIPAddr = addr.inet.ip;
  1423.             }
  1424.             if (cert_DecodeCertIPAddress(&(genname->name.other), &constraint, 
  1425.                                          &mask) != SECSuccess) {
  1426.                 continue;
  1427.             }
  1428.             if ((hostIPAddr & mask) == (constraint & mask)) {
  1429.                 rv = PR_TRUE;
  1430.             }
  1431.             else {
  1432.                 rv = PR_FALSE;
  1433.             }
  1434.             break;
  1435.         }
  1436.         default:
  1437.             /* ill-formed entry: abort */
  1438.             continue; /* go to the next entry */
  1439.         }
  1440.         if (!rv) {
  1441.             /* we do not need to check the port: go to the next entry */
  1442.             continue;
  1443.         }
  1444.         /* finally, check the optional port number */
  1445.         if ((entries[i]->port != 0) && (port != entries[i]->port)) {
  1446.             /* port number does not match */
  1447.             rv = PR_FALSE;
  1448.             continue;
  1449.         }
  1450.         /* we have a match */
  1451.         PR_ASSERT(rv);
  1452.         break;
  1453.     }
  1454. done:
  1455.     /* clean up entries */
  1456.     if (arena != NULL) {
  1457.         PORT_FreeArena(arena, PR_FALSE);
  1458.     }
  1459.     if (hostLower != NULL) {
  1460.         PR_Free(hostLower);
  1461.     }
  1462.     return rv;
  1463. }
  1464. /*
  1465.  * Function: SECStatus SSM_SSLGetClientAuthData()
  1466.  * Purpose: this callback function is used to pull client certificate
  1467.  * information upon server request
  1468.  *
  1469.  * Arguments and return values
  1470.  * - arg: SSL data connection
  1471.  * - socket: SSL socket we're dealing with
  1472.  * - caNames: list of CA names
  1473.  * - pRetCert: returns a pointer to a pointer to a valid certificate if
  1474.  *    successful; otherwise NULL
  1475.  * - pRetKey: returns a pointer to a pointer to the corresponding key if
  1476.  *   successful; otherwise NULL
  1477.  * - returns: SECSuccess if successful; error code otherwise
  1478.  */
  1479. SECStatus SSM_SSLGetClientAuthData(void* arg, PRFileDesc* socket,
  1480.    CERTDistNames* caNames,
  1481.    CERTCertificate** pRetCert,
  1482.    SECKEYPrivateKey** pRetKey)
  1483. {
  1484. void* wincx = NULL;
  1485. SECStatus rv = SECFailure;
  1486. SSMSSLDataConnection* conn;
  1487. SSMControlConnection* ctrlconn;
  1488.     PRArenaPool* arena = NULL;
  1489.     char** caNameStrings = NULL;
  1490.     CERTCertificate* cert = NULL;
  1491.     SECKEYPrivateKey* privKey = NULL;
  1492.     CERTCertList* certList = NULL;
  1493.     CERTCertListNode* node;
  1494.     CERTCertNicknames* nicknames = NULL;
  1495.     char* extracted = NULL;
  1496.     PRIntn keyError = 0; /* used for private key retrieval error */
  1497. SSM_DEBUG("Client authentication callback function called.n");
  1498. /* do some argument checking */
  1499. if (socket == NULL || caNames == NULL || pRetCert == NULL ||
  1500. pRetKey == NULL) {
  1501.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1502.         return SECFailure;
  1503. }
  1504. /* get PKCS11 pin argument */
  1505. wincx = SSL_RevealPinArg(socket);
  1506. if (wincx == NULL) {
  1507. return SECFailure;
  1508. }
  1509. /* get the right connections */
  1510. conn = (SSMSSLDataConnection*)wincx;
  1511. ctrlconn = (SSMControlConnection*)(SSMCONNECTION(conn)->m_parent);
  1512. PR_ASSERT(ctrlconn);
  1513.     /* create caNameStrings */
  1514.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1515.     if (arena == NULL) {
  1516.         goto loser;
  1517.     }
  1518.     caNameStrings = (char**)PORT_ArenaAlloc(arena, 
  1519.                                             sizeof(char*)*(caNames->nnames));
  1520.     if (caNameStrings == NULL) {
  1521.         goto loser;
  1522.     }
  1523.     rv = SSM_ConvertCANamesToStrings(arena, caNameStrings, caNames);
  1524.     if (rv != SECSuccess) {
  1525.         goto loser;
  1526.     }
  1527.     /* get the preference */
  1528. if (SSM_SetUserCertChoice(conn) != SSM_SUCCESS) {
  1529. goto loser;
  1530. }
  1531. /* find valid user cert and key pair */
  1532. if (certChoice == AUTO) {
  1533. /* automatically find the right cert */
  1534.         /* find all user certs that are valid and for SSL */
  1535.         certList = CERT_FindUserCertsByUsage(ctrlconn->m_certdb, 
  1536.                                              certUsageSSLClient, PR_TRUE,
  1537.                                              PR_TRUE, wincx);
  1538.         if (certList == NULL) {
  1539.             goto noCert;
  1540.         }
  1541.         /* filter the list to those issued by CAs supported by the server */
  1542.         rv = CERT_FilterCertListByCANames(certList, caNames->nnames,
  1543.                                           caNameStrings, certUsageSSLClient);
  1544.         if (rv != SECSuccess) {
  1545.             goto noCert;
  1546.         }
  1547.         /* make sure the list is not empty */
  1548.         node = CERT_LIST_HEAD(certList);
  1549.         if (CERT_LIST_END(node, certList)) {
  1550.             goto noCert;
  1551.         }
  1552.         /* loop through the list until we find a cert with a key */
  1553.         while (!CERT_LIST_END(node, certList)) {
  1554.             /* if the certificate has restriction and we do not satisfy it
  1555.              * we do not use it
  1556.              */
  1557.             if (!CERT_MatchesScopeOfUse(node->cert, conn->hostName,
  1558.                                         conn->hostIP, conn->port)) {
  1559.                 node = CERT_LIST_NEXT(node);
  1560.                 continue;
  1561.             }
  1562.             privKey = PK11_FindKeyByAnyCert(node->cert, wincx);
  1563.             if (privKey != NULL) {
  1564.                 /* this is a good cert to present */
  1565.                 cert = CERT_DupCertificate(node->cert);
  1566.                 break;
  1567.             }
  1568.             keyError = PR_GetError();
  1569.             if (keyError == SEC_ERROR_BAD_PASSWORD) {
  1570.                 /* problem with password: bail */
  1571.                 goto loser;
  1572.             }
  1573.             node = CERT_LIST_NEXT(node);
  1574.         }
  1575.         if (cert == NULL) {
  1576.             goto noCert;
  1577.         }
  1578. }
  1579. else {
  1580.         /* user selects a cert to present */
  1581.         int i;
  1582.         /* find all user certs that are valid and for SSL */
  1583.         /* note that we are allowing expired certs in this list */
  1584.         certList = CERT_FindUserCertsByUsage(ctrlconn->m_certdb, 
  1585.                                              certUsageSSLClient, PR_TRUE, 
  1586.                                              PR_FALSE, wincx);
  1587.         if (certList == NULL) {
  1588.             goto noCert;
  1589.         }
  1590.         if (caNames->nnames != 0) {
  1591.             /* filter the list to those issued by CAs supported by the 
  1592.              * server 
  1593.              */
  1594.             rv = CERT_FilterCertListByCANames(certList, caNames->nnames, 
  1595.                                               caNameStrings, 
  1596.                                               certUsageSSLClient);
  1597.             if (rv != SECSuccess) {
  1598.                 goto loser;
  1599.             }
  1600.         }
  1601.         if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
  1602.             /* list is empty - no matching certs */
  1603.             goto noCert;
  1604.         }
  1605.         /* filter it further for hostname restriction */
  1606.         node = CERT_LIST_HEAD(certList);
  1607.         while (!CERT_LIST_END(node, certList)) {
  1608.             if (!CERT_MatchesScopeOfUse(node->cert, conn->hostName,
  1609.                                         conn->hostIP, conn->port)) {
  1610.                 CERTCertListNode* removed = node;
  1611.                 node = CERT_LIST_NEXT(removed);
  1612.                 CERT_RemoveCertListNode(removed);
  1613.             }
  1614.             else {
  1615.                 node = CERT_LIST_NEXT(node);
  1616.             }
  1617.         }
  1618.         if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
  1619.             goto noCert;
  1620.         }
  1621.         nicknames = CERT_NicknameStringsFromCertList(certList,
  1622.                                                      NICKNAME_EXPIRED_STRING,
  1623.                                                      NICKNAME_NOT_YET_VALID_STRING);
  1624.         if (nicknames == NULL) {
  1625.             goto loser;
  1626.         }
  1627.         SSM_DEBUG("%d valid user certs found.n", nicknames->numnicknames);
  1628.         conn->m_UIInfo.numFilteredCerts = nicknames->numnicknames;
  1629.         if (ssm_client_auth_prepare_nicknames(conn, nicknames) != 
  1630.             SSM_SUCCESS) {
  1631.             goto loser;
  1632.         }
  1633.         /* create a cert selection dialog and get back the chosen nickname */
  1634.         if (SSM_SSLMakeClientAuthDialog(conn) != SSM_SUCCESS) {
  1635.             goto loser;
  1636.         }
  1637.         PR_ASSERT(conn->m_UIInfo.chosen >= 0);
  1638.         i = conn->m_UIInfo.chosen;
  1639.         SSM_DEBUG("Cert %s was selected.n", conn->m_UIInfo.certNicknames[i]);
  1640.         /* first we need to extract the real nickname in case the cert
  1641.          * is an expired or not a valid one yet
  1642.          */
  1643.         extracted = CERT_ExtractNicknameString(conn->m_UIInfo.certNicknames[i],
  1644.                                                NICKNAME_EXPIRED_STRING,
  1645.                                                NICKNAME_NOT_YET_VALID_STRING);
  1646.         if (extracted == NULL) {
  1647.             goto loser;
  1648.         }
  1649.         /* find the cert under that nickname */
  1650.         node = CERT_LIST_HEAD(certList);
  1651.         while (!CERT_LIST_END(node, certList)) {
  1652.             if (PL_strcmp(node->cert->nickname, extracted) == 0) {
  1653.                 cert = CERT_DupCertificate(node->cert);
  1654.                 break;
  1655.             }
  1656.             node = CERT_LIST_NEXT(node);
  1657.         }
  1658.         if (cert == NULL) {
  1659.             goto loser;
  1660.         }
  1661.         /* go get the private key */
  1662.         privKey = PK11_FindKeyByAnyCert(cert, wincx);
  1663.         if (privKey == NULL) {
  1664.             keyError = PR_GetError();
  1665.             if (keyError == SEC_ERROR_BAD_PASSWORD) {
  1666.                 /* problem with password: bail */
  1667.                 goto loser;
  1668.             }
  1669.             else {
  1670.                 goto noCert;
  1671.             }
  1672.         }
  1673. }
  1674. /* rv == SECSuccess */
  1675. SSM_DEBUG("Yahoo!  Client auth complete.n");
  1676. goto done;
  1677. noCert:
  1678. loser:
  1679.     if (rv == SECSuccess) {
  1680.         rv = SECFailure;
  1681.     }
  1682.     if (cert != NULL) {
  1683.         CERT_DestroyCertificate(cert);
  1684.         cert = NULL;
  1685.     }
  1686. done:
  1687.     if (extracted != NULL) {
  1688.         PR_Free(extracted);
  1689.     }
  1690.     if (nicknames != NULL) {
  1691.         CERT_FreeNicknames(nicknames);
  1692.     }
  1693.     if (certList != NULL) {
  1694.         CERT_DestroyCertList(certList);
  1695.     }
  1696.     if (arena != NULL) {
  1697.         PORT_FreeArena(arena, PR_FALSE);
  1698.     }
  1699.     *pRetCert = cert;
  1700.     *pRetKey = privKey;
  1701. return rv;
  1702. }
  1703. /*
  1704.  * Function: SSMStatus SSM_SetUserCertChoice()
  1705.  * Purpose: sets certChoice by reading the preference
  1706.  *
  1707.  * Arguments and return values
  1708.  * - conn: SSMSSLDataConnection
  1709.  * - returns: SSM_SUCCESS if successful; SSM_FAILURE otherwise
  1710.  *
  1711.  * Note: If done properly, this function will read the identifier strings
  1712.  *  for ASK and AUTO modes, read the selected strings from the
  1713.  *  preference, compare the strings, and determine in which mode it is
  1714.  *  in.
  1715.  *       We currently use ASK mode for UI apps and AUTO mode for UI-less
  1716.  *       apps without really asking for preferences.
  1717.  */
  1718. SSMStatus SSM_SetUserCertChoice(SSMSSLDataConnection* conn)
  1719. {
  1720.     SSMStatus rv;
  1721.     SSMControlConnection* parent;
  1722.     parent = SSMCONTROLCONNECTION(conn);
  1723.     if (parent->m_doesUI) {
  1724.         char* mode = NULL;
  1725.         rv = PREF_GetStringPref(parent->m_prefs, 
  1726.                                 "security.default_personal_cert", &mode);
  1727.         if (rv != PR_SUCCESS) {
  1728.             return SSM_FAILURE;
  1729.         }
  1730.         if (PL_strcmp(mode, "Select Automatically") == 0) {
  1731.             certChoice = AUTO;
  1732.         }
  1733.         else if (PL_strcmp(mode, "Ask Every Time") == 0) {
  1734.             certChoice = ASK;
  1735.         }
  1736.         else {
  1737.             return SSM_FAILURE;
  1738.         }
  1739.     }
  1740.     else {
  1741.         SSM_DEBUG("UI-less app: use auto cert selection.n");
  1742.         certChoice = AUTO;
  1743.     }
  1744. return SSM_SUCCESS;
  1745. }
  1746. /*
  1747.  * Function: SECStatus SSM_ConvertCANamesToStrings()
  1748.  * Purpose: creates CA names strings from (CERTDistNames* caNames)
  1749.  *
  1750.  * Arguments and return values
  1751.  * - arena: arena to allocate strings on
  1752.  * - caNameStrings: filled with CA names strings on return
  1753.  * - caNames: CERTDistNames to extract strings from
  1754.  * - return: SECSuccess if successful; error code otherwise
  1755.  *
  1756.  * Note: copied in its entirety from Nova code
  1757.  */
  1758. SECStatus SSM_ConvertCANamesToStrings(PRArenaPool* arena, char** caNameStrings,
  1759.                                       CERTDistNames* caNames)
  1760. {
  1761.     SECItem* dername;
  1762.     SECStatus rv;
  1763.     int headerlen;
  1764.     uint32 contentlen;
  1765.     SECItem newitem;
  1766.     int n;
  1767.     char* namestring;
  1768.     for (n = 0; n < caNames->nnames; n++) {
  1769.         newitem.data = NULL;
  1770.         dername = &caNames->names[n];
  1771.         rv = DER_Lengths(dername, &headerlen, &contentlen);
  1772.         if (rv != SECSuccess) {
  1773.             goto loser;
  1774.         }
  1775.         if (headerlen + contentlen != dername->len) {
  1776.             /* This must be from an enterprise 2.x server, which sent
  1777.              * incorrectly formatted der without the outer wrapper of
  1778.              * type and length.  Fix it up by adding the top level
  1779.              * header.
  1780.              */
  1781.             if (dername->len <= 127) {
  1782.                 newitem.data = (unsigned char *) PR_Malloc(dername->len + 2);
  1783.                 if (newitem.data == NULL) {
  1784.                     goto loser;
  1785.                 }
  1786.                 newitem.data[0] = (unsigned char)0x30;
  1787.                 newitem.data[1] = (unsigned char)dername->len;
  1788.                 (void)memcpy(&newitem.data[2], dername->data, dername->len);
  1789.             }
  1790.             else if (dername->len <= 255) {
  1791.                 newitem.data = (unsigned char *) PR_Malloc(dername->len + 3);
  1792.                 if (newitem.data == NULL) {
  1793.                     goto loser;
  1794.                 }
  1795.                 newitem.data[0] = (unsigned char)0x30;
  1796.                 newitem.data[1] = (unsigned char)0x81;
  1797.                 newitem.data[2] = (unsigned char)dername->len;
  1798.                 (void)memcpy(&newitem.data[3], dername->data, dername->len);
  1799.             }
  1800.             else {
  1801.                 /* greater than 256, better be less than 64k */
  1802.                 newitem.data = (unsigned char *) PR_Malloc(dername->len + 4);
  1803.                 if (newitem.data == NULL) {
  1804.                     goto loser;
  1805.                 }
  1806.                 newitem.data[0] = (unsigned char)0x30;
  1807.                 newitem.data[1] = (unsigned char)0x82;
  1808.                 newitem.data[2] = (unsigned char)((dername->len >> 8) & 0xff);
  1809.                 newitem.data[3] = (unsigned char)(dername->len & 0xff);
  1810.                 memcpy(&newitem.data[4], dername->data, dername->len);
  1811.             }
  1812.             dername = &newitem;
  1813.         }
  1814.         namestring = CERT_DerNameToAscii(dername);
  1815.         if (namestring == NULL) {
  1816.             /* XXX - keep going until we fail to convert the name */
  1817.             caNameStrings[n] = "";
  1818.         }
  1819.         else {
  1820.             caNameStrings[n] = PORT_ArenaStrdup(arena, namestring);
  1821.             PR_Free(namestring);
  1822.             if (caNameStrings[n] == NULL) {
  1823.                 goto loser;
  1824.             }
  1825.         }
  1826.         if (newitem.data != NULL) {
  1827.             PR_Free(newitem.data);
  1828.         }
  1829.     }
  1830.     return SECSuccess;
  1831. loser:
  1832.     if (newitem.data != NULL) {
  1833.         PR_Free(newitem.data);
  1834.     }
  1835.     return SECFailure;
  1836. }
  1837. /*
  1838.  * Function: SSMStatus ssm_client_auth_prepare_nicknames()
  1839.  * Purpose: (private) picks out the filtered nicknames and populates the
  1840.  *          nicknames field of the SSL connection object with them
  1841.  * Arguments and return values:
  1842.  * - conn: SSL connection object to be manipulated
  1843.  * - nicknames: nickname list
  1844.  *
  1845.  * Note: the valid nickname list is not empty if this function was called
  1846.  *       Also the memory for the nickname list is allocated here; the caller
  1847.  *       is responsible for freeing the nickname list before the client
  1848.  *       auth callback function returns
  1849.  */
  1850. SSMStatus ssm_client_auth_prepare_nicknames(SSMSSLDataConnection* conn,
  1851.                                             CERTCertNicknames* nicknames)
  1852. {
  1853.     int i;
  1854.     int number;
  1855.     PR_ASSERT(conn != NULL && conn->m_UIInfo.numFilteredCerts > 0 && 
  1856.       nicknames != NULL);
  1857.     number = conn->m_UIInfo.numFilteredCerts;
  1858.     /* allocate memory for nickname list */
  1859.     conn->m_UIInfo.certNicknames = (char**)PR_Calloc(number, sizeof(char*));
  1860.     if (conn->m_UIInfo.certNicknames == NULL) {
  1861.         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  1862.         goto loser;
  1863.     }
  1864.     /* fill in cert nicknames */
  1865.     for (i = 0; i < number; i++) {
  1866.         conn->m_UIInfo.certNicknames[i] = PL_strdup(nicknames->nicknames[i]);
  1867.         if (conn->m_UIInfo.certNicknames[i] == NULL) {
  1868.             goto loser;
  1869.         }
  1870.     }
  1871.     
  1872.     return SSM_SUCCESS;
  1873. loser:
  1874.     return SSM_FAILURE;
  1875. }
  1876. void SSM_SSLHandshakeCallback(PRFileDesc* socket, void* clientData)
  1877. {
  1878. SSMSSLDataConnection* conn;
  1879. PR_ASSERT(socket != NULL);
  1880. PR_ASSERT(clientData != NULL);
  1881. SSM_DEBUG("Handshake callback called.n");
  1882. conn = (SSMSSLDataConnection*)clientData;
  1883. /* update the security status info */
  1884.     (void)SSMSSLDataConnection_UpdateSecurityStatus(conn);
  1885.     /* we want to proceed even if the update has failed... */
  1886. /* check everything is hunky-dorey */    
  1887. SSMSSLSocketStatus_Invariant(conn->m_sockStat);
  1888. }
  1889. /*
  1890.  * Function: PRBool SSM_SSLErrorNeedsDialog()
  1891.  * Purpose: sorts out errors that require dialogs
  1892.  *
  1893.  * Arguments and return values
  1894.  * - error: error code
  1895.  * - returns: PR_TRUE if dialog needed; PR_FALSE otherwise
  1896.  */
  1897. PRBool SSM_SSLErrorNeedsDialog(int error)
  1898. {
  1899. return ((error == SEC_ERROR_UNKNOWN_ISSUER) ||
  1900.             (error == SEC_ERROR_UNTRUSTED_ISSUER) ||
  1901.             (error == SSL_ERROR_BAD_CERT_DOMAIN) ||
  1902.             (error == SSL_ERROR_POST_WARNING) ||
  1903.             (error == SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE) ||
  1904.             (error == SEC_ERROR_CA_CERT_INVALID) ||
  1905.             (error == SEC_ERROR_EXPIRED_CERTIFICATE));
  1906. }
  1907. SECStatus SSM_SSLMakeBadServerCertDialog(int error, 
  1908.                                          CERTCertificate* cert,
  1909.                                          SSMSSLDataConnection* conn)
  1910. {
  1911.     SECStatus rv;
  1912.     if ((error == SEC_ERROR_UNKNOWN_ISSUER) ||
  1913.         (error == SEC_ERROR_CA_CERT_INVALID) ||
  1914.         (error == SEC_ERROR_UNTRUSTED_ISSUER)) {
  1915.         rv = SSM_SSLMakeUnknownIssuerDialog(cert, conn);
  1916.     } 
  1917.     else if (error == SSL_ERROR_BAD_CERT_DOMAIN) {
  1918.         rv = SSM_SSLMakeCertBadDomainDialog(cert, conn);
  1919.     }
  1920.     else if (error == SSL_ERROR_POST_WARNING) {
  1921.         /*rv = SEC_MakeCertPostWarnDialog(proto_win, cert);*/
  1922.         rv = SECSuccess;
  1923.     }
  1924.     else if (error == SEC_ERROR_EXPIRED_CERTIFICATE) {
  1925.         rv = SSM_SSLMakeCertExpiredDialog(cert, conn);
  1926.     } 
  1927.     else if (error == SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE) {
  1928.         /*rv = SEC_MakeCAExpiredDialog(proto_win, cert);*/
  1929.         rv = SECSuccess;
  1930.     }
  1931.     else {
  1932.         rv = SECFailure;
  1933.     }
  1934.     return rv;
  1935. }
  1936. SECStatus SSM_DoubleCheckServerCert(CERTCertificate* cert,
  1937.                                     SSMSSLDataConnection* conn)
  1938. {
  1939.     PRBool checkSig = PR_FALSE;
  1940.     /* ### sjlee: it is bit discomforting to set checkSig to false, but
  1941.      *     the user already decided to be generous about the cert, so it
  1942.      *     could be OK???
  1943.      */
  1944.     SSM_DEBUG("One server cert problem was handled.  See if there's more.n");
  1945.     return SSM_SSLVerifyServerCert(SSMCONTROLCONNECTION(conn)->m_certdb, cert, 
  1946.                                    checkSig, conn);
  1947. }
  1948. /* This function does the same thing as SSL_AuthCertificate(),
  1949. ** but takes different arguments.  
  1950. */
  1951. SECStatus SSM_SSLVerifyServerCert(CERTCertDBHandle* handle,
  1952.                                   CERTCertificate* cert, PRBool checkSig, 
  1953.                                   SSMSSLDataConnection* conn)
  1954. {
  1955.     SECStatus rv;
  1956.     char* hostname = NULL;
  1957.     rv = CERT_VerifyCertNow(handle, cert, checkSig, certUsageSSLServer,
  1958.                             (void*)conn);
  1959.     if (rv != SECSuccess) {
  1960. return rv;
  1961.     }
  1962.     /* cert is OK. we will check the name field in the cert against the
  1963.      * desired hostname.
  1964.      */
  1965.     hostname = SSL_RevealURL(conn->socketSSL);
  1966.     if (hostname && hostname[0]) {
  1967.         rv = CERT_VerifyCertName(cert, hostname);
  1968.     }
  1969.     else {
  1970.         rv = SECFailure;
  1971.     }
  1972.     if (rv != SECSuccess) {
  1973. PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0);
  1974.     }
  1975.     if (hostname)
  1976.      PR_Free(hostname);
  1977.     return rv;
  1978. }
  1979. /* The following routines are callbacks and assorted functions that are used
  1980.  * with SSL/LDAP.
  1981.  */
  1982. /* SSL client-auth callback used for SSL/LDAP */
  1983. SECStatus SSM_LDAPSSLGetClientAuthData(void* arg, PRFileDesc* socket,
  1984.                                        CERTDistNames* caNames,
  1985.                                        CERTCertificate** pRetCert,
  1986.                                        SECKEYPrivateKey** pRetKey)
  1987. {
  1988.     SECStatus rv = SECFailure;
  1989.     void* wincx = NULL;
  1990.     PRArenaPool* arena = NULL;
  1991.     char** caNameStrings = NULL;
  1992.     CERTCertList* certList = NULL;
  1993.     CERTCertListNode* node;
  1994.     CERTCertificate* cert = NULL;
  1995.     SECKEYPrivateKey* privKey = NULL;
  1996.     CERTCertDBHandle* certdb;
  1997.     SSM_DEBUG("Doing client auth for LDAP/SSL.n");
  1998.     /* check arguments */
  1999.     if ((arg == NULL) || (socket == NULL) || (caNames == NULL) || 
  2000.         (pRetCert == NULL) || (pRetKey == NULL)) {
  2001.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  2002.         return SECFailure;
  2003.     }
  2004.     /* get PKCS11 pin argument */
  2005.     wincx = SSL_RevealPinArg(socket);
  2006.     if (wincx == NULL) {
  2007.         return SECFailure;
  2008.     }
  2009.     /* create caNameStrings */
  2010.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2011.     if (arena == NULL) {
  2012.         goto loser;
  2013.     }
  2014.     caNameStrings = (char**)PORT_ArenaAlloc(arena, 
  2015.                                             sizeof(char*)*(caNames->nnames));
  2016.     if (caNameStrings == NULL) {
  2017.         goto loser;
  2018.     }
  2019.     /* XXX to do: publish the following function in sslconn.h */
  2020.     rv = SSM_ConvertCANamesToStrings(arena, caNameStrings, caNames);
  2021.     if (rv != SECSuccess) {
  2022.         goto loser;
  2023.     }
  2024.     /* we will just do automatic cert selection for SSL/LDAP */
  2025.     /* get the cert DB */
  2026.     certdb = (CERTCertDBHandle*)arg;
  2027.     /* find all user certs that are valid and for SSL */
  2028.     certList = CERT_FindUserCertsByUsage(certdb, certUsageSSLClient, PR_TRUE,
  2029.                                          PR_TRUE, wincx);
  2030.     if (certList == NULL) {
  2031.         goto noCert;
  2032.     }
  2033.     /* filter the list to those issued by CAs supported by the server */
  2034.     rv = CERT_FilterCertListByCANames(certList, caNames->nnames, caNameStrings,
  2035.                                       certUsageSSLClient);
  2036.     if (rv != SECSuccess) {
  2037.         goto noCert;
  2038.     }
  2039.     /* make sure the list is not empty */
  2040.     node = CERT_LIST_HEAD(certList);
  2041.     if (CERT_LIST_END(node, certList)) {
  2042.         goto noCert;
  2043.     }
  2044.     /* loop through the list until we find a cert with a key */
  2045.     while (!CERT_LIST_END(node, certList)) {
  2046.         privKey = PK11_FindKeyByAnyCert(node->cert, wincx);
  2047.         if (privKey != NULL) {
  2048.             /* this is a good cert to present */
  2049.             cert = CERT_DupCertificate(node->cert);
  2050.             break;
  2051.         }
  2052.         node = CERT_LIST_NEXT(node);
  2053.     }
  2054.     if (cert == NULL) {
  2055.         goto noCert;
  2056.     }
  2057.     goto done;
  2058. noCert:
  2059.     PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0);
  2060.     rv = SECFailure;
  2061. loser:
  2062.     if (rv == SECSuccess) {
  2063.         rv = SECFailure;
  2064.     }
  2065.     if (cert != NULL) {
  2066.         CERT_DestroyCertificate(cert);
  2067.         cert = NULL;
  2068.     }
  2069. done:
  2070.     if (certList != NULL) {
  2071.         CERT_DestroyCertList(certList);
  2072.     }
  2073.     if (arena != NULL) {
  2074.         PORT_FreeArena(arena, PR_FALSE);
  2075.     }
  2076.     *pRetCert = cert;
  2077.     *pRetKey = privKey;
  2078.     return rv;
  2079. }
  2080. /* This function must get called when the socket was created but was not
  2081.  * SSL-ified or connected
  2082.  */
  2083. SECStatus SSM_LDAPSetupSSL(PRFileDesc* socket, PRFileDesc** sslSocket,
  2084.                            CERTCertDBHandle* certdb, const char* hostname, 
  2085.                            SSMResource* caller)
  2086. {
  2087.     SECStatus rv = SECFailure;
  2088.     /* check arguments */
  2089.     if ((socket == NULL) || (sslSocket == NULL) || (certdb == NULL) ||
  2090.         (hostname == NULL) || (caller == NULL)) {
  2091.         goto loser;
  2092.     }
  2093.     *sslSocket = NULL;
  2094.     /* import the socket into SSL layer */
  2095.     *sslSocket = SSL_ImportFD(NULL, socket);
  2096.     if (*sslSocket == NULL) {
  2097.         goto loser;
  2098.     }
  2099.     /* set some SSL settings for the socket */
  2100.     rv = SSL_Enable(*sslSocket, SSL_SECURITY, PR_TRUE);
  2101.     if (rv != SECSuccess) {
  2102.         goto loser;
  2103.     }
  2104.     rv = SSL_Enable(*sslSocket, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
  2105.     if (rv != SECSuccess) {
  2106.         goto loser;
  2107.     }
  2108.     /* set callbacks */
  2109.     rv = SSL_GetClientAuthDataHook(*sslSocket, 
  2110.                                    (SSLGetClientAuthData)SSM_LDAPSSLGetClientAuthData,
  2111.                                    (void*)certdb) == 0 ? SECSuccess : SECFailure;
  2112.     if (rv != SECSuccess) {
  2113.         goto loser;
  2114.     }
  2115.     rv = SSL_AuthCertificateHook(*sslSocket, 
  2116.                                  (SSLAuthCertificate)SSM_SSLAuthCertificate,
  2117.                                  (void*)certdb) == 0 ? SECSuccess : SECFailure;
  2118.     if (rv != SECSuccess) {
  2119.         goto loser;
  2120.     }
  2121.     rv = SSL_SetPKCS11PinArg(*sslSocket, (void*)caller) == 0 ? SECSuccess : SECFailure;
  2122.     if (rv != SECSuccess) {
  2123.         goto loser;
  2124.     }
  2125.     rv = SSL_SetURL(*sslSocket, hostname) == 0 ? SECSuccess : SECFailure;
  2126.     if (rv != SECSuccess) {
  2127.         goto loser;
  2128.     }
  2129.     return rv;
  2130. loser:
  2131.     if (*sslSocket == NULL) {
  2132.         if (socket != NULL) {
  2133.             PR_Close(socket);
  2134.         }
  2135.     }
  2136.     else {
  2137.         PR_Close(*sslSocket);
  2138.         *sslSocket = NULL;
  2139.     }
  2140.     return rv;
  2141. }