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

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 "p7dconn.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. #include "secmime.h"
  42. /* Shorthand macros for inherited classes */
  43. #define SSMRESOURCE(conn) (&(conn)->super.super.super)
  44. #define SSMCONNECTION(conn) (&(conn)->super.super)
  45. #define SSMDATACONNECTION(conn) (&(conn)->super)
  46. #define SSM_PARENT_CONN(conn) ((SSMControlConnection*)((conn)->super.super.m_parent))
  47. void SSMP7DecodeConnection_ServiceThread(void * arg);
  48. SSMStatus SSMP7DecodeConnection_StartDecoding(SSMP7DecodeConnection *conn);
  49. /* callbacks for PKCS7 decoder */
  50. void SSMP7DecodeConnection_ContentCallback(void *arg, 
  51.                                            const char *buf,
  52.                                            unsigned long len);
  53. PK11SymKey * SSMP7DecodeConnection_GetDecryptKey(void *arg, 
  54.                                                  SECAlgorithmID *algid);
  55. PRBool SSMP7DecodeConnection_DecryptionAllowed(SECAlgorithmID *algid,  
  56.                                                PK11SymKey *bulkkey);
  57. SECItem * SSMP7DecodeConnection_GetPasswordKey(void *arg,
  58.                                                SECKEYKeyDBHandle *handle);
  59. SSMStatus SSMP7DecodeConnection_Create(void *arg, 
  60.                                       SSMControlConnection * connection, 
  61.                                       SSMResource **res)
  62. {
  63.     SSMStatus rv = PR_SUCCESS;
  64.     SSMP7DecodeConnection *conn;
  65.     *res = NULL; /* in case we fail */
  66.     
  67.     conn = (SSMP7DecodeConnection *) PR_CALLOC(sizeof(SSMP7DecodeConnection));
  68.     if (!conn) goto loser;
  69.     SSMRESOURCE(conn)->m_connection = connection;
  70.     rv = SSMP7DecodeConnection_Init(conn, (SSMInfoP7Decode*) arg, 
  71.                                     SSM_RESTYPE_PKCS7_DECODE_CONNECTION);
  72.     if (rv != PR_SUCCESS) goto loser;
  73.     SSMP7DecodeConnection_Invariant(conn);
  74.     
  75.     *res = SSMRESOURCE(conn);
  76.     return PR_SUCCESS;
  77.  loser:
  78.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  79.     if (conn) 
  80.     {
  81.         SSM_ShutdownResource(SSMRESOURCE(conn), rv); /* force destroy */
  82.         SSM_FreeResource(SSMRESOURCE(conn));
  83.     }
  84.         
  85.     return rv;
  86. }
  87. SSMStatus SSMP7DecodeConnection_Init(SSMP7DecodeConnection *conn,
  88.                                     SSMInfoP7Decode *info,
  89.                                     SSMResourceType type)
  90. {
  91.     SSMStatus rv = PR_SUCCESS;
  92.  
  93.     rv = SSMDataConnection_Init(SSMDATACONNECTION(conn), info->ctrl, type);
  94.     if (rv != PR_SUCCESS) goto loser;
  95. /* Start the decoder */
  96. if (SSMP7DecodeConnection_StartDecoding(conn) != SSM_SUCCESS) {
  97. goto loser;
  98. }
  99.     /* Save the client UI context */
  100.     SSMRESOURCE(conn)->m_clientContext = info->clientContext;
  101.     /* Spin the service thread. */
  102.     SSM_DEBUG("Creating decoder service thread.n");
  103.     SSM_GetResourceReference(SSMRESOURCE(conn));
  104.     SSMDATACONNECTION(conn)->m_dataServiceThread =
  105.         SSM_CreateThread(SSMRESOURCE(conn), 
  106.                          SSMP7DecodeConnection_ServiceThread);
  107.     if (SSMDATACONNECTION(conn)->m_dataServiceThread == NULL) {
  108.         goto loser;
  109.     }
  110.     return PR_SUCCESS;
  111.  loser:
  112.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  113.     return rv;
  114. }
  115. SSMStatus
  116. SSMP7DecodeConnection_FinishDecoding(SSMP7DecodeConnection *conn)
  117. {
  118. SEC_PKCS7ContentInfo *p7info = NULL;
  119. SSMResourceID resID;
  120. SSMStatus rv = SSM_SUCCESS;
  121.     if (conn->m_cinfo)
  122.     {
  123.         SSM_FreeResource(&conn->m_cinfo->super);
  124.         conn->m_cinfo = NULL;
  125.     }
  126.     if (conn->m_context)
  127.     {
  128.         p7info = SEC_PKCS7DecoderFinish(conn->m_context);
  129. if (!p7info) {
  130. conn->m_error = PR_GetError();
  131. }
  132.         conn->m_context = NULL;
  133. if (p7info)
  134. {
  135. rv = SSM_CreateResource(SSM_RESTYPE_PKCS7_CONTENT_INFO,
  136. p7info,
  137.                                     SSM_PARENT_CONN(conn),
  138. &resID,
  139. (SSMResource **) &conn->m_cinfo);
  140. }
  141. else
  142. rv = PR_FAILURE;
  143.         SSM_LockResource(&conn->super.super.super);
  144.         SSM_NotifyResource(&conn->super.super.super);
  145.         SSM_UnlockResource(&conn->super.super.super);
  146.     }
  147.     return rv;
  148. }
  149. SSMStatus 
  150. SSMP7DecodeConnection_StartDecoding(SSMP7DecodeConnection *conn)
  151. {
  152.     PR_ASSERT(conn->m_context == NULL);
  153.     
  154.     SSM_LockResource(SSMRESOURCE(conn));
  155.     if (conn->m_context)
  156.         SSMP7DecodeConnection_FinishDecoding(conn);
  157.     conn->m_context = 
  158.         SEC_PKCS7DecoderStart(SSMP7DecodeConnection_ContentCallback,
  159.                               conn,
  160.                               SSMP7DecodeConnection_GetPasswordKey,
  161.                               conn,
  162.                               SSMP7DecodeConnection_GetDecryptKey,
  163.                               conn,
  164.                               SSMP7DecodeConnection_DecryptionAllowed);
  165.     SSM_UnlockResource(SSMRESOURCE(conn));
  166. /* Did we get a context */
  167. if (!conn->m_context) {
  168. conn->m_error = PR_GetError();
  169. return PR_FAILURE;
  170. } else {
  171. return PR_SUCCESS;
  172. }
  173. }
  174. SSMStatus SSMP7DecodeConnection_Destroy(SSMResource *res, PRBool doFree)
  175. {
  176.     SSMP7DecodeConnection *conn = (SSMP7DecodeConnection *) res;
  177.     if (doFree)
  178.         SSM_DEBUG("SSMP7DecodeConnection_Destroy called.n");
  179.     /* We should be shut down. */
  180.     PR_ASSERT(res->m_threadCount == 0);
  181.     /* Destroy our fields. */
  182.     SSM_LockResource(SSMRESOURCE(conn));
  183.     if (conn->m_context) 
  184.         SSMP7DecodeConnection_FinishDecoding(conn);
  185.     if (conn->m_cinfo)
  186.     {
  187.         SSM_FreeResource(&conn->m_cinfo->super);
  188.         conn->m_cinfo = NULL;
  189.     }
  190.     SSM_UnlockResource(SSMRESOURCE(conn));
  191.     
  192.     /* Destroy superclass fields. */
  193.     SSMDataConnection_Destroy(SSMRESOURCE(conn), PR_FALSE);
  194.     /* Free the connection object if asked. */
  195.     if (doFree)
  196.         PR_DELETE(conn);
  197.     return PR_SUCCESS;
  198. }
  199. void
  200. SSMP7DecodeConnection_Invariant(SSMP7DecodeConnection *conn)
  201. {
  202.     SSMDataConnection_Invariant(SSMDATACONNECTION(conn));
  203.     /* our specific invariants */
  204.     SSM_LockResource(SSMRESOURCE(conn));
  205.     /* check class */
  206.     PR_ASSERT(SSM_IsAKindOf(SSMRESOURCE(conn), SSM_RESTYPE_PKCS7_DECODE_CONNECTION));
  207.     /* we should not be simultaneously decoded and decoding */
  208.     if (conn->m_context)
  209.         PR_ASSERT(conn->m_cinfo == NULL);
  210.     SSM_UnlockResource(SSMRESOURCE(conn));
  211. }
  212. SSMStatus 
  213. SSMP7DecodeConnection_Shutdown(SSMResource *arg, SSMStatus status)
  214. {
  215.     SSMStatus rv = SSM_SUCCESS;
  216.     
  217.     /* Call our superclass shutdown. */
  218.     rv = SSMDataConnection_Shutdown(arg, status);
  219.     return rv;
  220. }
  221. /* 
  222.    PKCS7 decoding is performed by a single service thread. This thread
  223.    feeds data from the outgoing queue into the PKCS7 decoder. 
  224.  */
  225. void SSMP7DecodeConnection_ServiceThread(void * arg)
  226. {
  227.     SSMStatus rv = PR_SUCCESS;
  228.     SSMP7DecodeConnection* conn;
  229.     SSMControlConnection* ctrl;
  230.     SECItem* msg;
  231.     PRIntn read;
  232.     char buffer[LINESIZE+1] = {0};
  233.     SSM_RegisterNewThread("p7decode", (SSMResource *) arg);
  234.     conn = (SSMP7DecodeConnection *)arg;
  235.     SSM_DEBUG("initializing.n");
  236.     if (!arg) 
  237.     { 
  238.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  239.         goto loser;
  240.     }
  241.     SSMDATACONNECTION(conn)->m_dataServiceThread = PR_GetCurrentThread();
  242.     /* set up the client data socket and authenticate it with nonce */
  243.     rv = SSMDataConnection_SetupClientSocket(SSMDATACONNECTION(conn));
  244.     if (rv != PR_SUCCESS) {
  245.         goto loser;
  246.     }
  247.     /* Start decoding */
  248.     SSM_DEBUG("Start updating decoder..n");
  249.     while ((SSMRESOURCE(conn)->m_status == PR_SUCCESS) && 
  250.            (SSM_Count(SSMDATACONNECTION(conn)->m_shutdownQ) == 0) && 
  251.            (rv == PR_SUCCESS)) {
  252.         read = LINESIZE;    /* set the read size to the default line size */
  253.         rv = SSMDataConnection_ReadFromSocket(SSMDATACONNECTION(conn),
  254.                                               (PRInt32*)&read, buffer);
  255.         if (read > 0) {
  256.             /* there is data, pass it along to PKCS7 */
  257.             SSM_DEBUG("Received %ld bytes of data for decoder.n", read);
  258.             PR_ASSERT(conn->m_context);
  259.             if (SEC_PKCS7DecoderUpdate(conn->m_context, buffer, read) != SECSuccess) {
  260. conn->m_error = PR_GetError();
  261. goto finish;
  262. }
  263.         } else {
  264.             /* either EOF or an error condition */
  265.     /* If we have a decoder in progress, stop it. */
  266.     SSM_LockResource(SSMRESOURCE(conn));
  267. if (conn->m_context) {
  268.     SSM_DEBUG("Stopping PKCS7 decoder, generating content info struct.n");
  269.     SSMP7DecodeConnection_FinishDecoding(conn);
  270. }
  271. SSM_UnlockResource(SSMRESOURCE(conn));
  272. break;
  273.         }
  274.     }
  275. finish:
  276. /* we have an EOF, shut down the client socket */
  277.     PR_ASSERT(SSMDATACONNECTION(conn)->m_clientSocket != NULL);
  278.     if (SSMDATACONNECTION(conn)->m_clientSocket != NULL) {
  279. SSM_DEBUG("shutting down client socket.n");
  280.         SSM_LockResource(SSMRESOURCE(conn));
  281.         PR_Shutdown(SSMDATACONNECTION(conn)->m_clientSocket,
  282.                     PR_SHUTDOWN_SEND);
  283.         SSM_UnlockResource(SSMRESOURCE(conn));
  284.     }
  285.     /* If we've been asked to return the result, return it. */
  286.     if (SSMDATACONNECTION(conn)->m_sendResult) {
  287.         SSM_DEBUG("Responding to deferred content info request.n");
  288.         msg = (SECItem*)PORT_ZAlloc(sizeof(SECItem));
  289.         PR_ASSERT(msg != NULL);    /* need to have some preallocated
  290.                                       failure to send */
  291.         if (conn->m_cinfo) {
  292.             SSMAttributeValue value;
  293.             GetAttribReply reply;
  294.             value.type = SSM_RID_ATTRIBUTE;
  295.             rv = SSM_ClientGetResourceReference(&conn->m_cinfo->super,
  296.                                                 &value.u.rid);
  297.             if (rv != PR_SUCCESS) {
  298.                 goto loser;
  299.             }
  300.             msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_RESOURCE_ACTION
  301.                 | SSM_GET_ATTRIBUTE | SSM_RID_ATTRIBUTE);
  302.             reply.result = SSM_SUCCESS;
  303.             reply.value = value;
  304.             if (CMT_EncodeMessage(GetAttribReplyTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
  305.                 goto loser;
  306.             }
  307.             SSM_DEBUG("Generated a reply (t %lx/l %ld/d %lx)n", 
  308.                       msg->type, msg->len, msg->data);
  309.             /*
  310.              * We don't need the content info anymore since we sent it back
  311.              * Is it OK to release our reference?
  312.              */
  313.             SSM_FreeResource(&conn->m_cinfo->super);
  314.             conn->m_cinfo = NULL;
  315.         }
  316.         else {
  317.             SingleNumMessage reply;
  318.             msg->type = (SECItemType) (SSM_REPLY_ERR_MESSAGE | SSM_RESOURCE_ACTION
  319.                 | SSM_GET_ATTRIBUTE | SSM_STRING_ATTRIBUTE);
  320.             reply.value = SSM_ERR_ATTRIBUTE_MISSING;
  321.             if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
  322.                 goto loser;
  323.             }
  324.             SSM_DEBUG("Generated error reply (t %lx/l %ld/d %lx)n", 
  325.                       msg->type, msg->len, msg->data);
  326.         }
  327.         /* Post this message to the parent's control queue
  328.            for delivery back to the client. */
  329.         ctrl = (SSMControlConnection*)(SSMCONNECTION(conn)->m_parent);
  330.         PR_ASSERT(SSM_IsAKindOf(&ctrl->super.super, SSM_RESTYPE_CONTROL_CONNECTION));
  331.         rv = SSM_SendQMessage(ctrl->m_controlOutQ, 
  332.                               SSM_PRIORITY_NORMAL,
  333.                               msg->type, msg->len,
  334.                               (char*)msg->data, PR_TRUE);
  335.         SSM_FreeMessage(msg);
  336.         if (rv != PR_SUCCESS) goto loser;
  337.     }
  338.     
  339. loser:
  340.     SSM_DEBUG("** Thread shutting down ** (%ld)n", rv);
  341.     if (conn != NULL) {
  342.         SSM_ShutdownResource(SSMRESOURCE(conn), rv);
  343.         SSM_FreeResource(SSMRESOURCE(conn));
  344.     }
  345. }
  346. SSMStatus 
  347. SSMP7DecodeConnection_GetAttrIDs(SSMResource *res,
  348.                                  SSMAttributeID **ids,
  349.                                  PRIntn *count)
  350. {
  351.     SSMStatus rv;
  352.     rv = SSMDataConnection_GetAttrIDs(res, ids, count);
  353.     if (rv != PR_SUCCESS)
  354.         goto loser;
  355.     *ids = (SSMAttributeID *) PR_REALLOC(*ids, (*count + 1) * sizeof(SSMAttributeID));
  356.     if (! *ids) goto loser;
  357.     (*ids)[*count++] = SSM_FID_P7CONN_CONTENT_INFO;
  358.     goto done;
  359.  loser:
  360.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  361.  done:
  362.     return rv;
  363. }
  364. SSMStatus 
  365. SSMP7DecodeConnection_GetAttr(SSMResource *res,
  366.                               SSMAttributeID attrID,
  367.                               SSMResourceAttrType attrType,
  368.                               SSMAttributeValue *value)
  369. {
  370.     SSMStatus rv = PR_SUCCESS;
  371.     SSMP7DecodeConnection *dc = (SSMP7DecodeConnection *) res;
  372.     SSMP7DecodeConnection_Invariant(dc);
  373.     /* see what it is */
  374.     switch(attrID)
  375.     {
  376.     case SSM_FID_P7CONN_CONTENT_INFO:
  377.         if (!dc->m_cinfo) {
  378.             SSM_LockResource(res);
  379.             SSM_WaitResource(res, PR_TicksPerSecond());
  380.             SSM_UnlockResource(res);
  381.             /*
  382.              * If it's still NULL, then something really bad happened.
  383.              */
  384.             if (!dc->m_cinfo) 
  385.                 goto loser;
  386.         }
  387.         /* Allocate a resource ID */
  388.         value->type = SSM_RID_ATTRIBUTE;
  389.         rv = SSM_ClientGetResourceReference(&dc->m_cinfo->super, &value->u.rid);
  390.         if (rv != PR_SUCCESS)
  391.             goto loser;
  392.         /* Let's get rid of our reference to it and let the client inherit it.
  393.          */
  394.         SSM_LockResource(res);
  395.         SSM_FreeResource(&dc->m_cinfo->super);
  396.         dc->m_cinfo = NULL;
  397.         SSM_UnlockResource(res);
  398.         break;
  399. case SSM_FID_RESOURCE_ERROR:
  400. value->type = SSM_NUMERIC_ATTRIBUTE;
  401. value->u.numeric = dc->m_error;
  402. break;
  403.     default:
  404.         rv = SSMDataConnection_GetAttr(res,attrID,attrType,value);
  405.         if (rv != PR_SUCCESS)
  406.             goto loser;
  407.     }
  408.     goto done;
  409.  loser:
  410.     value->type = SSM_NO_ATTRIBUTE;
  411.     if (rv == PR_SUCCESS)
  412.         rv = PR_FAILURE;
  413.  done:
  414.     return rv;
  415. }
  416. /* Callback functions for decoder. For now, use empty/default functions. */
  417. void SSMP7DecodeConnection_ContentCallback(void *arg, 
  418.                                            const char *buf,
  419.                                            unsigned long len)
  420. {
  421.     SSMStatus rv;
  422.     SSMP7DecodeConnection *conn = (SSMP7DecodeConnection *)arg;
  423.     PRIntn sent = 0;
  424.     PRInt32 osErr;
  425.     SSM_DEBUG("writing data to socket.n");
  426.     PR_ASSERT(SSMDATACONNECTION(conn)->m_clientSocket != NULL);
  427.     sent = PR_Send(SSMDATACONNECTION(conn)->m_clientSocket, (void*)buf,
  428.                    (PRIntn)len, 0, PR_INTERVAL_NO_TIMEOUT);
  429.     if (sent != (PRIntn)len) {
  430.         rv = PR_GetError();
  431.         osErr = PR_GetOSError();
  432.         SSM_DEBUG("error writing data: %d OS error: %dn", rv, osErr);
  433.     }
  434. }
  435. PK11SymKey * SSMP7DecodeConnection_GetDecryptKey(void *arg, 
  436.                                                  SECAlgorithmID *algid)
  437. {
  438. return NULL;
  439. }
  440. PRBool SSMP7DecodeConnection_DecryptionAllowed(SECAlgorithmID *algid,  
  441.                                                PK11SymKey *bulkkey)
  442. {
  443. return SECMIME_DecryptionAllowed(algid, bulkkey);
  444. }
  445. SECItem * SSMP7DecodeConnection_GetPasswordKey(void *arg,
  446.                                                SECKEYKeyDBHandle *handle)
  447. {
  448. return NULL;
  449. }