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

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 "ssldlgs.h"
  36. #include "ctrlconn.h"
  37. #include "textgen.h"
  38. #include "resource.h"
  39. #include "certres.h"
  40. #include "minihttp.h"
  41. #include "cert.h"
  42. #include "certt.h"
  43. #include "certdb.h"
  44. #include "sechash.h"
  45. #include "nlsutil.h"
  46. #include "nlslayer.h"
  47. #define SSMRESOURCE(sslconn) (&(sslconn)->super.super.super)
  48. #define SSMCONTROLCONNECTION(sslconn) ((SSMControlConnection*)(sslconn->super.super.m_parent))
  49. /* private functions */
  50. SSMStatus ssm_client_auth_get_utf8_cert_list(SSMSSLDataConnection* conn, 
  51.                                              char* fmt, 
  52.                                              char** result);
  53. SSMStatus ssm_http_client_auth_handle_ok_button(HTTPRequest* req);
  54. SSMStatus ssm_http_client_auth_handle_cancel_button(HTTPRequest* req);
  55. SECStatus SSM_SSLServerCertResetTrust(CERTCertificate* cert, 
  56.       SSMBadServerCertAccept accept);
  57. static char* ssm_default_server_nickname(CERTCertificate* cert);
  58. SSMStatus ssm_http_server_auth_handle_ok_button(HTTPRequest* req);
  59. SSMStatus ssm_http_server_auth_handle_cancel_button(HTTPRequest* req);
  60. SSMStatus ssm_http_unknown_issuer_step1_handle_next_button(HTTPRequest* req);
  61. SSMStatus SSM_FormatCert(CERTCertificate* cert, char* fmt, 
  62.                          char** result)
  63. {
  64.     char* hostname = NULL;
  65.     char* orgname = NULL;
  66.     char* issuer = NULL;
  67.     char * notBefore = NULL, * notAfter = NULL;
  68.     SSMStatus rv = SSM_SUCCESS;
  69.     
  70.     /* check arguments */
  71.     if (cert == NULL || fmt == NULL || result == NULL) {
  72.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  73.         goto loser;
  74.     }
  75.     /* retrieve cert information */
  76.     hostname = CERT_GetCommonName(&cert->subject);
  77.     if (hostname == NULL) {
  78.         goto loser;
  79.     }
  80.     orgname = CERT_GetOrgName(&cert->subject);
  81.     if (orgname == NULL) {
  82.         goto loser;
  83.     }
  84.     issuer = CERT_GetOrgName(&cert->issuer);
  85.     if (issuer == NULL)
  86.     {
  87.         goto loser;
  88.     }
  89.     /* ### sjlee: should issuer be a localizable string? */
  90.     notBefore = DER_UTCDayToAscii(&cert->validity.notBefore);
  91.     if (!notBefore) 
  92.         notBefore = PL_strdup("No date found");
  93.     notAfter = DER_UTCDayToAscii(&cert->validity.notAfter);
  94.     if (!notAfter) 
  95.         notAfter = PL_strdup("No date found");
  96.     
  97.     *result = PR_smprintf(fmt, hostname, notBefore, notAfter, issuer, orgname);
  98.     SSM_DebugUTF8String("wrapped cert", *result);
  99.     goto done;
  100.  loser:
  101.     SSM_DEBUG("Formatting cert failed.n");
  102.     if (rv == SSM_SUCCESS) {
  103.         rv = SSM_FAILURE;
  104.     }
  105.  done:
  106.     if (hostname != NULL) {
  107.         PR_Free(hostname);
  108.     }
  109.     if (orgname != NULL) {
  110.         PR_Free(orgname);
  111.     }
  112.     if (issuer != NULL) {
  113.         PR_Free(issuer);
  114.     }
  115.     
  116.     PR_FREEIF(notBefore);
  117.     PR_FREEIF(notAfter);
  118.     return rv;
  119. }
  120. SSMStatus SSM_ServerCertKeywordHandler(SSMTextGenContext* cx)
  121. {
  122.     SSMResource* target = NULL;
  123.     SSMSSLDataConnection* sslconn = NULL;
  124.     SSMStatus rv;
  125.     char* pattern = NULL;
  126.     char* key = NULL;
  127.     char* formatKey = NULL;
  128.     char* simpleStr = NULL;
  129.     char* prettyStr = NULL;
  130.     CERTCertificate* serverCert = NULL;
  131.     const PRIntn CERT_FORMAT = (PRIntn)0;
  132.     const PRIntn CERT_WRAPPER = (PRIntn)1;
  133.     const PRIntn CERT_WRAPPER_NO_COMMENT = (PRIntn)2;
  134. PRIntn wrapper;
  135.     /* check arguments */
  136.     /* ### sjlee: might as well make this a helper function because most
  137.      *   keyword handlers will use this checking
  138.      */
  139.     PR_ASSERT(cx != NULL);
  140.     PR_ASSERT(cx->m_request != NULL);
  141.     PR_ASSERT(cx->m_params != NULL);
  142.     PR_ASSERT(cx->m_result != NULL);
  143.     if (cx == NULL || cx->m_request == NULL || cx->m_params == NULL ||
  144. cx->m_result == NULL) {
  145. PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  146. goto loser;
  147.     }
  148.     simpleStr = "simple";
  149.     prettyStr = "pretty";
  150.     /* retrieve the server cert */
  151.     target = SSMTextGen_GetTargetObject(cx);
  152.     PR_ASSERT(SSM_IsA(target, SSM_RESTYPE_SSL_DATA_CONNECTION));
  153.     sslconn = (SSMSSLDataConnection*)target;
  154.     serverCert = SSL_PeerCertificate(sslconn->socketSSL);
  155.     if (serverCert == NULL) {
  156. /* couldn't get the server cert: what do I do? */
  157. goto loser;
  158.     }
  159.     /* form the Format object */
  160.     /* first, find the keys */
  161.     formatKey = (char *) SSM_At(cx->m_params, CERT_FORMAT);
  162.     /* only show comments field if there are comments */
  163.     if (CERT_GetCertCommentString(serverCert))
  164.         wrapper = CERT_WRAPPER;
  165.     else 
  166.         wrapper = CERT_WRAPPER_NO_COMMENT;
  167.     key = (char *) SSM_At(cx->m_params, wrapper);
  168.     /* second, grab and expand the keyword objects */
  169.     rv = SSM_GetAndExpandTextKeyedByString(cx, key, &pattern);
  170.     if (rv != SSM_SUCCESS) {
  171. goto loser;
  172.     }
  173.     SSM_DebugUTF8String("server cert info pattern", pattern);
  174.     /* Now let's figure out if we're doing pretty print or simple print. */
  175.     PR_FREEIF(cx->m_result);
  176.     if (formatKey[0] ==  's') {
  177.         rv = SSM_FormatCert(serverCert, pattern, &cx->m_result);
  178.     } else if (formatKey[0] == 'p') {
  179.         rv = SSM_PrettyFormatCert(serverCert, pattern, 
  180.                                   &cx->m_result, PR_FALSE);
  181.     } else {
  182.         SSM_DEBUG("cannot understand the format key.n");
  183.         rv = SSM_FAILURE;
  184.     }
  185.     if (rv != SSM_SUCCESS) {
  186. goto loser;
  187.     }
  188.     goto done;
  189. loser:
  190.     if (rv == SSM_SUCCESS) {
  191. rv = SSM_FAILURE;
  192.     }
  193. done:
  194.     if (serverCert != NULL) {
  195. CERT_DestroyCertificate(serverCert);
  196.     }
  197.     PR_FREEIF(pattern);
  198.     return rv;
  199. }
  200. SSMStatus SSM_HTTPBadClientAuthButtonHandler(HTTPRequest* req)
  201. {
  202.     SSMStatus rv;
  203.     SSMSSLDataConnection* conn;
  204.     char* tmpStr = NULL;
  205.     PR_ASSERT(req->target != NULL);
  206.     conn = (SSMSSLDataConnection*)(req->target);
  207.     /* make sure you got the right baseRef */
  208.     rv = SSM_HTTPParamValue(req, "baseRef", &tmpStr);
  209.     if (rv != SSM_SUCCESS || 
  210. PL_strcmp(tmpStr, "windowclose_doclose_js") != 0) {
  211. goto loser;
  212.     }
  213.     return ssm_http_client_auth_handle_cancel_button(req);
  214. loser:
  215.     /* set the predicate to true and unblock the SSL thread */
  216.     SSM_LockResource(req->target);
  217.     conn->m_UIInfo.UICompleted = PR_TRUE;
  218.     conn->m_UIInfo.chosen = -1;
  219.     SSM_NotifyResource(req->target);
  220.     SSM_UnlockResource(req->target);
  221.     if (rv == SSM_SUCCESS) {
  222. rv = SSM_FAILURE;
  223.     }
  224.     return rv;
  225. }
  226. SSMStatus SSM_SSLMakeClientAuthDialog(SSMSSLDataConnection* conn)
  227. {
  228.     SSMStatus rv;
  229.     /* enter the SSL monitor */
  230.     SSM_LockResource(SSMRESOURCE(conn));
  231.     conn->m_UIInfo.UICompleted = PR_FALSE;
  232.     /* fire up the UI */
  233.     rv = SSMControlConnection_SendUIEvent(SSMCONTROLCONNECTION(conn), "get", 
  234.   "client_auth", SSMRESOURCE(conn), 
  235.   NULL, &SSMRESOURCE(conn)->m_clientContext, PR_TRUE);
  236.     if (rv != SSM_SUCCESS) {
  237. goto loser;
  238.     }
  239.     while (!conn->m_UIInfo.UICompleted) {
  240. SSM_WaitResource(SSMRESOURCE(conn), PR_INTERVAL_NO_TIMEOUT);
  241.     }
  242.     if (conn->m_UIInfo.chosen < 0) {
  243. /* "cancel" button clicked: bring up the no cert dialog? */
  244. if (rv == SSM_SUCCESS) {
  245.     rv = SSM_ERR_USER_CANCEL;
  246. }
  247.     }
  248.     /* the user selected a nickname; let's exit in orderly fashion */
  249. loser:
  250.     /* reset this bit to facilitate future UI events */
  251.     conn->m_UIInfo.UICompleted = PR_FALSE;
  252.     SSM_UnlockResource(SSMRESOURCE(conn));
  253.     return rv;
  254. }
  255. SSMStatus SSM_ClientAuthCertListKeywordHandler(SSMTextGenContext* cx)
  256. {
  257.     SSMStatus rv = SSM_SUCCESS;
  258.     SSMResource* target = NULL;
  259.     SSMSSLDataConnection* conn;
  260.     char* prefix = NULL;
  261.     char* wrapper = NULL;
  262.     char* suffix = NULL;
  263.     char* tmpStr = NULL;
  264.     char* prefixExp = NULL;
  265.     char* fmt = NULL;
  266.     char* certList = NULL;
  267.     const PRIntn CERT_LIST_PREFIX = (PRIntn)0;
  268.     const PRIntn CERT_LIST_WRAPPER = (PRIntn)1;
  269.     const PRIntn CERT_LIST_SUFFIX = (PRIntn)2;
  270.     const PRIntn CERT_LIST_PARAM_COUNT = (PRIntn)3;
  271.     /* 
  272.      * make sure cx, cx->m_request, cx->m_params, cx->m_result are not
  273.      * NULL
  274.      */
  275.     PR_ASSERT(cx != NULL && cx->m_request != NULL && cx->m_params != NULL &&
  276.       cx->m_result != NULL);
  277.     if (cx == NULL || cx->m_request == NULL || cx->m_params == NULL ||
  278. cx->m_result == NULL) {
  279. PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  280. goto loser;
  281.     }
  282.     if (SSM_Count(cx->m_params) != CERT_LIST_PARAM_COUNT) {
  283. SSM_HTTPReportSpecificError(cx->m_request, "_client_auth_certList: ",
  284.     "Incorrect number of parameters "
  285.     " (%d supplied, %d needed).n",
  286.     SSM_Count(cx->m_params), 
  287.     CERT_LIST_PARAM_COUNT);
  288. goto loser;
  289.     }
  290.     /* get the connection object */
  291.     target = SSMTextGen_GetTargetObject(cx);
  292.     PR_ASSERT(target != NULL);
  293.     conn = (SSMSSLDataConnection*)target;
  294.     /* form the MessageFormat object */
  295.     /* find arguments (prefix, wrapper, and suffix) */
  296.     prefix = (char *) SSM_At(cx->m_params, CERT_LIST_PREFIX);
  297.     wrapper = (char *) SSM_At(cx->m_params, CERT_LIST_WRAPPER);
  298.     suffix = (char *) SSM_At(cx->m_params, CERT_LIST_SUFFIX);
  299.     PR_ASSERT(prefix != NULL && wrapper != NULL && suffix != NULL);
  300.     /* grab the prefix and expand it */
  301.     rv = SSM_GetAndExpandTextKeyedByString(cx, prefix, &prefixExp);
  302.     if (rv != SSM_SUCCESS) {
  303. goto loser;
  304.     }
  305.     SSM_DebugUTF8String("client cert list prefix", prefixExp);
  306.     /* grab the wrapper */
  307.     rv = SSM_GetAndExpandTextKeyedByString(cx, wrapper, &fmt);
  308.     if (rv != SSM_SUCCESS) {
  309. goto loser;
  310.     }
  311.     SSM_DebugUTF8String("client cert list wrapper", fmt);
  312.     /* form the wrapped cert list UnicodeString */
  313.     rv = ssm_client_auth_get_utf8_cert_list(conn, fmt, &certList);
  314.     if (rv != SSM_SUCCESS) {
  315. goto loser;
  316.     }
  317.     /* grab the suffix and expand it */
  318.     rv = SSM_GetAndExpandTextKeyedByString(cx, suffix, &tmpStr);
  319.     if (rv != SSM_SUCCESS) {
  320. goto loser;
  321.     }
  322.     SSM_DebugUTF8String("client cert list suffix", tmpStr);
  323.     cx->m_result = PR_smprintf("%s%s%s", prefixExp, certList, tmpStr);
  324.     goto done;
  325. loser:
  326.     if (rv == SSM_SUCCESS) {
  327. rv = SSM_FAILURE;
  328.     }
  329. done:
  330.     PR_FREEIF(tmpStr);
  331.     PR_FREEIF(prefixExp);
  332.     PR_FREEIF(fmt);
  333.     PR_FREEIF(certList);
  334.     return rv;
  335. }
  336. /*
  337.  * Function: SSMStatus ssm_client_auth_get_utf8_cert_list()
  338.  * Purpose: forms the cert list UnicodeString
  339.  *
  340.  * Arguments and return values:
  341.  * - conn: SSL connection object
  342.  * - fmt: cert wrapper UnicodeString format
  343.  * - result: resulting UnicodeString
  344.  *
  345.  * Note: if we include the expired certs, we need to append to the end as
  346.  *       well
  347.  */
  348. SSMStatus ssm_client_auth_get_utf8_cert_list(SSMSSLDataConnection* conn, 
  349.                                              char* fmt, 
  350.                                              char** result)
  351. {
  352.     SSMStatus rv = SSM_SUCCESS;
  353.     char* tmpStr = NULL;
  354.     char* finalStr = NULL;
  355.     int i;
  356.     PR_ASSERT(conn != NULL && fmt != NULL && result != NULL);
  357.     /* in case we fail */
  358.     *result = NULL;
  359.     finalStr = PL_strdup("");
  360.     /* concatenate the string using the nicknames */
  361.     for (i = 0; i < conn->m_UIInfo.numFilteredCerts; i++) {
  362.         tmpStr = PR_smprintf(fmt, i, conn->m_UIInfo.certNicknames[i]);
  363.         if (SSM_ConcatenateUTF8String(&finalStr, tmpStr) != SSM_SUCCESS) {
  364.             goto loser;
  365.         }
  366.         PR_Free(tmpStr);
  367.         tmpStr = NULL;
  368.     }
  369.     
  370.     SSM_DebugUTF8String("client auth: final cert list", finalStr);
  371.     *result = finalStr;
  372.     return SSM_SUCCESS;
  373. loser:
  374.     SSM_DEBUG("client auth: wrapping cert list failed.n");
  375.     if (rv == SSM_SUCCESS) {
  376. rv = SSM_FAILURE;
  377.     }
  378.     PR_FREEIF(finalStr);
  379.     PR_FREEIF(tmpStr);
  380.     return rv;
  381. }
  382. SSMStatus SSM_ClientAuthCertSelectionButtonHandler(HTTPRequest* req)
  383. {
  384.     SSMStatus rv;
  385.     SSMResource* res;
  386.     SSMSSLDataConnection* conn;
  387.     res = (SSMResource*)(req->target);
  388.     conn = (SSMSSLDataConnection*)(req->target);
  389.     if (res->m_buttonType == SSM_BUTTON_OK) {
  390. /* "OK" button was clicked */
  391. rv = ssm_http_client_auth_handle_ok_button(req);
  392. goto done;
  393.     }
  394.     else if (res->m_buttonType == SSM_BUTTON_CANCEL) {
  395. /* "Cancel" button was clicked */
  396. rv = ssm_http_client_auth_handle_cancel_button(req);
  397. goto done;
  398.     }
  399.     else {
  400. SSM_DEBUG("Don't know which button was clicked.n");
  401. rv = SSM_FAILURE;
  402.     }
  403.     SSM_LockResource(res);
  404.     conn->m_UIInfo.chosen = -1;
  405.     conn->m_UIInfo.UICompleted = PR_TRUE;
  406.     SSM_NotifyResource(res);
  407.     SSM_UnlockResource(res);
  408. done:
  409.     /* this actually includes the error cases returned from individual
  410.      * button handlers
  411.      */
  412.     return rv;
  413. }
  414.     
  415.     
  416. SSMStatus SSM_HTTPClientAuthButtonHandler(HTTPRequest* req)
  417. {
  418.     SSMStatus rv;
  419.     SSMSSLDataConnection* conn;
  420.     char* tmpStr = NULL;
  421.     PR_ASSERT(req->target != NULL);
  422.     conn = (SSMSSLDataConnection*)(req->target);
  423.     /* make sure you got the right baseRef */
  424.     rv = SSM_HTTPParamValue(req, "baseRef", &tmpStr);
  425.     if (rv != SSM_SUCCESS || 
  426. PL_strcmp(tmpStr, "windowclose_doclose_js") != 0) {
  427. goto loser;
  428.     }
  429.     /* ### sjlee: this is a very ugly way to differentiate among different
  430.      *            buttons
  431.      */
  432.     rv = SSM_HTTPParamValue(req, "do_ok", &tmpStr);
  433.     if (rv == SSM_SUCCESS) {
  434. /* "OK" button was clicked */
  435. rv = ssm_http_client_auth_handle_ok_button(req);
  436. goto done;
  437.     }
  438.     rv = SSM_HTTPParamValue(req, "do_cancel", &tmpStr);
  439.     if (rv == SSM_SUCCESS) {
  440. /* "Cancel" button was clicked */
  441. rv = ssm_http_client_auth_handle_cancel_button(req);
  442. goto done;
  443.     }
  444.     rv = SSM_HTTPParamValue(req, "do_help", &tmpStr);
  445.     if (rv == SSM_SUCCESS) {
  446. /* "help" button was clicked */
  447. /* just use cancel handler for now */
  448. rv = ssm_http_client_auth_handle_cancel_button(req);
  449. goto done;
  450.     }
  451. loser:
  452.     if (rv == SSM_SUCCESS) {
  453. SSM_DEBUG("Don't know which button was clicked.n");
  454. rv = SSM_FAILURE;
  455.     }
  456.     SSM_LockResource(req->target);
  457.     conn->m_UIInfo.chosen = -1;
  458.     conn->m_UIInfo.UICompleted = PR_TRUE;
  459.     SSM_NotifyResource(req->target);
  460.     SSM_UnlockResource(req->target);
  461. done:
  462.     /* this actually includes the error cases returned from individual
  463.      * button handlers
  464.      */
  465.     return rv;
  466. }
  467. SSMStatus ssm_http_client_auth_handle_ok_button(HTTPRequest* req)
  468. {
  469.     SSMStatus rv;
  470.     SSMSSLDataConnection* conn;
  471.     char* chosen = NULL;
  472.     int i;
  473.     conn = (SSMSSLDataConnection*)(req->target);
  474.     SSM_LockResource(req->target);
  475.     /* retrieve the chosen nickname */
  476.     rv = SSM_HTTPParamValue(req, "chosen", &chosen);
  477.     if (rv != SSM_SUCCESS) {
  478. goto loser;
  479.     }
  480.     PR_ASSERT(chosen != NULL);
  481.     PR_sscanf(chosen, "%ld", &i);
  482.     PR_ASSERT(i >= 0 && i < conn->m_UIInfo.numFilteredCerts);
  483.     rv = SSM_HTTPCloseAndSleep(req);
  484.     if (rv != SSM_SUCCESS) {
  485.         goto loser;
  486.     }
  487.     /* set the predicate to true and unblock the SSL thread */
  488.     conn->m_UIInfo.chosen = i;
  489.     conn->m_UIInfo.UICompleted = PR_TRUE;
  490.     SSM_NotifyResource(req->target);
  491.     SSM_UnlockResource(req->target);
  492.     return rv;    /* SSM_SUCCESS */
  493. loser:
  494.     /* still we want to unblock the SSL thread: it will see NULL nickname */
  495.     conn->m_UIInfo.chosen = -1;
  496.     conn->m_UIInfo.UICompleted = PR_TRUE;
  497.     SSM_NotifyResource(req->target);
  498.     SSM_UnlockResource(req->target);
  499.     return rv;
  500. }
  501. SSMStatus ssm_http_client_auth_handle_cancel_button(HTTPRequest* req)
  502. {
  503.     SSMStatus rv;
  504.     SSMSSLDataConnection* conn;
  505.     conn = (SSMSSLDataConnection*)(req->target);
  506.     SSM_LockResource(req->target);
  507.     /* close the window */
  508.     rv = SSM_HTTPCloseAndSleep(req);
  509.     if (rv != SSM_SUCCESS) {
  510.         goto loser;
  511.     }
  512. loser:
  513.     /* set the predicate to true and unblock the SSL thread */
  514.     conn->m_UIInfo.chosen = -1;
  515.     conn->m_UIInfo.UICompleted = PR_TRUE;
  516.     SSM_NotifyResource(req->target);
  517.     SSM_UnlockResource(req->target);
  518.     return rv;
  519. }
  520. /*
  521.  * Function: SECStatus SSM_SSLMakeCertExpiredDialog()
  522.  * Purpose: dispatch the UI event to create the server cert expired
  523.  *          dialog
  524.  * Arguments and return values
  525.  * - cert: server cert we are dealing with
  526.  * - conn: SSL connection object
  527.  * - returns: SECSuccess if successful *and* the user decides to trust
  528.  *            the cert; appropriate error code otherwise
  529.  */
  530. SECStatus SSM_SSLMakeCertExpiredDialog(CERTCertificate* cert,
  531.                                        SSMSSLDataConnection* conn)
  532. {
  533.     SECStatus rv;
  534.     int64 now;
  535.     int64 notBefore;
  536.     int64 notAfter;
  537.     char* baseRef = NULL;
  538.     /* compare the time and determine which dialog box to bring up */
  539.     now = PR_Now();
  540.     rv = CERT_GetCertTimes(cert, &notBefore, &notAfter);
  541.     if (rv != SECSuccess) {
  542. return rv;
  543.     }
  544.     if (LL_CMP(now, >, notAfter)) {
  545. baseRef = PL_strdup("bad_server_cert_expired");
  546.     }
  547.     else {
  548. baseRef = PL_strdup("bad_server_cert_not_yet_valid");
  549.     }
  550.     if (baseRef == NULL) {
  551. return SECFailure;
  552.     }
  553.     SSM_LockResource(SSMRESOURCE(conn));
  554.     conn->m_UIInfo.UICompleted = PR_FALSE;
  555.     conn->m_UIInfo.trustBadServerCert = BSCA_NO;
  556.     /* fire up the UI */
  557.     if (SSMControlConnection_SendUIEvent(SSMCONTROLCONNECTION(conn), "get", 
  558. baseRef, SSMRESOURCE(conn), NULL,&SSMRESOURCE(conn)->m_clientContext, PR_TRUE) != SSM_SUCCESS) {
  559.         rv = SECFailure;
  560.         goto loser;
  561.     }
  562.     /* wait until the UI event is complete */
  563.     while (!conn->m_UIInfo.UICompleted) {
  564. SSM_WaitResource(SSMRESOURCE(conn), PR_INTERVAL_NO_TIMEOUT);
  565.     }
  566.     if (conn->m_UIInfo.trustBadServerCert == BSCA_NO) {
  567. /* user did not want to continue.  Cancel here. */
  568. if (rv == SECSuccess) {
  569.     rv = SECFailure;
  570. }
  571. goto loser;
  572.     }
  573.     /* ### sjlee: ugliness warning! accessing cert fields directly */
  574.     cert->timeOK = PR_TRUE;
  575. #if 0 /* Setting timeOK suffices.  Setting trust flags is unnecessary. */
  576.     rv = SSM_SSLServerCertResetTrust(cert, conn->m_UIInfo.trustBadServerCert);
  577.     if (rv != SECSuccess) {
  578. goto loser;
  579.     }
  580. #endif
  581. loser:
  582.     conn->m_UIInfo.trustBadServerCert = BSCA_NO;
  583.     conn->m_UIInfo.UICompleted = PR_FALSE;
  584.     SSM_UnlockResource(SSMRESOURCE(conn));
  585.     if (baseRef != NULL) {
  586. PR_Free(baseRef);
  587.     }
  588.     return rv;
  589. }
  590. SECStatus SSM_SSLServerCertResetTrust(CERTCertificate* cert, 
  591.       SSMBadServerCertAccept accept)
  592. {
  593.     char* nickname = NULL;
  594.     CERTCertTrust trust;
  595.     CERTCertTrust* trustPtr = NULL;
  596.     SECStatus rv;
  597.     
  598.     if (accept == BSCA_NO) {
  599. /* this usually shouldn't happen */
  600. goto loser;
  601.     }
  602.     else if (accept == BSCA_PERMANENT) {
  603. memset((void*)&trust, 0, sizeof(trust));
  604. /*trust.sslFlags = CERTDB_VALID_PEER | CERTDB_TRUSTED;*/
  605. /* this resets the SSL flags CERTDB_VALID_PEER | CERTDB_TRUSTED */
  606. rv = CERT_DecodeTrustString(&trust, "P");
  607. if (rv != SECSuccess) {
  608.     goto loser;
  609. }
  610. /* XXX not neccessary? */
  611. /*
  612. if (mystate->postwarn) {
  613.     trust.sslFlags |= CERTDB_SEND_WARN;
  614.     rv = CERT_DecodeTrustString(&trust, "w");
  615. }
  616. */
  617. nickname = ssm_default_server_nickname(cert);
  618. if (nickname == NULL) {
  619.     goto loser;
  620. }
  621. /* add a temporary certificate to the permanent database */
  622. rv = CERT_AddTempCertToPerm(cert, nickname, &trust);
  623. if (nickname != NULL) {
  624.     PR_Free(nickname);
  625. }
  626. if (rv != SECSuccess) {
  627.     goto loser;
  628. }
  629.     } else if (accept == BSCA_SESSION) {
  630. /* bump the ref count on the cert so that it stays around for
  631.  * the entire session
  632.  */
  633. /* ### sjlee: ugliness warning: accessing fields directly */
  634. cert->keepSession = PR_TRUE;
  635. if (cert->trust != NULL) {
  636.     trustPtr = cert->trust;
  637. }
  638. else {
  639.     trustPtr = (CERTCertTrust*)PORT_ArenaZAlloc(cert->arena,
  640. sizeof(CERTCertTrust));
  641.     cert->trust = trustPtr;
  642. }
  643. if (trustPtr == NULL) {
  644.     goto loser;
  645. }
  646. /* set the trust value */
  647. /*trustptr->sslFlags |= (CERTDB_VALID_PEER | CERTDB_TRUSTED);*/
  648. /* reset the trust SSL bit to CERTDB_VALID_PEER | CERTDB_TRUSTED */
  649. rv = CERT_DecodeTrustString(trustPtr, "P");
  650. if (rv != SECSuccess) {
  651.     goto loser;
  652. }
  653. /*
  654. if (mystate->postwarn) {
  655.     trustptr->sslFlags |= CERTDB_SEND_WARN;
  656.     rv = CERT_DecodeTrustString(trustptr, "w");
  657. }
  658. */
  659.     }
  660.     return rv;
  661. loser:
  662.     if (rv == SECSuccess) {
  663. rv = SECFailure;
  664.     }
  665.     return rv;
  666. }
  667. /* This is also called in oldfunc.c when creating default nickname for 
  668.  * a new certificate.
  669.  */
  670. void _ssm_compress_spaces(char* psrc)
  671. {
  672.     char* pdst;
  673.     char c;
  674.     PRBool lastspace = PR_FALSE;
  675.     
  676.     if (psrc == NULL) {
  677. return;
  678.     }
  679.     
  680.     pdst = psrc;
  681.     while (((c = *psrc) != 0) && isspace(c)) {
  682. psrc++;
  683. /* swallow leading spaces */
  684.     }
  685.     
  686.     
  687.     while ((c = *psrc++) != 0) {
  688. if (isspace(c)) {
  689.     if (!lastspace) {
  690. *pdst++ = ' ';
  691.     }
  692.     lastspace = PR_TRUE;
  693. } else {
  694.     *pdst++ = c;
  695.     lastspace = PR_FALSE;
  696. }
  697.     }
  698.     *pdst = '';
  699.     /* if the last character is a space, then remove it too */
  700.     pdst--;
  701.     c = *pdst;
  702.     if (isspace(c)) {
  703. *pdst = '';
  704.     }
  705.     
  706.     return;
  707. }
  708. /*
  709.  * Function: char* ssm_default_server_nickname()
  710.  * Purpose: creates a default nickname for a bad server cert in case the
  711.  *          user wanted to continue
  712.  * Arguments and return values
  713.  * - cert: cert in question
  714.  * - returns: the composed nickname; NULL if failure
  715.  *
  716.  * Note: shamelessly copied from the Nova code
  717.  */
  718. static char* ssm_default_server_nickname(CERTCertificate* cert)
  719. {
  720.     char* nickname = NULL;
  721.     int count;
  722.     PRBool conflict;
  723.     char* servername = NULL;
  724.     
  725.     servername = CERT_GetCommonName(&cert->subject);
  726.     if (servername == NULL) {
  727. goto loser;
  728.     }
  729.     
  730.     count = 1;
  731.     while (1) {
  732. if (count == 1) {
  733.     nickname = PR_smprintf("%s", servername);
  734. }
  735. else {
  736.     nickname = PR_smprintf("%s #%d", servername, count);
  737. }
  738. if (nickname == NULL) {
  739.     goto loser;
  740. }
  741. _ssm_compress_spaces(nickname);
  742. conflict = SEC_CertNicknameConflict(nickname, &cert->derSubject,
  743.     cert->dbhandle);
  744. if (conflict == PR_SUCCESS) {
  745.     goto done;
  746. }
  747. /* free the nickname */
  748. PORT_Free(nickname);
  749. count++;
  750.     }
  751.     
  752. loser:
  753.     if (nickname != NULL) {
  754. PR_Free(nickname);
  755. nickname = NULL;
  756.     }
  757. done:
  758.     if (servername != NULL) {
  759. PR_Free(servername);
  760.     }
  761.     
  762.     return nickname;
  763. }
  764. SSMStatus SSM_CurrentTimeKeywordHandler(SSMTextGenContext* cx)
  765. {
  766.     SSMStatus rv;
  767.     char* wrapper = NULL;
  768.     char* key = NULL;
  769.     void* dfmt = NULL;
  770.     char* utf8Now = NULL;
  771.     int64 now;
  772.     const PRIntn TIME_WRAPPER = (PRIntn)0;
  773.     /* we have one keyword */
  774.     /* check arguments */
  775.     /* ### sjlee: might as well make this a helper function because most
  776.      *   keyword handlers will use this checking
  777.      */
  778.     PR_ASSERT(cx != NULL);
  779.     /*    PR_ASSERT(cx->m_request != NULL);*/
  780.     PR_ASSERT(cx->m_params != NULL);
  781.     PR_ASSERT(cx->m_result != NULL);
  782.     if (cx == NULL || cx->m_params == NULL || cx->m_result == NULL) {
  783. PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  784. goto loser;
  785.     }
  786.     /* form the DateFormat object */
  787. dfmt = nlsNewDateFormat();
  788. if (!dfmt) {
  789. goto loser;
  790. }
  791.     /* form the MessageFormat object */
  792.     /* first, find the key (wrapper) */
  793.     key = (char *) SSM_At(cx->m_params, TIME_WRAPPER);
  794.     /* second, grab and expand the key word object */
  795.     rv = SSM_GetAndExpandTextKeyedByString(cx, key, &wrapper);
  796.     if (rv != SSM_SUCCESS) {
  797. goto loser;
  798.     }
  799.     SSM_DebugUTF8String("current time wrapper", wrapper);
  800.     now = PR_Now();
  801. utf8Now = nslPRTimeToUTF8String(dfmt, now);
  802.     if (!utf8Now) {
  803. goto loser;
  804.     }
  805.     
  806.     SSMTextGen_UTF8StringClear(&cx->m_result);
  807.     PR_FREEIF(cx->m_result);
  808.     cx->m_result = PR_smprintf(wrapper, utf8Now);
  809.     SSM_DebugUTF8String("result of wrapping", cx->m_result);
  810.     goto done;
  811. loser:
  812.     if (rv == SSM_SUCCESS) {
  813. rv = SSM_FAILURE;
  814.     }
  815. done:
  816.     PR_FREEIF(wrapper);
  817.     if (dfmt != NULL) {
  818. nlsFreeDateFormat(dfmt);
  819.     }
  820.     return rv;
  821. }
  822. /* this function handles the button clicks for all server auth failure dialogs
  823.  * except the unknown issuers case
  824.  */
  825. SSMStatus SSM_ServerAuthFailureButtonHandler(HTTPRequest* req)
  826. {
  827.     SSMStatus rv;
  828.     SSMResource* res;
  829.     SSMSSLDataConnection* conn;
  830.     res = (SSMResource*)(req->target);
  831.     conn = (SSMSSLDataConnection*)(req->target);
  832.     if (res->m_buttonType == SSM_BUTTON_OK) {
  833. /* "OK" button was clicked */
  834. rv = ssm_http_server_auth_handle_ok_button(req);
  835. goto done;
  836.     }
  837.     else if (res->m_buttonType == SSM_BUTTON_CANCEL) {
  838. /* "Cancel" button was clicked */
  839. rv = ssm_http_server_auth_handle_cancel_button(req);
  840. goto done;
  841.     }
  842.     else {
  843. SSM_DEBUG("Don't know which button was clicked.n");
  844. rv = SSM_FAILURE;
  845.     }
  846.     SSM_LockResource(res);
  847.     conn->m_UIInfo.UICompleted = PR_TRUE;
  848.     /* the default course of action if something goes wrong is not to trust */
  849.     conn->m_UIInfo.trustBadServerCert = BSCA_NO;
  850.     SSM_NotifyResource(res);
  851.     SSM_UnlockResource(res);
  852. done:
  853.     /* this actually includes the error cases returned from individual
  854.      * button handlers
  855.      */
  856.     return rv;
  857. }
  858. SSMStatus ssm_http_server_auth_handle_ok_button(HTTPRequest* req)
  859. {
  860.     SSMStatus rv;
  861.     SSMSSLDataConnection* conn;
  862.     char* accept = NULL;
  863.     conn = (SSMSSLDataConnection*)(req->target);
  864.     SSM_LockResource(req->target);
  865.     /* if the user wanted to go ahead, accept="session" */
  866.     rv = SSM_HTTPParamValue(req, "accept", &accept);
  867.     if (rv != SSM_SUCCESS) {
  868. /* either the user did not want to continue or something went wrong */
  869. conn->m_UIInfo.trustBadServerCert = BSCA_NO;
  870. goto loser;
  871.     }
  872.     PR_ASSERT(accept != NULL);
  873.     if (PL_strcmp(accept, "session") == 0) {
  874. conn->m_UIInfo.trustBadServerCert = BSCA_SESSION;
  875.     }
  876.     else if (PL_strcmp(accept, "permanent") == 0) {
  877. conn->m_UIInfo.trustBadServerCert = BSCA_PERMANENT;
  878.     }
  879.     else {
  880. /* either something went wrong or the user did not want to continue */
  881. conn->m_UIInfo.trustBadServerCert = BSCA_NO;
  882.     }
  883. loser:
  884.     /* close the window */
  885.     rv = SSM_HTTPCloseAndSleep(req);
  886.     /* set the predicate to true and unblock the SSL thread */
  887.     conn->m_UIInfo.UICompleted = PR_TRUE;
  888.     SSM_NotifyResource(req->target);
  889.     SSM_UnlockResource(req->target);
  890.     return rv;
  891. }
  892. SSMStatus ssm_http_server_auth_handle_cancel_button(HTTPRequest* req)
  893. {
  894.     SSMStatus rv;
  895.     SSMSSLDataConnection* conn;
  896.     
  897.     conn = (SSMSSLDataConnection*)(req->target);
  898.     SSM_LockResource(req->target);
  899.     /* close the window */
  900.     rv = SSM_HTTPCloseAndSleep(req);
  901.     /* leave the cert untrusted */
  902.     conn->m_UIInfo.trustBadServerCert = BSCA_NO;
  903.     conn->m_UIInfo.UICompleted = PR_TRUE;
  904.     SSM_NotifyResource(req->target);
  905.     SSM_UnlockResource(req->target);
  906.     return rv;
  907. }
  908. SSMStatus SSM_ServerAuthDomainNameKeywordHandler(SSMTextGenContext* cx)
  909. {
  910.     SSMResource* target = NULL;
  911.     SSMSSLDataConnection* sslconn = NULL;
  912.     SSMStatus rv;
  913.     char* pattern = NULL;
  914.     char* key = NULL;
  915.     CERTCertificate* serverCert = NULL;
  916.     char* hostname = NULL;
  917.     char* URLHostname = NULL;
  918.     const PRIntn DOMAIN_NAME_FORMAT = (PRIntn)0;
  919.     /* we have one keyword */
  920.     /* check arguments */
  921.     /* ### sjlee: might as well make this a helper function because most
  922.      *   keyword handlers will use this checking
  923.      */
  924.     PR_ASSERT(cx != NULL);
  925.     PR_ASSERT(cx->m_request != NULL);
  926.     PR_ASSERT(cx->m_params != NULL);
  927.     PR_ASSERT(cx->m_result != NULL);
  928.     if (cx == NULL || cx->m_request == NULL || cx->m_params == NULL ||
  929. cx->m_result == NULL) {
  930. PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  931. goto loser;
  932.     }
  933.     /* retrieve the server cert */
  934.     target = SSMTextGen_GetTargetObject(cx);
  935.     PR_ASSERT(SSM_IsA(target, SSM_RESTYPE_SSL_DATA_CONNECTION));
  936.     sslconn = (SSMSSLDataConnection*)target;
  937.     serverCert = SSL_PeerCertificate(sslconn->socketSSL);
  938.     if (serverCert == NULL) {
  939. /* couldn't get the server cert: what do I do? */
  940. goto loser;
  941.     }
  942.     /* get the hostname from the cert */
  943.     hostname = CERT_GetCommonName(&serverCert->subject);
  944.     if (hostname == NULL) {
  945. goto loser;
  946.     }
  947.     /* get the URL hostname from the socket */
  948.     URLHostname = SSL_RevealURL(sslconn->socketSSL);
  949.     if (URLHostname == NULL) {
  950. goto loser;
  951.     }
  952.     /* form the MessageFormat object */
  953.     /* first, find the key (format argument) */
  954.     key = (char *) SSM_At(cx->m_params, DOMAIN_NAME_FORMAT);
  955.     /* second, grab and expand the key word object */
  956.     rv = SSM_GetAndExpandTextKeyedByString(cx, key, &pattern);
  957.     if (rv != SSM_SUCCESS) {
  958. goto loser;
  959.     }
  960.     SSM_DebugUTF8String("domain name string pattern", pattern);
  961.     SSMTextGen_UTF8StringClear(&cx->m_result);
  962.     
  963.     PR_FREEIF(cx->m_result);
  964.     cx->m_result = PR_smprintf(pattern, URLHostname, hostname);
  965.     if (cx->m_result == NULL) {
  966.         goto loser;
  967.     }
  968.     SSM_DebugUTF8String("wrapped domain name string", cx->m_result);
  969.     goto done;
  970. loser:
  971.     if (rv == SSM_SUCCESS) {
  972. rv = SSM_FAILURE;
  973.     }
  974. done:
  975.     if (serverCert != NULL) {
  976. CERT_DestroyCertificate(serverCert);
  977.     }
  978.     if (hostname != NULL) {
  979. PR_Free(hostname);
  980.     }
  981.     if (URLHostname != NULL) {
  982. PR_Free(URLHostname);
  983.     }
  984.     PR_FREEIF(pattern);
  985.     return rv;
  986. }
  987. /*
  988.  * Function: SECStatus SSM_SSLMakeCertBadDomainDialog()
  989.  * Purpose: dispatch the UI event to create the server cert domain name
  990.  *          mismatch dialog
  991.  * Arguments and return values
  992.  * - cert: server cert we are dealing with
  993.  * - conn: SSL connection object
  994.  * - returns: SECSuccess if successful *and* the user decides to trust
  995.  *            the cert; appropriate error code otherwise
  996.  */
  997. SECStatus SSM_SSLMakeCertBadDomainDialog(CERTCertificate* cert,
  998.                                          SSMSSLDataConnection* conn)
  999. {
  1000. char *           sslHostname = NULL;
  1001.     SECStatus        rv          = SECSuccess;
  1002.     SSM_LockResource(SSMRESOURCE(conn));
  1003.     conn->m_UIInfo.UICompleted = PR_FALSE;
  1004.     conn->m_UIInfo.trustBadServerCert = BSCA_NO;
  1005.     /* fire up the UI */
  1006.     if (SSMControlConnection_SendUIEvent(SSMCONTROLCONNECTION(conn), "get", 
  1007.  "bad_server_cert_domain", 
  1008.  SSMRESOURCE(conn), NULL, 
  1009.                      &SSMRESOURCE(conn)->m_clientContext, 
  1010.                      PR_TRUE) != SSM_SUCCESS) {
  1011.         rv = SECFailure;
  1012.         goto loser;
  1013.     }
  1014.     /* wait until the UI event is complete */
  1015.     while (!conn->m_UIInfo.UICompleted) {
  1016. SSM_WaitResource(SSMRESOURCE(conn), PR_INTERVAL_NO_TIMEOUT);
  1017.     }
  1018.     if (conn->m_UIInfo.trustBadServerCert == BSCA_NO) {
  1019. /* user did not want to continue.  Cancel here. */
  1020. if (rv == SECSuccess) {
  1021.     rv = SECFailure;
  1022. }
  1023. goto loser;
  1024.     }
  1025. sslHostname = SSL_RevealURL(conn->socketSSL);
  1026. if (!sslHostname)
  1027. goto loser;
  1028. rv = CERT_AddOKDomainName(cert, sslHostname);
  1029. PORT_Free(sslHostname);
  1030. #if 0 /* this is not neccessary, and is wrong (in this case) */
  1031.     rv = SSM_SSLServerCertResetTrust(cert, conn->m_UIInfo.trustBadServerCert);
  1032. #endif
  1033.     if (rv != SECSuccess) {
  1034. goto loser;
  1035.     }
  1036. loser:
  1037.     conn->m_UIInfo.trustBadServerCert = BSCA_NO;
  1038.     conn->m_UIInfo.UICompleted = PR_FALSE;
  1039.     SSM_UnlockResource(SSMRESOURCE(conn));
  1040.     return rv;
  1041. }
  1042. SSMStatus SSM_PrettyFormatCert(CERTCertificate* cert, char* fmt, 
  1043.                                char** result,PRBool addIssuerLink)
  1044. {
  1045.     SSMStatus rv = SSM_SUCCESS;
  1046.     char * displayName = NULL, *location=NULL, *state = NULL, *country = NULL;
  1047.     char * emailaddr = NULL, * orgName = NULL, *unitName = NULL;
  1048.     char* issuer = NULL;
  1049.     char* serialNumber = NULL;
  1050.     char * notBefore = NULL;
  1051.     char * notAfter = NULL;
  1052.     char * tmp = NULL;
  1053.     unsigned char fingerprint[16];
  1054.     SECItem fpItem;
  1055.     char* fpStr = NULL;
  1056.     char* commentString = NULL;
  1057.     /* check arguments */
  1058.     if (cert == NULL || fmt == NULL || result == NULL) {
  1059. PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1060. goto loser;
  1061.     }
  1062.     
  1063.     /* retrieve cert information */
  1064.     
  1065.     displayName = CERT_GetCommonName(&cert->subject);
  1066.     emailaddr = CERT_GetCertEmailAddress(&cert->subject);
  1067.     orgName = CERT_GetOrgName(&cert->subject);
  1068.     unitName = CERT_GetOrgUnitName(&cert->subject);
  1069.     if (!displayName) 
  1070.         displayName = PL_strdup("");
  1071.     if (!emailaddr)
  1072.         emailaddr = PL_strdup("");
  1073.     if (!orgName) 
  1074.         orgName = PL_strdup("");
  1075.     if (!unitName)
  1076.         unitName = PL_strdup("");
  1077.     
  1078.     location = CERT_GetLocalityName(&cert->subject);
  1079.     if (!location) 
  1080.       location = PL_strdup("");
  1081.     state = CERT_GetStateName(&cert->subject);
  1082.     if (!state)
  1083.         state = PL_strdup("");
  1084.     country = CERT_GetCountryName(&cert->subject);
  1085.     if (!country)
  1086.         country = PL_strdup("");
  1087.     issuer = CERT_GetOrgName(&cert->issuer);
  1088.     if (issuer == NULL) {
  1089.         issuer = PL_strdup("");
  1090.     } else {
  1091.         /*
  1092.          * Don't add the extra link if this is a self-signed cert.
  1093.          */
  1094.         if (addIssuerLink &&
  1095.             CERT_CompareName(&cert->subject, &cert->issuer) != SECEqual) {
  1096.             tmp=PR_smprintf("<a href="javascript:openIssuerWindow();">%s</a>",
  1097.                               issuer);
  1098.             PR_Free(issuer);
  1099.             issuer = tmp;
  1100.             tmp = NULL;
  1101.         }
  1102.     }
  1103.     serialNumber = CERT_Hexify(&cert->serialNumber, 1);
  1104.     if (serialNumber == NULL) {
  1105. serialNumber = PL_strdup("");
  1106.     }
  1107.     notBefore = DER_UTCDayToAscii(&cert->validity.notBefore);
  1108.     if (!notBefore) 
  1109.         notBefore = PL_strdup("");
  1110.     notAfter = DER_UTCDayToAscii(&cert->validity.notAfter);
  1111.     if (!notAfter) 
  1112.         notAfter = PL_strdup("");
  1113.     MD5_HashBuf(fingerprint, cert->derCert.data, cert->derCert.len);
  1114.     fpItem.data = fingerprint;
  1115.     fpItem.len = sizeof(fingerprint);
  1116.     fpStr = CERT_Hexify(&fpItem, 1);
  1117.     if (fpStr == NULL) {
  1118. fpStr = PL_strdup("");
  1119.     }
  1120.     commentString = CERT_GetCertCommentString(cert);
  1121.     if (commentString == NULL) {
  1122. commentString = PL_strdup(" ");
  1123.     }
  1124.     /* comments can be NULL */
  1125.     *result = PR_smprintf(fmt, displayName, emailaddr, unitName, orgName, 
  1126.                           location, state, country, issuer, serialNumber, 
  1127.                           notBefore, notAfter, fpStr, commentString);
  1128.     if (*result == NULL) {
  1129.         goto loser;
  1130.     }
  1131.     SSM_DebugUTF8String("wrapped view cert string", *result);
  1132.     goto done;
  1133. loser:
  1134.     SSM_DEBUG("Pretty formatting cert failed.n");
  1135.     if (rv == SSM_SUCCESS) {
  1136. rv = SSM_FAILURE;
  1137.     }
  1138. done:
  1139.     if (issuer != NULL) {
  1140. PR_Free(issuer);
  1141.     }
  1142.     if (serialNumber != NULL) {
  1143. PR_Free(serialNumber);
  1144.     }
  1145.     if (fpStr != NULL) {
  1146. PR_Free(fpStr);
  1147.     }
  1148.     if (commentString != NULL) {
  1149. PR_Free(commentString);
  1150.     }
  1151.     PR_FREEIF(notBefore);
  1152.     PR_FREEIF(notAfter);
  1153.     PR_FREEIF(displayName);
  1154.     PR_FREEIF(emailaddr);
  1155.     PR_FREEIF(orgName);
  1156.     PR_FREEIF(unitName);
  1157.     return rv;
  1158. }
  1159. SSMStatus SSM_VerifyServerCertKeywordHandler(SSMTextGenContext* cx)
  1160. {
  1161.     SSMStatus rv;
  1162.     SSMResource* target = NULL;
  1163.     SSMSSLDataConnection* sslconn = NULL;
  1164.     CERTCertDBHandle* handle = NULL;
  1165.     CERTCertificate* serverCert = NULL;
  1166.     char* nickname = NULL;
  1167.     char* pattern = NULL;
  1168.     PR_ASSERT(cx != NULL);
  1169.     PR_ASSERT(cx->m_request != NULL);
  1170.     PR_ASSERT(cx->m_params != NULL);
  1171.     PR_ASSERT(cx->m_result != NULL);
  1172.     /* retrieve the server cert */
  1173.     target = SSMTextGen_GetTargetObject(cx);
  1174.     PR_ASSERT(SSM_IsA(target, SSM_RESTYPE_SSL_DATA_CONNECTION));
  1175.     sslconn = (SSMSSLDataConnection*)target;
  1176.     handle = SSMCONTROLCONNECTION(sslconn)->m_certdb;
  1177.     
  1178.     serverCert = SSL_PeerCertificate(sslconn->socketSSL);
  1179.     if (serverCert == NULL) {
  1180. goto loser;
  1181.     }
  1182.     nickname = CERT_GetNickName(serverCert, handle, serverCert->arena);
  1183.     if (nickname == NULL) {
  1184.         /* nickname was not found: that's still OK, let's do this */
  1185.         nickname = PL_strdup("Unknown");
  1186. if (nickname == NULL) {
  1187.     goto loser;
  1188. }
  1189.     }
  1190.     /* don't free it! */
  1191.     /* if we want to verify the cert, we would do something like this...
  1192.     srv = CERT_VerifyCertNow(ctrlconn->m_certdb, cert, PR_TRUE, certSSLServer,
  1193.      conn);
  1194.     */
  1195.     SSMTextGen_UTF8StringClear(&cx->m_result);
  1196.     rv = SSM_GetAndExpandTextKeyedByString(cx, "not_verified_text", 
  1197.                                            &cx->m_result);
  1198.     if (rv != SSM_SUCCESS) {
  1199. goto loser;
  1200.     }
  1201.     SSM_DebugUTF8String("wrapped verification string %s", cx->m_result);
  1202.     goto done;
  1203. loser:
  1204.     if (rv == SSM_SUCCESS) {
  1205. rv = SSM_FAILURE;
  1206.     }
  1207. done:
  1208.     if (serverCert != NULL) {
  1209. CERT_DestroyCertificate(serverCert);
  1210.     }
  1211.     if (nickname != NULL) {
  1212. PR_Free(nickname);
  1213.     }
  1214.     PR_FREEIF(pattern);
  1215.     return rv;
  1216. }
  1217. /*
  1218.  * Function: SECStatus SSM_SSLMakeUnknownIssuerDialog()
  1219.  * Purpose: dispatch the UI event to create the unknown issuer dialog
  1220.  * Arguments and return values
  1221.  * - cert: server cert we are dealing with
  1222.  * - conn: SSL connection object
  1223.  * - returns: SECSuccess if successful *and* the user decides to trust
  1224.  *            the cert; appropriate error code otherwise
  1225.  */
  1226. SECStatus SSM_SSLMakeUnknownIssuerDialog(CERTCertificate* cert,
  1227.                                          SSMSSLDataConnection* conn)
  1228. {
  1229.     SECStatus rv = SECSuccess;
  1230.     SSM_LockResource(SSMRESOURCE(conn));
  1231.     conn->m_UIInfo.UICompleted = PR_FALSE;
  1232.     conn->m_UIInfo.trustBadServerCert = BSCA_NO;
  1233.     /* fire up the UI */
  1234.     if (SSMControlConnection_SendUIEvent(SSMCONTROLCONNECTION(conn), "get", 
  1235.  "bad_server_cert_unknown_issuer1", 
  1236.  SSMRESOURCE(conn), NULL, 
  1237.                      &SSMRESOURCE(conn)->m_clientContext, PR_TRUE) != SSM_SUCCESS) {
  1238. rv = SECFailure;
  1239. goto loser;
  1240.     }
  1241.     /* wait until the UI event is complete */
  1242.     while (!conn->m_UIInfo.UICompleted) {
  1243. SSM_WaitResource(SSMRESOURCE(conn), PR_INTERVAL_NO_TIMEOUT);
  1244.     }
  1245.     if (conn->m_UIInfo.trustBadServerCert == BSCA_NO) {
  1246. /* user did not want to continue.  Cancel here. */
  1247. if (rv == SECSuccess) {
  1248.     rv = SECFailure;
  1249. }
  1250. goto loser;
  1251.     }
  1252.     /* reset the trust bit for the session and continue */
  1253.     rv = SSM_SSLServerCertResetTrust(cert, conn->m_UIInfo.trustBadServerCert);
  1254.     if (rv != SECSuccess) {
  1255. goto loser;
  1256.     }
  1257. loser:
  1258.     conn->m_UIInfo.trustBadServerCert = BSCA_NO;
  1259.     conn->m_UIInfo.UICompleted = PR_FALSE;
  1260.     SSM_UnlockResource(SSMRESOURCE(conn));
  1261.     return rv;
  1262. }
  1263. SSMStatus SSM_HTTPUnknownIssuerStep1ButtonHandler(HTTPRequest* req)
  1264. {
  1265.     SSMStatus rv;
  1266.     SSMSSLDataConnection* conn;
  1267.     char* tmpStr = NULL;
  1268.     PR_ASSERT(req->target != NULL);
  1269.     conn = (SSMSSLDataConnection*)(req->target);
  1270.     /* make sure you got the right baseRef */
  1271.     rv = SSM_HTTPParamValue(req, "baseRef", &tmpStr);
  1272.     if (rv != SSM_SUCCESS || 
  1273. PL_strcmp(tmpStr, "windowclose_doclose_js") != 0) {
  1274. goto loser;
  1275.     }
  1276.     rv = SSM_HTTPParamValue(req, "do_cancel", &tmpStr);
  1277.     if (rv == SSM_SUCCESS) {
  1278. /* cancel button was clicked */
  1279. req->target->m_buttonType = SSM_BUTTON_CANCEL;
  1280.     }
  1281.     else {
  1282. rv = SSM_HTTPParamValue(req, "do_next", &tmpStr);
  1283. if (rv == SSM_SUCCESS) {
  1284.     /* next button was clicked */
  1285.     req->target->m_buttonType = SSM_BUTTON_OK;    /* close enough */
  1286. }
  1287.     }
  1288.     if (rv != SSM_SUCCESS) {
  1289. rv = SSM_ERR_NO_BUTTON;
  1290. goto loser;
  1291.     }
  1292.     switch (req->target->m_buttonType)
  1293.     {
  1294.     case SSM_BUTTON_CANCEL:
  1295.         rv = ssm_http_server_auth_handle_cancel_button(req);
  1296. break;
  1297.     case SSM_BUTTON_OK:
  1298.         rv = ssm_http_unknown_issuer_step1_handle_next_button(req);
  1299. break;
  1300.     default:
  1301.         break;
  1302.     }
  1303.     return rv;    /* error code will be properly set */
  1304. loser:
  1305.     /* set the predicate to true and unblock the SSL thread */
  1306.     SSM_LockResource(req->target);
  1307.     conn->m_UIInfo.UICompleted = PR_TRUE;
  1308.     conn->m_UIInfo.trustBadServerCert = BSCA_NO;
  1309.     SSM_NotifyResource(req->target);
  1310.     SSM_UnlockResource(req->target);
  1311.     if (rv == SSM_SUCCESS) {
  1312. rv = SSM_FAILURE;
  1313.     }
  1314.     return rv;
  1315. }
  1316. SSMStatus ssm_http_unknown_issuer_step1_handle_next_button(HTTPRequest* req)
  1317. {
  1318.     SSMStatus rv;
  1319.     SSMSSLDataConnection* conn;
  1320.     conn = (SSMSSLDataConnection*)(req->target);
  1321.     SSM_LockResource(req->target);
  1322.     /* do away with the first dialog */
  1323.     rv = SSM_HTTPCloseAndSleep(req);
  1324.     if (rv != SSM_SUCCESS) {
  1325. goto loser;
  1326.     }
  1327.     /* fire up the next dialog */
  1328.     rv = SSMControlConnection_SendUIEvent(SSMCONTROLCONNECTION(conn), "get", 
  1329.   "bad_server_cert_unknown_issuer2", 
  1330.   SSMRESOURCE(conn), NULL, &SSMRESOURCE(conn)->m_clientContext, PR_TRUE);
  1331.     if (rv != SSM_SUCCESS) {
  1332. goto loser;
  1333.     }
  1334.     conn->m_UIInfo.UICompleted = PR_FALSE;
  1335.     /* the above is redundant but for peace of mind */
  1336.     SSM_UnlockResource(req->target);
  1337.     return rv;    /* SSM_SUCCESS */
  1338. loser:
  1339.     /* still we want to unblock the SSL thread: the connection will fail */
  1340.     conn->m_UIInfo.trustBadServerCert = BSCA_NO;
  1341.     conn->m_UIInfo.UICompleted = PR_TRUE;
  1342.     SSM_NotifyResource(req->target);
  1343.     SSM_UnlockResource(req->target);
  1344.     return rv;
  1345. }