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

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. #include "serv.h"
  34. #include "minihttp.h"
  35. #include "signtextres.h"
  36. #include "protocolf.h"
  37. #include "base64.h"
  38. #include "secmime.h"
  39. #include "newproto.h"
  40. #include "messages.h"
  41. #include "certres.h"
  42. #include "sechash.h"
  43. #define SSMRESOURCE(object) (&(object)->super)
  44. SSMStatus
  45. SSM_CreateSignTextRequest(SECItem *msg, SSMControlConnection *conn) 
  46. {
  47.     SSMStatus rv;
  48.     SSMSignTextResource *signTextRes = NULL;
  49.     int i;
  50.     SignTextRequest request;
  51.     /* Decode the sign text protocol message */
  52.     if (CMT_DecodeMessage(SignTextRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
  53.         goto loser;
  54.     }
  55.     /* Get the resource */
  56.     rv = SSMControlConnection_GetResource(conn, (SSMResourceID)request.resID,
  57.   (SSMResource**)&signTextRes);
  58.     if ((rv != PR_SUCCESS) || (signTextRes == NULL)) {
  59.         goto loser;
  60.     }
  61.     /* Get a reference to it */
  62.     SSM_GetResourceReference(SSMRESOURCE(signTextRes));
  63.     if (!SSM_IsAKindOf(SSMRESOURCE(signTextRes), SSM_RESTYPE_SIGNTEXT)) {
  64.         goto loser;
  65.     }
  66.     /* Set the request data */
  67.     signTextRes->m_stringToSign = PL_strdup(request.stringToSign);
  68.     signTextRes->m_hostName = PL_strdup(request.hostName);
  69.     if (PL_strcasecmp(request.caOption, "auto") == 0) {
  70.         signTextRes->m_autoFlag = PR_TRUE;
  71.     } else if (PL_strcasecmp(request.caOption, "ask") == 0) {
  72.         signTextRes->m_autoFlag = PR_FALSE;
  73.     } else {
  74.         goto loser;
  75.     }
  76.     signTextRes->m_numCAs = request.numCAs;
  77.     if (signTextRes->m_numCAs > 0) {
  78.         signTextRes->m_caNames = (char **) PR_CALLOC(sizeof(char*)*(signTextRes->m_numCAs));
  79.         if (!signTextRes->m_caNames) {
  80.             goto loser;
  81.         }
  82.         for (i=0;i<signTextRes->m_numCAs;i++) {
  83.             signTextRes->m_caNames[i] = PL_strdup(request.caNames[i]);
  84.         }
  85.     }
  86.     signTextRes->m_conn = conn;
  87.     signTextRes->m_action = SIGN_TEXT_WAITING;
  88.     signTextRes->m_thread = SSM_CreateAndRegisterThread(PR_USER_THREAD,
  89.                                    SSMSignTextResource_ServiceThread,
  90.                                    (void*)signTextRes,
  91.                                    PR_PRIORITY_NORMAL,
  92.                                    PR_LOCAL_THREAD,
  93.                                    PR_UNJOINABLE_THREAD, 0);
  94.     if (!signTextRes->m_thread) {
  95.         goto loser;
  96.     }
  97.     return PR_SUCCESS;
  98. loser:
  99.     /* XXX Free request */
  100.     return PR_FAILURE;
  101. }
  102. SSMStatus
  103. SSMSignTextResource_Create(void *arg, SSMControlConnection * conn, SSMResource **res)
  104. {
  105.     SSMSignTextResource *signTextRes;
  106.     SSMStatus rv;
  107.     signTextRes = PR_NEWZAP(SSMSignTextResource);
  108.     if (!signTextRes) {
  109.         goto loser;
  110.     }
  111.     rv = SSMSignTextResource_Init(conn, signTextRes, SSM_RESTYPE_SIGNTEXT);
  112.     if (rv != PR_SUCCESS) {
  113.         goto loser;
  114.     }
  115.     *res = SSMRESOURCE(signTextRes);
  116.     return PR_SUCCESS;
  117. loser:
  118.     if (signTextRes != NULL) {
  119.         SSM_FreeResource(SSMRESOURCE(signTextRes));
  120.     }
  121.     *res = NULL;
  122.     return PR_FAILURE;
  123. }
  124. SSMStatus
  125. SSMSignTextResource_Init(SSMControlConnection *conn, SSMSignTextResource *in,
  126.                         SSMResourceType type)
  127. {
  128.     SSMStatus rv;
  129.     rv = SSMResource_Init(conn, SSMRESOURCE(in), type);
  130.     if (rv != PR_SUCCESS) {
  131.         goto loser;
  132.     }
  133.     /* Set all our data to zero */
  134.     in->m_stringToSign = NULL;
  135.     in->m_hostName = NULL;
  136.     in->m_autoFlag = PR_FALSE;
  137.     in->m_numCAs = 0;
  138.     in->m_caNames = NULL;
  139.     in->m_conn = conn;
  140.     in->m_thread = NULL;
  141.     in->m_certs = NULL;
  142.     in->m_action = SIGN_TEXT_INIT;
  143.     in->m_nickname = NULL;
  144.     in->m_resultString = NULL;
  145.     return PR_SUCCESS;
  146. loser:
  147.     return PR_FAILURE;
  148. }
  149. SSMStatus SSMSignTextResource_Destroy(SSMResource *res, PRBool doFree)
  150. {
  151.     SSMSignTextResource *signTextRes = (SSMSignTextResource*)res;
  152.     if (res == NULL) {
  153.         return PR_FAILURE;
  154.     }
  155.     PR_ASSERT(res->m_threadCount == 0);
  156.     /* Free our data */
  157.     /* Destroy the super class */
  158.     SSMResource_Destroy(res, PR_FALSE);
  159.     /* Free our memory */
  160.     if (doFree) {
  161.         PR_DELETE(signTextRes);
  162.     }
  163.     return PR_SUCCESS;
  164. }
  165. SSMStatus SSMSignTextResource_Shutdown(SSMResource *arg, SSMStatus status)
  166. {
  167.     return PR_SUCCESS;
  168. }
  169. void
  170. SSMSignTextResource_SendTaskCompletedEvent(SSMSignTextResource *res)
  171. {
  172.     SECItem msg;
  173.     SSMStatus rv;
  174.     TaskCompletedEvent event;
  175.     /* Assemble the event. */
  176.     SSM_DEBUG("Sign Text Resource Task completed event: id %ld, status %dn",
  177.                   SSMRESOURCE(res)->m_id, SSMRESOURCE(res)->m_status);
  178.     event.resourceID = SSMRESOURCE(res)->m_id;
  179.     event.numTasks = 0;
  180.     event.result = SSMRESOURCE(res)->m_status;
  181.     if (CMT_EncodeMessage(TaskCompletedEventTemplate, (CMTItem*)&msg, &event) != CMTSuccess) {
  182.         return;
  183.     }
  184.     if (msg.data) {
  185.         /* Send the event to the control queue. */
  186.         rv = SSM_SendQMessage(SSMRESOURCE(res)->m_connection->m_controlOutQ,
  187.                               SSM_PRIORITY_NORMAL,
  188.                               SSM_EVENT_MESSAGE | SSM_TASK_COMPLETED_EVENT,
  189.                               (int) msg.len, (char *) msg.data, PR_FALSE);
  190.         SSM_DEBUG("Sent message, rv = %d.n", rv);
  191.     }
  192. }
  193. void
  194. SSMSignTextResource_ServiceThread(void *arg)
  195. {
  196.     SSMSignTextResource *signTextRes = (SSMSignTextResource*)arg;
  197.     SSMStatus rv;
  198.     unsigned char hashVal[SHA1_LENGTH];
  199.     SECItem digest, signedResult, *tmpItem;
  200.     SEC_PKCS7ContentInfo *ci = NULL;
  201.     CERTCertificate *cert = NULL;
  202.     CERTCertListNode *node;
  203.     int i,numCerts;
  204.     SSM_LockResource(SSMRESOURCE(signTextRes));
  205.     PR_ASSERT(signTextRes);
  206.     PR_ASSERT(SSM_IsAKindOf(SSMRESOURCE(signTextRes), SSM_RESTYPE_SIGNTEXT));
  207.     memset(&signedResult, 0, sizeof(SECItem));
  208.     /* Get the certificates */
  209.     signTextRes->m_certs = CERT_MatchUserCert(signTextRes->m_conn->m_certdb, 
  210.                                 certUsageEmailSigner,
  211.                                 signTextRes->m_numCAs,
  212.                                 signTextRes->m_caNames,
  213.                                 signTextRes->m_conn);
  214.     numCerts = SSM_CertListCount(signTextRes->m_certs);
  215.     if((signTextRes->m_certs == NULL) || (numCerts == 0)) {
  216.         signTextRes->m_resultString = strdup("error:noMatchingCert");
  217.         goto loser;
  218.     }
  219.     /* Send UI event to client */
  220.     if (signTextRes->m_autoFlag == PR_TRUE) {
  221.         rv = SSMControlConnection_SendUIEvent(signTextRes->m_conn, "get", 
  222.       "signtext_auto", 
  223.       SSMRESOURCE(signTextRes), NULL,
  224.       &SSMRESOURCE(signTextRes)->m_clientContext,
  225.       PR_TRUE);
  226.     } else {
  227.         rv = SSMControlConnection_SendUIEvent(signTextRes->m_conn, "get", "signtext_ask", SSMRESOURCE(signTextRes), NULL,
  228.             &SSMRESOURCE(signTextRes)->m_clientContext, PR_TRUE);
  229.     }
  230.     if (rv != PR_SUCCESS) {
  231.         goto loser;
  232.     }
  233.     /* Here we wait for the user to confirm or deny the signing */
  234.     SSM_WaitResource(SSMRESOURCE(signTextRes), PR_INTERVAL_NO_TIMEOUT);
  235.     switch (SSMRESOURCE(signTextRes)->m_buttonType) {
  236.     case SSM_BUTTON_OK:
  237.         /* Get the signing cert */
  238.      node = (CERTCertListNode *)PR_LIST_HEAD(&signTextRes->m_certs->list);
  239.      if (signTextRes->m_nickname == NULL ) {
  240.         /* this is the "auto" case */
  241.          cert = node->cert;
  242.      } else {
  243.         /* this is the "ask" case */
  244.          for ( i = 0; i < numCerts; i++ ) {
  245.          if ( PL_strcasecmp(signTextRes->m_nickname, node->cert->nickname) == 0 ) {
  246.             cert = node->cert;
  247.             break;
  248.         }
  249.         node = (struct CERTCertListNodeStr *) node->links.next;
  250.         }
  251.         }
  252.         /* Hash the string to be signed */
  253.         rv = HASH_HashBuf(HASH_AlgSHA1, hashVal,
  254.                           (unsigned char *) signTextRes->m_stringToSign, 
  255.                           strlen(signTextRes->m_stringToSign));
  256.         if (rv != SECSuccess) {
  257.             goto loser;
  258.         }
  259.         digest.len = SHA1_LENGTH;
  260.         digest.data = hashVal;
  261.         /* Sign the hash */
  262.         ci = SECMIME_CreateSigned(cert, cert, cert->dbhandle, SEC_OID_SHA1,
  263.                                     &digest, NULL, signTextRes->m_conn);
  264.         if (ci == NULL) {
  265.             goto loser;
  266.         }
  267.         /* Create the PKCS#7 object */
  268.         tmpItem = SEC_PKCS7EncodeItem(NULL, &signedResult, ci, NULL, NULL,
  269.                                       signTextRes->m_conn);
  270.         if (tmpItem != &signedResult) {
  271.             goto loser;
  272.         }
  273.         /* Convert the result to base 64 */
  274.         signTextRes->m_resultString = BTOA_DataToAscii(signedResult.data, signedResult.len);
  275.         if (signTextRes->m_resultString == NULL) {
  276.             goto loser;
  277.         }
  278.         break;
  279.     case SSM_BUTTON_CANCEL:
  280.         signTextRes->m_resultString= PL_strdup("error:userCancel");
  281.         break;
  282.     default:
  283.         break;
  284.     }
  285.     SSM_UnlockResource(SSMRESOURCE(signTextRes));
  286. loser:
  287.     /* Free data */
  288.     if (signTextRes->m_stringToSign) {
  289.         PR_Free(signTextRes->m_stringToSign);
  290.     }
  291.     if (signTextRes->m_hostName) {
  292.         PR_Free(signTextRes->m_hostName);
  293.     }
  294.     if (signTextRes->m_certs) {
  295.         CERT_DestroyCertList(signTextRes->m_certs);
  296.     }
  297.     /* Send the task complete event here */
  298.     SSMSignTextResource_SendTaskCompletedEvent(signTextRes);
  299.     return;
  300. }
  301. SSMStatus 
  302. SSMSignTextResource_Print(SSMResource   *res,
  303.   char *fmt,
  304.                           PRIntn numParam,
  305.   char ** value,
  306.   char **resultStr)
  307. {
  308.     char *hostName = NULL, *stringToSign = NULL;
  309.     SSMSignTextResource *signTextRes = (SSMSignTextResource*)res;
  310.     hostName = signTextRes->m_hostName;
  311.     stringToSign = signTextRes->m_stringToSign;
  312.     if (numParam) 
  313.       SSMResource_Print(res, fmt, numParam, value, resultStr);
  314.     else if (signTextRes->m_autoFlag) {
  315.       CERTCertListNode *node;
  316.       CERTCertificate *cert;
  317.       
  318.       /* Get the cert nickname */
  319.       node = (CERTCertListNode*)PR_LIST_HEAD(&signTextRes->m_certs->list);
  320.       cert = node->cert;
  321.       
  322.       /* Get the nickname */
  323.       *resultStr = PR_smprintf(fmt, signTextRes->super.m_id, hostName,
  324.        stringToSign, cert->nickname);
  325.     } else {
  326.       *resultStr = PR_smprintf(fmt, signTextRes->super.m_id, hostName,
  327.        stringToSign);
  328.       
  329.     }
  330.     return (*resultStr != NULL) ? PR_SUCCESS : PR_FAILURE;
  331. }
  332. SSMStatus
  333. SSMSignTextResource_GetAttr(SSMResource *res, SSMAttributeID attrID,
  334.     SSMResourceAttrType attrType,
  335.     SSMAttributeValue *value)
  336. {
  337.     SSMSignTextResource *signTextRes = (SSMSignTextResource*)res;
  338.     if (!signTextRes || !signTextRes->m_resultString) {
  339.         goto loser;
  340.     }
  341.     switch (attrID) {
  342.         case SSM_FID_SIGNTEXT_RESULT:
  343.             if (!signTextRes->m_resultString) {
  344.                 goto loser;
  345.             }
  346.             value->type = SSM_STRING_ATTRIBUTE;
  347.             value->u.string.len = PL_strlen(signTextRes->m_resultString);
  348.             value->u.string.data = (unsigned char *) PL_strdup(signTextRes->m_resultString);
  349.             break;
  350.         default:
  351.             goto loser;
  352.     }
  353.     return PR_SUCCESS;
  354. loser:
  355.     return PR_FAILURE;
  356. }
  357. SSMStatus
  358. SSMSignTextResource_FormSubmitHandler(SSMResource* res,
  359.                                       HTTPRequest* req)
  360. {
  361.     SSMStatus rv;
  362.     char* tmpStr;
  363.     SSMSignTextResource *signTextRes = (SSMSignTextResource*)res;
  364.     SSM_LockResource(res);
  365.     rv = SSM_HTTPParamValue(req, "baseRef", &tmpStr);
  366.     if (rv != SSM_SUCCESS ||
  367.         PL_strcmp(tmpStr, "windowclose_doclose_js") != 0) {
  368.         goto loser;
  369.     }
  370.     /* Detect which button was pressed */
  371.     if (res->m_buttonType == SSM_BUTTON_OK) {
  372.         /* Get the certificate nickname */
  373.         SSM_HTTPParamValue(req, "chose", &signTextRes->m_nickname);
  374.     }
  375. loser:
  376.     /* Close the window */
  377.     SSM_HTTPCloseAndSleep(req);
  378.     /* Unblock the sign text thread waiting on this */
  379.     SSM_NotifyResource(res);
  380.     SSM_UnlockResource(res);
  381.     return rv;
  382. }
  383. SSMStatus SSM_SignTextCertListKeywordHandler(SSMTextGenContext* cx)
  384. {
  385.     SSMStatus rv = SSM_SUCCESS;
  386.     SSMResource* target = NULL;
  387.     SSMSignTextResource* res;
  388.     char* prefix = NULL;
  389.     char* wrapper = NULL;
  390.     char* suffix = NULL;
  391.     char* tmpStr = NULL;
  392.     char* fmt = NULL;
  393.     const PRIntn CERT_LIST_PREFIX = (PRIntn)0;
  394.     const PRIntn CERT_LIST_WRAPPER = (PRIntn)1;
  395.     const PRIntn CERT_LIST_SUFFIX = (PRIntn)2;
  396.     const PRIntn CERT_LIST_PARAM_COUNT = (PRIntn)3;
  397.     /* 
  398.      * make sure cx, cx->m_request, cx->m_params, cx->m_result are not
  399.      * NULL
  400.      */
  401.     PR_ASSERT(cx != NULL && cx->m_request != NULL && cx->m_params != NULL &&
  402.       cx->m_result != NULL);
  403.     if (cx == NULL || cx->m_request == NULL || cx->m_params == NULL ||
  404.     cx->m_result == NULL) {
  405.      PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  406.      goto loser;
  407.     }
  408.     if (SSM_Count(cx->m_params) != CERT_LIST_PARAM_COUNT) {
  409.         SSM_HTTPReportSpecificError(cx->m_request, "_signtext_certList: ",
  410.     "Incorrect number of parameters "
  411.     " (%d supplied, %d needed).n",
  412.     SSM_Count(cx->m_params), 
  413.     CERT_LIST_PARAM_COUNT);
  414.     goto loser;
  415.     }
  416.     /* get the connection object */
  417.     target = SSMTextGen_GetTargetObject(cx);
  418.     PR_ASSERT(target != NULL);
  419.     res = (SSMSignTextResource*)target;
  420.     /* form the MessageFormat object */
  421.     /* find arguments (prefix, wrapper, and suffix) */
  422.     prefix = (char *) SSM_At(cx->m_params, CERT_LIST_PREFIX);
  423.     wrapper = (char *) SSM_At(cx->m_params, CERT_LIST_WRAPPER);
  424.     suffix = (char *) SSM_At(cx->m_params, CERT_LIST_SUFFIX);
  425.     PR_ASSERT(prefix != NULL && wrapper != NULL && suffix != NULL);
  426.     /* grab the prefix and expand it */
  427.     rv = SSM_GetAndExpandTextKeyedByString(cx, prefix, &tmpStr);
  428.     if (rv != SSM_SUCCESS) {
  429. goto loser;
  430.     }
  431.     /* append the prefix */
  432.     rv = SSM_ConcatenateUTF8String(&cx->m_result, tmpStr);
  433.     SSMTextGen_UTF8StringClear(&tmpStr);
  434.     SSM_DebugUTF8String("signtext cert list prefix", cx->m_result);
  435.     /* grab the wrapper */
  436.     rv = SSM_GetAndExpandTextKeyedByString(cx, wrapper, &tmpStr);
  437.     if (rv != SSM_SUCCESS) {
  438.         goto loser;
  439.     }
  440.     SSM_DebugUTF8String("sign text cert list wrapper", fmt);
  441.     /* form the wrapped cert list UnicodeString */
  442.     rv = ssm_signtext_get_unicode_cert_list(res, tmpStr, &tmpStr);
  443.     if (rv != SSM_SUCCESS) {
  444.         goto loser;
  445.     }
  446.     /* append the wrapped cert list */
  447.     rv = SSM_ConcatenateUTF8String(&cx->m_result, tmpStr);
  448.     if (rv != SSM_SUCCESS) {
  449.       goto loser;
  450.     }
  451.     SSMTextGen_UTF8StringClear(&tmpStr);
  452.     /* grab the suffix and expand it */
  453.     rv = SSM_GetAndExpandTextKeyedByString(cx, suffix, &tmpStr);
  454.     if (rv != SSM_SUCCESS) {
  455. goto loser;
  456.     }
  457.     SSM_DebugUTF8String("client cert list suffix", tmpStr);
  458.     /* append the suffix */
  459.     rv = SSM_ConcatenateUTF8String(&cx->m_result, tmpStr);
  460.     if (rv != SSM_SUCCESS) {
  461.       goto loser;
  462.     }
  463.     goto done;
  464. loser:
  465.     if (rv == SSM_SUCCESS) {
  466. rv = SSM_FAILURE;
  467.     }
  468. done:
  469.     PR_FREEIF(fmt);
  470.     PR_FREEIF(tmpStr);
  471.     return rv;
  472. }
  473. /*
  474.  * Function: SSMStatus ssm_client_auth_get_unicode_cert_list()
  475.  * Purpose: forms the cert list UnicodeString
  476.  *
  477.  * Arguments and return values:
  478.  * - conn: SSL connection object
  479.  * - fmt: cert wrapper UnicodeString format
  480.  * - result: resulting UnicodeString
  481.  *
  482.  * Note: if we include the expired certs, we need to append to the end as
  483.  *       well
  484.  */
  485. SSMStatus ssm_signtext_get_unicode_cert_list(SSMSignTextResource* res, 
  486.      char* fmt, 
  487.      char** result)
  488. {
  489.     SSMStatus rv = SSM_SUCCESS;
  490.     char * tmpStr = NULL;
  491.     char * finalStr = NULL;
  492.     int i;
  493.     CERTCertListNode *head = NULL;
  494.     int numCerts;
  495.     PR_ASSERT(res != NULL && fmt != NULL && result != NULL);
  496.     /* in case we fail */
  497.     *result = NULL;
  498.     /* concatenate the string using the nicknames */
  499.     head = (CERTCertListNode *)PR_LIST_HEAD(&res->m_certs->list);
  500.     numCerts = SSM_CertListCount(res->m_certs);
  501.     for (i = 0; i < numCerts; i++) {
  502.         tmpStr = PR_smprintf(fmt, i, head->cert->nickname);
  503. rv = SSM_ConcatenateUTF8String(&finalStr, tmpStr);
  504. if (rv != SSM_SUCCESS) {
  505.   goto loser;
  506. }
  507. PR_Free(tmpStr);
  508.         tmpStr = NULL;
  509.         head = (CERTCertListNode *)head->links.next;
  510.     }
  511.     SSM_DebugUTF8String("client auth: final cert list", finalStr);
  512.     *result = finalStr;
  513.     return SSM_SUCCESS;
  514. loser:
  515.     SSM_DEBUG("client auth: wrapping cert list failed.n");
  516.     if (rv == SSM_SUCCESS) {
  517.         rv = SSM_FAILURE;
  518.     }
  519.     PR_FREEIF(finalStr);
  520.     PR_FREEIF(tmpStr);
  521.     return rv;
  522. }