/* -*- 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" #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; } SSMStatus SSMControlConnection_ProcessMiscRequest(SSMControlConnection * ctrl, SECItem * msg) { SingleNumMessage req; SingleItemMessage reply; char *buf; 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_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; itype & 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 ? strdup(request.hostname) : NULL); infoSecAdvisor.senderAddr = (request.senderAddr ? strdup(request.senderAddr) : NULL); 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; }