mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 04:27:37 +00:00
2914 lines
86 KiB
C
2914 lines
86 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* The contents of this file are subject to the Mozilla Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is the Netscape security libraries.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the
|
|
* terms of the GNU General Public License Version 2 or later (the
|
|
* "GPL"), in which case the provisions of the GPL are applicable
|
|
* instead of those above. If you wish to allow use of your
|
|
* version of this file only under the terms of the GPL and not to
|
|
* allow others to use your version of this file under the MPL,
|
|
* indicate your decision by deleting the provisions above and
|
|
* replace them with the notice and other provisions required by
|
|
* the GPL. If you do not delete the provisions above, a recipient
|
|
* may use your version of this file under either the MPL or the
|
|
* GPL.
|
|
*/
|
|
#include "ctrlconn.h"
|
|
#include "dataconn.h"
|
|
#include "sslconn.h"
|
|
#include "servimpl.h"
|
|
#include "serv.h"
|
|
#include "ssmerrs.h"
|
|
#include "certt.h"
|
|
#include "keyres.h"
|
|
#include "crmfres.h"
|
|
#include "kgenctxt.h"
|
|
#include "processmsg.h"
|
|
#include "signtextres.h"
|
|
#include "textgen.h"
|
|
#include "secmod.h"
|
|
#include "cert.h"
|
|
#include "newproto.h"
|
|
#include "messages.h"
|
|
#include "signtextres.h"
|
|
#include "advisor.h"
|
|
#include "ssl.h"
|
|
#include "protocolshr.h"
|
|
#include "msgthread.h"
|
|
#include "pk11sdr.h"
|
|
#include "sdrres.h"
|
|
|
|
#define SSL_SC_RSA 0x00000001L
|
|
#define SSL_SC_MD2 0x00000010L
|
|
#define SSL_SC_MD5 0x00000020L
|
|
#define SSL_SC_RC2_CBC 0x00001000L
|
|
#define SSL_SC_RC4 0x00002000L
|
|
#define SSL_SC_DES_CBC 0x00004000L
|
|
#define SSL_SC_DES_EDE3_CBC 0x00008000L
|
|
#define SSL_SC_IDEA_CBC 0x00010000L
|
|
|
|
/* The ONLY reason why we can use these macros for both control and
|
|
data connections is that they inherit from the same superclass.
|
|
Do NOT try this at home. */
|
|
#define SSMCONNECTION(c) (&(c)->super)
|
|
#define SSMRESOURCE(c) (&(c)->super.super)
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessGenKeyOldStyleToken(SSMControlConnection * ctrl,
|
|
SECItem * msg)
|
|
{
|
|
GenKeyOldStyleTokenReply reply;
|
|
SSMResource * res;
|
|
SSMStatus rv = PR_FAILURE;
|
|
|
|
/* message contains token name to use for KEYGEN */
|
|
if (CMT_DecodeMessage(GenKeyOldStyleTokenReplyTemplate, &reply,
|
|
(CMTItem*)msg) != CMTSuccess)
|
|
goto loser;
|
|
|
|
rv = SSMControlConnection_GetResource(ctrl, reply.rid, &res);
|
|
if (rv != SSM_SUCCESS || !res)
|
|
goto loser;
|
|
|
|
if (!reply.cancel)
|
|
res->m_uiData = (void *)PK11_FindSlotByName(reply.tokenName);
|
|
SSM_NotifyUIEvent(res);
|
|
|
|
/* now generate the key */
|
|
|
|
rv = SSM_ERR_DEFER_RESPONSE;
|
|
loser:
|
|
if (res) /* release reference */
|
|
SSM_FreeResource(res);
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessGenKeyPassword(SSMControlConnection * ctrl,
|
|
SECItem * msg)
|
|
{
|
|
GenKeyOldStylePasswordReply passwordreply;
|
|
SSMStatus rv = SSM_FAILURE;
|
|
SSMResource * res = NULL;
|
|
PK11SlotInfo *slot = NULL;
|
|
|
|
if (CMT_DecodeMessage(GenKeyOldStylePasswordReplyTemplate, &passwordreply,
|
|
(CMTItem*)msg) != CMTSuccess)
|
|
goto loser;
|
|
rv = SSMControlConnection_GetResource(ctrl, passwordreply.rid, &res);
|
|
if (rv != SSM_SUCCESS)
|
|
goto loser;
|
|
|
|
if (!SSM_IsAKindOf(res, SSM_RESTYPE_KEYGEN_CONTEXT))
|
|
goto loser;
|
|
|
|
slot = ((SSMKeyGenContext *)res)->slot;
|
|
/* we are here because there is no password on the slot */
|
|
if (!passwordreply.cancel)
|
|
PK11_InitPin(slot, NULL, passwordreply.password);
|
|
SSM_NotifyUIEvent(res);
|
|
rv = SSM_ERR_DEFER_RESPONSE;
|
|
|
|
loser:
|
|
return rv;
|
|
}
|
|
|
|
|
|
/* Thread functions for SDR_ENCRYPT */
|
|
static SSMStatus
|
|
sdrencrypt(SSMControlConnection *ctrl, SECItem *msg)
|
|
{
|
|
SSMStatus rv = SSM_SUCCESS;
|
|
CMTStatus crv;
|
|
PK11SlotInfo *slot = PK11_GetInternalKeySlot();
|
|
EncryptRequestMessage request;
|
|
EncryptReplyMessage reply;
|
|
SECStatus s;
|
|
SSMResourceID id;
|
|
SSMResource *res = NULL;
|
|
|
|
SSM_DEBUG("sdrEncrypt\n");
|
|
|
|
request.keyid.data = NULL;
|
|
request.data.data = NULL;
|
|
request.ctx.data = NULL;
|
|
|
|
reply.item.data = NULL;
|
|
|
|
/* Decode the message (frees message data) */
|
|
crv = CMT_DecodeMessage(EncryptRequestTemplate, &request, (CMTItem*)msg);
|
|
if (crv != CMTSuccess) { rv = SSM_FAILURE; goto loser; }
|
|
|
|
/* Create a resource for handling UI events */
|
|
rv = SSM_CreateResource(SSM_RESTYPE_SDR_CONTEXT, 0, ctrl, &id, &res);
|
|
if (rv != SSM_SUCCESS) goto loser;
|
|
|
|
/* Set client context field for UI events
|
|
* NOTE: the resource will be deleted before the request data
|
|
* is freed
|
|
*/
|
|
res->m_clientContext = request.ctx;
|
|
|
|
/* Make sure user has initialized database password */
|
|
if (PK11_NeedUserInit(slot)) {
|
|
SSM_DEBUG("Calling SSM_SetUserPassword\n");
|
|
rv = SSM_SetUserPassword(slot, res);
|
|
SSM_DEBUG("SSM_SetUserPassword returns %d\n", rv);
|
|
if (rv != SSM_SUCCESS) { rv = SSM_ERR_NEED_USER_INIT_DB; goto loser; }
|
|
}
|
|
|
|
if (PK11_Authenticate(PK11_GetInternalKeySlot(), PR_TRUE, res) != SECSuccess) {
|
|
rv = SSM_ERR_BAD_DB_PASSWORD;
|
|
goto loser;
|
|
}
|
|
|
|
s = PK11SDR_Encrypt((SECItem*)&request.keyid, (SECItem*)&request.data,
|
|
(SECItem*)&reply.item, res);
|
|
SSM_DEBUG("Encrypt returns %d\n", s);
|
|
SSM_DEBUG(" -> Item: %lx (%d)\n", reply.item.data, reply.item.len);
|
|
|
|
/* Generate response */
|
|
msg->type = SSM_SDR_ENCRYPT_REPLY;
|
|
crv = CMT_EncodeMessage(EncryptReplyTemplate, (CMTItem*)msg, &reply);
|
|
if (crv != CMTSuccess) { rv = SSM_FAILURE; goto loser; /* Unknown error */ }
|
|
|
|
loser:
|
|
if (res) SSM_FreeResource(res);
|
|
if (request.keyid.data) PR_Free(request.keyid.data);
|
|
if (request.data.data) PR_Free(request.data.data);
|
|
if (request.ctx.data) PR_Free(request.ctx.data);
|
|
if (reply.item.data) PR_Free(reply.item.data);
|
|
|
|
return rv;
|
|
}
|
|
|
|
static SSMStatus
|
|
sdrdecrypt(SSMControlConnection *ctrl, SECItem *msg)
|
|
{
|
|
SSMStatus rv = SSM_SUCCESS;
|
|
CMTStatus crv;
|
|
SECStatus s;
|
|
DecryptRequestMessage request;
|
|
DecryptReplyMessage reply;
|
|
SSMResourceID id;
|
|
SSMResource *res = NULL;
|
|
|
|
request.data.data = NULL;
|
|
request.ctx.data = NULL;
|
|
reply.item.data = NULL;
|
|
|
|
SSM_DEBUG("sdrDecrypt\n");
|
|
|
|
crv = CMT_DecodeMessage(DecryptRequestTemplate, &request, (CMTItem*)msg);
|
|
if (crv != CMTSuccess) { rv = SSM_FAILURE; goto loser; }
|
|
|
|
/* Create a resource for handling UI events */
|
|
rv = SSM_CreateResource(SSM_RESTYPE_SDR_CONTEXT, 0, ctrl, &id, &res);
|
|
if (rv != SSM_SUCCESS) goto loser;
|
|
|
|
/* Set client context field for UI events
|
|
* NOTE: the resource will be deleted before the request data
|
|
* is freed
|
|
*/
|
|
res->m_clientContext = request.ctx;
|
|
|
|
if (PK11_Authenticate(PK11_GetInternalKeySlot(), PR_TRUE, res) != SECSuccess) {
|
|
rv = SSM_ERR_BAD_DB_PASSWORD;
|
|
goto loser;
|
|
}
|
|
|
|
s = PK11SDR_Decrypt((SECItem*)&request.data, (SECItem*)&reply.item, res);
|
|
if (s != SECSuccess) { rv = SSM_FAILURE; goto loser; }
|
|
|
|
msg->type = SSM_SDR_DECRYPT_REPLY;
|
|
crv = CMT_EncodeMessage(DecryptReplyTemplate, (CMTItem*)msg, &reply);
|
|
if (crv != CMTSuccess) { rv = SSM_FAILURE; goto loser; /* Unknown error */ }
|
|
|
|
loser:
|
|
if (res) SSM_FreeResource(res);
|
|
if (request.data.data) PR_Free(request.data.data);
|
|
if (request.ctx.data) PR_Free(request.ctx.data);
|
|
if (reply.item.data) PR_Free(reply.item.data);
|
|
|
|
return rv;
|
|
}
|
|
|
|
static SSMStatus
|
|
sdrChangePassword(SSMControlConnection *ctrl, SECItem *msg)
|
|
{
|
|
SSMStatus rv = SSM_SUCCESS;
|
|
SingleItemMessage req;
|
|
PK11SlotInfo *slot = PK11_GetInternalKeySlot();
|
|
SSMResourceID id;
|
|
SSMResource *res = NULL;
|
|
|
|
SSM_DEBUG("sdrChangePassword\n");
|
|
|
|
req.item.data = 0;
|
|
|
|
if (CMT_DecodeMessage(SingleItemMessageTemplate, &req, (CMTItem*)msg) != CMTSuccess) {
|
|
rv = SSM_FAILURE;
|
|
goto loser;
|
|
}
|
|
|
|
/* Create a resource for handling UI events */
|
|
rv = SSM_CreateResource(SSM_RESTYPE_SDR_CONTEXT, 0, ctrl, &id, &res);
|
|
if (rv != SSM_SUCCESS) goto loser;
|
|
|
|
/* Set client context field for UI events
|
|
* NOTE: the resource will be deleted before the request data
|
|
* is freed
|
|
*/
|
|
res->m_clientContext = req.item;
|
|
|
|
/* Invoke the UI for setting password */
|
|
rv = SSM_SetUserPassword(slot, res);
|
|
|
|
loser:
|
|
if (res) SSM_FreeResource(res);
|
|
if (req.item.data) PR_Free(req.item.data);
|
|
|
|
return rv;
|
|
}
|
|
|
|
static SSMStatus
|
|
ProcessMiscUI(SSMControlConnection *ctrl, SECItem *msg)
|
|
{
|
|
SSMStatus rv;
|
|
|
|
rv = SSM_ProcessMsgOnThreadReply(sdrChangePassword, ctrl, msg);
|
|
msg->type = (SSM_REPLY_OK_MESSAGE|SSM_MISC_ACTION|SSM_MISC_UI|SSM_UI_CHANGE_PASSWORD);
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessMiscRequest(SSMControlConnection * ctrl,
|
|
SECItem * msg)
|
|
{
|
|
SingleNumMessage req;
|
|
SingleItemMessage reply;
|
|
char *buf = NULL;
|
|
SSMStatus rv = SSM_SUCCESS;
|
|
SECStatus srv;
|
|
|
|
SSM_DEBUG("Got a misc request.\n");
|
|
switch (msg->type & SSM_SUBTYPE_MASK)
|
|
{
|
|
case SSM_MISC_GET_RNG_DATA:
|
|
if (CMT_DecodeMessage(SingleNumMessageTemplate, &req,
|
|
(CMTItem*)msg) != CMTSuccess)
|
|
goto loser;
|
|
|
|
/* Generate as much random data as they want. */
|
|
SSM_DEBUG("The client wants %ld bytes of random data.\n", req.value);
|
|
buf = (char *) PR_CALLOC(req.value);
|
|
if (!buf)
|
|
goto loser;
|
|
srv = RNG_GenerateGlobalRandomBytes(buf, req.value);
|
|
if (srv != SECSuccess)
|
|
goto loser;
|
|
|
|
/* Presumably we have random bytes now. Send them back. */
|
|
reply.item.len = req.value;
|
|
reply.item.data = (unsigned char *) buf;
|
|
|
|
if (CMT_EncodeMessage(SingleItemMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess)
|
|
goto loser;
|
|
if (msg->data == NULL || msg->len == 0)
|
|
goto loser;
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_MISC_ACTION | SSM_MISC_GET_RNG_DATA);
|
|
goto done;
|
|
|
|
|
|
case SSM_MISC_SDR_ENCRYPT:
|
|
rv = SSM_ProcessMsgOnThread(sdrencrypt, ctrl, msg);
|
|
if (rv != PR_SUCCESS) goto loser;
|
|
|
|
rv = SSM_ERR_DEFER_RESPONSE;
|
|
goto done;
|
|
|
|
case SSM_MISC_SDR_DECRYPT:
|
|
rv = SSM_ProcessMsgOnThread(sdrdecrypt, ctrl, msg);
|
|
if (rv != PR_SUCCESS) goto loser;
|
|
|
|
rv = SSM_ERR_DEFER_RESPONSE;
|
|
|
|
goto done;
|
|
|
|
case SSM_MISC_UI:
|
|
rv = ProcessMiscUI(ctrl, msg);
|
|
if (rv != PR_SUCCESS) goto loser;
|
|
|
|
/* rv = SSM_ERR_DEFER_RESPONSE; */
|
|
goto done;
|
|
|
|
case SSM_MISC_PUT_RNG_DATA:
|
|
default:
|
|
SSM_DEBUG("Unknown misc request (%lx).\n", (msg->type & SSM_SUBTYPE_MASK));
|
|
goto loser;
|
|
}
|
|
goto done;
|
|
loser:
|
|
SSM_DEBUG("ProcessMiscRequest: loser hit, rv = %ld.\n",
|
|
rv);
|
|
if (msg->data)
|
|
{
|
|
PR_Free(msg->data);
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
}
|
|
if (rv == PR_SUCCESS) rv = PR_FAILURE;
|
|
done:
|
|
if (buf)
|
|
PR_Free(buf);
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessCertRequest(SSMControlConnection * ctrl,
|
|
SECItem * msg)
|
|
{
|
|
SSMStatus rv = PR_SUCCESS;
|
|
|
|
SSM_DEBUG("Got a cert-related request.\n");
|
|
switch (msg->type & SSM_SUBTYPE_MASK) {
|
|
case SSM_VERIFY_CERT:
|
|
rv = SSMControlConnection_ProcessVerifyCertRequest(ctrl, msg);
|
|
break;
|
|
case SSM_IMPORT_CERT:
|
|
rv = SSMControlConnection_ProcessImportCertRequest(ctrl, msg);
|
|
break;
|
|
case SSM_DECODE_CERT:
|
|
rv = SSMControlConnection_ProcessDecodeCertRequest(ctrl, msg);
|
|
break;
|
|
case SSM_FIND_BY_NICKNAME:
|
|
rv = SSMControlConnection_ProcessFindCertByNickname(ctrl, msg);
|
|
break;
|
|
case SSM_FIND_BY_KEY:
|
|
rv = SSMControlConnection_ProcessFindCertByKey(ctrl, msg);
|
|
break;
|
|
case SSM_FIND_BY_EMAILADDR:
|
|
rv = SSMControlConnection_ProcessFindCertByEmailAddr(ctrl, msg);
|
|
break;
|
|
case SSM_ADD_TO_DB:
|
|
rv = SSMControlConnection_ProcessAddCertToDB(ctrl, msg);
|
|
break;
|
|
case SSM_MATCH_USER_CERT:
|
|
rv = SSMControlConnection_ProcessMatchUserCert(ctrl, msg);
|
|
break;
|
|
case SSM_DESTROY_CERT:
|
|
rv = SSMControlConnection_ProcessDestroyCert(ctrl, msg);
|
|
break;
|
|
case SSM_DECODE_TEMP_CERT:
|
|
rv = SSMControlConnection_ProcessDecodeAndCreateTempCert(ctrl, msg);
|
|
break;
|
|
case SSM_REDIRECT_COMPARE:
|
|
rv = SSMControlConnection_ProcessRedirectCompare(ctrl, msg);
|
|
break;
|
|
case SSM_DECODE_CRL:
|
|
rv = SSMControlConnection_ProcessDecodeCRLRequest(ctrl, msg);
|
|
break;
|
|
case SSM_EXTENSION_VALUE:
|
|
rv = SSMControlConnection_ProcessGetExtensionRequest(ctrl, msg);
|
|
break;
|
|
case SSM_HTML_INFO:
|
|
rv = SSMControlConnection_ProcessHTMLCertInfoRequest(ctrl, msg);
|
|
break;
|
|
default:
|
|
SSM_DEBUG("Unknown cert request (%lx).\n",
|
|
(msg->type & SSM_SUBTYPE_MASK));
|
|
goto loser;
|
|
}
|
|
goto done;
|
|
loser:
|
|
SSM_DEBUG("ProcessCertRequest: loser hit, rv = %ld.\n",
|
|
rv);
|
|
if (msg->data)
|
|
{
|
|
PR_Free(msg->data);
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
}
|
|
if (rv == PR_SUCCESS) rv = PR_FAILURE;
|
|
done:
|
|
return rv;
|
|
}
|
|
|
|
PRStatus
|
|
SSMControlConnection_ProcessKeygenTag(SSMControlConnection * ctrl,
|
|
SECItem * msg)
|
|
{
|
|
SSMStatus rv = PR_SUCCESS;
|
|
|
|
SSM_DEBUG("Got a KEYGEN form tag processing request.\n");
|
|
switch (msg->type & SSM_SUBTYPE_MASK) {
|
|
case SSM_GET_KEY_CHOICE:
|
|
rv = SSMControlConnection_ProcessGetKeyChoiceList(ctrl, msg);
|
|
break;
|
|
case SSM_KEYGEN_TOKEN:
|
|
rv = SSMControlConnection_ProcessGenKeyOldStyleToken(ctrl, msg);
|
|
break;
|
|
case SSM_KEYGEN_PASSWORD:
|
|
rv = SSMControlConnection_ProcessGenKeyPassword(ctrl, msg);
|
|
break;
|
|
case SSM_KEYGEN_START:
|
|
/* We might need to do another message exchange before
|
|
* we complete this request, to get slot password.
|
|
* Therefore, generate keys on a separate thread,
|
|
* and let this thread service other messages. -jp
|
|
*/
|
|
{
|
|
genKeyArg * arg = (genKeyArg *) PR_Malloc(sizeof(genKeyArg));
|
|
if (!arg)
|
|
SSM_DEBUG("Memory allocation error!\n");
|
|
arg->ctrl = ctrl;
|
|
arg->msg = SECITEM_DupItem(msg);
|
|
|
|
if (SSM_CreateAndRegisterThread(PR_USER_THREAD,
|
|
SSMControlConnection_ProcessGenKeyOldStyle,
|
|
(void *)arg,
|
|
PR_PRIORITY_NORMAL,
|
|
PR_LOCAL_THREAD,
|
|
PR_UNJOINABLE_THREAD, 0)== NULL) {
|
|
SSM_DEBUG("Can't start a new thread for old-style keygen!\n");
|
|
rv = SSM_FAILURE;
|
|
}
|
|
else rv = SSM_ERR_DEFER_RESPONSE;
|
|
}
|
|
break;
|
|
default:
|
|
SSM_DEBUG("Unknown KEYGEN request (%lx).\n",
|
|
(msg->type & SSM_SUBTYPE_MASK));
|
|
goto loser;
|
|
}
|
|
goto done;
|
|
loser:
|
|
SSM_DEBUG("ProcessKeygenTag: loser hit, rv = %ld.\n",
|
|
rv);
|
|
if (msg->data)
|
|
{
|
|
PR_Free(msg->data);
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
}
|
|
if (rv == PR_SUCCESS) rv = PR_FAILURE;
|
|
done:
|
|
return (PRStatus) rv;
|
|
}
|
|
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessVerifyCertRequest(SSMControlConnection * ctrl,
|
|
SECItem * msg)
|
|
{
|
|
SSMResource *obj;
|
|
SSMStatus rv;
|
|
VerifyCertRequest request;
|
|
SingleNumMessage reply;
|
|
|
|
SSM_DEBUG("Got a Cert Verify request.\n");
|
|
/* Decode message and get resource/field ID */
|
|
if (CMT_DecodeMessage(VerifyCertRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
msg->data = NULL;
|
|
SSM_DEBUG("Rsrc ID %ld, certUsage %d.\n", request.resID, request.certUsage);
|
|
|
|
rv = SSMControlConnection_GetResource(ctrl, request.resID, &obj);
|
|
if (rv != PR_SUCCESS) goto loser;
|
|
PR_ASSERT(obj != NULL);
|
|
|
|
/* getting this far means success, send the result of verification */
|
|
rv = SSM_VerifyCert((SSMResourceCert *)obj, (SECCertUsage) request.certUsage);
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
msg->type = (SECItemType) (SSM_CERT_ACTION | SSM_VERIFY_CERT | SSM_REPLY_OK_MESSAGE);
|
|
|
|
reply.value = rv;
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
if (msg->data == NULL || msg->len == 0) goto loser;
|
|
return PR_SUCCESS;
|
|
|
|
/* something went wrong, could not perform cert verification */
|
|
loser:
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessDecodeCertRequest(SSMControlConnection * ctrl,
|
|
SECItem * msg)
|
|
{
|
|
SSMStatus rv;
|
|
CERTCertificate * cert;
|
|
SSMResourceID certID;
|
|
SSMResource * certRes;
|
|
SingleItemMessage request;
|
|
SingleNumMessage reply;
|
|
|
|
SSM_DEBUG("Got an DecodeCert request.\n");
|
|
/* Decode message */
|
|
if (CMT_DecodeMessage(SingleItemMessageTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
|
|
/* decode the cert */
|
|
cert = CERT_DecodeCertFromPackage((char *) request.item.data, (int) request.item.len);
|
|
if (!cert) {
|
|
SSM_DEBUG("Can't decode a cert from the buffer!\n");
|
|
goto loser;
|
|
}
|
|
|
|
/* create cert resource for this new cert */
|
|
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE, cert, ctrl, &certID, &certRes);
|
|
if (rv != PR_SUCCESS) {
|
|
SSM_DEBUG("In decode cert: can't create certificate resource.\n");
|
|
goto loser;
|
|
}
|
|
SSM_ClientGetResourceReference(certRes, NULL);
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_CERT_ACTION | SSM_DECODE_CERT);
|
|
reply.value = certID;
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
if (!msg->data || msg->len == 0)
|
|
goto loser;
|
|
|
|
return PR_SUCCESS;
|
|
|
|
loser:
|
|
/* compose error reply */
|
|
msg->type = (SECItemType) (SSM_REPLY_ERR_MESSAGE | SSM_CERT_ACTION | SSM_DECODE_CERT);
|
|
if (msg->data)
|
|
PR_Free(msg->data);
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
char *
|
|
SSMControlConnection_GenerateKeyOldStyle(SSMControlConnection * ctrl,
|
|
char * choiceString, char * challenge,
|
|
char * typeString, char * pqgString);
|
|
|
|
void
|
|
SSMControlConnection_ProcessGenKeyOldStyle(void * arg)
|
|
{
|
|
char * keydata = NULL;
|
|
GenKeyOldStyleRequest request;
|
|
SingleStringMessage reply;
|
|
genKeyArg * myarg = (genKeyArg *)arg;
|
|
CMTItem * msg = (CMTItem*)myarg->msg;
|
|
SSMControlConnection * ctrl = myarg->ctrl;
|
|
SSMStatus rv = SSM_FAILURE;
|
|
|
|
if (CMT_DecodeMessage(GenKeyOldStyleRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
reply.string = SSMControlConnection_GenerateKeyOldStyle(ctrl,
|
|
request.choiceString,
|
|
request.challenge,
|
|
request.typeString,
|
|
request.pqgString);
|
|
if (!reply.string)
|
|
goto loser;
|
|
|
|
/* create reply message */
|
|
msg->type = SSM_REPLY_OK_MESSAGE | SSM_KEYGEN_TAG | SSM_KEYGEN_DONE;
|
|
if (CMT_EncodeMessage(SingleStringMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
if (!msg->len || !msg->data)
|
|
goto loser;
|
|
rv = SSM_SendQMessage(ctrl->m_controlOutQ, SSM_PRIORITY_NORMAL,
|
|
msg->type, msg->len, (char *)msg->data, PR_TRUE);
|
|
|
|
loser:
|
|
/* clean up */
|
|
if (reply.string)
|
|
PR_Free(reply.string);
|
|
if (request.choiceString)
|
|
PR_Free(request.choiceString);
|
|
if (request.challenge)
|
|
PR_Free(request.challenge);
|
|
if (request.pqgString)
|
|
PR_Free(request.pqgString);
|
|
if (request.typeString)
|
|
PR_Free(request.typeString);
|
|
if (keydata)
|
|
PR_Free(keydata);
|
|
SSMControlConnection_RecycleItem((SECItem*)msg);
|
|
msg = NULL;
|
|
PR_Free(myarg);
|
|
if (rv != SSM_SUCCESS) {
|
|
SingleNumMessage err_reply;
|
|
msg = (CMTItem *) PORT_ZAlloc(sizeof(CMTItem));
|
|
SSM_DEBUG("Problems generating keys old style!\n");
|
|
msg->type = SSM_REPLY_ERR_MESSAGE;
|
|
err_reply.value = rv;
|
|
CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &err_reply);
|
|
SSM_SendQMessage(ctrl->m_controlOutQ, SSM_PRIORITY_NORMAL,
|
|
msg->type, msg->len, (char *)msg->data, PR_TRUE);
|
|
SSMControlConnection_RecycleItem((SECItem*)msg);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
char ** SSM_GetKeyChoiceList(char * type, char *pqgString, int *nchoices);
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessGetKeyChoiceList(SSMControlConnection * ctrl,
|
|
SECItem * msg)
|
|
{
|
|
char ** choices;
|
|
PRInt32 i=0, nchoices = 0;
|
|
GetKeyChoiceListRequest request;
|
|
GetKeyChoiceListReply reply;
|
|
|
|
if (CMT_DecodeMessage(GetKeyChoiceListRequestTemplate, &request,
|
|
(CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
choices = SSM_GetKeyChoiceList(request.type, request.pqgString, &nchoices);
|
|
if (!choices)
|
|
goto loser;
|
|
|
|
msg->type = (SECItemType)(SSM_REPLY_OK_MESSAGE | SSM_KEYGEN_TAG | SSM_GET_KEY_CHOICE);
|
|
|
|
reply.nchoices = nchoices;
|
|
reply.choices = choices;
|
|
if (CMT_EncodeMessage(GetKeyChoiceListReplyTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* free the result array */
|
|
while (choices[i])
|
|
PR_Free(choices[i++]);
|
|
PR_Free(choices);
|
|
|
|
return PR_SUCCESS;
|
|
|
|
loser:
|
|
/* compose error reply */
|
|
msg->type = (SECItemType) (SSM_REPLY_ERR_MESSAGE | SSM_KEYGEN_TAG | SSM_GET_KEY_CHOICE);
|
|
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
if (choices) {
|
|
/* free the result array */
|
|
while (choices[i])
|
|
PR_Free(choices[i++]);
|
|
PR_Free(choices);
|
|
}
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessImportCertRequest(SSMControlConnection * ctrl,
|
|
SECItem * msg)
|
|
{
|
|
SSMResource *obj;
|
|
SSMStatus rv;
|
|
SingleItemMessage request;
|
|
ImportCertReply reply;
|
|
|
|
SSM_DEBUG("Got an ImportCert request.\n");
|
|
/* Decode message */
|
|
if (CMT_DecodeMessage(SingleItemMessageTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
|
|
/* Unpickle cert and create a resource */
|
|
rv = SSM_UnpickleResource(&obj, SSM_RESTYPE_CERTIFICATE, ctrl,
|
|
request.item.len, request.item.data);
|
|
if (rv != PR_SUCCESS)
|
|
goto loser;
|
|
SSM_DEBUG("Imported cert rsrc ID %ld.\n", obj->m_id);
|
|
/* getting this far means success, send the resource ID */
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
msg->type = (SECItemType) (SSM_CERT_ACTION | SSM_IMPORT_CERT | SSM_REPLY_OK_MESSAGE);
|
|
reply.result = rv;
|
|
reply.resID = obj->m_id;
|
|
if (CMT_EncodeMessage(ImportCertReplyTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
if (msg->data == NULL || msg->len == 0)
|
|
goto loser;
|
|
PR_Free(request.item.data);
|
|
return PR_SUCCESS;
|
|
|
|
/* something went wrong, could not import cert */
|
|
loser:
|
|
if (request.item.data)
|
|
PR_Free(request.item.data);
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessFindCertByNickname(SSMControlConnection *ctrl, SECItem *msg)
|
|
{
|
|
SSMStatus rv;
|
|
CERTCertificate *cert = NULL;
|
|
SSMResourceID certID;
|
|
SSMResourceCert * certRes = NULL;
|
|
SingleStringMessage request;
|
|
SingleNumMessage reply;
|
|
|
|
SSM_DEBUG("Get a Find Cert By Nickname request\n");
|
|
|
|
/* Decode the request */
|
|
if (CMT_DecodeMessage(SingleStringMessageTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Look for the cert in out db */
|
|
cert = CERT_FindCertByNickname(ctrl->m_certdb, request.string);
|
|
|
|
/* Create a resource for this cert and get an id */
|
|
if (cert) {
|
|
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE,
|
|
cert,
|
|
ctrl,
|
|
&certID,
|
|
(SSMResource**)&certRes);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
rv = SSM_ClientGetResourceReference(&certRes->super, &certID);
|
|
SSM_FreeResource(&certRes->super);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
} else {
|
|
/* Not found. Return res id 0 */
|
|
certID = 0;
|
|
}
|
|
|
|
/* Pack the reply */
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
msg->type = (SECItemType) (SSM_CERT_ACTION | SSM_FIND_BY_NICKNAME | SSM_REPLY_OK_MESSAGE);
|
|
reply.value = certID;
|
|
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
if (msg->data == NULL || msg->len == 0) {
|
|
goto loser;
|
|
}
|
|
|
|
PR_Free(request.string);
|
|
return PR_SUCCESS;
|
|
|
|
/* something went wrong */
|
|
loser:
|
|
if (request.string) {
|
|
PR_Free(request.string);
|
|
}
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessFindCertByKey(SSMControlConnection *ctrl, SECItem *msg)
|
|
{
|
|
SSMStatus rv;
|
|
CERTCertificate *cert = NULL;
|
|
SSMResourceID certID;
|
|
SSMResourceCert * certRes = NULL;
|
|
SingleItemMessage request;
|
|
SingleNumMessage reply;
|
|
|
|
SSM_DEBUG("Get a Find Cert By Key request\n");
|
|
|
|
/* Decode the request */
|
|
if (CMT_DecodeMessage(SingleItemMessageTemplate, &request,
|
|
(CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Look for the cert in out db */
|
|
cert = CERT_FindCertByKey(ctrl->m_certdb, (SECItem*)&request.item);
|
|
|
|
/* Create a resource for this cert and get an id */
|
|
if (cert) {
|
|
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE,
|
|
cert,
|
|
ctrl,
|
|
&certID,
|
|
(SSMResource**)&certRes);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
rv = SSM_ClientGetResourceReference(&certRes->super, &certID);
|
|
SSM_FreeResource(&certRes->super);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
} else {
|
|
/* Not found. Return res id 0 */
|
|
certID = 0;
|
|
}
|
|
|
|
SSM_DEBUG("Returning cert resource %d\n", certID);
|
|
|
|
/* Pack the reply */
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
msg->type = (SECItemType) (SSM_CERT_ACTION | SSM_FIND_BY_KEY | SSM_REPLY_OK_MESSAGE);
|
|
reply.value = certID;
|
|
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
PR_Free(request.item.data);
|
|
return PR_SUCCESS;
|
|
|
|
/* something went wrong */
|
|
loser:
|
|
if (request.item.data) {
|
|
PR_Free(request.item.data);
|
|
}
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
int LDAPCertSearch (const char * rcpt_address, const char * server_name,
|
|
const char * baseDN, int port, int connect_type,
|
|
const char * certdb_path, const char * auth_dn,
|
|
const char * auth_password, const char * mail_attribs,
|
|
const char * cert_attribs, void ** cert, int * cert_len);
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessFindCertByEmailAddr(SSMControlConnection *ctrl,
|
|
SECItem *msg)
|
|
{
|
|
SSMStatus rv;
|
|
CERTCertificate *cert = NULL;
|
|
SSMResourceID certID = 0;
|
|
SSMResourceCert * certRes = NULL;
|
|
SingleStringMessage request;
|
|
SingleNumMessage reply;
|
|
|
|
SSM_DEBUG("Got a Find Cert By Email Addr request\n");
|
|
|
|
/* Decode the request */
|
|
if (CMT_DecodeMessage(SingleStringMessageTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Look for the cert in out db */
|
|
cert = CERT_FindCertByEmailAddr(ctrl->m_certdb, request.string);
|
|
|
|
/* If there is no search or the cert is not valid */
|
|
if (!cert || (CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE) != secCertTimeValid)) {
|
|
char* default_server = NULL;
|
|
|
|
/* get the default server name */
|
|
rv = PREF_GetStringPref(ctrl->m_prefs, "ldap_2.default",
|
|
&default_server);
|
|
if (rv != SSM_SUCCESS) {
|
|
/* if there is no default server, bail */
|
|
goto loser;
|
|
}
|
|
|
|
rv = SSM_CompleteLDAPLookup(ctrl, default_server, request.string);
|
|
if (rv != SSM_SUCCESS) {
|
|
cert = NULL;
|
|
goto done;
|
|
}
|
|
|
|
cert = CERT_FindCertByEmailAddr(ctrl->m_certdb, request.string);
|
|
if (cert && (CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE) != secCertTimeValid)) {
|
|
cert = NULL;
|
|
}
|
|
}
|
|
|
|
done:
|
|
/* Create a resource for this cert and get an id */
|
|
if (cert) {
|
|
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE,
|
|
cert,
|
|
ctrl,
|
|
&certID,
|
|
(SSMResource**)&certRes);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
rv = SSM_ClientGetResourceReference(&certRes->super, &certID);
|
|
SSM_FreeResource(&certRes->super);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
} else {
|
|
/* Not found. Return res id 0 */
|
|
certID = 0;
|
|
}
|
|
|
|
SSM_DEBUG("Returning cert resource %d\n", certID);
|
|
|
|
/* Pack the reply */
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
msg->type = (SECItemType) (SSM_CERT_ACTION | SSM_FIND_BY_EMAILADDR | SSM_REPLY_OK_MESSAGE);
|
|
reply.value = certID;
|
|
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
if (msg->data == NULL || msg->len == 0) {
|
|
goto loser;
|
|
}
|
|
|
|
PR_Free(request.string);
|
|
return PR_SUCCESS;
|
|
|
|
/* something went wrong */
|
|
loser:
|
|
if (request.string)
|
|
PR_Free(request.string);
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessAddCertToDB(SSMControlConnection *ctrl, SECItem *msg)
|
|
{
|
|
SSMStatus rv;
|
|
SSMResourceCert *certRes;
|
|
CERTCertificate *cert;
|
|
CERTCertTrust trust;
|
|
AddTempCertToDBRequest request;
|
|
|
|
SSM_DEBUG("Add Cert to DB");
|
|
|
|
/* Decode the request */
|
|
if (CMT_DecodeMessage(AddTempCertToDBRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
trust.sslFlags = request.sslFlags;
|
|
trust.emailFlags = request.emailFlags;
|
|
trust.objectSigningFlags = request.objSignFlags;
|
|
|
|
/* Get the resource for this id */
|
|
rv = SSMControlConnection_GetResource(ctrl, request.resID,
|
|
(SSMResource**)&certRes);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Get the CERTCertificate pointer for this resource */
|
|
cert = certRes->cert;
|
|
|
|
/* Add the certificate to the database */
|
|
if (CERT_AddTempCertToPerm(cert, request.nickname, &trust) != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Pack the reply */
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
msg->type = (SECItemType) (SSM_CERT_ACTION | SSM_ADD_TO_DB | SSM_REPLY_OK_MESSAGE);
|
|
|
|
PR_Free(request.nickname);
|
|
return PR_SUCCESS;
|
|
|
|
loser:
|
|
if (request.nickname) {
|
|
PR_Free(request.nickname);
|
|
}
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessDestroyCert(SSMControlConnection * ctrl,
|
|
SECItem * msg)
|
|
{
|
|
SSMStatus rv = PR_FAILURE;
|
|
SSMResource * resource;
|
|
SingleNumMessage request;
|
|
|
|
if (!msg || !msg->data)
|
|
goto done;
|
|
|
|
if (CMT_DecodeMessage(SingleNumMessageTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto done;
|
|
}
|
|
|
|
PR_Free(msg->data);
|
|
msg->data = NULL;
|
|
|
|
rv = SSMControlConnection_GetResource(ctrl, request.value, &resource);
|
|
if (rv != PR_SUCCESS)
|
|
goto done;
|
|
|
|
rv = SSMResourceCert_Destroy(resource, PR_TRUE);
|
|
if (rv == PR_SUCCESS) {
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_CERT_ACTION | SSM_DESTROY_CERT);
|
|
msg->len = 0;
|
|
}
|
|
done:
|
|
return rv;
|
|
}
|
|
|
|
typedef struct MatchUserCertArgStr {
|
|
PRBool isOwnThread;
|
|
SSMControlConnection *ctrl;
|
|
SECItem *msg;
|
|
} MatchUserCertArg;
|
|
|
|
static void
|
|
ssm_match_user_cert(void *arg)
|
|
{
|
|
MatchUserCertArg *matchArgs = (MatchUserCertArg*)arg;
|
|
SSMControlConnection *ctrl = matchArgs->ctrl;
|
|
SECItem *msg = matchArgs->msg;
|
|
SSMCertList *certList;
|
|
CERTCertList *certs = NULL;
|
|
CERTCertListNode *node = NULL;
|
|
SSMResourceCert *certRes;
|
|
SSMResourceID certResID;
|
|
SSMStatus rv;
|
|
int i;
|
|
MatchUserCertRequest request;
|
|
MatchUserCertReply reply;
|
|
SingleNumMessage badReply;
|
|
|
|
#if DEBUG
|
|
if (matchArgs->isOwnThread) {
|
|
SSM_RegisterThread("match user cert", NULL);
|
|
}
|
|
#endif
|
|
/* Decode the request */
|
|
if (CMT_DecodeMessage(MatchUserCertRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
certList = PR_NEWZAP(SSMCertList);
|
|
if (!certList) {
|
|
goto loser;
|
|
}
|
|
|
|
PR_INIT_CLIST(&certList->certs);
|
|
|
|
/* Find the certs */
|
|
certs = CERT_MatchUserCert(ctrl->m_certdb, (SECCertUsage) request.certType,
|
|
request.numCANames, request.caNames, ctrl);
|
|
if (!certs) {
|
|
reply.numCerts = 0;
|
|
reply.certs = NULL;
|
|
goto done;
|
|
}
|
|
|
|
reply.numCerts = SSM_CertListCount(certs);
|
|
reply.certs = (CMInt32*)malloc(sizeof(CMInt32)*reply.numCerts);
|
|
node = (CERTCertListNode*)PR_LIST_HEAD(&certs->list);
|
|
for (i = 0; i < reply.numCerts; i++) {
|
|
|
|
/* Create the cert resource */
|
|
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE,
|
|
node->cert,
|
|
ctrl,
|
|
&certResID,
|
|
(SSMResource**)&certRes);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
reply.certs[i] = certResID;
|
|
node = (struct CERTCertListNodeStr *) node->links.next;
|
|
}
|
|
|
|
done:
|
|
/* Generate the reply message */
|
|
/* Pack the reply */
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
msg->type = (SECItemType) (SSM_CERT_ACTION | SSM_MATCH_USER_CERT | SSM_REPLY_OK_MESSAGE);
|
|
if (CMT_EncodeMessage(MatchUserCertReplyTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
if (msg->data == NULL || msg->len == 0) {
|
|
goto loser;
|
|
}
|
|
SSM_DEBUG("queueing reply: type %lx, len %ld.\n", msg->type, msg->len);
|
|
SSM_SendQMessage(ctrl->m_controlOutQ,
|
|
SSM_PRIORITY_NORMAL,
|
|
msg->type, msg->len,
|
|
(char *)msg->data, PR_TRUE);
|
|
/* Clean up */
|
|
/* Free the certs list */
|
|
SSM_FreeResource(&ctrl->super.super);
|
|
SECITEM_FreeItem(msg, PR_TRUE);
|
|
PR_Free(arg);
|
|
return;
|
|
|
|
loser:
|
|
if (rv == SSM_SUCCESS)
|
|
rv = SSM_FAILURE;
|
|
|
|
badReply.value = rv;
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate,
|
|
(CMTItem*)msg, &badReply) == CMTSuccess) {
|
|
SSM_DEBUG("queueing reply: type %lx, len %ld.\n",
|
|
msg->type, msg->len);
|
|
SSM_SendQMessage(ctrl->m_controlOutQ,
|
|
SSM_PRIORITY_NORMAL,
|
|
msg->type, msg->len,
|
|
(char *)msg->data, PR_TRUE);
|
|
} else {
|
|
/* We need to send something back here. */
|
|
PR_ASSERT(0);
|
|
}
|
|
/* Clean up */
|
|
SSM_FreeResource(&ctrl->super.super);
|
|
SECITEM_FreeItem(msg, PR_TRUE);
|
|
PR_Free(arg);
|
|
return;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessMatchUserCert(SSMControlConnection *ctrl,
|
|
SECItem *msg)
|
|
{
|
|
MatchUserCertArg *arg;
|
|
PK11SlotList *slotList;
|
|
PK11SlotListElement *currSlot;
|
|
PRBool externalTokenExists = PR_FALSE;
|
|
|
|
/* This could potentially require authentication to an
|
|
* external token which would cause Cartman to dead-lock
|
|
* waiting for the password reply. So we spin off a separate
|
|
* iff external tokens are installed.
|
|
*/
|
|
arg = SSM_ZNEW(MatchUserCertArg);
|
|
if (arg == NULL) {
|
|
return SSM_FAILURE;
|
|
}
|
|
SSM_GetResourceReference(&ctrl->super.super);
|
|
arg->ctrl = ctrl;
|
|
arg->msg = SECITEM_DupItem(msg);
|
|
/* Now let's figure out if there are external tokens installed.*/
|
|
slotList = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE,
|
|
ctrl);
|
|
PR_ASSERT(slotList);
|
|
currSlot = slotList->head;
|
|
do {
|
|
if (!PK11_IsInternal(currSlot->slot)) {
|
|
externalTokenExists = PR_TRUE;
|
|
break;
|
|
}
|
|
currSlot = currSlot->next;
|
|
} while (currSlot != slotList->head && currSlot != NULL);
|
|
|
|
arg->isOwnThread = externalTokenExists;
|
|
if (arg->isOwnThread) {
|
|
SSM_CreateAndRegisterThread(PR_USER_THREAD, ssm_match_user_cert, (void*)arg,
|
|
PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
|
|
PR_UNJOINABLE_THREAD, 0);
|
|
} else {
|
|
ssm_match_user_cert(arg);
|
|
}
|
|
PK11_FreeSlotList(slotList);
|
|
return SSM_ERR_DEFER_RESPONSE;
|
|
|
|
}
|
|
SSMStatus
|
|
SSMControlConnection_ProcessConserveRequest(SSMControlConnection * ctrl,
|
|
SECItem * msg)
|
|
{
|
|
SSMStatus rv = PR_SUCCESS;
|
|
|
|
switch (msg->type & SSM_SPECIFIC_MASK) {
|
|
case SSM_PICKLE_RESOURCE:
|
|
rv = SSMControlConnection_ProcessPickleRequest(ctrl, msg);
|
|
break;
|
|
case SSM_UNPICKLE_RESOURCE:
|
|
rv = SSMControlConnection_ProcessUnpickleRequest(ctrl, msg);
|
|
break;
|
|
case SSM_PICKLE_SECURITY_STATUS:
|
|
rv = SSMControlConnection_ProcessPickleSecurityStatusRequest(ctrl, msg);
|
|
break;
|
|
default:
|
|
rv = SSM_ERR_ATTRIBUTE_TYPE_MISMATCH;
|
|
goto loser;
|
|
}
|
|
goto done;
|
|
loser:
|
|
SSM_DEBUG("ProcessConserveResourceRequest: loser hit, rv = %ld.\n", rv);
|
|
if (msg->data)
|
|
{
|
|
PR_Free(msg->data);
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
}
|
|
if (rv == PR_SUCCESS) rv = PR_FAILURE;
|
|
done:
|
|
return rv;
|
|
}
|
|
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessPickleRequest(SSMControlConnection * ctrl,
|
|
SECItem * msg)
|
|
{
|
|
SSMResource *obj;
|
|
SSMStatus rv;
|
|
PRIntn len;
|
|
void * dataBlob = NULL;
|
|
SingleNumMessage request;
|
|
PickleResourceReply reply;
|
|
|
|
SSM_DEBUG("Got a PickleResource request.\n");
|
|
|
|
/* Decode the request */
|
|
if (CMT_DecodeMessage(SingleNumMessageTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
msg->data = NULL;
|
|
SSM_DEBUG("Rsrc ID %ld.\n", request.value);
|
|
|
|
rv = SSMControlConnection_GetResource(ctrl, request.value, &obj);
|
|
if (rv != PR_SUCCESS)
|
|
goto loser;
|
|
PR_ASSERT(obj != NULL);
|
|
|
|
rv = SSM_PickleResource(obj, &len, &dataBlob);
|
|
if (rv != PR_SUCCESS)
|
|
goto loser;
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
msg->type = (SECItemType) (SSM_RESOURCE_ACTION | SSM_PICKLE_RESOURCE
|
|
| SSM_CONSERVE_RESOURCE | SSM_REPLY_OK_MESSAGE);
|
|
reply.result = rv;
|
|
reply.blob.len = len;
|
|
reply.blob.data = (unsigned char *) dataBlob;
|
|
if (CMT_EncodeMessage(PickleResourceReplyTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
if (msg->data == NULL || msg->len == 0) goto loser;
|
|
PR_Free(dataBlob);
|
|
return PR_SUCCESS;
|
|
|
|
/* something went wrong, could not pickle resource */
|
|
loser:
|
|
if (dataBlob)
|
|
PR_Free(dataBlob);
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessUnpickleRequest(SSMControlConnection * ctrl,
|
|
SECItem * msg)
|
|
{
|
|
SSMResource *obj;
|
|
SSMStatus rv;
|
|
UnpickleResourceRequest request;
|
|
UnpickleResourceReply reply;
|
|
|
|
|
|
SSM_DEBUG("Got an UnpickleResource request.\n");
|
|
|
|
/* Decode the message */
|
|
if (CMT_DecodeMessage(UnpickleResourceRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
msg->data = NULL;
|
|
|
|
rv = SSM_UnpickleResource(&obj, (SSMResourceType) request.resourceType, ctrl,
|
|
(unsigned int) request.resourceData.len, request.resourceData.data);
|
|
if (rv != PR_SUCCESS)
|
|
goto loser;
|
|
SSM_DEBUG("Unpickled rsrc ID %ld.\n", obj->m_id);
|
|
/* getting this far means success, send the resource ID */
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
msg->type = (SECItemType) (SSM_RESOURCE_ACTION | SSM_UNPICKLE_RESOURCE |
|
|
SSM_CONSERVE_RESOURCE | SSM_REPLY_OK_MESSAGE);
|
|
reply.result = rv;
|
|
reply.resID = obj->m_id;
|
|
if (CMT_EncodeMessage(UnpickleResourceReplyTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
if (msg->data == NULL || msg->len == 0) goto loser;
|
|
PR_Free(request.resourceData.data);
|
|
return PR_SUCCESS;
|
|
|
|
/* something went wrong, could not unpickle cert */
|
|
loser:
|
|
if (request.resourceData.data)
|
|
PR_Free(request.resourceData.data);
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
|
|
SSMStatus SSMControlConnection_ProcessPickleSecurityStatusRequest(SSMControlConnection* ctrl,
|
|
SECItem* msg)
|
|
{
|
|
SSMStatus rv;
|
|
SSMResource* obj = NULL;
|
|
PRIntn len;
|
|
void* blob = NULL;
|
|
PRIntn securityLevel;
|
|
SingleNumMessage request;
|
|
PickleSecurityStatusReply reply;
|
|
|
|
SSM_DEBUG("Got an PickleSecurityStatus request.\n");
|
|
|
|
/* decode the message */
|
|
if (CMT_DecodeMessage(SingleNumMessageTemplate, &request, (CMTItem*)msg) !=
|
|
CMTSuccess) {
|
|
return PR_FAILURE;
|
|
}
|
|
SSM_DEBUG("Rsrc ID %ld.\n", request.value);
|
|
|
|
rv = SSMControlConnection_GetResource(ctrl, request.value, &obj);
|
|
if (rv != PR_SUCCESS) {
|
|
return rv;
|
|
}
|
|
PR_ASSERT(obj != NULL);
|
|
|
|
/* the resource'd better be an SSMSSLDataConnection */
|
|
if (SSM_IsA(obj, SSM_RESTYPE_SSL_DATA_CONNECTION) != PR_TRUE) {
|
|
goto loser;
|
|
}
|
|
|
|
/* now have the SSL connection handle the action */
|
|
rv = SSMSSLDataConnection_PickleSecurityStatus((SSMSSLDataConnection*)obj,
|
|
&len, &blob,
|
|
&securityLevel);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_RESOURCE_ACTION |
|
|
SSM_CONSERVE_RESOURCE | SSM_PICKLE_SECURITY_STATUS);
|
|
|
|
reply.result = rv;
|
|
reply.securityLevel = securityLevel;
|
|
reply.blob.len = len;
|
|
reply.blob.data = (unsigned char *) blob;
|
|
if (CMT_EncodeMessage(PickleSecurityStatusReplyTemplate, (CMTItem*)msg,
|
|
&reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
if (msg->data == NULL || msg->len == 0) {
|
|
goto loser;
|
|
}
|
|
PR_Free(blob);
|
|
SSM_FreeResource(obj);
|
|
return PR_SUCCESS;
|
|
|
|
/* something went wrong, could not pickle security status */
|
|
loser:
|
|
if (blob != NULL) {
|
|
PR_Free(blob);
|
|
}
|
|
if (obj != NULL) {
|
|
SSM_FreeResource(obj);
|
|
}
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
|
|
SECStatus
|
|
SSMControlConnection_AddNewSecurityModule(SSMControlConnection *ctrl,
|
|
SECItem *msg)
|
|
{
|
|
SECStatus srv=SECFailure;
|
|
AddNewSecurityModuleRequest request;
|
|
|
|
if (CMT_DecodeMessage(AddNewSecurityModuleRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
srv = SECMOD_AddNewModule(request.moduleName, request.libraryPath,
|
|
SECMOD_PubMechFlagstoInternal(request.pubMechFlags),
|
|
SECMOD_PubCipherFlagstoInternal(request.pubCipherFlags));
|
|
loser:
|
|
if (request.moduleName != NULL) {
|
|
PR_Free(request.moduleName);
|
|
}
|
|
if (request.libraryPath != NULL) {
|
|
PR_Free(request.libraryPath);
|
|
}
|
|
return srv;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_DeleteSecurityModule(SSMControlConnection *ctrl,
|
|
SECItem *msg,
|
|
PRInt32 *moduleType)
|
|
{
|
|
SECStatus srv;
|
|
SingleStringMessage request;
|
|
|
|
if (moduleType == NULL) {
|
|
goto loser;
|
|
}
|
|
|
|
if (CMT_DecodeMessage(SingleStringMessageTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* To avoid any possible addition of data due to differing data types.*/
|
|
*moduleType = 0;
|
|
srv = SECMOD_DeleteModule(request.string, moduleType);
|
|
if (srv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
PR_Free(request.string);
|
|
return PR_SUCCESS;
|
|
loser:
|
|
if (request.string != NULL) {
|
|
PR_Free(request.string);
|
|
}
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
static PRBool
|
|
SSM_CiphersEnabled(PRInt32 *ciphers, PRInt16 numCiphers)
|
|
{
|
|
PRInt16 i;
|
|
SECStatus rv;
|
|
PRInt32 policy;
|
|
|
|
for (i=0; i<numCiphers; i++) {
|
|
rv = SSL_CipherPolicyGet(ciphers[i], &policy);
|
|
if (rv == SECSuccess && policy == SSL_ALLOWED) {
|
|
return PR_TRUE;
|
|
}
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
#define SSL_CB_RC4_128_WITH_MD5 (SSL_EN_RC4_128_WITH_MD5)
|
|
#define SSL_CB_RC4_128_EXPORT40_WITH_MD5 (SSL_EN_RC4_128_EXPORT40_WITH_MD5)
|
|
#define SSL_CB_RC2_128_CBC_WITH_MD5 (SSL_EN_RC2_128_CBC_WITH_MD5)
|
|
#define SSL_CB_RC2_128_CBC_EXPORT40_WITH_MD5 (SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5)
|
|
#define SSL_CB_IDEA_128_CBC_WITH_MD5 (SSL_EN_IDEA_128_CBC_WITH_MD5)
|
|
#define SSL_CB_DES_64_CBC_WITH_MD5 (SSL_EN_DES_64_CBC_WITH_MD5)
|
|
#define SSL_CB_DES_192_EDE3_CBC_WITH_MD5 (SSL_EN_DES_192_EDE3_CBC_WITH_MD5)
|
|
|
|
|
|
static CMInt32
|
|
SSM_GetSSLCapabilities(void)
|
|
{
|
|
CMInt32 allowed = (SSL_SC_RSA | SSL_SC_MD2 | SSL_SC_MD5);
|
|
PRInt32 policies[2];
|
|
|
|
policies[0] = SSL_CB_RC2_128_CBC_WITH_MD5;
|
|
policies[1] = SSL_CB_RC2_128_CBC_EXPORT40_WITH_MD5;
|
|
if (SSM_CiphersEnabled(policies, 2)) {
|
|
allowed |= SSL_SC_RC2_CBC;
|
|
}
|
|
|
|
policies[0] = SSL_CB_RC4_128_WITH_MD5;
|
|
policies[1] = SSL_CB_RC4_128_EXPORT40_WITH_MD5;
|
|
if (SSM_CiphersEnabled(policies, 2)) {
|
|
allowed |= SSL_SC_RC4;
|
|
}
|
|
|
|
policies[0] = SSL_CB_DES_64_CBC_WITH_MD5;
|
|
if (SSM_CiphersEnabled(policies, 1)) {
|
|
allowed |= SSL_SC_DES_CBC;
|
|
}
|
|
|
|
policies[0] = SSL_CB_DES_192_EDE3_CBC_WITH_MD5;
|
|
if (SSM_CiphersEnabled(policies, 1)) {
|
|
allowed |= SSL_SC_DES_EDE3_CBC;
|
|
}
|
|
|
|
policies[0] = SSL_CB_IDEA_128_CBC_WITH_MD5;
|
|
if (SSM_CiphersEnabled(policies, 1)) {
|
|
allowed |= SSL_SC_IDEA_CBC;
|
|
}
|
|
|
|
return allowed;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessPKCS11Request(SSMControlConnection * ctrl,
|
|
SECItem * msg)
|
|
{
|
|
SSMResourceID rsrcid;
|
|
SSMStatus rv;
|
|
SECStatus srv;
|
|
PRInt32 moduleType;
|
|
SingleNumMessage reply;
|
|
|
|
SSM_DEBUG("Got a PKCS11 request.\n");
|
|
|
|
switch (msg->type & SSM_SUBTYPE_MASK) {
|
|
case SSM_CREATE_KEY_PAIR: /*Should just call a function that does the
|
|
*approprieate action */
|
|
SSM_DEBUG("Generating a key pair.\n");
|
|
rv = SSMKeyGenContext_BeginGeneratingKeyPair(ctrl, msg, &rsrcid);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
/* Getting this far means success */
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_PKCS11_ACTION | SSM_CREATE_KEY_PAIR);
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
reply.value = rsrcid;
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
break;
|
|
case SSM_FINISH_KEY_GEN:
|
|
SSM_DEBUG("Finish generating all of the key pairs. \n");
|
|
rv = SSMKeyGenContext_FinishGeneratingAllKeyPairs(ctrl, msg);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_PKCS11_ACTION | SSM_FINISH_KEY_GEN);
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
break;
|
|
case SSM_ADD_NEW_MODULE:
|
|
SSM_DEBUG("Adding a new PKCS11 module.\n");
|
|
srv = SSMControlConnection_AddNewSecurityModule(ctrl, msg);
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_PKCS11_ACTION |
|
|
SSM_ADD_NEW_MODULE);
|
|
reply.value = srv;
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
break;
|
|
case SSM_DEL_MODULE:
|
|
rv = SSMControlConnection_DeleteSecurityModule(ctrl, msg, &moduleType);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
PR_Free(msg->data);
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_PKCS11_ACTION |
|
|
SSM_DEL_MODULE);
|
|
reply.value = moduleType;
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
break;
|
|
case SSM_LOGOUT_ALL:
|
|
PK11_LogoutAll();
|
|
if (msg->data) {
|
|
PR_Free(msg->data);
|
|
}
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_PKCS11_ACTION |
|
|
SSM_LOGOUT_ALL);
|
|
break;
|
|
case SSM_ENABLED_CIPHERS:
|
|
reply.value = SSM_GetSSLCapabilities();
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_PKCS11_ACTION |
|
|
SSM_ENABLED_CIPHERS);
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate,
|
|
(CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
break;
|
|
default:
|
|
SSM_DEBUG("Unknown PKCS11 message %lx\n",msg->type);
|
|
goto loser;
|
|
}
|
|
return PR_SUCCESS;
|
|
|
|
loser:
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessCRMFRequest(SSMControlConnection * ctrl,
|
|
SECItem *msg)
|
|
{
|
|
SSMResourceID rsrcid;
|
|
char *challengeResponse;
|
|
SSMStatus rv;
|
|
PRInt32 challengeLen;
|
|
|
|
SSM_DEBUG("Got a CRMF/CMMF request\n");
|
|
|
|
switch(msg->type & SSM_SUBTYPE_MASK) {
|
|
case SSM_CREATE_CRMF_REQ:
|
|
{
|
|
SingleNumMessage reply;
|
|
SSM_DEBUG("Generating a new CRMF request\n");
|
|
rv = SSM_CreateNewCRMFRequest(msg, ctrl, &rsrcid);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_CRMF_ACTION | SSM_CREATE_CRMF_REQ);
|
|
reply.value = rsrcid;
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
}
|
|
break;
|
|
case SSM_DER_ENCODE_REQ:
|
|
{
|
|
SSMCRMFThreadArg *arg;
|
|
|
|
arg = SSM_NEW(SSMCRMFThreadArg);
|
|
if (arg == NULL) {
|
|
goto loser;
|
|
}
|
|
arg->ctrl = ctrl;
|
|
arg->msg = SECITEM_DupItem(msg);
|
|
if (arg->msg == NULL) {
|
|
PR_Free(arg);
|
|
}
|
|
SSM_GetResourceReference(&ctrl->super.super);
|
|
if (SSM_CreateAndRegisterThread(PR_USER_THREAD,
|
|
SSM_CRMFEncodeThread,
|
|
(void*)arg,
|
|
PR_PRIORITY_NORMAL,
|
|
PR_LOCAL_THREAD,
|
|
PR_UNJOINABLE_THREAD, 0) == NULL) {
|
|
SSM_DEBUG("Couldn't start thread for CRMF encoding");
|
|
SECITEM_FreeItem(arg->msg, PR_TRUE);
|
|
PR_Free(arg);
|
|
SSM_FreeResource(&ctrl->super.super);
|
|
goto loser;
|
|
}
|
|
return SSM_ERR_DEFER_RESPONSE;
|
|
}
|
|
break;
|
|
case SSM_PROCESS_CMMF_RESP:
|
|
SSM_DEBUG("Process a CMMF Response.\n");
|
|
rv = SSM_ProcessCMMFCertResponse(msg, ctrl);
|
|
if (rv != SSM_ERR_DEFER_RESPONSE) {
|
|
goto loser;
|
|
}
|
|
return rv;
|
|
case SSM_CHALLENGE:
|
|
{
|
|
SingleItemMessage reply;
|
|
|
|
SSM_DEBUG("Doing a Challenge-Response for Proof Of Possession.\n");
|
|
rv = SSM_RespondToPOPChallenge(msg, ctrl, &challengeResponse,
|
|
(unsigned int *) &challengeLen);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_CRMF_ACTION | SSM_CHALLENGE);
|
|
reply.item.len = challengeLen;
|
|
reply.item.data = (unsigned char *) challengeResponse;
|
|
if (CMT_EncodeMessage(SingleItemMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
SSM_DEBUG("Answering challenge with following response:\n%s\n",
|
|
challengeResponse);
|
|
PR_Free(challengeResponse);
|
|
}
|
|
break;
|
|
default:
|
|
SSM_DEBUG("Got unkown CRMF/CMMF message %lx\n", msg->type);
|
|
goto loser;
|
|
}
|
|
return PR_SUCCESS;
|
|
loser:
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
char*
|
|
get_string_key(SSMLocalizedString whichString)
|
|
{
|
|
char *key;
|
|
switch(whichString) {
|
|
case SSM_STRING_BAD_PK11_LIB_PARAM:
|
|
key = "module_invalid_module_name";
|
|
break;
|
|
case SSM_STRING_BAD_PK11_LIB_PATH:
|
|
key = "module_invalid_library";
|
|
break;
|
|
case SSM_STRING_ADD_MOD_SUCCESS:
|
|
key = "module_add_success";
|
|
break;
|
|
case SSM_STRING_ADD_MOD_FAILURE:
|
|
key = "module_add_failure";
|
|
break;
|
|
case SSM_STRING_BAD_MOD_NAME:
|
|
key = "module_invalid_library";
|
|
break;
|
|
case SSM_STRING_EXT_MOD_DEL:
|
|
key = "module_ext_mod_del";
|
|
break;
|
|
case SSM_STRING_INT_MOD_DEL:
|
|
key = "module_int_mod_del";
|
|
break;
|
|
case SSM_STRING_MOD_DEL_FAIL:
|
|
key = "module_del_failure";
|
|
break;
|
|
case SSM_STRING_ADD_MOD_WARN:
|
|
key = "module_add_warning";
|
|
break;
|
|
case SSM_STRING_MOD_PROMPT:
|
|
key = "module_prompt";
|
|
break;
|
|
case SSM_STRING_DLL_PROMPT:
|
|
key = "module_library_prompt";
|
|
break;
|
|
case SSM_STRING_DEL_MOD_WARN:
|
|
key = "module_del_warning";
|
|
break;
|
|
case SSM_STRING_INVALID_CRL:
|
|
key = "invalid_crl";
|
|
break;
|
|
case SSM_STRING_INVALID_CKL:
|
|
key = "invalid_krl";
|
|
break;
|
|
case SSM_STRING_ROOT_CKL_CERT_NOT_FOUND:
|
|
key = "root_ckl_cert_not_found";
|
|
break;
|
|
case SSM_STRING_BAD_CRL_SIGNATURE:
|
|
key = "bad_crl_signature";
|
|
break;
|
|
case SSM_STRING_BAD_CKL_SIGNATURE:
|
|
key = "bad_ckl_signature";
|
|
break;
|
|
case SSM_STRING_ERR_ADD_CRL:
|
|
key = "error_adding_crl";
|
|
break;
|
|
case SSM_STRING_ERR_ADD_CKL:
|
|
key = "error_adding_ckl";
|
|
break;
|
|
case SSM_STRING_JAVASCRIPT_DISABLED:
|
|
key = "javascript_diabled";
|
|
break;
|
|
default:
|
|
key = NULL;
|
|
break;
|
|
}
|
|
if (key == NULL) {
|
|
return NULL;
|
|
}
|
|
return PL_strdup(key);
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessLocalizedTextRequest(SSMControlConnection *ctrl,
|
|
SECItem * msg)
|
|
{
|
|
SSMStatus rv;
|
|
char *localizedString;
|
|
char *key=NULL;
|
|
SSMTextGenContext *txtGenCxt=NULL;
|
|
SingleNumMessage request;
|
|
GetLocalizedTextReply reply;
|
|
|
|
SSM_DEBUG("Retrieving localized text\n");
|
|
/* Decode the message */
|
|
if (CMT_DecodeMessage(SingleNumMessageTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
key = get_string_key((SSMLocalizedString) request.value);
|
|
if (key == NULL) {
|
|
goto loser;
|
|
}
|
|
rv = SSMTextGen_NewContext(NULL, NULL, NULL, NULL, &txtGenCxt);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
rv = SSM_FindUTF8StringInBundles(txtGenCxt, key, &localizedString);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_LOCALIZED_TEXT);
|
|
reply.whichString = request.value;
|
|
reply.localizedString = localizedString;
|
|
|
|
if (CMT_EncodeMessage(GetLocalizedTextReplyTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
if (msg->len == 0 || msg->data == NULL) {
|
|
goto loser;
|
|
}
|
|
SSM_DEBUG("Returning the string \"%s\"\n", localizedString);
|
|
PR_Free(localizedString);
|
|
PR_Free(key);
|
|
return PR_SUCCESS;
|
|
loser:
|
|
if (key != NULL) {
|
|
PR_Free(key);
|
|
}
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessFormSigningRequest(SSMControlConnection * ctrl,
|
|
SECItem *msg)
|
|
{
|
|
SSMStatus rv;
|
|
|
|
SSM_DEBUG("Got a From Signing request\n");
|
|
|
|
switch(msg->type & SSM_SUBTYPE_MASK) {
|
|
case SSM_SIGN_TEXT:
|
|
SSM_DEBUG("Generating a new sign text request\n");
|
|
rv = SSM_CreateSignTextRequest(msg, ctrl);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_FORMSIGN_ACTION | SSM_SIGN_TEXT);
|
|
PR_Free(msg->data);
|
|
msg->data = NULL;
|
|
msg->len = 0;
|
|
break;
|
|
default:
|
|
SSM_DEBUG("Got unkown Form Signing message %lx\n", msg->type);
|
|
goto loser;
|
|
break;
|
|
}
|
|
return PR_SUCCESS;
|
|
loser:
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessRedirectCompare(SSMControlConnection *ctrl,
|
|
SECItem * msg)
|
|
{
|
|
RedirectCompareRequest request;
|
|
SSMSSLSocketStatus *ss1=NULL, *ss2=NULL;
|
|
SingleNumMessage reply;
|
|
|
|
SSM_DEBUG("Comparing Certs for re-direct\n");
|
|
if (CMT_DecodeMessage(RedirectCompareRequestTemplate, &request,
|
|
(CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
if (SSMSSLSocketStatus_Unpickle((SSMResource**)&ss1,
|
|
ctrl, request.socketStatus1Data.len,
|
|
request.socketStatus1Data.data) != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
if (SSMSSLSocketStatus_Unpickle((SSMResource**)&ss2,
|
|
ctrl, request.socketStatus2Data.len,
|
|
request.socketStatus2Data.data) != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
reply.value =
|
|
(CMInt32)CERT_CompareCertsForRedirection(ss1->m_cert->cert,
|
|
ss2->m_cert->cert);
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply)
|
|
!= CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_CERT_ACTION | SSM_REDIRECT_COMPARE);
|
|
SSMSSLSocketStatus_Destroy((SSMResource*)ss1, PR_TRUE);
|
|
SSMSSLSocketStatus_Destroy((SSMResource*)ss2, PR_TRUE);
|
|
SSM_DEBUG("Finished comparing certs for re-direction.\n");
|
|
return PR_SUCCESS;
|
|
loser:
|
|
if (ss1 != NULL) {
|
|
SSMSSLSocketStatus_Destroy((SSMResource*)ss1, PR_TRUE);
|
|
}
|
|
if (ss2 != NULL) {
|
|
SSMSSLSocketStatus_Destroy((SSMResource*)ss2, PR_TRUE);
|
|
}
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessDecodeCRLRequest(SSMControlConnection *ctrl,
|
|
SECItem *msg)
|
|
{
|
|
DecodeAndAddCRLRequest request;
|
|
SingleNumMessage reply;
|
|
PRArenaPool *arena = NULL;
|
|
CERTCertificate *caCert;
|
|
SECItem derName = { siBuffer, NULL, 0 };
|
|
CERTSignedData sd;
|
|
SECStatus rv;
|
|
int type;
|
|
CERTSignedCrl *crl;
|
|
|
|
SSM_DEBUG("Adding a CRL\n");
|
|
reply.value = 0xffffffff; /* Set the return value to some invalid
|
|
* enumeration for localized strings.
|
|
*/
|
|
if (CMT_DecodeMessage(DecodeAndAddCRLRequestTemplate, &request,
|
|
(CMTItem*)msg) != CMTSuccess) {
|
|
goto done;
|
|
}
|
|
type = request.type;
|
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
if (arena == NULL) {
|
|
goto done;
|
|
}
|
|
memset(&sd, 0, sizeof(sd));
|
|
|
|
/* The Crl inherits the arena passed in.*/
|
|
rv = CERT_KeyFromDERCrl(arena, (SECItem*)&request.derCrl, &derName);
|
|
if (rv != SECSuccess) {
|
|
reply.value = (type == SEC_CRL_TYPE) ? SSM_STRING_INVALID_CRL :
|
|
SSM_STRING_INVALID_CKL;
|
|
goto done;
|
|
}
|
|
caCert = CERT_FindCertByName(ctrl->m_certdb, &derName);
|
|
if (caCert == NULL) {
|
|
if (type == SEC_KRL_TYPE){
|
|
reply.value = SSM_STRING_ROOT_CKL_CERT_NOT_FOUND;
|
|
goto done;
|
|
}
|
|
} else {
|
|
rv = SEC_ASN1DecodeItem(arena,
|
|
&sd, CERT_SignedDataTemplate,
|
|
(SECItem*)&request.derCrl);
|
|
if (rv != SECSuccess) {
|
|
reply.value = (type == SEC_CRL_TYPE) ? SSM_STRING_INVALID_CRL :
|
|
SSM_STRING_INVALID_CKL;
|
|
goto done;
|
|
}
|
|
rv = CERT_VerifySignedData(&sd, caCert, PR_Now(),
|
|
ctrl);
|
|
if (rv != SECSuccess) {
|
|
reply.value =
|
|
(type == SEC_CRL_TYPE) ? SSM_STRING_BAD_CRL_SIGNATURE :
|
|
SSM_STRING_BAD_CKL_SIGNATURE;
|
|
}
|
|
}
|
|
|
|
crl = SEC_NewCrl(ctrl->m_certdb, request.url, (SECItem*)&request.derCrl,
|
|
type);
|
|
if (!crl) {
|
|
reply.value = (type == SEC_CRL_TYPE) ? SSM_STRING_ERR_ADD_CRL :
|
|
SSM_STRING_ERR_ADD_CKL;
|
|
goto done;
|
|
}
|
|
reply.value = 0;
|
|
/* Not sure if we still need to do this, but the Nova code does it,
|
|
* so I'll do it here as well.
|
|
* -javi
|
|
*/
|
|
SSL_ClearSessionCache();
|
|
|
|
SEC_DestroyCrl(crl);
|
|
done:
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply)
|
|
!= CMTSuccess) {
|
|
return PR_FAILURE;
|
|
}
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_CERT_ACTION | SSM_DECODE_CRL);
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
PRStatus
|
|
SSMControlConnection_ProcessSecurityAdvsiorRequest(SSMControlConnection *ctrl,
|
|
SECItem *msg)
|
|
{
|
|
SecurityAdvisorRequest request;
|
|
SingleNumMessage reply;
|
|
InfoSecAdvisor infoSecAdvisor;
|
|
PRStatus rv;
|
|
SSMResource *res;
|
|
|
|
/* Decode the request message */
|
|
if (CMT_DecodeMessage(SecurityAdvisorRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Get the request data */
|
|
infoSecAdvisor.infoContext = request.infoContext;
|
|
infoSecAdvisor.resID = request.resID;
|
|
infoSecAdvisor.hostname = request.hostname;
|
|
infoSecAdvisor.senderAddr = request.senderAddr;
|
|
infoSecAdvisor.encryptedP7CInfo = request.encryptedP7CInfo;
|
|
infoSecAdvisor.signedP7CInfo = request.signedP7CInfo;
|
|
infoSecAdvisor.decodeError = request.decodeError;
|
|
infoSecAdvisor.verifyError = request.verifyError;
|
|
infoSecAdvisor.encryptthis = request.encryptthis;
|
|
infoSecAdvisor.signthis = request.signthis;
|
|
infoSecAdvisor.numRecipients = request.numRecipients;
|
|
infoSecAdvisor.recipients = request.recipients;
|
|
|
|
/* Create the security advisor context. */
|
|
rv = (PRStatus) SSMSecurityAdvisorContext_Create(ctrl, &infoSecAdvisor, &res);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
|
|
msg->type = (SECItemType) (SSM_SECURITY_ADVISOR | SSM_REPLY_OK_MESSAGE);
|
|
/* Encode the reply */
|
|
reply.value = res->m_id;
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
return PR_SUCCESS;
|
|
loser:
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
/* XXX Do I need to destroy the cert in these functions??? */
|
|
PRStatus
|
|
SSMControlConnection_ProcessSCAddCertToTempDB(SSMControlConnection* ctrl,
|
|
SECItem* msg)
|
|
{
|
|
PRStatus rv = PR_FAILURE;
|
|
SingleItemMessage request;
|
|
CERTCertificate* impcert = NULL;
|
|
CERTCertificate* cert = NULL;
|
|
SingleItemMessage reply;
|
|
|
|
SSM_DEBUG("SecurityConfig: add cert to temp DB\n");
|
|
|
|
/* fill in reply in case of failure */
|
|
reply.item.len = 0;
|
|
reply.item.data = NULL;
|
|
|
|
/* Decode the request */
|
|
if (CMT_DecodeMessage(SingleItemMessageTemplate, &request,
|
|
(CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* decode the package that the cert came in */
|
|
impcert = CERT_DecodeCertFromPackage((char *) request.item.data, (int) request.item.len);
|
|
if (impcert == NULL) {
|
|
goto done;
|
|
}
|
|
|
|
/* load the cert into the temporary database */
|
|
cert = CERT_NewTempCertificate(ctrl->m_certdb, &impcert->derCert, NULL,
|
|
PR_FALSE, PR_TRUE);
|
|
CERT_DestroyCertificate(impcert);
|
|
if (cert == NULL) {
|
|
goto done;
|
|
}
|
|
|
|
reply.item.len = cert->certKey.len;
|
|
reply.item.data = cert->certKey.data;
|
|
|
|
done:
|
|
/* pack cert key into the reply */
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_SEC_CFG_ACTION |
|
|
SSM_ADD_CERT_TO_TEMP_DB);
|
|
|
|
if (CMT_EncodeMessage(SingleItemMessageTemplate, (CMTItem*)msg, &reply) !=
|
|
CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
rv = PR_SUCCESS;
|
|
loser:
|
|
(void)SSMControlConnection_RecycleItem((SECItem*)&request.item);
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
PRStatus
|
|
SSMControlConnection_ProcessSCAddTempCertToPermDB(SSMControlConnection* ctrl,
|
|
SECItem* msg)
|
|
{
|
|
PRStatus rv = PR_FAILURE;
|
|
SECStatus srv = SECFailure;
|
|
SCAddTempCertToPermDBRequest request;
|
|
SingleNumMessage reply;
|
|
CERTCertificate* cert = NULL;
|
|
CERTCertTrust trust;
|
|
|
|
SSM_DEBUG("SecurityConfig: add temp cert to perm DB\n");
|
|
|
|
/* Decode the request */
|
|
if (CMT_DecodeMessage(SCAddTempCertToPermDBRequestTemplate, &request,
|
|
(CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* look up cert in database */
|
|
cert = CERT_FindCertByKey(ctrl->m_certdb, (SECItem*)&request.certKey);
|
|
if (cert == NULL) {
|
|
goto done;
|
|
}
|
|
|
|
/* decode the trust flags string */
|
|
srv = CERT_DecodeTrustString(&trust, request.trustStr);
|
|
if (srv != SECSuccess) {
|
|
goto done;
|
|
}
|
|
|
|
/* if no nickname was passed in, then there must already be a nickname
|
|
* for the cert's subject name
|
|
*/
|
|
if ((request.nickname == NULL) || (*request.nickname == '\0')) {
|
|
if ((cert->subjectList == NULL) ||
|
|
(cert->subjectList->entry == NULL) ||
|
|
(cert->subjectList->entry->nickname == NULL)) {
|
|
srv = SECFailure;
|
|
goto done;
|
|
}
|
|
/* force zero length string case to null */
|
|
request.nickname = NULL;
|
|
}
|
|
|
|
/* add the cert to the perm database */
|
|
if (cert->isperm) {
|
|
srv = SECFailure;
|
|
goto done;
|
|
}
|
|
else {
|
|
srv = CERT_AddTempCertToPerm(cert, request.nickname, &trust);
|
|
}
|
|
|
|
done:
|
|
/* pack the reply */
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_SEC_CFG_ACTION |
|
|
SSM_ADD_TEMP_CERT_TO_DB);
|
|
|
|
reply.value = (CMInt32)srv;
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) !=
|
|
CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
rv = PR_SUCCESS;
|
|
loser:
|
|
(void)SSMControlConnection_RecycleItem((SECItem*)&request.certKey);
|
|
if (request.trustStr != NULL) {
|
|
PR_Free(request.trustStr);
|
|
}
|
|
if (request.nickname != NULL) {
|
|
PR_Free(request.nickname);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
static SECStatus SC_DeleteCertCB(CERTCertificate* cert, void* arg)
|
|
{
|
|
return SEC_DeletePermCertificate(cert);
|
|
}
|
|
|
|
PRStatus
|
|
SSMControlConnection_ProcessSCDeletePermCerts(SSMControlConnection* ctrl,
|
|
SECItem* msg)
|
|
{
|
|
PRStatus rv = PR_FAILURE;
|
|
SECStatus srv = SECFailure;
|
|
SCDeletePermCertsRequest request;
|
|
SingleNumMessage reply;
|
|
CERTCertificate* cert = NULL;
|
|
|
|
SSM_DEBUG("SecurityConfig: delete perm certs\n");
|
|
|
|
if (CMT_DecodeMessage(SCDeletePermCertsRequestTemplate, &request,
|
|
(CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
cert = CERT_FindCertByKey(ctrl->m_certdb, (SECItem*)&request.certKey);
|
|
if (cert == NULL) {
|
|
goto done;
|
|
}
|
|
|
|
if (request.deleteAll == PR_TRUE) {
|
|
srv = CERT_TraversePermCertsForSubject(ctrl->m_certdb,
|
|
&cert->derSubject,
|
|
SC_DeleteCertCB, NULL);
|
|
}
|
|
else {
|
|
srv = SEC_DeletePermCertificate(cert);
|
|
}
|
|
|
|
/* XXX original Nova code actually returns PR_SUCCESS even if delete
|
|
* operation fails: what gives?
|
|
*/
|
|
done:
|
|
/* pack the reply */
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_SEC_CFG_ACTION |
|
|
SSM_DELETE_PERM_CERTS);
|
|
reply.value = (CMInt32)srv;
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) !=
|
|
CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
rv = PR_SUCCESS;
|
|
loser:
|
|
(void)SSMControlConnection_RecycleItem((SECItem*)&request.certKey);
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
PRStatus SSMControlConnection_ProcessSCFindKey(SSMControlConnection* ctrl,
|
|
SECItem* msg)
|
|
{
|
|
SingleStringMessage request;
|
|
CERTCertificate* cert = NULL;
|
|
SingleItemMessage reply;
|
|
|
|
SSM_DEBUG("SecurityConfig: find key\n");
|
|
|
|
if (CMT_DecodeMessage(SingleStringMessageTemplate, &request,
|
|
(CMTItem*)msg) != CMTSuccess) {
|
|
return (PRStatus) SSM_FAILURE;
|
|
}
|
|
|
|
switch (msg->type & SSM_SPECIFIC_MASK) {
|
|
case SSM_FIND_KEY_BY_NICKNAME:
|
|
cert = CERT_FindCertByNickname(ctrl->m_certdb, request.string);
|
|
msg->type = (SECItemType)(SSM_SEC_CFG_ACTION | SSM_FIND_CERT_KEY |
|
|
SSM_FIND_KEY_BY_NICKNAME);
|
|
break;
|
|
case SSM_FIND_KEY_BY_EMAIL_ADDR:
|
|
cert = CERT_FindCertByEmailAddr(ctrl->m_certdb, request.string);
|
|
msg->type = (SECItemType)(SSM_SEC_CFG_ACTION | SSM_FIND_CERT_KEY |
|
|
SSM_FIND_KEY_BY_EMAIL_ADDR);
|
|
break;
|
|
case SSM_FIND_KEY_BY_DN:
|
|
cert = CERT_FindCertByNameString(ctrl->m_certdb, request.string);
|
|
msg->type = (SECItemType)(SSM_SEC_CFG_ACTION | SSM_FIND_CERT_KEY |
|
|
SSM_FIND_KEY_BY_DN);
|
|
break;
|
|
default:
|
|
SSM_DEBUG("Wrong subtype!");
|
|
break;
|
|
}
|
|
|
|
/* pack cert key into the reply */
|
|
if (cert == NULL) {
|
|
reply.item.len = 0;
|
|
reply.item.data = NULL;
|
|
msg->type = (SECItemType) ((long) msg->type | (long) SSM_REPLY_ERR_MESSAGE);
|
|
}
|
|
else {
|
|
reply.item.len = cert->certKey.len;
|
|
reply.item.data = cert->certKey.data;
|
|
msg->type = (SECItemType) ((long) msg->type | (long) SSM_REPLY_OK_MESSAGE);
|
|
}
|
|
|
|
if (CMT_EncodeMessage(SingleItemMessageTemplate, (CMTItem*)msg, &reply) !=
|
|
CMTSuccess) {
|
|
return (PRStatus) SSM_FAILURE;
|
|
}
|
|
|
|
return (PRStatus) SSM_SUCCESS;
|
|
}
|
|
|
|
static SSMStatus
|
|
SSMControlConnection_ProcessSCGetCertPropString(CERTCertificate* cert,
|
|
SECItem* msg)
|
|
{
|
|
SSMStatus rv = SSM_SUCCESS;
|
|
SingleStringMessage reply;
|
|
|
|
reply.string = NULL;
|
|
switch (msg->type & SSM_SPECIFIC_MASK) {
|
|
case SSM_SECCFG_GET_NICKNAME:
|
|
if (cert->nickname != NULL) {
|
|
reply.string = PL_strdup(cert->nickname);
|
|
}
|
|
break;
|
|
case SSM_SECCFG_GET_EMAIL_ADDR:
|
|
if (cert->emailAddr != NULL) {
|
|
reply.string = PL_strdup(cert->emailAddr);
|
|
}
|
|
break;
|
|
case SSM_SECCFG_GET_DN:
|
|
if (cert->subjectName != NULL) {
|
|
reply.string = PL_strdup(cert->subjectName);
|
|
}
|
|
break;
|
|
case SSM_SECCFG_GET_TRUST:
|
|
reply.string = CERT_EncodeTrustString(cert->trust);
|
|
break;
|
|
case SSM_SECCFG_GET_SERIAL_NO:
|
|
reply.string = CERT_Hexify(&cert->serialNumber, 1);
|
|
break;
|
|
case SSM_SECCFG_GET_ISSUER:
|
|
if (cert->issuerName != NULL) {
|
|
reply.string = PL_strdup(cert->issuerName);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
msg->type = (SECItemType)(SSM_REPLY_OK_MESSAGE | SSM_SEC_CFG_ACTION |
|
|
SSM_GET_CERT_PROP_BY_KEY);
|
|
if (CMT_EncodeMessage(SingleStringMessageTemplate, (CMTItem*)msg,
|
|
&reply) != CMTSuccess) {
|
|
rv = SSM_FAILURE;
|
|
goto loser;
|
|
}
|
|
loser:
|
|
if (reply.string != NULL) {
|
|
PR_Free(reply.string);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
static
|
|
SSMStatus SSMControlConnection_ProcessSCGetCertPropTime(CERTCertificate* cert,
|
|
SECItem* msg)
|
|
{
|
|
TimeMessage reply = {0};
|
|
PRExplodedTime prtime;
|
|
int64 time;
|
|
|
|
switch (msg->type & SSM_SPECIFIC_MASK) {
|
|
case SSM_SECCFG_GET_NOT_BEFORE:
|
|
if (DER_UTCTimeToTime(&time, &cert->validity.notBefore) !=
|
|
SECSuccess) {
|
|
msg->type = (SECItemType)(SSM_REPLY_ERR_MESSAGE |
|
|
SSM_SEC_CFG_ACTION |
|
|
SSM_GET_CERT_PROP_BY_KEY);
|
|
goto loser;
|
|
}
|
|
break;
|
|
case SSM_SECCFG_GET_NOT_AFTER:
|
|
if (DER_UTCTimeToTime(&time, &cert->validity.notAfter) !=
|
|
SECSuccess) {
|
|
msg->type = (SECItemType)(SSM_REPLY_ERR_MESSAGE |
|
|
SSM_SEC_CFG_ACTION |
|
|
SSM_GET_CERT_PROP_BY_KEY);
|
|
goto loser;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
PR_ExplodeTime(time, PR_GMTParameters, &prtime);
|
|
|
|
reply.year = prtime.tm_year;
|
|
reply.month = prtime.tm_month;
|
|
reply.day = prtime.tm_mday;
|
|
reply.hour = prtime.tm_hour;
|
|
reply.minute = prtime.tm_min;
|
|
reply.second = prtime.tm_sec;
|
|
|
|
msg->type = (SECItemType)(SSM_REPLY_OK_MESSAGE | SSM_SEC_CFG_ACTION |
|
|
SSM_GET_CERT_PROP_BY_KEY);
|
|
loser:
|
|
if (CMT_EncodeMessage(TimeMessageTemplate, (CMTItem*)msg, &reply) !=
|
|
CMTSuccess) {
|
|
return SSM_FAILURE;
|
|
}
|
|
return SSM_SUCCESS;
|
|
}
|
|
|
|
static
|
|
SSMStatus SSMControlConnection_ProcessSCCertIsPerm(CERTCertificate* cert,
|
|
SECItem* msg)
|
|
{
|
|
SingleNumMessage reply;
|
|
|
|
if (cert->isperm) {
|
|
reply.value = 1; /* non-zero value */
|
|
}
|
|
else {
|
|
reply.value = 0;
|
|
}
|
|
|
|
msg->type = (SECItemType)(SSM_REPLY_OK_MESSAGE | SSM_SEC_CFG_ACTION |
|
|
SSM_GET_CERT_PROP_BY_KEY);
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) !=
|
|
CMTSuccess) {
|
|
return SSM_FAILURE;
|
|
}
|
|
|
|
return SSM_SUCCESS;
|
|
}
|
|
|
|
static
|
|
SSMStatus SSMControlConnection_ProcessSCGetCertPropKey(CERTCertificate* cert,
|
|
SECItem* msg)
|
|
{
|
|
CERTCertificate* tmpCert = NULL;
|
|
SingleItemMessage reply;
|
|
|
|
switch (msg->type & SSM_SPECIFIC_MASK) {
|
|
case SSM_SECCFG_GET_ISSUER_KEY:
|
|
tmpCert = CERT_FindCertIssuer(cert, PR_Now(), certUsageAnyCA);
|
|
break;
|
|
case SSM_SECCFG_GET_SUBJECT_NEXT:
|
|
tmpCert = CERT_NextSubjectCert(cert);
|
|
break;
|
|
case SSM_SECCFG_GET_SUBJECT_PREV:
|
|
tmpCert = CERT_PrevSubjectCert(cert);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (tmpCert == NULL) {
|
|
/* error */
|
|
reply.item.len = 0;
|
|
reply.item.data = NULL;
|
|
msg->type = (SECItemType)(SSM_REPLY_ERR_MESSAGE | SSM_SEC_CFG_ACTION |
|
|
SSM_GET_CERT_PROP_BY_KEY);
|
|
}
|
|
else {
|
|
reply.item.len = tmpCert->certKey.len;
|
|
reply.item.data = tmpCert->certKey.data;
|
|
msg->type = (SECItemType)(SSM_REPLY_OK_MESSAGE | SSM_SEC_CFG_ACTION |
|
|
SSM_GET_CERT_PROP_BY_KEY);
|
|
}
|
|
if (CMT_EncodeMessage(SingleItemMessageTemplate, (CMTItem*)msg, &reply) !=
|
|
CMTSuccess) {
|
|
return SSM_FAILURE;
|
|
}
|
|
return SSM_SUCCESS;
|
|
}
|
|
|
|
static
|
|
SSMStatus SSMControlConnection_ProcessSCGetCertProp(SSMControlConnection* ctrl,
|
|
SECItem* msg)
|
|
{
|
|
SSMStatus rv = SSM_FAILURE;
|
|
SingleItemMessage request;
|
|
CERTCertificate* cert = NULL;
|
|
|
|
SSM_DEBUG("SecurityConfig: get cert prop\n");
|
|
|
|
if (CMT_DecodeMessage(SingleItemMessageTemplate, &request,
|
|
(CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* find the cert itself */
|
|
cert = CERT_FindCertByKey(ctrl->m_certdb, (SECItem*)&request.item);
|
|
if (cert == NULL) {
|
|
goto loser;
|
|
}
|
|
|
|
switch (msg->type & SSM_SPECIFIC_MASK) {
|
|
case SSM_SECCFG_GET_NICKNAME:
|
|
case SSM_SECCFG_GET_EMAIL_ADDR:
|
|
case SSM_SECCFG_GET_DN:
|
|
case SSM_SECCFG_GET_TRUST:
|
|
case SSM_SECCFG_GET_SERIAL_NO:
|
|
case SSM_SECCFG_GET_ISSUER:
|
|
rv = SSMControlConnection_ProcessSCGetCertPropString(cert, msg);
|
|
break;
|
|
case SSM_SECCFG_GET_NOT_BEFORE:
|
|
case SSM_SECCFG_GET_NOT_AFTER:
|
|
rv = SSMControlConnection_ProcessSCGetCertPropTime(cert, msg);
|
|
break;
|
|
case SSM_SECCFG_CERT_IS_PERM:
|
|
rv = SSMControlConnection_ProcessSCCertIsPerm(cert, msg);
|
|
break;
|
|
case SSM_SECCFG_GET_ISSUER_KEY:
|
|
case SSM_SECCFG_GET_SUBJECT_NEXT:
|
|
case SSM_SECCFG_GET_SUBJECT_PREV:
|
|
rv = SSMControlConnection_ProcessSCGetCertPropKey(cert, msg);
|
|
break;
|
|
default:
|
|
SSM_DEBUG("Got unknown specific mask.\n");
|
|
goto loser;
|
|
break;
|
|
}
|
|
|
|
loser:
|
|
(void)SSMControlConnection_RecycleItem((SECItem*)&request.item);
|
|
|
|
return rv;
|
|
}
|
|
|
|
typedef struct {
|
|
PRIntn type;
|
|
PRIntn length;
|
|
PRIntn allocSize;
|
|
CertEnumElement* list;
|
|
} enumCertState;
|
|
|
|
#define CERT_ENUM_INIT_SIZE 10
|
|
|
|
static SECStatus EnumCertCallback(CERTCertificate* cert, SECItem* k,
|
|
void* data)
|
|
{
|
|
enumCertState* state;
|
|
char* name;
|
|
|
|
state = (enumCertState*)data;
|
|
|
|
switch (state->type) {
|
|
case 0:
|
|
name = cert->nickname;
|
|
break;
|
|
case 1:
|
|
name = cert->emailAddr;
|
|
break;
|
|
case 2:
|
|
name = cert->subjectName;
|
|
break;
|
|
}
|
|
|
|
if (name && (*name != '\0')) {
|
|
if (state->length == state->allocSize) {
|
|
/* need to resize: double it each time */
|
|
state->list = (CertEnumElement*)
|
|
PR_Realloc((void*)state->list,
|
|
((state->allocSize)*2)*sizeof(CertEnumElement));
|
|
if (state->list == NULL) {
|
|
goto loser;
|
|
}
|
|
state->allocSize *= 2;
|
|
}
|
|
|
|
/* populate the list */
|
|
state->list[state->length].name = name;
|
|
state->list[state->length].certKey.len = cert->certKey.len;
|
|
state->list[state->length].certKey.data = cert->certKey.data;
|
|
(state->length)++;
|
|
}
|
|
|
|
return SECSuccess;
|
|
loser:
|
|
return SECFailure;
|
|
}
|
|
|
|
static SSMStatus
|
|
SSMControlConnection_ProcessSCCertIndexEnum(SSMControlConnection* ctrl,
|
|
SECItem* msg)
|
|
{
|
|
SSMStatus rv = SSM_SUCCESS;
|
|
enumCertState state = {0};
|
|
SCCertIndexEnumReply reply = {0};
|
|
|
|
SSM_DEBUG("SecurityConfig: cert index enum\n");
|
|
|
|
/* create the list with the initial size */
|
|
state.allocSize = CERT_ENUM_INIT_SIZE;
|
|
state.list = (CertEnumElement*)PR_Calloc(state.allocSize,
|
|
sizeof(CertEnumElement));
|
|
if (state.list == NULL) {
|
|
goto loser;
|
|
}
|
|
|
|
/* don't really need to decode the message: sufficient to look at mask */
|
|
switch (msg->type & SSM_SPECIFIC_MASK) {
|
|
case SSM_FIND_KEY_BY_NICKNAME:
|
|
state.type = 0;
|
|
break;
|
|
case SSM_FIND_KEY_BY_EMAIL_ADDR:
|
|
state.type = 1;
|
|
break;
|
|
case SSM_FIND_KEY_BY_DN:
|
|
state.type = 2;
|
|
break;
|
|
default:
|
|
goto loser;
|
|
break;
|
|
}
|
|
|
|
if (SEC_TraversePermCerts(ctrl->m_certdb, EnumCertCallback,
|
|
(void*)&state) != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* list is now populated */
|
|
reply.length = state.length;
|
|
reply.list = state.list;
|
|
|
|
/* pack the reply */
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_SEC_CFG_ACTION |
|
|
SSM_CERT_INDEX_ENUM);
|
|
|
|
if (CMT_EncodeMessage(SCCertIndexEnumReplyTemplate, (CMTItem*)msg,
|
|
&reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
goto done;
|
|
loser:
|
|
if (rv == SSM_SUCCESS) {
|
|
rv = SSM_FAILURE;
|
|
}
|
|
done:
|
|
if (state.list != NULL) {
|
|
PR_Free(state.list);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus SSMControlConnection_ProcessSecCfgRequest(SSMControlConnection* ctrl,
|
|
SECItem* msg)
|
|
{
|
|
SSMStatus rv;
|
|
|
|
SSM_DEBUG("Got a security config related request\n");
|
|
|
|
switch(msg->type & SSM_SUBTYPE_MASK) {
|
|
case SSM_ADD_CERT_TO_TEMP_DB:
|
|
rv = SSMControlConnection_ProcessSCAddCertToTempDB(ctrl, msg);
|
|
break;
|
|
case SSM_ADD_TEMP_CERT_TO_DB:
|
|
rv = SSMControlConnection_ProcessSCAddTempCertToPermDB(ctrl, msg);
|
|
break;
|
|
case SSM_DELETE_PERM_CERTS:
|
|
rv = SSMControlConnection_ProcessSCDeletePermCerts(ctrl, msg);
|
|
break;
|
|
case SSM_FIND_CERT_KEY:
|
|
rv = SSMControlConnection_ProcessSCFindKey(ctrl, msg);
|
|
break;
|
|
case SSM_GET_CERT_PROP_BY_KEY:
|
|
rv = SSMControlConnection_ProcessSCGetCertProp(ctrl, msg);
|
|
break;
|
|
case SSM_CERT_INDEX_ENUM:
|
|
rv = SSMControlConnection_ProcessSCCertIndexEnum(ctrl, msg);
|
|
break;
|
|
default:
|
|
SSM_DEBUG("Got unknown security config message %lx\n", msg->type);
|
|
rv = SSM_FAILURE;
|
|
break;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus SSMControlConnection_ProcessTLSRequest(SSMControlConnection* ctrl,
|
|
SECItem* msg)
|
|
{
|
|
SSMStatus rv;
|
|
TLSStepUpRequest request;
|
|
SingleNumMessage reply;
|
|
SSMSSLDataConnection* conn = NULL;
|
|
|
|
SSM_DEBUG("Got a TLS step-up request.\n");
|
|
|
|
if (CMT_DecodeMessage(TLSStepUpRequestTemplate, &request, (CMTItem*)msg) !=
|
|
CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
rv = SSMControlConnection_GetResource(ctrl, request.connID,
|
|
(SSMResource**)&conn);
|
|
if (rv != SSM_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
|
|
PR_ASSERT(conn != NULL);
|
|
PR_ASSERT(conn->isTLS);
|
|
PR_ASSERT(conn->stepUpFD != NULL);
|
|
|
|
/* turn on security for this connection */
|
|
SSM_LockResource(&(conn->super.super.super));
|
|
|
|
/* Set the client context so that the SSL connection knows
|
|
how to interact with the user/client. */
|
|
conn->super.super.super.m_clientContext = request.clientContext;
|
|
|
|
/* Poke the step-up FD to make the SSL connection object
|
|
turn on encryption. */
|
|
PR_SetPollableEvent(conn->stepUpFD);
|
|
|
|
/* Wait until the connection has been {SSL,TLS}-enabled. */
|
|
SSM_WaitResource(&(conn->super.super.super), PR_INTERVAL_NO_TIMEOUT);
|
|
rv = conn->m_error; /* get result code */
|
|
|
|
SSM_UnlockResource(&(conn->super.super.super));
|
|
|
|
loser:
|
|
/* compose reply */
|
|
reply.value = rv;
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_RESOURCE_ACTION |
|
|
SSM_TLS_STEPUP);
|
|
|
|
CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply);
|
|
rv = SSM_SUCCESS;
|
|
if (conn != NULL) {
|
|
SSM_FreeResource((SSMResource*)conn);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessProxyStepUpRequest(SSMControlConnection* ctrl,
|
|
SECItem* msg)
|
|
{
|
|
SSMStatus rv;
|
|
ProxyStepUpRequest request;
|
|
SingleNumMessage reply;
|
|
SSMSSLDataConnection* conn = NULL;
|
|
|
|
SSM_DEBUG("Got a proxy step-up request.\n");
|
|
|
|
if (CMT_DecodeMessage(ProxyStepUpRequestTemplate, &request,
|
|
(CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
rv = SSMControlConnection_GetResource(ctrl, request.connID,
|
|
(SSMResource**)&conn);
|
|
if (rv != SSM_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
|
|
PR_ASSERT(conn != NULL);
|
|
PR_ASSERT(conn->isTLS);
|
|
PR_ASSERT(conn->stepUpFD != NULL);
|
|
|
|
/* turn on security for this connection */
|
|
SSM_LockResource(&(conn->super.super.super));
|
|
|
|
/* Set the client context so that the SSL connection knows
|
|
how to interact with the user/client. */
|
|
conn->super.super.super.m_clientContext = request.clientContext;
|
|
|
|
/* replace the hostname with the actual URL (remote host) */
|
|
/* XXX sjlee: I don't need to copy the string??? */
|
|
conn->hostName = request.url;
|
|
/* Poke the step-up FD to make the SSL connection object
|
|
turn on encryption. */
|
|
PR_SetPollableEvent(conn->stepUpFD);
|
|
|
|
/* Wait until the connection has been {SSL,TLS}-enabled. */
|
|
SSM_WaitResource(&(conn->super.super.super), PR_INTERVAL_NO_TIMEOUT);
|
|
rv = conn->m_error; /* get result code */
|
|
|
|
SSM_UnlockResource(&(conn->super.super.super));
|
|
|
|
loser:
|
|
/* compose reply */
|
|
reply.value = rv;
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_RESOURCE_ACTION |
|
|
SSM_PROXY_STEPUP);
|
|
|
|
CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply);
|
|
rv = SSM_SUCCESS;
|
|
if (conn != NULL) {
|
|
SSM_FreeResource((SSMResource*)conn);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessGetExtensionRequest(SSMControlConnection *ctrl,
|
|
SECItem *msg)
|
|
{
|
|
GetCertExtension request;
|
|
SSMStatus rv;
|
|
SSMResource *res=NULL;
|
|
SSMResourceCert *certRes;
|
|
SECStatus srv;
|
|
SingleItemMessage reply;
|
|
|
|
if (CMT_DecodeMessage(GetCertExtensionTemplate, &request,
|
|
(CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
rv = SSMControlConnection_GetResource(ctrl, request.resID, &res);
|
|
if (rv != SSM_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
if (!SSM_IsAKindOf(res, SSM_RESTYPE_CERTIFICATE)) {
|
|
goto loser;
|
|
}
|
|
certRes = (SSMResourceCert*)res;
|
|
reply.item.data = NULL;
|
|
reply.item.len = 0;
|
|
srv = CERT_FindCertExtension(certRes->cert, request.extension,
|
|
(SECItem*)&reply.item);
|
|
if (srv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (CMT_EncodeMessage(SingleItemMessageTemplate, (CMTItem*)msg,
|
|
&reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
if (msg->data == NULL || msg->len == 0) {
|
|
goto loser;
|
|
}
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_CERT_ACTION | SSM_EXTENSION_VALUE);
|
|
SSM_FreeResource(res);
|
|
return SSM_SUCCESS;
|
|
loser:
|
|
if (res) {
|
|
SSM_FreeResource(res);
|
|
}
|
|
return SSM_FAILURE;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessHTMLCertInfoRequest(SSMControlConnection *ctrl,
|
|
SECItem *msg)
|
|
{
|
|
HTMLCertInfoRequest request;
|
|
SingleStringMessage reply;
|
|
SSMResource *res = NULL;
|
|
SSMResourceCert *certRes = NULL;
|
|
SSMStatus rv;
|
|
|
|
if(CMT_DecodeMessage(HTMLCertInfoRequestTemplate, &request,
|
|
(CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
rv = SSMControlConnection_GetResource(ctrl, request.certID, &res);
|
|
if (rv != SSM_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
if (!SSM_IsAKindOf(res, SSM_RESTYPE_CERTIFICATE)) {
|
|
goto loser;
|
|
}
|
|
certRes = (SSMResourceCert*)res;
|
|
reply.string = CERT_HTMLCertInfo(certRes->cert, request.showImages,
|
|
request.showIssuer);
|
|
if (reply.string == NULL) {
|
|
goto loser;
|
|
}
|
|
|
|
if (CMT_EncodeMessage(SingleStringMessageTemplate, (CMTItem*)msg,
|
|
&reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
if (msg->data == NULL || msg->len == 0) {
|
|
goto loser;
|
|
}
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_CERT_ACTION | SSM_HTML_INFO);
|
|
SSM_FreeResource(res);
|
|
return SSM_SUCCESS;
|
|
loser:
|
|
if (res) {
|
|
SSM_FreeResource(res);
|
|
}
|
|
return SSM_FAILURE;
|
|
}
|