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

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 "p7econn.h"
  35. #include "serv.h"
  36. #include "servimpl.h"
  37. #include "ssmerrs.h"
  38. #include "newproto.h"
  39. #include "messages.h"
  40. #include "collectn.h"
  41. /* Shorthand macros for inherited classes */
  42. #define SSMRESOURCE(conn) (&(conn)->super.super.super)
  43. #define SSMCONNECTION(conn) (&(conn)->super.super)
  44. #define SSMDATACONNECTION(conn) (&(conn)->super)
  45. #define SSM_PARENT_CONN(conn) ((SSMControlConnection*)((conn)->super.super.m_parent))
  46. void SSMP7EncodeConnection_ServiceThread(void * arg);
  47. /* callbacks for PKCS7 encoder */
  48. void SSMP7EncodeConnection_ContentCallback(void *arg, 
  49.                                            const char *buf,
  50.                                            unsigned long len);
  51. SECItem * SSMP7EncodeConnection_GetPasswordKey(void *arg,
  52.                                                SECKEYKeyDBHandle *handle);
  53. SSMStatus SSMP7EncodeConnection_Create(void *arg, 
  54.                                       SSMControlConnection *connection, 
  55.                                       SSMResource **res)
  56. {
  57.     SSMStatus rv = PR_SUCCESS;
  58.     SSMP7EncodeConnection *conn;
  59.     *res = NULL; /* in case we fail */
  60.     
  61.     conn = (SSMP7EncodeConnection *) PR_CALLOC(sizeof(SSMP7EncodeConnection));
  62.     if (!conn)
  63.         goto loser;
  64.     SSMRESOURCE(conn)->m_connection = connection;
  65.     rv = SSMP7EncodeConnection_Init(conn, (SSMInfoP7Encode *) arg, 
  66.                                     SSM_RESTYPE_PKCS7_ENCODE_CONNECTION);
  67.     if (rv != PR_SUCCESS)
  68.         goto loser;
  69.     SSMP7EncodeConnection_Invariant(conn);
  70.     
  71.     *res = SSMRESOURCE(conn);
  72.     return PR_SUCCESS;
  73. loser:
  74.     if (rv == PR_SUCCESS)
  75.         rv = PR_FAILURE;
  76.     if (conn) {
  77.         SSM_ShutdownResource(SSMRESOURCE(conn), rv); /* force destroy */
  78.         SSM_FreeResource(SSMRESOURCE(conn));
  79.     }
  80.         
  81.     return rv;
  82. }
  83. SSMStatus SSMP7EncodeConnection_Init(SSMP7EncodeConnection *conn,
  84.                                     SSMInfoP7Encode *info,
  85.                                     SSMResourceType type)
  86. {
  87.     SSMStatus rv = PR_SUCCESS;
  88.     SSMP7ContentInfo *cinfo;
  89.  
  90.     rv = SSMDataConnection_Init(SSMDATACONNECTION(conn), info->ctrl, type);
  91.     if (rv != PR_SUCCESS)
  92.         goto loser;
  93.     /* Spin the service thread. */
  94.     SSM_DEBUG("Creating encoder service thread.n");
  95.     SSM_GetResourceReference(SSMRESOURCE(conn));
  96.     rv = SSMControlConnection_GetResource(SSM_PARENT_CONN(conn), info->ciRID,
  97.                                           (SSMResource **)&cinfo);
  98.     if (rv != PR_SUCCESS)
  99.         goto loser;
  100.     conn->m_cinfo = cinfo;
  101.     /* Save the client UI context */
  102.     SSMRESOURCE(conn)->m_clientContext = info->clientContext;
  103.     SSMDATACONNECTION(conn)->m_dataServiceThread =
  104.         SSM_CreateThread(SSMRESOURCE(conn), 
  105.                          SSMP7EncodeConnection_ServiceThread);
  106.     if (SSMDATACONNECTION(conn)->m_dataServiceThread == NULL) {
  107.         goto loser;
  108.     }
  109.     return PR_SUCCESS;
  110. loser:
  111.     if (rv == PR_SUCCESS)
  112.         rv = PR_FAILURE;
  113.     return rv;
  114. }
  115. SSMStatus
  116. SSMP7EncodeConnection_FinishEncoding(SSMP7EncodeConnection *conn)
  117. {
  118. SECStatus rv = SECSuccess;
  119.     SSM_LockResource(SSMRESOURCE(conn));
  120.     if (conn->m_cinfo) {
  121.         SSM_FreeResource(&conn->m_cinfo->super);
  122.         conn->m_cinfo = NULL;
  123.     }
  124.     if (conn->m_context) {
  125.         conn->m_retValue = SEC_PKCS7EncoderFinish(conn->m_context,
  126.                                     SSMP7EncodeConnection_GetPasswordKey,
  127.                                     conn);
  128.         conn->m_error = PR_GetError();
  129.         conn->m_context = NULL;
  130.     }
  131.     SSM_UnlockResource(SSMRESOURCE(conn));
  132.     return rv;
  133. }
  134. SSMStatus
  135. SSMP7EncodeConnection_StartEncoding(SSMP7EncodeConnection *conn)
  136. {
  137.     PR_ASSERT(conn->m_context == NULL);
  138.     
  139.     SSM_LockResource(SSMRESOURCE(conn));
  140.     if (conn->m_context)
  141.         SSMP7EncodeConnection_FinishEncoding(conn);
  142.     conn->m_context = 
  143.         SEC_PKCS7EncoderStart(conn->m_cinfo->m_cinfo,
  144.                               SSMP7EncodeConnection_ContentCallback,
  145.                               conn, NULL);
  146.     SSM_UnlockResource(SSMRESOURCE(conn));
  147.     return PR_SUCCESS;
  148. }
  149. SSMStatus SSMP7EncodeConnection_Destroy(SSMResource *res, PRBool doFree)
  150. {
  151.     SSMP7EncodeConnection *conn = (SSMP7EncodeConnection *) res;
  152.     if (doFree)
  153.         SSM_DEBUG("SSMHashConnection_Destroy called.n");
  154.     /* We should be shut down. */
  155.     PR_ASSERT(res->m_threadCount == 0);
  156.     /* Destroy our fields. */
  157.     SSM_LockResource(SSMRESOURCE(conn));
  158.     if (conn->m_context)
  159.         SSMP7EncodeConnection_FinishEncoding(conn);
  160.     if (conn->m_cinfo) {
  161.         SSM_FreeResource(&conn->m_cinfo->super);
  162.         conn->m_cinfo = NULL;
  163.     }
  164.     SSM_UnlockResource(SSMRESOURCE(conn));
  165.     
  166.     /* Destroy superclass fields. */
  167.     SSMDataConnection_Destroy(SSMRESOURCE(conn), PR_FALSE);
  168.     /* Free the connection object if asked. */
  169.     if (doFree)
  170.         PR_DELETE(conn);
  171.     return PR_SUCCESS;
  172. }
  173. void
  174. SSMP7EncodeConnection_Invariant(SSMP7EncodeConnection *conn)
  175. {
  176.     SSMDataConnection_Invariant(SSMDATACONNECTION(conn));
  177.     /* our specific invariants */
  178.     SSM_LockResource(SSMRESOURCE(conn));
  179.     /* check class */
  180.     PR_ASSERT(SSM_IsAKindOf(SSMRESOURCE(conn),
  181.                             SSM_RESTYPE_PKCS7_ENCODE_CONNECTION));
  182.     /* we should not be simultaneously encoded and encoding */
  183.     if (conn->m_context)
  184.         PR_ASSERT(conn->m_cinfo != NULL);
  185.     SSM_UnlockResource(SSMRESOURCE(conn));
  186. }
  187. SSMStatus 
  188. SSMP7EncodeConnection_Shutdown(SSMResource *arg, SSMStatus status)
  189. {
  190.     SSMStatus rv = SSM_SUCCESS;
  191.     
  192.     /* Call our superclass shutdown. */
  193.     rv = SSMDataConnection_Shutdown(arg, status);
  194.     return rv;
  195. }
  196. /* 
  197.    PKCS7 decoding is performed by a single service thread. This thread
  198.    feeds data from the outgoing queue into the PKCS7 encoder. 
  199.  */
  200. void SSMP7EncodeConnection_ServiceThread(void * arg)
  201. {
  202.     SSMStatus rv = PR_SUCCESS;
  203.     SSMP7EncodeConnection * conn;
  204.     SSMControlConnection *ctrl;
  205.     SECItem *msg;
  206.     PRIntn read;
  207.     char buffer[LINESIZE+1] = {0};
  208.     SSM_RegisterNewThread("p7encode", (SSMResource *) arg);
  209.     conn = (SSMP7EncodeConnection *)arg;
  210.     SSM_DEBUG("initializing.n");
  211.     if (!arg) { 
  212.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  213.         goto loser;
  214.     }
  215.     SSMDATACONNECTION(conn)->m_dataServiceThread = PR_GetCurrentThread();
  216.     /* set up the client data socket and authenticate it with nonce */
  217.     rv = SSMDataConnection_SetupClientSocket(SSMDATACONNECTION(conn));
  218.     if (rv != PR_SUCCESS) {
  219.         goto loser;
  220.     }
  221.     /* Start encoding */
  222.     SSM_DEBUG("Creating encoder.n");
  223.     SSMP7EncodeConnection_StartEncoding(conn);
  224.     while ((SSMRESOURCE(conn)->m_status == PR_SUCCESS) && 
  225.            (SSM_Count(SSMDATACONNECTION(conn)->m_shutdownQ) == 0) && 
  226.            (rv == PR_SUCCESS)) {
  227.         read = LINESIZE;    /* set the read size to the default line size */
  228.         rv = SSMDataConnection_ReadFromSocket(SSMDATACONNECTION(conn),
  229.                                               (PRInt32*)&read, buffer);
  230.         
  231.         if (read > 0) {
  232.             /* there is data, pass it along to PKCS7 */
  233.             SSM_DEBUG("Received %ld bytes of data for encoder.n", read);
  234.             PR_ASSERT(conn->m_context);
  235.             SEC_PKCS7EncoderUpdate(conn->m_context, buffer, read);
  236.         }
  237.         else {
  238.             /* either EOF or an error condition */
  239.             goto finish;
  240.         }
  241.     }
  242. finish:
  243.     SSM_DEBUG("Stopping PKCS7 encoder.n");
  244.     /* If we have a encoder in progress, stop it. */
  245.     SSM_LockResource(SSMRESOURCE(conn));
  246.     if (conn->m_context) {
  247.         SSMP7EncodeConnection_FinishEncoding(conn);
  248.     }
  249.     SSM_UnlockResource(SSMRESOURCE(conn));
  250.     if (rv == PR_SUCCESS) {
  251.         /* we have an EOF, shut down the client socket. */
  252.         PR_ASSERT(SSMDATACONNECTION(conn)->m_clientSocket != NULL);
  253.         if (SSMDATACONNECTION(conn)->m_clientSocket != NULL) {
  254.             SSM_DEBUG("shutting down client socket.n");
  255.             SSM_LockResource(SSMRESOURCE(conn));
  256.             PR_Shutdown(SSMDATACONNECTION(conn)->m_clientSocket,
  257.                         PR_SHUTDOWN_SEND);
  258.             SSM_UnlockResource(SSMRESOURCE(conn));
  259.         }
  260.     }
  261.     /* If we've been asked to return the result, return it. */
  262.     if (SSMDATACONNECTION(conn)->m_sendResult) {
  263.         SSM_DEBUG("Responding to deferred content info request.n");
  264.         msg = (SECItem*)PORT_ZAlloc(sizeof(SECItem));
  265.         PR_ASSERT(msg != NULL);    /* need to have some preallocated
  266.                                       failure to send */
  267.         if (conn->m_cinfo) {
  268.             SSMAttributeValue value;
  269.             GetAttribReply reply;
  270.             value.type = SSM_RID_ATTRIBUTE;
  271.             rv = SSM_ClientGetResourceReference(&conn->m_cinfo->super,
  272.                                                 &value.u.rid);
  273.             if (rv != PR_SUCCESS) {
  274.                 goto loser;
  275.             }
  276.             msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_RESOURCE_ACTION
  277.                 | SSM_GET_ATTRIBUTE | SSM_RID_ATTRIBUTE);
  278.             reply.value = value;
  279.             reply.result = SSM_SUCCESS;
  280.             if (CMT_EncodeMessage(GetAttribReplyTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
  281.                 goto loser;
  282.             }
  283.             SSM_DEBUG("Generated a reply (t %lx/l %ld/d %lx)n", 
  284.                       msg->type, msg->len, msg->data);
  285.         } else {
  286.             SingleNumMessage reply;
  287.             msg->type = (SECItemType) (SSM_REPLY_ERR_MESSAGE | SSM_RESOURCE_ACTION
  288.                 | SSM_GET_ATTRIBUTE | SSM_STRING_ATTRIBUTE);
  289.             reply.value = SSM_ERR_ATTRIBUTE_MISSING;
  290.             if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
  291.                 goto loser;
  292.             }
  293.             SSM_DEBUG("Generated error reply (t %lx/l %ld/d %lx)n", 
  294.                       msg->type, msg->len, msg->data);
  295.         }
  296.         /* Post this message to the parent's control queue
  297.            for delivery back to the client. */
  298.         ctrl = (SSMControlConnection*)(SSMCONNECTION(conn)->m_parent);
  299.         PR_ASSERT(SSM_IsAKindOf(&ctrl->super.super,
  300.                                 SSM_RESTYPE_CONTROL_CONNECTION));
  301.         rv = SSM_SendQMessage(ctrl->m_controlOutQ, 
  302.                               SSM_PRIORITY_NORMAL,
  303.                               msg->type, msg->len,
  304.                               (char*)msg->data, PR_TRUE);
  305.         SSM_FreeMessage(msg);
  306.         if (rv != PR_SUCCESS)
  307.             goto loser;
  308.     }
  309. loser:
  310.     SSM_DEBUG("** Thread shutting down ** (%ld)n", rv);
  311.     if (conn != NULL) {
  312.         SSM_ShutdownResource(SSMRESOURCE(conn), rv);
  313.         SSM_FreeResource(SSMRESOURCE(conn));
  314.     }
  315. }
  316. /* Callback functions for encoder. For now, use empty/default functions. */
  317. void SSMP7EncodeConnection_ContentCallback(void *arg, 
  318.                                            const char *buf,
  319.                                            unsigned long len)
  320. {
  321.     SSMStatus rv;
  322.     SSMP7EncodeConnection *conn = (SSMP7EncodeConnection *)arg;
  323.     PRIntn sent = 0;
  324.     if (len == 0)
  325.         return;
  326.     SSM_DEBUG("writing data to socket.n");
  327.     PR_ASSERT(SSMDATACONNECTION(conn)->m_clientSocket != NULL);
  328.     sent = PR_Send(SSMDATACONNECTION(conn)->m_clientSocket, (void*)buf,
  329.                    (PRIntn)len, 0, PR_INTERVAL_NO_TIMEOUT);
  330.     if (sent != (PRIntn)len) {
  331.         rv = PR_GetError();
  332.         SSM_DEBUG("error writing data: %d n", rv);
  333.     }
  334. }
  335. SECItem * SSMP7EncodeConnection_GetPasswordKey(void *arg,
  336.                                                SECKEYKeyDBHandle *handle)
  337. {
  338. return NULL;
  339. }
  340. SSMStatus SSMP7EncodeConnection_SetAttr(SSMResource *res,
  341.                               SSMAttributeID attrID,
  342.                               SSMAttributeValue *value)
  343. {
  344.     switch(attrID) {
  345.     case SSM_FID_CLIENT_CONTEXT:
  346.       SSM_DEBUG("Setting PKCS7 Encode client contextn");
  347.       if (value->type != SSM_STRING_ATTRIBUTE) {
  348.           goto loser;
  349.       }
  350.       if (!(res->m_clientContext.data = (unsigned char *) PR_Malloc(value->u.string.len))) {
  351.           goto loser;
  352.       }
  353.       memcpy(res->m_clientContext.data, value->u.string.data, value->u.string.len);
  354.       res->m_clientContext.len = value->u.string.len;
  355.       break;
  356.     default:
  357.       SSM_DEBUG("Got unknown P7 Encoder Set Attribute Request %dn", attrID);
  358.       goto loser;
  359.       break;
  360.     }
  361.     return PR_SUCCESS;
  362. loser:
  363.     return PR_FAILURE;
  364. }
  365. SSMStatus SSMP7EncodeConnection_GetAttr(SSMResource *res,
  366.                                         SSMAttributeID attrID,
  367.                                         SSMResourceAttrType attrType,
  368.                                         SSMAttributeValue *value)
  369. {
  370.     SSMP7EncodeConnection *ec = (SSMP7EncodeConnection*)res;
  371.     SSMP7EncodeConnection_Invariant(ec);
  372.     switch (attrID) {
  373.     case SSM_FID_P7CONN_RETURN_VALUE:
  374.         value->type = SSM_NUMERIC_ATTRIBUTE;
  375.         value->u.numeric = ec->m_retValue;
  376.         break;
  377.     case SSM_FID_P7CONN_ERROR_VALUE:
  378.         value->type = SSM_NUMERIC_ATTRIBUTE;
  379.         value->u.numeric = ec->m_error;
  380.         break;
  381.     default:
  382.         SSM_DEBUG("Got unknown P7 Encoder Set Attribute Request %dn", attrID);
  383.         goto loser;
  384.         break;
  385.     }
  386.     return PR_SUCCESS;
  387. loser:
  388.     return PR_FAILURE;
  389. }