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

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 "kgenctxt.h"
  35. #include "ssmerrs.h"
  36. #include "minihttp.h"
  37. #include "textgen.h"
  38. #include "base64.h"
  39. #include "newproto.h"
  40. #include "messages.h"
  41. #include "advisor.h"
  42. #include "oldfunc.h"
  43. #include "secmod.h"
  44. #define SSMRESOURCE(ct) (&(ct)->super)
  45. #define DEFAULT_KEY_GEN_ALLOC 5
  46. void SSMKeyGenContext_ServiceThread(void *arg);
  47. static PRBool
  48. ssmkeygencontext_can_escrow(SSMKeyGenType keyGenType);
  49. #if 1
  50. /*
  51.  * We're cheating for now so that escrowing keys on smart cards 
  52.  * will work.
  53.  */
  54. SECKEYPrivateKey*
  55. pk11_loadPrivKey(PK11SlotInfo *slot,SECKEYPrivateKey *privKey,
  56.                 SECKEYPublicKey *pubKey, PRBool token, PRBool sensitive);
  57. #endif
  58. /* Initialize an SSMKeyGenContext object. */
  59. SSMStatus
  60. SSMKeyGenContext_Init(SSMKeyGenContext *ct, 
  61.                       SSMKeyGenContextCreateArg *arg, 
  62.                       SSMResourceType type)
  63. {
  64.     SSMStatus rv;
  65.     SSMControlConnection * parent = arg->parent;
  66.     rv = SSMResource_Init(parent, SSMRESOURCE(ct), type);
  67.     if (rv != PR_SUCCESS) goto loser;
  68.     ct->m_parent = parent;
  69.     ct->m_ctxtype = arg->type;
  70.     if (arg->param) {
  71.         ct->super.m_clientContext.data = arg->param->data;
  72.         ct->super.m_clientContext.len  = arg->param->len;
  73.     }
  74.     /*
  75.      *  Create full keyGenContext for CRMF request and 
  76.      *  keyGenContext-light for old-style keygen.
  77.      *  Differentiate on arg->type.
  78.      */
  79.     switch (arg->type) { 
  80.       case SSM_CRMF_KEYGEN:
  81.         /* Create message queue and key collection. */
  82.         ct->m_incomingQ = SSM_NewCollection();
  83.         if (!ct->m_incomingQ) goto loser;
  84.         ct->m_serviceThread = SSM_CreateThread(SSMRESOURCE(ct),
  85.                                                SSMKeyGenContext_ServiceThread);
  86.         if (!ct->m_serviceThread)
  87.           goto loser;
  88.         break;
  89.       case SSM_OLD_STYLE_KEYGEN:
  90.         /* don't need to do anything */
  91.         ct->m_serviceThread = NULL;
  92.         SSM_DEBUG("Creating a keygen context for old-style keygen.n");
  93.         break;
  94.       default:
  95.         goto loser;
  96.         break;
  97.     }
  98.       
  99.     /* this is temporary hack, need to send this event in any case -jane */
  100.     rv = SSMControlConnection_SendUIEvent(ct->m_parent,
  101.                                           "get",
  102.                                           "keygen_window",
  103.                                           SSMRESOURCE(ct),
  104.                                           NULL,
  105.                                           &SSMRESOURCE(ct)->m_clientContext,
  106.                                           PR_FALSE);
  107.     /*
  108.      * UI isn't crucial for the keygen to work, don't bail if sending UI
  109.      * didn't work.
  110.      */
  111.     if (arg->type == SSM_CRMF_KEYGEN) {
  112.       rv = SSM_SendQMessage(ct->m_incomingQ, SSM_PRIORITY_SHUTDOWN,
  113.                           SSM_KEYGEN_CXT_MESSAGE_DATA_PROVIDER_OPEN,
  114.                           0, NULL, PR_FALSE);
  115.       if (rv != PR_SUCCESS)
  116.         goto loser;
  117.       ct->m_keyGens = SSM_ZNEW_ARRAY(SSMKeyGenParams*, DEFAULT_KEY_GEN_ALLOC);
  118.       if (ct->m_keyGens == NULL) {
  119.         goto loser;
  120.       }
  121.     }
  122.     ct->m_numKeyGens = 0;
  123.     ct->m_allocKeyGens = DEFAULT_KEY_GEN_ALLOC;
  124.     ct->m_eaCert = NULL;
  125.     ct->m_userCancel = PR_FALSE;
  126.     goto done;
  127.  loser:
  128.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  129.     ct->m_serviceThread = PR_GetCurrentThread();
  130.  done:
  131. /* 
  132. Prevent the control thread from responding if we successfully
  133. created this object. This is because we want to make sure that
  134. the Create Resource response is sent before the UI event due
  135. to total weirdness in the browser. 
  136. See SSMKeyGenContext_ServiceThread below; at the top of that
  137. routine, the Create Resource request is sent just before the
  138. UI event.
  139. "Icepicks in my forehead!" 
  140.                 (Only needs that for CRMF context)
  141. */
  142. if (rv == PR_SUCCESS && arg->type == SSM_CRMF_KEYGEN) 
  143.           rv = SSM_ERR_DEFER_RESPONSE;
  144.     return rv;
  145. }
  146. SSMStatus
  147. SSMKeyGenContext_Shutdown(SSMResource *res, SSMStatus status)
  148. {
  149.     SSMKeyGenContext *ct = (SSMKeyGenContext *) res;
  150.     SSMStatus rv = PR_SUCCESS, trv;
  151.     SSMKeyGenContext_Invariant(ct);
  152.     SSM_LockResource(res);
  153.     if (res->m_resourceShutdown) {
  154.         rv = SSM_ERR_ALREADY_SHUT_DOWN;
  155.     } else {
  156.         /* If this is the service thread, deregister it. */
  157.         rv = SSMResource_Shutdown(res, status);
  158.         
  159.         if (rv == PR_SUCCESS)
  160.         {
  161.             /* Post shutdown msgs to all applicable queues. */
  162.             
  163.             if (status != PR_SUCCESS && ct->m_incomingQ)
  164.                 trv = SSM_SendQMessage(ct->m_incomingQ,
  165.                                        SSM_PRIORITY_SHUTDOWN,
  166.                                        SSM_DATA_PROVIDER_SHUTDOWN,
  167.                                        0, NULL, PR_TRUE);
  168.             
  169.             /* Wake up the keygen thread */
  170.             if (ct->m_serviceThread)
  171.                 PR_Interrupt(ct->m_serviceThread);
  172.         }
  173.     }
  174.     SSM_NotifyResource(res);
  175.     res->m_resourceShutdown = PR_TRUE;
  176.     SSM_UnlockResource(res);
  177.     return rv;
  178. }
  179. SSMStatus
  180. SSMKeyGenContext_Destroy(SSMResource *res, PRBool doFree)
  181. {
  182.     SSMKeyGenContext *ct = (SSMKeyGenContext *) res;
  183.     int i;
  184.     
  185.     PR_ASSERT(SSM_IsAKindOf(res, SSM_RESTYPE_KEYGEN_CONTEXT));
  186.     PR_ASSERT(res->m_threadCount == 0);
  187.     SSM_LockResource(res);
  188.     if (ct->slot) 
  189.         PK11_FreeSlot(ct->slot);
  190.     
  191.     ct->slot = NULL; 
  192.     if (ct->m_incomingQ)
  193.         ssm_DrainAndDestroyQueue(&ct->m_incomingQ);
  194.     if (ct->m_eaCert != NULL) {
  195.         CERT_DestroyCertificate(ct->m_eaCert);
  196.     }
  197.     ct->m_eaCert = NULL;
  198.     if (ct->m_keyGens) {
  199.         for (i=0; i<ct->m_numKeyGens; i++) {
  200.             SSM_FreeResource(SSMRESOURCE(ct->m_keyGens[i]->kp));
  201.             PR_Free(ct->m_keyGens[i]);
  202.             ct->m_keyGens[i] = NULL;
  203.         }
  204.         PR_Free(ct->m_keyGens);
  205.         ct->m_keyGens = NULL;
  206.     }
  207.     
  208.     SSM_UnlockResource(res); /* we're done, stand aside for superclass */
  209.     SSMResource_Destroy(res, PR_FALSE); /* destroy superclass fields */
  210.     if (doFree)
  211.         PR_DELETE(res);
  212.     return PR_SUCCESS;
  213. }
  214. /* 
  215.    SSMKeyGenContext_Create creates an SSMKeyGenContext object. 
  216.    The value argument is ignored.
  217. */
  218. SSMStatus
  219. SSMKeyGenContext_Create(void *arg, SSMControlConnection * connection, 
  220.                         SSMResource **res)
  221. {
  222.     SSMStatus rv = PR_SUCCESS;
  223.     SSMKeyGenContext *ct;
  224.     SSMKeyGenContextCreateArg *carg = (SSMKeyGenContextCreateArg *) arg;
  225.     *res = NULL; /* in case we fail */
  226.     if (!arg)
  227.     {
  228.         rv = PR_INVALID_ARGUMENT_ERROR;
  229.         goto loser;
  230.     }
  231.     ct = (SSMKeyGenContext *) PR_CALLOC(sizeof(SSMKeyGenContext));
  232.     if (!ct) 
  233.     {
  234.         rv = PR_OUT_OF_MEMORY_ERROR;
  235.         goto loser;
  236.     }
  237.     SSMRESOURCE(ct)->m_connection = connection;
  238.     rv = SSMKeyGenContext_Init(ct, carg, SSM_RESTYPE_KEYGEN_CONTEXT);
  239.     if ((rv != PR_SUCCESS) && (rv != SSM_ERR_DEFER_RESPONSE)) goto loser;
  240.     SSMKeyGenContext_Invariant(ct);
  241.     
  242.     *res = &ct->super;
  243.     return rv;
  244.  loser:
  245.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  246.     if (ct) 
  247.     {
  248.         SSM_ShutdownResource(SSMRESOURCE(ct), rv); /* force destroy */
  249.         SSM_FreeResource(&ct->super);
  250.     }
  251.     return rv;
  252. }
  253. SSMStatus
  254. SSMKeyGenContext_FormSubmitHandler(SSMResource * res, HTTPRequest * req)
  255. {
  256.    SSMStatus rv = SSM_FAILURE;
  257.    char * tmpStr = NULL;
  258.   /* make sure you got the right baseRef */
  259.   rv = SSM_HTTPParamValue(req, "baseRef", &tmpStr);
  260.   if (rv != SSM_SUCCESS ||
  261.       PL_strcmp(tmpStr, "windowclose_doclose_js") != 0) {
  262.     goto loser;
  263.   }
  264.   if (!res->m_formName)
  265.     goto loser;
  266.   if (PL_strcmp(res->m_formName, "set_db_password") == 0)
  267.     return rv = SSM_SetDBPasswordHandler(req);
  268.   else 
  269.     goto loser;
  270. loser:
  271.   return SSM_HTTPDefaultCommandHandler(req);
  272. }
  273. SSMStatus 
  274. SSMKeyGenContext_Print(SSMResource   *res,
  275.                        char *fmt,
  276.                        PRIntn numParams,
  277.                        char **value,
  278.                        char **resultStr)
  279. {
  280.     SSMKeyGenContext  *ct              = (SSMKeyGenContext*)res;
  281.     char              *escrowCAName    = NULL;
  282.     SSMTextGenContext *textGenCxt      = NULL;
  283.     SSMStatus          rv = PR_FAILURE;
  284.     char              mechStr[48];
  285.     PR_ASSERT(resultStr != NULL);
  286.     if (resultStr == NULL) {
  287.         return PR_FAILURE;
  288.     }
  289.     if (!SSM_IsAKindOf(res, SSM_RESTYPE_KEYGEN_CONTEXT)) {
  290.         goto loser;
  291.     }
  292.     /* 
  293.      * arghh, this function thinks it's always called for key escrow dialog.
  294.      * not so, it is also called for set password dialog, and maybe called for
  295.      * other things too. 
  296.      * Assume, if no param values are supplied through the arguments, it is
  297.      * indeed key escrow case, otherwise use arguments.
  298.      */
  299.     if (!numParams) {
  300.         if (ct->m_eaCert != NULL) {
  301.             escrowCAName = CERT_GetCommonName(&ct->m_eaCert->subject);
  302.         }
  303.         if(escrowCAName == NULL) {
  304.             if (SSMTextGen_NewTopLevelContext(NULL, &textGenCxt) != 
  305.                 SSM_SUCCESS) 
  306.                 goto loser;
  307.             
  308.             rv = SSM_FindUTF8StringInBundles(textGenCxt, 
  309.                                              "certificate_authority_text",
  310.                                              &escrowCAName); 
  311.             if (rv != PR_SUCCESS)
  312.                 goto loser;
  313.         }
  314.         /* The escrow name should be in a format we can print already. */
  315.         /* We supply one parameter to NLS_MessageFormat, the resource ID. */
  316.         PR_snprintf(mechStr, 48, "%d", 
  317.                     SSMKeyGenContext_GenMechToAlgMech(ct->mech));
  318.         *resultStr = PR_smprintf(fmt, res->m_id, mechStr, escrowCAName);
  319.     } else 
  320.         SSMResource_Print(res, fmt, numParams, value, resultStr);
  321.     
  322.     rv = (*resultStr == NULL) ? PR_FAILURE : PR_SUCCESS;
  323.  loser:
  324.     PR_FREEIF(escrowCAName);
  325.     return rv;
  326. }
  327. SSMStatus SSMKeyGenContext_SetEscrowAuthority(SSMKeyGenContext *ct,
  328.                                              char             *base64Cert)
  329. {
  330.     SECItem   derCert = { siBuffer, NULL, 0 };
  331.     SECStatus rv;
  332.     if (base64Cert    == NULL ||
  333.         ct->m_eaCert != NULL) {
  334.         return PR_FAILURE;
  335.     }
  336.     rv = ATOB_ConvertAsciiToItem(&derCert, base64Cert);
  337.     if (rv != SECSuccess) {
  338.         goto loser;
  339.     }
  340.     ct->m_eaCert = CERT_NewTempCertificate(ct->super.m_connection->m_certdb,
  341.                                            &derCert, NULL, PR_FALSE, PR_TRUE);
  342.     if (ct->m_eaCert == NULL) {
  343.         goto loser;
  344.     }
  345.     return PR_SUCCESS;
  346.  loser:
  347.     if (ct->m_eaCert != NULL) {
  348.         CERT_DestroyCertificate(ct->m_eaCert);
  349.     }
  350.     ct->m_eaCert = NULL;
  351.     return PR_FAILURE;
  352. }
  353. /*
  354.  * This function is very similar to SECMOD_FindSlotByName.
  355.  * The main difference is that we want to look for the slot
  356.  * name and then see if a token exists.  The NSS version looks
  357.  * at the token name if the token is present when doing this.
  358.  */
  359. PK11SlotInfo*
  360. SSM_FindSlotByNameFromModule(SECMODModule *module, char *slotName)
  361. {
  362.     int i;
  363.     PK11SlotInfo *currSlot = NULL;
  364.     char *currSlotName = NULL;
  365.     
  366.     for (i=0; i<module->slotCount; i++) {
  367.         currSlot = module->slots[i];
  368.         if (currSlot == NULL) {
  369.             continue;
  370.         }
  371.         currSlotName = PK11_GetSlotName(currSlot);
  372.         if (currSlotName == NULL) {
  373.             continue;
  374.         }
  375.         if (PL_strcmp(currSlotName, slotName) == 0 &&
  376.             PK11_IsPresent(currSlot)) {
  377.             return currSlot;
  378.         }
  379.     }
  380.     return NULL;
  381. }
  382. PK11SlotInfo*
  383. SSM_FindSlotByName(SSMControlConnection *conn, char *slotName)
  384. {
  385.     SECMODModuleList *modList, *currMod;
  386.     PK11SlotInfo *slot = NULL;
  387.     modList = SECMOD_GetDefaultModuleList();
  388.     currMod = modList;
  389.     /*
  390.      * Iterate through the modules looking for the correct slot.
  391.      */
  392.     while (currMod != NULL && currMod->module != NULL) {
  393.         slot = SSM_FindSlotByNameFromModule(currMod->module, slotName);
  394.         if (slot != NULL){
  395.             return PK11_ReferenceSlot(slot);
  396.         }
  397.         currMod = currMod->next;
  398.     }
  399.     return NULL;
  400. }
  401. SSMStatus SSMKeyGenContext_SetDefaultToken(SSMKeyGenContext *ct, 
  402.                                            CMTItem          *string,
  403.                                            PRBool            bySlotName)
  404. {
  405.     PK11SlotInfo *oldSlot;
  406.     oldSlot = ct->slot;
  407.     ct->slot = NULL;
  408.     ct->m_slotName = SSM_NEW_ARRAY(char, (string->len+1));
  409.     if (ct->m_slotName == NULL) {
  410.         goto loser;
  411.     }
  412.     memcpy(ct->m_slotName, string->data, string->len);
  413.     ct->m_slotName[string->len] = '';
  414.     if (bySlotName) {
  415.         ct->slot = SSM_FindSlotByName(ct->super.m_connection, ct->m_slotName);
  416.     } else {
  417.         ct->slot = PK11_FindSlotByName(ct->m_slotName);
  418.     }
  419.     if (ct->slot == NULL) {
  420.         goto loser;
  421.     }
  422.     if (oldSlot != NULL) {
  423.         PK11_FreeSlot(oldSlot);
  424.     }
  425.     return SSM_SUCCESS;
  426.  loser:
  427.     if (ct->slot) {
  428.         PK11_FreeSlot(ct->slot);
  429.     }
  430.     ct->slot = oldSlot;
  431.     if (ct->m_slotName) {
  432.         PR_Free(ct->m_slotName);
  433.         ct->m_slotName = NULL;
  434.     }
  435.     return SSM_FAILURE;
  436. }
  437. SSMStatus SSMKeyGenContext_SetAttr(SSMResource *res,
  438.                                   SSMAttributeID attrID,
  439.                                   SSMAttributeValue *value)
  440. {
  441.     SSMKeyGenContext *ct = (SSMKeyGenContext*)res;
  442.     SSMStatus rv = PR_FAILURE;
  443.     PR_ASSERT(SSM_IsAKindOf(res, SSM_RESTYPE_KEYGEN_CONTEXT));
  444.     switch(attrID) {
  445.     case SSM_FID_KEYGEN_ESCROW_AUTHORITY:
  446.       SSM_DEBUG("Setting the Escrow Authority to n%sn", value->u.string.data);
  447.       if (value->type != SSM_STRING_ATTRIBUTE) {
  448.           goto loser;
  449.       }
  450.       rv = SSMKeyGenContext_SetEscrowAuthority(ct, (char *) value->u.string.data);
  451.       break;
  452.     case SSM_FID_CLIENT_CONTEXT:
  453.       SSM_DEBUG("Setting the Key Gen UI contextn");
  454.       if (value->type != SSM_STRING_ATTRIBUTE) {
  455.           goto loser;
  456.       }
  457.       if (!(res->m_clientContext.data = (unsigned char *) PR_Malloc(value->u.string.len))) {
  458.           goto loser;
  459.       }
  460.       memcpy(res->m_clientContext.data, value->u.string.data, value->u.string.len);
  461.       res->m_clientContext.len = value->u.string.len;
  462.       rv = SSM_SUCCESS;
  463.       break;
  464.     case SSM_FID_KEYGEN_SLOT_NAME:
  465.         rv = SSMKeyGenContext_SetDefaultToken(ct, &value->u.string, PR_TRUE);
  466.         break;
  467.     case SSM_FID_KEYGEN_TOKEN_NAME:
  468.         rv = SSMKeyGenContext_SetDefaultToken(ct, &value->u.string, PR_FALSE);
  469.         break;
  470.     case SSM_FID_DISABLE_ESCROW_WARN:
  471.       ct->m_disableEscrowWarning = PR_TRUE;
  472.       rv = SSM_SUCCESS;
  473.       break;
  474.     default:
  475.       rv = SSMResource_SetAttr(res, attrID, value);
  476.       break;
  477.     }
  478.     return rv;
  479. loser:
  480.     return PR_FAILURE;
  481. }
  482. SSMStatus SSMKeyGenContext_GetAttr(SSMResource *res,
  483.                                    SSMAttributeID attrID,
  484.                                    SSMResourceAttrType attrType,
  485.                                    SSMAttributeValue *value)
  486. {
  487.     SSMKeyGenContext *cxt;
  488.     SSMStatus rv;
  489.     PR_ASSERT(SSM_IsAKindOf(res, SSM_RESTYPE_KEYGEN_CONTEXT));
  490.     cxt = (SSMKeyGenContext*)res;
  491.     switch(attrID) {
  492.     case SSM_FID_CLIENT_CONTEXT:
  493.       SSM_DEBUG("Getting the Key Gen UI context");
  494.       value->type = SSM_STRING_ATTRIBUTE;
  495.       if (!(value->u.string.data = (unsigned char *) PR_Malloc(res->m_clientContext.len))) {
  496.           goto loser;
  497.       }
  498.       memcpy(value->u.string.data, res->m_clientContext.data, res->m_clientContext.len);
  499.       value->u.string.len = res->m_clientContext.len;
  500.       break;
  501.     case SSM_FID_CHOOSE_TOKEN_URL:
  502.       {
  503.         PRUint32 width, height;
  504.         char * mech, *url;
  505.         mech = PR_smprintf("mech=%d&task=keygen&unused=unused",
  506.                            SSMKeyGenContext_GenMechToAlgMech(cxt->mech));
  507.         rv = SSM_GenerateURL(res->m_connection,"get", "select_token", res, 
  508.                              mech, &width, &height, &url);
  509.         PR_FREEIF(mech);
  510.         if (rv != SSM_SUCCESS) {
  511.             goto loser;
  512.         }
  513.         value->u.string.data = (unsigned char*)url;
  514.         value->u.string.len  = PL_strlen(url);
  515.         value->type = SSM_STRING_ATTRIBUTE;
  516.       }
  517.       break;
  518.     case SSM_FID_INIT_DB_URL:
  519.       {
  520.           char *url;
  521.           
  522.           url = SSM_GenerateChangePasswordURL(cxt->slot, res);
  523.           if (url == NULL){
  524.               goto loser;
  525.           }
  526.           value->u.string.data = (unsigned char*)url;
  527.           value->u.string.len  = PL_strlen(url);
  528.           value->type = SSM_STRING_ATTRIBUTE;
  529.       }
  530.       break;
  531.     default:
  532.       SSM_DEBUG("Got unkown KeyGenContext Get Attribute Request %dn", attrID);
  533.       goto loser;
  534.       break;
  535.     }
  536.     return PR_SUCCESS;
  537. loser:
  538.     value->type = SSM_NO_ATTRIBUTE;
  539.     return PR_FAILURE;
  540. }
  541. /* As a sanity check, make sure we have data structures consistent
  542.    with our type. */
  543. void SSMKeyGenContext_Invariant(SSMKeyGenContext *ct)
  544. {
  545. #ifdef DEBUG
  546.     if (ct)
  547.     {
  548.         SSMResource_Invariant(&(ct->super));
  549.         SSM_LockResource(SSMRESOURCE(ct));
  550.         PR_ASSERT(SSM_IsAKindOf(SSMRESOURCE(ct), SSM_RESTYPE_KEYGEN_CONTEXT));
  551.         PR_ASSERT(ct->m_ctxtype == SSM_CRMF_KEYGEN || 
  552.                   ct->m_ctxtype == SSM_OLD_STYLE_KEYGEN);
  553.         if (ct->m_ctxtype == SSM_CRMF_KEYGEN) {
  554.           PR_ASSERT(ct->m_incomingQ != NULL);
  555. #if 0
  556.           PR_ASSERT(ct->m_serviceThread != NULL); /* context == service thread */
  557. #endif /* If the user canceled, then this thread will be NULL. */
  558.         }
  559.         SSM_UnlockResource(SSMRESOURCE(ct));
  560.     }
  561. #endif
  562. }
  563. static SSMStatus
  564. ssm_process_next_pqg_param(SECItem *dest, unsigned char *curParam)
  565. {
  566.     PRUint32 tmpLong;
  567.     tmpLong = PR_ntohl(*(PRUint32*)curParam);
  568.     dest->len = tmpLong;
  569.     curParam += sizeof (PRUint32);
  570.     dest->data = PORT_ZNewArray(unsigned char, tmpLong);
  571.     PORT_Memcpy(dest->data, curParam, tmpLong);
  572.     return PR_SUCCESS;
  573. }
  574. void*
  575. ssm_ConvertToActualKeyGenParams(PRUint32 keyGenMech, unsigned char *params,
  576. PRUint32 paramLen, PRUint32 keySize)
  577. {
  578.     void          *returnParams = NULL;
  579.     unsigned char *curPtr;
  580.     PRUint32       tmpLong;
  581.     if (params != NULL && paramLen > 0) {
  582.         curPtr = params;
  583.         switch (keyGenMech) {
  584. case CKM_RSA_PKCS_KEY_PAIR_GEN:
  585.   {
  586.       PK11RSAGenParams *rsaParams;
  587.       
  588.       rsaParams = PORT_New(PK11RSAGenParams);
  589.       if (rsaParams == NULL) {
  590.   return NULL;
  591.       }
  592.       rsaParams->keySizeInBits = keySize;
  593.       tmpLong = PR_ntohl(*(PRUint32*)curPtr);
  594.       rsaParams->pe = (unsigned long) tmpLong;
  595.       returnParams = rsaParams;
  596.       break;
  597.   }
  598. case CKM_DSA_KEY_PAIR_GEN:
  599.   {
  600.       PQGParams *pqgParams;
  601.       pqgParams = PORT_ZNew(PQGParams);
  602.       if (pqgParams == NULL) {
  603.   return NULL;
  604.       }
  605.       ssm_process_next_pqg_param(&pqgParams->prime, curPtr);
  606.       curPtr += sizeof(PRUint32) + pqgParams->prime.len;
  607.       ssm_process_next_pqg_param(&pqgParams->subPrime, curPtr);
  608.       curPtr += sizeof(PRUint32) + pqgParams->subPrime.len;
  609.       ssm_process_next_pqg_param(&pqgParams->base, curPtr);
  610.       returnParams = pqgParams;
  611.       break;
  612.   }
  613. default:
  614.     returnParams = NULL;
  615. }
  616.     } else {
  617.         /* In this case we provide the parameters ourselves. */
  618.         switch (keyGenMech) {
  619. case CKM_RSA_PKCS_KEY_PAIR_GEN:
  620.   {
  621.       PK11RSAGenParams *rsaParams;
  622.       rsaParams = PORT_New(PK11RSAGenParams);
  623.       if (rsaParams == NULL) {
  624.   return NULL;
  625.       }
  626.       /* I'm just taking the same parameters used in 
  627.        * certdlgs.c:GenKey
  628.        */
  629.       if (keySize > 0) {
  630.   rsaParams->keySizeInBits = keySize;
  631.       } else {
  632.   rsaParams->keySizeInBits = 1024;
  633.       }
  634.       rsaParams->pe = 65537L;
  635.       returnParams = rsaParams;
  636.       break;
  637.   }
  638. case CKM_DSA_KEY_PAIR_GEN:
  639.   {
  640.       PQGParams *pqgParams = NULL;
  641.               PQGVerify *vfy = NULL;
  642.       SECStatus  rv;
  643.       int        index;
  644.       
  645.       index = PQG_PBITS_TO_INDEX(keySize);
  646.       if (index == -1) {
  647. returnParams = NULL;
  648. break;
  649.       }
  650.       rv = PQG_ParamGen(0, &pqgParams, &vfy);
  651.               if (vfy) {
  652.                   PQG_DestroyVerify(vfy);
  653.               }
  654.       if (rv != SECSuccess) {
  655.   if (pqgParams) {
  656.       PQG_DestroyParams(pqgParams);
  657.   }
  658.   return NULL;
  659.       }
  660.       returnParams = pqgParams;
  661.       break;
  662.   }
  663. default:
  664.   returnParams = NULL;
  665. }
  666.     }
  667.     return returnParams;
  668. }
  669. static void
  670. ssm_FreeKeyGenParams(CK_MECHANISM_TYPE keyGenMechanism, void *params)
  671. {
  672.     switch (keyGenMechanism) {
  673.     case CKM_RSA_PKCS_KEY_PAIR_GEN:
  674.         PORT_Free(params);
  675. break;
  676.     case CKM_DSA_KEY_PAIR_GEN:
  677. PQG_DestroyParams((PQGParams*) params);
  678. break;
  679.     }
  680. }
  681. SSMStatus 
  682. SSMKeyGenContext_BeginGeneratingKeyPair(SSMControlConnection * ctrl,
  683.                                         SECItem *msg, SSMResourceID *destID)
  684. {
  685.     SSMKeyGenContext    *ct=NULL;
  686.     SSMKeyGenParams        *kg=NULL;
  687.     SSMKeyPair          *kp=NULL; 
  688.     void                *actualParams=NULL;
  689.     SSMStatus             rv = PR_SUCCESS;
  690.     SSMKeyPairArg        keyPairArg;
  691.     KeyPairGenRequest request;
  692.     if (msg == NULL || msg->data == NULL || destID == NULL) 
  693.         return PR_INVALID_ARGUMENT_ERROR;
  694.     if (CMT_DecodeMessage(KeyPairGenRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
  695.         goto loser;
  696.     }
  697.     /* Find the requested key gen context. */
  698.     rv = SSMControlConnection_GetResource(ctrl, request.keyGenCtxtID,
  699.                                           (SSMResource **) &ct);
  700.     if (rv != PR_SUCCESS) 
  701. goto loser;
  702.     if ((!ct) || 
  703.         (!SSM_IsAKindOf(SSMRESOURCE(ct), SSM_RESTYPE_KEYGEN_CONTEXT)))
  704.     {
  705.         rv = PR_INVALID_ARGUMENT_ERROR;
  706.         goto loser;
  707.     }
  708.     if (ct->m_userCancel) {
  709.         rv = (SSMStatus)SSM_ERR_USER_CANCEL;
  710.         goto loser;
  711.     }
  712.     if (!SSM_KeyGenAllowedForSize(request.keySize)) {
  713.         goto loser;
  714.     }
  715.     /* Convert to actual key generation params. */
  716.     actualParams = ssm_ConvertToActualKeyGenParams(request.genMechanism, 
  717.                                                    request.params.data, request.params.len,
  718.                                                    request.keySize);
  719.     if (actualParams == NULL)  {
  720. goto loser;
  721. }
  722.     /* Create a key pair resource so that we can return its ID. */
  723.     keyPairArg.keyGenContext = ct;
  724.     if ((rv = SSMKeyPair_Create(&keyPairArg, SSMRESOURCE(ct)->m_connection, 
  725.                                 (SSMResource **) &kp)) != PR_SUCCESS)
  726.         goto loser;
  727.     /* Create a parameter lump with which we'll generate the key
  728.        later. */
  729.     if (!(kg = (SSMKeyGenParams *) PR_CALLOC(sizeof(SSMKeyGenParams)))) {
  730. goto loser;
  731. }
  732.     kg->keyGenMechanism = request.genMechanism;
  733.     kg->kp = kp;
  734.     kg->actualParams = actualParams;
  735.     SSM_LockResource(SSMRESOURCE(ct));
  736.     if (ct->m_numKeyGens == ct->m_allocKeyGens) {
  737.         int newSize = ct->m_allocKeyGens * 2;
  738.         SSMKeyGenParams **tmp = (SSMKeyGenParams **) 
  739.             PR_Realloc(ct->m_keyGens,
  740.                        sizeof(SSMKeyGenParams*)*newSize);
  741.         if (tmp == NULL) {
  742.             rv = PR_FAILURE;
  743.             SSM_UnlockResource(SSMRESOURCE(ct));
  744.             goto loser;
  745.         }
  746.         ct->m_keyGens = tmp;
  747.         ct->m_allocKeyGens = newSize;
  748.     }
  749.     ct->m_keyGens[ct->m_numKeyGens] = kg;
  750.     ct->m_numKeyGens++;
  751.     SSM_UnlockResource(SSMRESOURCE(ct));
  752.     SSM_FreeResource(&kp->super);
  753.     *destID = kp->super.m_id;
  754.     goto done;
  755.  loser:
  756.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  757.     PR_FREEIF(kg);
  758.     /*
  759.      * Something went wrong, so we should get rid of the key gen context
  760.      * as well as locally allocated data.
  761.      */
  762.     SSM_ShutdownResource(SSMRESOURCE(ct), PR_FAILURE);
  763.  done:
  764.     SSM_FreeResource(&ct->super);
  765.     return rv;
  766. }
  767. #define SSM_PARENT_CONN(x) &((x)->m_parent->super)
  768. SSMStatus
  769. SSMKeyGenContext_FinishGeneratingKeyPair(SSMKeyGenContext *ct,
  770.                                          SSMKeyGenParams *kg)
  771. {
  772.     SSMKeyPair          *kp = NULL;
  773.     void                *actualParams = NULL;
  774.     PK11SlotInfo        *slot = NULL, *intSlot = NULL, *origSlot = NULL;
  775.     SSMStatus             rv = PR_SUCCESS;
  776.     PRUint32             keyGenMechanism;
  777.     SECKEYPublicKey      *pubKey = NULL;
  778.     SECKEYPrivateKey     *privKey = NULL;
  779.     PRBool                isPerm;
  780.     SSM_DEBUG("Inside FinishGeneratingKeyPair.n");
  781.     PR_ASSERT((kg != NULL) && (ct != NULL));
  782.     /* If the context is already exiting due to an error,
  783.        abort the key generation. */
  784.     rv = SSMRESOURCE(ct)->m_status;
  785.     if (rv != PR_SUCCESS) goto loser;
  786.     /* Restore parameters from the message. */
  787.     keyGenMechanism = kg->keyGenMechanism;
  788.     kp = kg->kp;
  789.     actualParams = kg->actualParams;
  790.     /* Finish key generation. */
  791.     if (ct->mech != kg->keyGenMechanism) {
  792.         goto loser;
  793.     }
  794.    
  795.     slot = ct->slot;
  796.     if (!slot) 
  797.       goto loser;
  798.     if (ssmkeygencontext_can_escrow(kp->m_KeyGenType) &&
  799.         ct->m_eaCert != NULL && !PK11_IsInternal(slot)) {
  800.         intSlot = PK11_GetInternalSlot();
  801.         origSlot = slot;
  802.         slot = intSlot;
  803.         isPerm = PR_FALSE;
  804.     } else {
  805.         isPerm = PR_TRUE;
  806.     }
  807.     SSM_DEBUG("Creating key pair.n");
  808.     privKey = PK11_GenerateKeyPair(slot, keyGenMechanism, 
  809.                                    actualParams,
  810.                                    &pubKey, isPerm,
  811.                                    isPerm, NULL);
  812.     if ((!privKey) || (!pubKey)) 
  813.     {
  814.         rv = PR_FAILURE;
  815.         goto loser;
  816.     }
  817.     /*
  818.      * If we generated the key pair on the internal slot because the
  819.      * keys were going to be escrowed, move the keys over right now.
  820.      */
  821.     if (intSlot != NULL) {
  822.         SECKEYPrivateKey *newPrivKey;
  823.         newPrivKey = pk11_loadPrivKey(origSlot, privKey, pubKey, 
  824.                                       PR_TRUE, PR_TRUE);
  825.         if (newPrivKey == NULL) {
  826.             rv = PR_FAILURE;
  827.             goto loser;
  828.         }
  829.         /*
  830.          * The key is stored away on the final slot now, and the
  831.          * the copy we keep around is on the internal slot so we
  832.          * can escrow it if we have to.
  833.          */
  834.         SECKEY_DestroyPrivateKey(newPrivKey);
  835.         PK11_FreeSlot(intSlot);
  836.         intSlot = NULL;
  837.     }
  838.     /* Put the newly generated keys into the key pair object. */
  839.     kp->m_PubKey = pubKey;
  840.     kp->m_PrivKey = privKey;
  841.     /* Set the wincx of the private key so that crypto operations 
  842.      * that use the signing key as the source for the wincx pass
  843.      * a non NULL value to the authentication functions.
  844.      */
  845.     kp->m_PrivKey->wincx = kp->super.m_connection;
  846.     goto done;
  847.  loser:
  848.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  849.     /* Destroy keys if we've generated them. */
  850.     if (pubKey)
  851.         SECKEY_DestroyPublicKey(pubKey);
  852.     if (privKey)
  853.         SECKEY_DestroyPrivateKey(privKey);
  854.  done:
  855.     /* Free the PKCS11 key gen params. */
  856.     if (actualParams != NULL)
  857.         ssm_FreeKeyGenParams(keyGenMechanism, actualParams);
  858.     SSM_DEBUG("FinishGeneratingKeyPair returned rv = %d.n", rv);
  859.     return rv;
  860. }
  861. void
  862. SSMKeyGenContext_SendCompleteEvent(SSMKeyGenContext *ct)
  863. {
  864.     SSMStatus rv = PR_SUCCESS;
  865.     PR_ASSERT(ct->m_parent);
  866.     if (ct->m_parent)
  867.     {
  868.         SECItem msg;
  869.         TaskCompletedEvent event;
  870.         /* Assemble the event. */
  871.         SSM_DEBUG("Task completed event: id %ld, count %ld, status %dn",
  872.                   SSMRESOURCE(ct)->m_id, ct->m_count, 
  873.                   SSMRESOURCE(ct)->m_status);
  874.         event.resourceID = SSMRESOURCE(ct)->m_id;
  875.         event.numTasks = ct->m_count;
  876.         event.result = SSMRESOURCE(ct)->m_status;
  877.         if (CMT_EncodeMessage(TaskCompletedEventTemplate, (CMTItem*)&msg, (CMTItem*)&event) != CMTSuccess) {
  878.             return;
  879.         }
  880.         if (msg.data)
  881.         {
  882.             /* Send the event to the control queue. */
  883.             rv = SSM_SendQMessage(ct->m_parent->m_controlOutQ,
  884.                                   SSM_PRIORITY_NORMAL,
  885.                                   SSM_EVENT_MESSAGE | SSM_TASK_COMPLETED_EVENT,
  886.                                   (int) msg.len, (char *) msg.data, PR_FALSE);
  887.             SSM_DEBUG("Sent message, rv = %d.n", rv);
  888.         }
  889.     }
  890. }
  891. SSMStatus
  892. SSMKeyGenContext_SendEscrowWarning(SSMKeyGenContext   *ct,
  893.                                    SSMEscrowWarnParam *escrowParam)
  894. {
  895.     SSMStatus rv;
  896.     rv = SSMControlConnection_SendUIEvent(SSMRESOURCE(ct)->m_connection,
  897.                                           "get", "escrow_warning",
  898.                                           SSMRESOURCE(ct), NULL, 
  899.                                           &SSMRESOURCE(ct)->m_clientContext,
  900.                                           PR_FALSE);
  901.     if (rv != SSM_SUCCESS) {
  902.         goto loser;
  903.     }
  904.     PR_ASSERT(SSMRESOURCE(ct)->m_buttonType == SSM_BUTTON_NONE);
  905.     while (SSMRESOURCE(ct)->m_buttonType == SSM_BUTTON_NONE) {
  906.       SSM_WaitForOKCancelEvent(SSMRESOURCE(ct), PR_INTERVAL_NO_TIMEOUT);
  907.     }
  908.     /* ### sjlee: this unfortunate hack is due to the fact that bad things
  909.      *            happen if we do not finish closing the window before
  910.      *            another window pops up: this will be supplanted by a
  911.      *            more complete fix later
  912.      */
  913.     PR_Sleep(PR_TicksPerSecond()*2);
  914.     return (SSMRESOURCE(ct)->m_buttonType == SSM_BUTTON_OK) ? PR_SUCCESS :
  915.                                                               PR_FAILURE;
  916.  loser:
  917.     return PR_FAILURE;
  918. }
  919. static PRBool
  920. ssmkeygencontext_can_escrow(SSMKeyGenType keyGenType)
  921. {
  922.     /* For now, we only escrow rsa-encryption keys. */
  923.     return (PRBool)(keyGenType == rsaEnc);
  924. }
  925. static SSMStatus
  926. ssmkg_DoKeyEscrowWarning(SSMKeyGenContext *ct)
  927. {
  928.   int i;
  929.   SSMStatus rv = PR_SUCCESS;
  930.   if (ct->m_eaCert == NULL || ct->m_disableEscrowWarning) {
  931.     /* No Escrow Authority Certificate, return Success so that
  932.      * key generation continues.
  933.      */
  934.     return PR_SUCCESS;
  935.   }
  936.   for (i=0; i < ct->m_numKeyGens; i++) {
  937.       if (ssmkeygencontext_can_escrow(ct->m_keyGens[i]->kp->m_KeyGenType)) {
  938.           rv = SSMKeyGenContext_SendEscrowWarning(ct, NULL);
  939.           break;
  940.       }
  941.   }
  942.   return rv;
  943. }
  944. SSMStatus
  945. SSMKeyGenContext_GenerateAllKeys(SSMKeyGenContext *ct)
  946. {
  947.     SSMStatus rv = PR_FAILURE;
  948.     int i;
  949.     /* Make sure the UI is up before we start. */
  950.     PR_Sleep(PR_TicksPerSecond()*2);    
  951.     /* First figure out if we are going to try and escrow,
  952.      * pop up UI if we are
  953.      */
  954.     rv = ssmkg_DoKeyEscrowWarning(ct);
  955.     if (rv != PR_SUCCESS) {
  956.         /* Tell the service thread to shut itself down. */
  957.         SSM_SendQMessage(ct->m_incomingQ,
  958.                          SSM_PRIORITY_SHUTDOWN,
  959.                          SSM_DATA_PROVIDER_SHUTDOWN,
  960.                          0, NULL, PR_TRUE);
  961.         goto loser;
  962.     }
  963.     /*
  964.      * We'll force all key gens to use the same mechanism so that when
  965.      * we create dual keys, we won't prompt the user multiple times for
  966.      * a slot to create the keys on.
  967.      */
  968.     PR_ASSERT(ct->m_numKeyGens > 0);
  969.     ct->mech = ct->m_keyGens[0]->keyGenMechanism;
  970.     rv = SSMKeyGenContext_GetSlot(ct, ct->mech); 
  971.     if (rv != SSM_SUCCESS) 
  972.         goto loser;
  973.     for (i=0; i<ct->m_numKeyGens; i++) {
  974.         /* Lock so that we can finish a keygen without the state
  975.            changing underneath us. */
  976.         SSM_DEBUG("Waiting for lock in order to start new keygen.n", rv);
  977.         SSM_LockResource(SSMRESOURCE(ct));
  978.         /* Do key generation. */
  979.         rv = SSMKeyGenContext_FinishGeneratingKeyPair(ct, ct->m_keyGens[i]);
  980.         if (ct->super.m_status == PR_SUCCESS) {
  981.             ct->super.m_status = rv;
  982.         }
  983.         /* No matter what, update the completed count. */
  984.         ct->m_count++;
  985.         
  986.         /* Having finished the request, send back a Context Completed
  987.            event describing our results. */
  988.         SSM_DEBUG("Sending Task Completed event to client.n", rv);
  989.         SSMKeyGenContext_SendCompleteEvent(ct);
  990.         /* Unlock the object so that the canceller can work. */
  991.         SSM_UnlockResource(SSMRESOURCE(ct));
  992.         if (rv != PR_SUCCESS) {
  993.             
  994.             break;
  995.         }
  996.     }
  997.  loser:
  998.     if (ct != NULL) {
  999.         if (SSMRESOURCE(ct)->m_status != PR_SUCCESS) {
  1000.             rv = SSMRESOURCE(ct)->m_status;
  1001.         }
  1002.     }
  1003.     return rv;
  1004. }
  1005. void
  1006. SSMKeyGenContext_ServiceThread(void *arg)
  1007. {
  1008.     SSMKeyGenContext *ct = (SSMKeyGenContext *) arg;
  1009.     SSMResource      *res = SSMRESOURCE(ct);
  1010.     PRInt32 type, len;
  1011.     char *url = NULL;
  1012.     char *data = NULL;
  1013.     char *tmp = NULL;
  1014.     SSMStatus rv = PR_SUCCESS;
  1015.     PRBool processingKeys = PR_FALSE;
  1016.     SECItem msg;
  1017.     CreateResourceReply reply;
  1018.     PR_ASSERT(ct);
  1019.     PR_ASSERT(SSM_IsAKindOf(SSMRESOURCE(ct), SSM_RESTYPE_KEYGEN_CONTEXT));
  1020.     SSM_RegisterNewThread("keygen", (SSMResource*)arg);
  1021. SSM_DEBUG("Sending Create Resource response to client.n");
  1022.     reply.result = PR_SUCCESS;
  1023.     reply.resID = SSMRESOURCE(ct)->m_id;
  1024.     if (CMT_EncodeMessage(CreateResourceReplyTemplate, (CMTItem*)&msg, &reply) != CMTSuccess) {
  1025.         goto loser;
  1026.     }
  1027.     if (!msg.data || !msg.len) 
  1028.     {
  1029.         rv = PR_OUT_OF_MEMORY_ERROR;
  1030.         goto loser;
  1031.     }
  1032.     /* Post the message on the outgoing control channel. */
  1033. PR_ASSERT(SSM_IsAKindOf(&(ct->m_parent->super.super), SSM_RESTYPE_CONTROL_CONNECTION));
  1034.     rv = SSM_SendQMessage(ct->m_parent->m_controlOutQ, SSM_PRIORITY_NORMAL, 
  1035.                           SSM_REPLY_OK_MESSAGE 
  1036.   | SSM_RESOURCE_ACTION
  1037.   | SSM_CREATE_RESOURCE,
  1038.                           (int) msg.len, (char *) msg.data, PR_FALSE);
  1039.     if (rv != PR_SUCCESS) goto loser;
  1040.     /* Start serving key gen requests. */
  1041.     while(1)
  1042.     {
  1043.         /* Get the next request from the queue.
  1044.            If we've been cancelled or if there's an error,
  1045.            drain what we have but don't wait around. */
  1046.         SSM_DEBUG("Reading message from queue.n");
  1047. #if 1
  1048.         if (processingKeys)
  1049.         {
  1050. #endif
  1051.             SSM_DEBUG("Looking for keygen requests (and anything else).n");
  1052.             rv = SSM_RecvQMessage(ct->m_incomingQ, SSM_PRIORITY_ANY,
  1053.                                   &type, &len, &data, 
  1054.                                   (SSMRESOURCE(ct)->m_status == PR_SUCCESS));
  1055. #if 1
  1056.         }
  1057.         else
  1058.     {
  1059.             SSM_DEBUG("Looking only for open/shutdown messages.n");
  1060.             rv = SSM_RecvQMessage(ct->m_incomingQ, SSM_PRIORITY_SHUTDOWN,
  1061.                                   &type, &len, &data,
  1062.                                   PR_TRUE);
  1063.         }
  1064. #endif
  1065.         SSM_DEBUG("rv = %d reading from queue.n", rv);
  1066.         if (rv != SSM_SUCCESS) goto loser;
  1067.         
  1068.         /* If it's a keygen request, then attend to it. */
  1069.         switch (type) {
  1070.         case SSM_KEYGEN_CXT_MESSAGE_DATA_PROVIDER_OPEN:
  1071.             processingKeys = PR_TRUE;
  1072.             break;
  1073.         case SSM_KEYGEN_CXT_MESSAGE_DATA_PROVIDER_SHUTDOWN:
  1074.             goto loser; /*destroy object */
  1075.         case SSM_KEYGEN_CXT_MESSAGE_GEN_KEY:
  1076.             if (!processingKeys)
  1077.             {
  1078.                 SSM_DEBUG("**** Dropping keygen request on the floor ****n");
  1079.                 break;
  1080.             }
  1081.             rv = SSMKeyGenContext_GenerateAllKeys(ct);
  1082.             /*
  1083.              * We're done generating keys, so let's bail out of this thread.
  1084.              */
  1085.             goto loser;
  1086.         default:
  1087.             SSM_DEBUG("Don't understand this request.n");
  1088.             /* ### mwelch Don't know what to do with this request */
  1089.             rv = (SSMStatus) SSM_ERR_BAD_REQUEST;
  1090.             break;
  1091.         }
  1092.     }    
  1093.  loser:
  1094.     SSM_LockResource(res);
  1095.     /* De-register ourselves from the resource thread count. */
  1096.     if (PR_GetCurrentThread() == ct->m_serviceThread)
  1097.     {
  1098.         ct->m_serviceThread = NULL;
  1099.     }
  1100.     res->m_threadCount--;
  1101.     SSM_UnlockResource(res);
  1102.     PR_FREEIF(tmp);
  1103.     PR_FREEIF(url);
  1104. SSM_DEBUG("Shutting down keygen context.n");
  1105.     SSM_ShutdownResource(SSMRESOURCE(ct), rv);
  1106.     SSM_FreeResource(SSMRESOURCE(ct));
  1107.     SSM_DEBUG("Exiting, status %d.n", rv);
  1108. }
  1109. void
  1110. SSMKeyGenContext_CancelKeyGen(SSMKeyGenContext *ct)
  1111. {
  1112.     /* set the status so that subsequent keygen attempts will drop out */
  1113.     SSM_ShutdownResource(SSMRESOURCE(ct), SSM_ERR_USER_CANCEL);
  1114.     ct->m_userCancel = PR_TRUE;
  1115.     SSMRESOURCE(ct)->m_status = SSM_ERR_USER_CANCEL;
  1116. }
  1117. SSMStatus
  1118. SSMKeyGenContext_FinishGeneratingAllKeyPairs(SSMControlConnection *ctrl,
  1119.                                              SECItem              *msg)
  1120. {
  1121.     SSMStatus rv;
  1122.     SSMKeyGenContext *ct;
  1123.     SingleNumMessage request;
  1124.     SSM_DEBUG("SSMKeyGenContext_FinishGeneratingAllKeyPairs...n");
  1125.     if (CMT_DecodeMessage(SingleNumMessageTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
  1126.         goto loser;
  1127.     }
  1128.     rv = SSMControlConnection_GetResource(ctrl, request.value, (SSMResource **) &ct);
  1129.     if (rv != PR_SUCCESS) {
  1130.         goto loser;
  1131.     }
  1132.     if (!ct ||
  1133.         !SSM_IsAKindOf(SSMRESOURCE(ct), SSM_RESTYPE_KEYGEN_CONTEXT)) {
  1134.         rv = PR_INVALID_ARGUMENT_ERROR;
  1135.         goto loser;
  1136.     }
  1137.     if (ct->m_userCancel) {
  1138.         rv = (SSMStatus)SSM_ERR_USER_CANCEL;
  1139.         goto loser;
  1140.     }
  1141.     rv = SSM_SendQMessage(ct->m_incomingQ, SSM_PRIORITY_NORMAL, 
  1142.                           SSM_KEYGEN_CXT_MESSAGE_GEN_KEY,
  1143.                           0, NULL, PR_FALSE);
  1144.  loser:
  1145.     if (ct != NULL) {
  1146.         SSM_FreeResource(&ct->super);
  1147.     }
  1148.     return rv;
  1149. }