gecko-dev/security/psm/server/advisor.c

3366 строки
102 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.
*/
#ifdef XP_MAC
#include "platform.h"
#endif
#include "advisor.h"
#include "nlsutil.h"
#include "minihttp.h"
#include "p12res.h"
#include "textgen.h"
#include "sslskst.h"
#include "certlist.h"
#include "ocsp.h"
#include "secoid.h"
#include "prefs.h"
#include "messages.h"
#include "secerr.h"
#include "sslerr.h"
#include "base64.h"
/*
* This is the structure used to gather all of the CA's that can be used
* for OCSP responders.
*/
typedef struct SSMDefaultOCSPRespondersListStr{
SSMSortedList *respondersWithAIA;
SSMSortedList *respondersWithoutAIA;
SSMTextGenContext *cx;
char *wrapper, *defaultSigner;
} SSMDefaultOCSPRespondersList;
SSMStatus SSM_SetSelectedItemInfo(SSMSecurityAdvisorContext* cx);
#define SSMRESOURCE(object) (&object->super)
#define SSM_NO_INFO "sa_no_info"
#define SSM_NAVIGATOR_NO_SEC "sa_navigator_no_sec"
#define SSM_NAVIGATOR_SSL "sa_navigator_ssl"
#define SSM_NAVIGATOR_BAD_SSL "sa_navigator_bad_ssl"
#define SSM_MESSAGE "sa_message"
#define SSM_MESSAGE_NOT_SIGNED "sa_message_not_signed"
#define SSM_MESSAGE_NOT_ENCRYPTED "sa_message_not_encrypted"
#define SSM_MESSAGE_SIGNED "sa_message_signed"
#define SSM_MESSAGE_ENCRYPTED "sa_message_encrypted"
#define SSM_MESSAGE_BAD_SIGNED "sa_message_bad_signed"
#define SSM_MESSAGE_BAD_ENCRYPTED "sa_message_bad_encrypted"
/* A list of User agent strings that we know can do S/MIME
* and want the Java tab as well.
*/
#define COMMON_TO_SMIME_AND_JAVA "Mozilla/4.7"
const char *kSMimeApps[] = {COMMON_TO_SMIME_AND_JAVA, NULL};
const char *kJavaJSApps[] = {COMMON_TO_SMIME_AND_JAVA, NULL};
char * SSM_ConvertStringToHTMLString(char * string);
char * SSMUI_GetPKCS12Error(PRIntn error, PRBool isBackup);
PRBool
SSM_IsCRLPresent(SSMControlConnection *ctrl)
{
SECStatus rv = SECFailure;
CERTCrlHeadNode *head = NULL;
PRBool retVal = PR_FALSE;
rv = SEC_LookupCrls(ctrl->m_certdb, &head, -1);
if (rv != SECSuccess) {
goto done;
}
if (head == NULL) {
goto done;
}
retVal = (head->first == NULL) ? PR_FALSE : PR_TRUE;
PORT_FreeArena(head->arena, PR_FALSE);
done:
return retVal;
}
SSMStatus
SSMSecurityAdvisorContext_Create(SSMControlConnection *ctrl,
InfoSecAdvisor *info,
SSMResource **res)
{
SSMStatus rv = PR_SUCCESS;
SSMSecurityAdvisorContext *ct;
int i;
*res = NULL; /* in case we fail */
ct = (SSMSecurityAdvisorContext *)
PR_CALLOC(sizeof(SSMSecurityAdvisorContext));
if (!ct)
goto loser;
rv = SSMResource_Init(ctrl, &ct->super, SSM_RESTYPE_SECADVISOR_CONTEXT);
if (rv != PR_SUCCESS)
goto loser;
/* this hash will contail list of formatted certs nickname to display */
ct->m_certhash = NULL;
ct->m_certsIncluded = 0;
/* register us with ControlConection */
if (!ctrl->m_secAdvisorList) {
ctrl->m_secAdvisorList = (SECItem *) PR_Malloc(sizeof(SECItem));
ctrl->m_secAdvisorList->len = 0;
ctrl->m_secAdvisorList->data = NULL;
}
ctrl->m_secAdvisorList->len++;
ctrl->m_secAdvisorList->data = (unsigned char *) PR_REALLOC(ctrl->m_secAdvisorList->data,
ctrl->m_secAdvisorList->len);
ctrl->m_secAdvisorList->data[ ctrl->m_secAdvisorList->len - 1 ] =
((SSMResource *)ct)->m_id;
if (info) {
ct->infoContext = info->infoContext;
ct->resID = info->resID;
ct->hostname = info->hostname ? PL_strdup(info->hostname) : NULL;
ct->senderAddr = info->senderAddr ? PL_strdup(info->senderAddr) : NULL;
ct->encryptedP7CInfo = info->encryptedP7CInfo;
ct->signedP7CInfo = info->signedP7CInfo;
ct->decodeError = info->decodeError;
ct->verifyError = info->verifyError;
ct->encryptthis = info->encryptthis;
ct->signthis = info->signthis;
ct->numRecipients = info->numRecipients;
if (info->numRecipients > 0) {
ct->recipients = (char **) PR_CALLOC(sizeof(char*)*(info->numRecipients));
if (!ct->recipients) {
goto loser;
}
for (i=0;i<info->numRecipients;i++) {
ct->recipients[i] = PL_strdup(info->recipients[i]);
}
}
SSM_SetSelectedItemInfo(ct);
}
/* Create a URL for the security advisor window. */
rv = (SSMStatus) SSM_GenerateURL(ctrl, "get", "secadvisor",
&ct->super, NULL,
&ct->m_width, &ct->m_height,
&ct->m_url);
if (rv != SSM_SUCCESS)
goto loser;
SSMSecurityAdvisorContext_Invariant(ct);
*res = &ct->super;
return PR_SUCCESS;
loser:
if (rv == PR_SUCCESS) rv = PR_FAILURE;
if (ct)
{
ct->super.m_refCount = 1; /* force destroy */
SSM_FreeResource(&ct->super);
}
return rv;
}
char * SSMUI_GetPKCS12Error(PRIntn error, PRBool isBackup)
{
char * responseKey;
switch (error) {
case SSM_ERR_NO_PASSWORD:
responseKey = "pkcs12_bad_portable_password_restore";
break;
case SSM_ERR_BAD_DB_PASSWORD:
responseKey = "pkcs12_bad_db_password";
break;
case SSM_ERR_BAD_FILENAME:
responseKey = "pkcs12_bad_filepath";
break;
case SSM_ERR_NEED_USER_INIT_DB:
responseKey = "pkcs12_need_db_init";
break;
case SSM_ERR_CANNOT_DECODE:
responseKey="pkcs12_cannot_decode";
break;
case SSM_PKCS12_CERT_ALREADY_EXISTS:
responseKey="pkcs12_cert_already_exists";
break;
case SSM_ERR_BAD_REQUEST:
default:
responseKey = (isBackup) ? "pkcs12_backup_failure" :
"pkcs12_restore_failure";
}
return responseKey;
}
SSMStatus
SSMSecurityAdvisorContext_Destroy(SSMResource *res, PRBool doFree)
{
SSMSecurityAdvisorContext *ct = (SSMSecurityAdvisorContext *) res;
PRIntn i = 0, others = 0;
if (ct)
{
PR_ASSERT(SSM_IsAKindOf(res, SSM_RESTYPE_SECADVISOR_CONTEXT));
SSMResource_Destroy(res, PR_FALSE);
/* Dereference the security info object */
if (ct->m_infoSource)
{
SSM_FreeResource(ct->m_infoSource);
ct->m_infoSource = NULL;
}
/* Free the URL */
PR_FREEIF(ct->m_url);
if (ct->m_certhash)
SSMSortedList_Destroy(ct->m_certhash);
/* deregister with control connection */
while (i < res->m_connection->m_secAdvisorList->len) {
if (res->m_connection->m_secAdvisorList->data[i] == res->m_id)
res->m_connection->m_secAdvisorList->data[i] = 0;
if (res->m_connection->m_secAdvisorList->data[i])
others ++;
i++;
}
if (!others) {
SECITEM_ZfreeItem(res->m_connection->m_secAdvisorList, PR_TRUE);
res->m_connection->m_secAdvisorList = NULL;
}
if (ct->socketStatus) {
SSM_FreeResource(&ct->socketStatus->super);
}
PR_FREEIF(ct->hostname);
PR_FREEIF(ct->senderAddr);
if (ct->recipients) {
for (i=0; i<ct->numRecipients; i++) {
PR_FREEIF(ct->recipients[i]);
}
PR_FREEIF(ct->recipients);
}
/* Free if asked */
if (doFree)
PR_Free(ct);
}
return PR_SUCCESS; /* no way to fail, really */
}
void
SSMSecurityAdvisorContext_Invariant(SSMSecurityAdvisorContext *ct)
{
/* Check superclass. */
SSMResource_Invariant(&ct->super);
/* Make sure we always have a URL. */
PR_ASSERT(ct->m_url != NULL);
}
SSMStatus
SSMSecurityAdvisorContext_GetAttrIDs(SSMResource *res,
SSMAttributeID **ids,
PRIntn *count)
{
SSMStatus rv;
rv = SSMResource_GetAttrIDs(res, ids, count);
if (rv != PR_SUCCESS)
goto loser;
*ids = (SSMAttributeID *) PR_REALLOC(*ids, (*count + 4) * sizeof(SSMAttributeID));
if (! *ids) goto loser;
(*ids)[*count++] = SSM_FID_SECADVISOR_URL;
(*ids)[*count++] = SSM_FID_SECADVISOR_WIDTH;
(*ids)[*count++] = SSM_FID_SECADVISOR_HEIGHT;
(*ids)[*count++] = SSM_FID_CLIENT_CONTEXT;
goto done;
loser:
if (rv == PR_SUCCESS) rv = PR_FAILURE;
done:
return rv;
}
SSMStatus
SSMSecurityAdvisorContext_GetAttr(SSMResource *res,
SSMAttributeID attrID,
SSMResourceAttrType attrType,
SSMAttributeValue *value)
{
SSMStatus rv = PR_SUCCESS;
SSMSecurityAdvisorContext *ct = (SSMSecurityAdvisorContext *) res;
SSMSecurityAdvisorContext_Invariant(ct);
switch(attrID)
{
case SSM_FID_SECADVISOR_URL:
/* Duplicate and return the string. */
value->type = SSM_STRING_ATTRIBUTE;
value->u.string.len = PL_strlen(ct->m_url);
value->u.string.data = (unsigned char *) PL_strdup(ct->m_url);
break;
case SSM_FID_SECADVISOR_WIDTH:
case SSM_FID_SECADVISOR_HEIGHT:
value->type = SSM_NUMERIC_ATTRIBUTE;
value->u.numeric = (attrID == SSM_FID_SECADVISOR_WIDTH) ?
ct->m_width : ct->m_height;
break;
case SSM_FID_CLIENT_CONTEXT:
SSM_DEBUG("Getting security advisor client context");
value->type = SSM_STRING_ATTRIBUTE;
if (!(value->u.string.data = (unsigned char *) PR_Malloc(res->m_clientContext.len))) {
goto loser;
}
memcpy(value->u.string.data, res->m_clientContext.data, res->m_clientContext.len);
value->u.string.len = res->m_clientContext.len;
break;
default:
rv = SSMResource_GetAttr(res,attrID,attrType,value);
if (rv != PR_SUCCESS)
goto loser;
}
goto done;
loser:
value->type = SSM_NO_ATTRIBUTE;
if (rv == PR_SUCCESS)
rv = PR_FAILURE;
done:
return rv;
}
SSMStatus SSMSecurityAdvisorContext_SetAttr(SSMResource *res,
SSMAttributeID attrID,
SSMAttributeValue *value)
{
switch(attrID) {
case SSM_FID_CLIENT_CONTEXT:
SSM_DEBUG("Setting security advisor client context\n");
if (value->type != SSM_STRING_ATTRIBUTE) {
goto loser;
}
if (!(res->m_clientContext.data = (unsigned char *) PR_Malloc(value->u.string.len))) {
goto loser;
}
memcpy(res->m_clientContext.data, value->u.string.data, value->u.string.len);
res->m_clientContext.len = value->u.string.len;
break;
default:
SSM_DEBUG("Got unknown security advisor Set Attribute Request %d\n", attrID);
goto loser;
break;
}
return PR_SUCCESS;
loser:
return PR_FAILURE;
}
/* Preference keys used in Security Advisor JavaScript.
* They are used to cache temporary changes the user has made.
*/
#define SSL2_SPK "enable_ssl2"
#define SSL3_SPK "enable_ssl3"
#define TLS_SPK "enable_tls"
#define CLIENT_AUTH_SPK "client_auth_auto_select"
#define EMAIL_CERT_SPK "default_email_cert"
#define WARN_ENTER_SECURE_SPK "warn_entering_secure"
#define WARN_LEAVE_SECURE_SPK "warn_leaving_secure"
#define WARN_VIEW_MIXED_SPK "warn_viewing_mixed"
#define WARN_SUBMIT_INSECURE_SPK "warn_submit_insecure"
#define ENCRYPT_MAIL_SPK "mail_encrypt_outgoing_mail"
#define SIGN_MAIL_SPK "mail_crypto_sign_outgoing_mail"
#define SIGN_NEWS_SPK "mail_crypto_sign_outgoing_news"
/* maximum number of pref items that will be sent back to the client */
#define ITEMS_MAX 11
static SSMStatus SSMSecurityAdvisor_get_bool_value(HTTPRequest* req,
char* key, PRBool* value)
{
SSMStatus rv;
char* tmpStr = NULL;
rv = SSM_HTTPParamValue(req, key, &tmpStr);
if (rv != SSM_SUCCESS) {
return rv;
}
if (PL_strcmp(tmpStr, "true") == 0) {
*value = PR_TRUE;
}
else if (PL_strcmp(tmpStr, "false") == 0) {
*value = PR_FALSE;
}
else {
SSM_DEBUG("I don't understand the value.\n");
return SSM_FAILURE;
}
return rv;
}
static SSMStatus ssm_set_pack_bool_pref(PrefSet* prefs, char* key,
PRBool value, SetPrefElement* list,
PRIntn* n)
{
SSMStatus rv;
/* set the change to memory */
rv = PREF_SetBoolPref(prefs, key, value);
if (rv != PR_SUCCESS) {
return rv;
}
/* pack the change */
list[*n].key = PL_strdup(key);
list[*n].type = BOOL_PREF;
if (value == PR_TRUE) {
list[*n].value = PL_strdup("true");
}
else {
list[*n].value = PL_strdup("false");
}
(*n)++;
return rv;
}
static SSMStatus
SSMSecurityAdvisorContext_SavePrefs(SSMSecurityAdvisorContext* cx,
HTTPRequest* req)
{
SSMStatus rv;
SSMControlConnection* ctrl = NULL;
PrefSet* prefs = NULL;
PRBool ssl2on;
PRBool ssl3on;
PRBool tlson;
PRBool autoSelect;
PRBool warnEnterSecure;
PRBool warnLeaveSecure;
PRBool warnViewMixed;
PRBool warnSubmitInsecure;
PRBool encryptMail;
PRBool signMail;
PRBool signNews;
char* autoStr = NULL;
char* defaultCert = NULL;
SetPrefElement list[ITEMS_MAX];
SetPrefListMessage request;
PRIntn n = 0; /* counter */
int i;
CMTItem message;
PR_ASSERT(cx != NULL && cx->super.m_connection != NULL &&
cx->super.m_connection->m_prefs != NULL);
ctrl = cx->super.m_connection;
prefs = ctrl->m_prefs;
/* retrieve pref values */
rv = SSMSecurityAdvisor_get_bool_value(req, SSL2_SPK, &ssl2on);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSMSecurityAdvisor_get_bool_value(req, SSL3_SPK, &ssl3on);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSMSecurityAdvisor_get_bool_value(req, TLS_SPK, &tlson);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSMSecurityAdvisor_get_bool_value(req, CLIENT_AUTH_SPK, &autoSelect);
if (rv != SSM_SUCCESS) {
goto loser;
}
if (autoSelect == PR_TRUE) {
autoStr = "Select Automatically";
}
else {
autoStr = "Ask Every Time";
}
rv = SSM_HTTPParamValue(req, EMAIL_CERT_SPK, &defaultCert);
if (defaultCert[0] == '\0') {
defaultCert = NULL;
rv = SSM_SUCCESS;
}
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSMSecurityAdvisor_get_bool_value(req, WARN_ENTER_SECURE_SPK,
&warnEnterSecure);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSMSecurityAdvisor_get_bool_value(req, WARN_LEAVE_SECURE_SPK,
&warnLeaveSecure);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSMSecurityAdvisor_get_bool_value(req, WARN_VIEW_MIXED_SPK,
&warnViewMixed);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSMSecurityAdvisor_get_bool_value(req, WARN_SUBMIT_INSECURE_SPK,
&warnSubmitInsecure);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSMSecurityAdvisor_get_bool_value(req, ENCRYPT_MAIL_SPK,
&encryptMail);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSMSecurityAdvisor_get_bool_value(req, SIGN_MAIL_SPK, &signMail);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSMSecurityAdvisor_get_bool_value(req, SIGN_NEWS_SPK, &signNews);
if (rv != SSM_SUCCESS) {
goto loser;
}
/* commit the changes */
if (PREF_BoolPrefChanged(prefs, "security.enable_ssl2", ssl2on)) {
/* value has changed */
rv = ssm_set_pack_bool_pref(prefs, "security.enable_ssl2", ssl2on,
(SetPrefElement*)list, &n);
SSL_EnableDefault(SSL_ENABLE_SSL2, ssl2on);
}
if (PREF_BoolPrefChanged(prefs, "security.enable_ssl3", ssl3on)) {
rv = ssm_set_pack_bool_pref(prefs, "security.enable_ssl3", ssl3on,
(SetPrefElement*)list, &n);
SSL_EnableDefault(SSL_ENABLE_SSL3, ssl3on);
}
if (PREF_BoolPrefChanged(prefs, "security.enable_tls", tlson)) {
rv = ssm_set_pack_bool_pref(prefs, "security.enable_tls", tlson,
(SetPrefElement*)list, &n);
SSL_EnableDefault(SSL_ENABLE_TLS, tlson);
}
if (PREF_StringPrefChanged(prefs, "security.default_personal_cert",
autoStr)) {
rv = PREF_SetStringPref(prefs, "security.default_personal_cert",
autoStr);
list[n].key = PL_strdup("security.default_personal_cert");
list[n].type = STRING_PREF;
list[n].value = PL_strdup(autoStr);
n++;
}
if (PREF_StringPrefChanged(prefs, "security.default_mail_cert",
defaultCert)) {
rv = PREF_SetStringPref(prefs, "security.default_mail_cert",
defaultCert);
list[n].key = PL_strdup("security.default_mail_cert");
list[n].type = STRING_PREF;
list[n].value = PL_strdup(defaultCert);
n++;
}
if (PREF_BoolPrefChanged(prefs, "security.warn_entering_secure",
warnEnterSecure)) {
rv = ssm_set_pack_bool_pref(prefs, "security.warn_entering_secure",
warnEnterSecure, (SetPrefElement*)list,
&n);
}
if (PREF_BoolPrefChanged(prefs, "security.warn_leaving_secure",
warnLeaveSecure)) {
rv = ssm_set_pack_bool_pref(prefs, "security.warn_leaving_secure",
warnLeaveSecure, (SetPrefElement*)list,
&n);
}
if (PREF_BoolPrefChanged(prefs, "security.warn_viewing_mixed",
warnViewMixed)) {
rv = ssm_set_pack_bool_pref(prefs, "security.warn_viewing_mixed",
warnViewMixed, (SetPrefElement*)list, &n);
}
if (PREF_BoolPrefChanged(prefs, "security.warn_submit_insecure",
warnSubmitInsecure)) {
rv = ssm_set_pack_bool_pref(prefs, "security.warn_submit_insecure",
warnSubmitInsecure, (SetPrefElement*)list,
&n);
}
if (PREF_BoolPrefChanged(prefs, "mail.encrypt_outgoing_mail",
encryptMail)) {
rv = ssm_set_pack_bool_pref(prefs, "mail.encrypt_outgoing_mail",
encryptMail, (SetPrefElement*)list, &n);
}
if (PREF_BoolPrefChanged(prefs, "mail.crypto_sign_outgoing_mail",
signMail)) {
rv = ssm_set_pack_bool_pref(prefs, "mail.crypto_sign_outgoing_mail",
signMail, (SetPrefElement*)list, &n);
}
if (PREF_BoolPrefChanged(prefs, "mail.crypto_sign_outgoing_news",
signNews)) {
rv = ssm_set_pack_bool_pref(prefs, "mail.crypto_sign_outgoing_news",
signNews, (SetPrefElement*)list, &n);
}
rv = SSM_HTTPDefaultCommandHandler(req);
if (rv != PR_SUCCESS) {
goto loser;
}
/* finally, send the changes to the plugin so that it can save the
* changes
*/
if (n > 0) {
/* we need to send this event only if prefs changed */
request.length = n;
request.list = list;
message.type = SSM_EVENT_MESSAGE | SSM_SAVE_PREF_EVENT;
if (CMT_EncodeMessage(SetPrefListMessageTemplate, &message,
&request) != CMTSuccess) {
goto loser;
}
/* send the message through the control out queue */
SSM_SendQMessage(ctrl->m_controlOutQ, SSM_PRIORITY_NORMAL,
message.type, message.len, (char*)message.data,
PR_TRUE);
}
loser:
/* clean out list */
for (i = 0; i < n; i++) {
if (list[i].key != NULL) {
PR_Free(list[i].key);
}
if (list[i].value != NULL) {
PR_Free(list[i].value);
}
}
return rv;
}
SSMStatus
SSMSecurityAdvisorContext_DoPKCS12Response(SSMSecurityAdvisorContext *advisor,
HTTPRequest *req,
const char *responseKey)
{
SSMTextGenContext *cx = NULL;
SSMStatus rv = SSM_FAILURE;
char name[256];
char *page = "pkcs12_action_followup";
char *type = NULL, *hdrs = NULL, *content = NULL;
char *alertMessage = NULL, *out = NULL;
rv = SSMTextGen_NewTopLevelContext(req, &cx);
if (rv != SSM_SUCCESS) {
SSM_HTTPReportSpecificError(req, "DoPKCS12Response: Error%d "
"attempting to create textgen context.",
rv);
goto loser;
}
PR_snprintf(name, 256, "%s_type", page);
rv = SSM_GetUTF8Text(cx, name, &type);
if (rv != SSM_SUCCESS) {
goto loser;
}
PR_snprintf(name, 256, "%s_content", page);
rv = SSM_GetAndExpandText(cx, name, &content);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSM_GetUTF8Text(cx, responseKey, &alertMessage);
if (rv != SSM_SUCCESS) {
goto loser;
}
out = PR_smprintf(content, alertMessage, advisor->super.m_id);
rv = SSM_HTTPSendOKHeader(req, hdrs, type);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSM_HTTPSendUTF8String(req, out);
if (rv != SSM_SUCCESS) {
goto loser;
}
req->sentResponse = PR_TRUE;
goto done;
loser:
if (rv == SSM_SUCCESS) rv = SSM_FAILURE;
done:
if (cx != NULL) {
SSMTextGen_DestroyContext(cx);
}
PR_FREEIF(type);
PR_FREEIF(hdrs);
PR_FREEIF(content);
PR_FREEIF(out);
PR_FREEIF(alertMessage);
return rv;
}
static SSMStatus
SSMSecurityAdvisorContext_DoNewDefMailReponse(SSMPKCS12Context *p12Cxt,
HTTPRequest *req)
{
SSMTextGenContext *cx = NULL;
char *fmt=NULL, *content=NULL, *defEmailCert=NULL, *expContent=NULL;
SSMStatus rv;
rv = SSMTextGen_NewTopLevelContext(req, &cx);
if (rv != SSM_SUCCESS) {
SSM_HTTPReportSpecificError(req, "DoNewDefMailReponse: Failed to "
"create new TextGenContext.");
goto loser;
}
rv = SSM_FindUTF8StringInBundles(cx, "pkcs12_restore_success_new_mail",
&fmt);
if (rv != SSM_SUCCESS || fmt == NULL) {
goto loser;
}
rv = PREF_GetStringPref(req->ctrlconn->m_prefs,
"security.default_mail_cert", &defEmailCert);
if (rv != SSM_SUCCESS || defEmailCert == NULL) {
goto loser;
}
content = PR_smprintf(fmt, defEmailCert, req->target->m_id);
if (content == NULL) {
goto loser;
}
rv = SSMTextGen_SubstituteString(cx, content, &expContent);
if (rv != SSM_SUCCESS || expContent == NULL) {
goto loser;
}
rv = SSM_HTTPSendOKHeader(req, "", "text/html");
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSM_HTTPSendUTF8String(req, expContent);
if (rv != SSM_SUCCESS) {
goto loser;
}
PR_Free(expContent);
PR_Free(content);
PR_Free(fmt);
req->sentResponse = PR_TRUE;
return SSM_SUCCESS;
loser:
if (cx != NULL) {
SSMTextGen_DestroyContext(cx);
}
PR_FREEIF(fmt);
PR_FREEIF(content);
PR_FREEIF(expContent);
return SSM_FAILURE;
}
SSMStatus SSMSecurityAdvisorContext_DoPKCS12Restore(
SSMSecurityAdvisorContext *res,
HTTPRequest *req)
{
SSMStatus rv;
SSMPKCS12CreateArg p12Create;
SSMPKCS12Context *p12Cxt=NULL;
SSMResourceID rid;
const char *responseKey;
p12Create.isExportContext = PR_FALSE;
rv = (SSMStatus) SSM_CreateResource(SSM_RESTYPE_PKCS12_CONTEXT,
(void*)&p12Create,
SSMRESOURCE(res)->m_connection,
&rid, (SSMResource **)(&p12Cxt));
if (rv != PR_SUCCESS) {
goto done;
}
/* pass along Advisor's client context for window management */
/* pass along Advisor's client context for window management */
SSM_CopyCMTItem(&((SSMResource *)p12Cxt)->m_clientContext,
&((SSMResource *)res)->m_clientContext);
rv = SSMPKCS12Context_RestoreCertFromPKCS12File(p12Cxt);
if (rv == SSM_ERR_NEW_DEF_MAIL_CERT) {
SSM_ChangeCertSecAdvisorList(req, NULL, certHashAdd);
rv = SSMSecurityAdvisorContext_DoNewDefMailReponse(p12Cxt,req);
} else {
if (p12Cxt->super.m_buttonType == SSM_BUTTON_CANCEL){
rv = SSM_SUCCESS;
SSM_HTTPReportError(req, HTTP_NO_CONTENT);
} else if (rv != SSM_SUCCESS) {
responseKey = SSMUI_GetPKCS12Error(rv, PR_FALSE);
} else {
responseKey = "pkcs12_restore_success";
SSM_ChangeCertSecAdvisorList(req, NULL, certHashAdd);
}
rv = SSMSecurityAdvisorContext_DoPKCS12Response(res, req, responseKey);
}
done:
if (p12Cxt != NULL) {
SSM_FreeResource(SSMRESOURCE(p12Cxt));
}
return rv;
}
static CERTCertificate*
SSMSecurityAdvisorContext_FindCertByNickname(SSMSecurityAdvisorContext *cx,
HTTPRequest *req,
char *certNickname)
{
CERTCertList *certList = NULL;
CERTCertificate *cert = NULL;
CERTCertListNode *certListNode = NULL;
PRInt32 numcerts = 0;
SSMTextGenContext *textGenCx = NULL;
SSMStatus rv;
char *htmlTemplate = NULL;
certList = CERT_NewCertList();
certList = CERT_CreateNicknameCertList(certList,
cx->super.m_connection->m_certdb,
certNickname, PR_Now(), PR_FALSE);
if (certList == NULL) {
certList = PK11_FindCertsFromNickname(certNickname, &cx->super);
if (certList == NULL) {
SSM_DEBUG("Could not find a certificate with nick '%s' "
"in cert database\n", certNickname);
goto loser;
}
}
certListNode = CERT_LIST_HEAD(certList);
while (!CERT_LIST_END(certListNode, certList)) {
numcerts++;
certListNode = CERT_LIST_NEXT(certListNode);
}
if (numcerts > 1) {
char * formName = NULL, *params = NULL;
rv = SSM_HTTPParamValue(req, "formName", &formName);
if (rv != SSM_SUCCESS || !formName)
SSM_DEBUG("AdvisorContext_FindCertByNickname:Can't get original form\n");
params = PR_smprintf("origin=%s",formName);
cx->m_nickname = PL_strdup(certNickname);
rv = SSMControlConnection_SendUIEvent(cx->super.m_connection,
"get",
"choose_cert",
&cx->super,
params,
&cx->super.m_clientContext,
PR_TRUE);
/* Now wait until we are notified by the handler that the user
* has selected a cert.
*/
SSM_LockUIEvent(&cx->super);
SSM_WaitUIEvent(&cx->super, PR_INTERVAL_NO_TIMEOUT);
cert = (CERTCertificate*)cx->super.m_connection->super.super.m_uiData;
if (cx->super.m_buttonType != SSM_BUTTON_CANCEL) {
/*
* If we don't sleep for a bit here, we cause Communicator to crash
* because it tries to re-use a Window that gets killed. Guess
* we're just too fast for Communicator.
*/
PR_Sleep(PR_TicksPerSecond()*1);
}
PR_FREEIF(cx->m_nickname);
cx->m_nickname = NULL;
PR_FREEIF(params);
} else {
cert = CERT_FindCertByNickname(cx->super.m_connection->m_certdb,
certNickname);
cx->super.m_buttonType = SSM_BUTTON_OK;
}
CERT_DestroyCertList(certList);
return cert;
loser:
PR_FREEIF(htmlTemplate);
if (certList != NULL) {
CERT_DestroyCertList(certList);
}
if (cert != NULL) {
CERT_DestroyCertificate(cert);
}
if (textGenCx != NULL) {
SSMTextGen_DestroyContext(textGenCx);
}
return NULL;
}
typedef struct SSMFindMineArgStr {
CERTCertList *certList;
SSMControlConnection *ctrl;
} SSMFindMineArg;
static SSMStatus
ssm_find_all_mine(PRIntn index, void *arg, void *key, void *itemdata)
{
ssmCertData * data = (ssmCertData*)itemdata;
SSMFindMineArg *findArg = (SSMFindMineArg*) arg;
char *nick = (char*)key;
SSMStatus rv = SSM_FAILURE;
if (data->usage == clAllMine) {
CERTCertList *tmpList;
tmpList = CERT_CreateNicknameCertList(findArg->certList,
findArg->ctrl->m_certdb,
nick, PR_Now(), PR_FALSE);
if (tmpList != NULL) {
rv = SSM_SUCCESS;
}
}
return rv;
}
SSMStatus
SSMSecurityAdvisorContext_BackupAllMineCerts(SSMSecurityAdvisorContext *cx,
HTTPRequest *req)
{
SSMFindMineArg arg;
CERTCertList *certList=NULL;
SSMPKCS12Context *p12Cxt=NULL;
SSMPKCS12CreateArg p12Create;
SSMResourceID rid;
SSMStatus rv;
CERTCertificate **certArr = NULL;
int numCerts,i, finalCerts, currIndex;
CERTCertListNode *node;
PRIntn numNicks;
const char *responseKey;
certList = CERT_NewCertList();
if (certList == NULL) {
goto loser;
}
arg.certList = certList;
arg.ctrl = req->ctrlconn;
numNicks = SSMSortedList_Enumerate(cx->m_certhash, ssm_find_all_mine,
&arg);
if (numNicks <= 0){
/* No certs to backup */
SSM_HTTPReportError(req, HTTP_NO_CONTENT);
goto loser;
}
certList = arg.certList;
p12Create.isExportContext = PR_TRUE;
rv = (SSMStatus) SSM_CreateResource(SSM_RESTYPE_PKCS12_CONTEXT,
(void*)&p12Create, req->ctrlconn,
&rid, (SSMResource**)(&p12Cxt));
if (rv != SSM_SUCCESS) {
goto loser;
}
SSM_CopyCMTItem(&p12Cxt->super.m_clientContext,
&cx->super.m_clientContext);
numCerts = SSM_CertListCount(certList);
certArr = SSM_NEW_ARRAY(CERTCertificate*,numCerts);
if (certArr == NULL) {
goto loser;
}
node = CERT_LIST_HEAD(certList);
for (i=0, currIndex=0, finalCerts=numCerts; i<numCerts; i++) {
if (node->cert->slot == NULL ||
PK11_IsInternal(node->cert->slot)) {
certArr[currIndex] = node->cert;
currIndex++;
} else {
finalCerts--;
}
node = CERT_LIST_NEXT(node);
}
rv = SSMPKCS12Context_CreatePKCS12FileForMultipleCerts(p12Cxt,
PR_TRUE,
certArr,
finalCerts);
PR_Free(certArr);
certArr = NULL;
CERT_DestroyCertList(certList);
certList = NULL;
if (rv == SSM_SUCCESS) {
responseKey = (finalCerts > 1) ? "pkcs12_backup_multiple_success" :
"pkcs12_backup_success";
} else {
if (p12Cxt->super.m_buttonType == SSM_BUTTON_CANCEL) {
goto loser;
} else {
responseKey = SSMUI_GetPKCS12Error(rv, PR_TRUE);
}
}
SSM_FreeResource(&p12Cxt->super);
p12Cxt = NULL;
if (SSMSecurityAdvisorContext_DoPKCS12Response(cx, req, responseKey)
!= SSM_SUCCESS) {
goto loser;
}
return SSM_SUCCESS;
loser:
PR_FREEIF(certArr);
if (certList != NULL) {
CERT_DestroyCertList(certList);
}
if (p12Cxt != NULL) {
SSM_FreeResource(&p12Cxt->super);
}
SSM_HTTPReportError(req, HTTP_NO_CONTENT);
return SSM_FAILURE;
}
SSMStatus SSMSecurityAdvisorContext_DoPKCS12Backup(
SSMSecurityAdvisorContext *cx,
HTTPRequest *req)
{
SSMStatus rv;
char *certNickname;
const char *responseKey;
SSMPKCS12CreateArg p12Create;
SSMResourceID rid;
SSMPKCS12Context *p12Cxt;
p12Create.isExportContext = PR_TRUE;
rv = (SSMStatus) SSM_CreateResource(SSM_RESTYPE_PKCS12_CONTEXT,
(void*)&p12Create,
SSMRESOURCE(cx)->m_connection,
&rid, (SSMResource **)(&p12Cxt));
if (rv != PR_SUCCESS) {
goto loser;
}
/* pass along Advisor's client context for window management */
SSM_CopyCMTItem(&((SSMResource *)p12Cxt)->m_clientContext,
&((SSMResource *)cx)->m_clientContext);
rv = SSM_HTTPParamValue(req, "selectCert", &certNickname);
if (rv != SSM_SUCCESS) {
goto loser;
}
p12Cxt->m_cert =
SSMSecurityAdvisorContext_FindCertByNickname(cx, req, certNickname);
if (cx->super.m_buttonType == SSM_BUTTON_CANCEL) {
goto loser;
}
if (p12Cxt->m_cert == NULL) {
goto loser;
}
/* p12Cxt->super.m_clientContext = cx->super.m_clientContext; */
rv = SSMPKCS12Context_CreatePKCS12File(p12Cxt, PR_TRUE);
if (rv == SSM_SUCCESS) {
responseKey = "pkcs12_backup_success";
} else {
if (p12Cxt->super.m_buttonType == SSM_BUTTON_CANCEL) {
goto loser;
} else {
responseKey = SSMUI_GetPKCS12Error(rv, PR_TRUE);
}
}
if (SSMSecurityAdvisorContext_DoPKCS12Response(cx, req, responseKey)
!= SSM_SUCCESS) {
goto loser;
}
SSM_FreeResource(&p12Cxt->super);
return SSM_SUCCESS;
loser:
if (p12Cxt != NULL) {
SSM_FreeResource(&p12Cxt->super);
}
SSM_HTTPReportError(req, HTTP_NO_CONTENT);
return SSM_FAILURE;
}
char *
ssm_packb64_name(char *b64Name)
{
char *htmlString = NULL;
int numPercentSigns = 0;
char *cursor, *retString;
int i, newLen, origHTMLStrLen;
htmlString = SSM_ConvertStringToHTMLString(b64Name);
/*
* Now let's see if there are any '%' characters that need
* to be escaped so that printf statements succeed.
*/
cursor = htmlString;
while ((cursor = PL_strchr(cursor, '%')) != NULL) {
numPercentSigns++;
cursor++;
}
if (numPercentSigns == 0) {
htmlString;
}
origHTMLStrLen = PL_strlen(htmlString);
newLen = origHTMLStrLen + numPercentSigns + 1;
retString = SSM_NEW_ARRAY(char, newLen);
for (i=0,cursor=retString; i<origHTMLStrLen+1; i++,cursor++) {
if (htmlString[i] == '%') {
char *dollarSign, *placeHolder;
/*
* Let's see if this a urlencoded escape or a printf parameter.
*/
placeHolder = &htmlString[i];
dollarSign = PL_strchr(placeHolder, '$');
if (dollarSign && ((dollarSign - placeHolder) < 2)) {
/*
* OK, this is a numbered parameter for printf
*/
*cursor = htmlString[i];
} else {
/*
* This is an escape for url encoding. Escape it so printf
* doesn't blow up.
*/
*cursor = '%';
cursor++;
*cursor = '%';
}
} else {
*cursor = htmlString[i];
}
}
PR_Free(htmlString);
return retString;
}
SSMStatus
SSMSecurityAdvisorContext_ProcessCRLDialog (HTTPRequest *req)
{
SSMHTTPParamMultValues crlNames={NULL, NULL, 0};
CERTSignedCrl *realCrl;
SECItem crlDERName;
PRBool flushSSLCache = PR_FALSE;
SSMStatus rv;
SECStatus srv;
int i, type;
rv = SSM_HTTPParamValueMultiple(req, "crlNames", &crlNames);
if (rv != SSM_SUCCESS || crlNames.numValues == 0) {
goto loser;
}
memset (&crlDERName, 0, sizeof(SECItem));
for (i=0; i<crlNames.numValues; i++) {
/*
* The first character in the value string represents the type,
* either 1 (SEC_CRL_TYPE) or 0 (SEC_KRL_TYPE)
*/
srv = ATOB_ConvertAsciiToItem(&crlDERName, crlNames.values[i]+1);
if (srv != SECSuccess) {
goto loser;
}
type = (crlNames.values[i][0] == '1') ? SEC_CRL_TYPE : SEC_KRL_TYPE;
realCrl = SEC_FindCrlByName(req->ctrlconn->m_certdb,
&crlDERName, type);
SECITEM_FreeItem(&crlDERName, PR_FALSE);
if (realCrl) {
SEC_DeletePermCRL(realCrl);
SEC_DestroyCrl(realCrl);
flushSSLCache = PR_TRUE;
}
}
if (flushSSLCache) {
SSL_ClearSessionCache();
}
if (!SSM_IsCRLPresent(req->ctrlconn)) {
/*
* In this case, there are no more CRLs in the database,
* so we'll replace the baseRef with one that will cause
* the security advisor to refresh itself and elminate the
* "Delete CRLs" button.
*/
for (i=0; i<req->numParams; i++) {
char *crlCloseKey = "crlclose_doclose_js";
if (PL_strcmp(req->paramNames[i], "baseRef") == 0) {
memcpy (req->paramValues[i], crlCloseKey,
PL_strlen(crlCloseKey)+1);
break;
}
}
}
if (SSM_HTTPDefaultCommandHandler(req) != SSM_SUCCESS) {
goto loser;
}
PR_FREEIF(crlNames.values);
return SSM_SUCCESS;
loser:
PR_FREEIF(crlNames.values);
return SSM_FAILURE;
}
SSMStatus SSMSecurityAdvisorContext_Process_cert_mine_form(
SSMSecurityAdvisorContext *res,
HTTPRequest *req)
{
SSMStatus rv= SSM_FAILURE;
char *button;
/* Figure out which one of the buttons on the form was pressed. */
if (SSM_HTTPParamValue(req, "backup", &button) == SSM_SUCCESS) {
if (button != NULL) {
rv = SSMSecurityAdvisorContext_DoPKCS12Backup(res, req);
}
} else if (SSM_HTTPParamValue(req, "restore", &button) == SSM_SUCCESS) {
if (button != NULL) {
rv = SSMSecurityAdvisorContext_DoPKCS12Restore(res, req);
}
} else if (SSM_HTTPParamValue(req, "delete", &button) == SSM_SUCCESS) {
if (button != NULL) {
rv = SSM_ProcessCertDeleteButton(req);
}
} else if (SSM_HTTPParamValue(req, "password", &button) == SSM_SUCCESS) {
if (button != NULL) {
rv = SSM_ProcessPasswordWindow(req);
}
} else if (SSM_HTTPParamValue(req, "ldap", &button) == SSM_SUCCESS) {
if (button != NULL) {
rv = SSM_ProcessLDAPWindow(req);
}
} else if (SSM_HTTPParamValue(req, "backup_all", &button) == SSM_SUCCESS) {
if (button != NULL) {
rv = SSMSecurityAdvisorContext_BackupAllMineCerts(res, req);
}
} else if (SSM_HTTPParamValue(req, "crlButton", &button) == SSM_SUCCESS) {
if (button != NULL) {
rv = SSM_HTTPReportError(req, HTTP_NO_CONTENT);
}
}
return rv;
}
static SSMStatus
SSMSecurityAdvisorContext_SetConfigOCSP(SSMSecurityAdvisorContext *cx,
HTTPRequest *req)
{
char *responderURL = NULL, *caNickname = NULL;
char *enableOCSP = NULL;
CERTCertDBHandle *db;
SSMStatus rv;
SECStatus srv;
db = cx->super.m_connection->m_certdb;
rv = SSM_HTTPParamValue(req, "enableOCSP", &enableOCSP);
if (rv != SSM_SUCCESS) {
goto loser;
}
if (!strcmp(enableOCSP,"noOCSP")) {
CERT_DisableOCSPChecking(db);
SSMControlConnection_SaveBoolPref(req->ctrlconn,
"security.OCSP.enabled",
PR_FALSE);
SSMControlConnection_SaveBoolPref(req->ctrlconn,
"security.OCSP.useDefaultResponder",
PR_FALSE);
CERT_DisableOCSPChecking(db);
CERT_DisableOCSPDefaultResponder(db);
} else if (!strcmp(enableOCSP,"noDefaultResponder")) {
srv = CERT_EnableOCSPChecking(db);
SSMControlConnection_SaveBoolPref(req->ctrlconn,
"security.OCSP.enabled",
PR_TRUE);
SSMControlConnection_SaveBoolPref(req->ctrlconn,
"security.OCSP.useDefaultResponder",
PR_FALSE);
if (srv != SECSuccess) {
goto loser;
}
CERT_DisableOCSPDefaultResponder(db);
} else if (!strcmp(enableOCSP,"useDefaultResponder")) {
srv = CERT_EnableOCSPChecking(db);
SSMControlConnection_SaveBoolPref(req->ctrlconn,
"security.OCSP.enabled",
PR_TRUE);
SSMControlConnection_SaveBoolPref(req->ctrlconn,
"security.OCSP.useDefaultResponder",
PR_TRUE);
if (srv != SECSuccess) {
goto loser;
}
rv = SSM_HTTPParamValue(req, "ocspURL", &responderURL);
if (rv != SSM_SUCCESS) {
goto loser;
}
SSMControlConnection_SaveStringPref(req->ctrlconn,
"security.OCSP.URL",
responderURL);
rv = SSM_HTTPParamValue(req, "selectCert", &caNickname);
if (rv != SSM_SUCCESS) {
goto loser;
}
SSMControlConnection_SaveStringPref(req->ctrlconn,
"security.OCSP.signingCA",
caNickname);
srv = CERT_SetOCSPDefaultResponder(db, responderURL, caNickname);
if (srv != SECSuccess) {
goto loser;
}
srv = CERT_EnableOCSPDefaultResponder(db);
if (srv != SECSuccess) {
goto loser;
}
} else {
goto loser;
}
return SSM_SUCCESS;
loser:
return SSM_FAILURE;
}
static SSMStatus
SSMSecurityAdvisorContext_ProcessOCSPForm(SSMSecurityAdvisorContext *cx,
HTTPRequest *req)
{
SSMStatus rv = SSM_SUCCESS;
/*
* First, if the Cancel button was pressed, then don't
* process the form.
*/
if (cx->super.m_buttonType == SSM_BUTTON_OK) {
rv = SSMSecurityAdvisorContext_SetConfigOCSP(cx, req);
}
SSM_HTTPDefaultCommandHandler(req);
return rv;
}
SSMStatus SSMSecurityAdvisorContext_FormSubmitHandler(SSMResource *res,
HTTPRequest *req)
{
SSMStatus rv;
char *formName;
if (!SSM_IsAKindOf(res, SSM_RESTYPE_SECADVISOR_CONTEXT)) {
return SSM_FAILURE;
}
/* First figure out which form we're processing. */
rv = SSM_HTTPParamValue(req, "formName", &formName);
if (rv != SSM_SUCCESS) {
goto loser;
}
if (PL_strcmp(formName, "prefs_submit_form") == 0) {
/* save pref changes and close the Security Advisor */
rv = SSMSecurityAdvisorContext_SavePrefs
((SSMSecurityAdvisorContext*)res, req);
}
else if (!strcmp(formName, "cert_mine_form") ||
!strcmp(formName, "cert_others_form") ||
!strcmp(formName, "cert_websites_form") ||
!strcmp(formName, "cert_authorities_form")) {
rv = SSMSecurityAdvisorContext_Process_cert_mine_form
((SSMSecurityAdvisorContext*)res, req);
} else if (!strcmp(formName, "choose_cert_by_usage")) {
rv = SSM_ChooseCertUsageHandler(req);
} else if (!strcmp(formName, "set_db_password")) {
rv = SSM_SetDBPasswordHandler(req);
} else if (!strcmp(formName, "configureOCSPForm")){
rv = SSMSecurityAdvisorContext_ProcessOCSPForm
((SSMSecurityAdvisorContext*)res, req);
} else if (!strcmp(formName, "crlDialog")){
rv = SSMSecurityAdvisorContext_ProcessCRLDialog(req);
}else {
rv = SSM_ERR_BAD_REQUEST;
SSM_HTTPReportSpecificError(req, "Do not know how to process form %s",
formName);
}
loser:
return rv;
}
SSMStatus
SSMSecurityAdvisorContext_Print(SSMResource *res,
char *fmt, PRIntn numParam,
char **value, char **resultStr)
{
SSMSecurityAdvisorContext *cx = (SSMSecurityAdvisorContext*)res;
SSMStatus rv;
PR_ASSERT(fmt != NULL && resultStr != NULL);
if (!SSM_IsAKindOf(res, SSM_RESTYPE_SECADVISOR_CONTEXT)) {
return PR_FAILURE;
}
/* We don't use the extra parameters */
if (cx->m_nickname != NULL) {
*resultStr = PR_smprintf(fmt, res->m_id, "backup", cx->m_nickname, *value);
rv = (*resultStr == NULL) ? PR_FAILURE : PR_SUCCESS;
} else {
rv = SSMResource_Print(res, fmt, numParam, value, resultStr);
}
return rv;
}
SSMStatus SSM_SetSelectedItemInfo(SSMSecurityAdvisorContext* cx)
{
SSMStatus rv = SSM_SUCCESS;
switch (cx->infoContext)
{
case SSM_NOINFO:
cx->selectedItemPage = SSM_NO_INFO;
break;
case SSM_COMPOSE:
break;
case SSM_SNEWS_MESSAGE:
case SSM_NEWS_MESSAGE:
case SSM_MAIL_MESSAGE:
cx->selectedItemPage = SSM_MESSAGE;
if (cx->encryptedP7CInfo) {
/* Get the P7 Content info resource */
rv = SSMControlConnection_GetResource(SSMRESOURCE(cx)->m_connection, (SSMResourceID)cx->encryptedP7CInfo,
(SSMResource**)&cx->encryptedP7CInfoRes);
if ((rv != PR_SUCCESS) || (cx->encryptedP7CInfoRes == NULL)) {
goto loser;
}
}
if (cx->signedP7CInfo) {
/* Get the P7 Content info resource */
rv = SSMControlConnection_GetResource(SSMRESOURCE(cx)->m_connection, (SSMResourceID)cx->signedP7CInfo,
(SSMResource**)&cx->signedP7CInfoRes);
if ((rv != PR_SUCCESS) || (cx->signedP7CInfoRes == NULL)) {
goto loser;
}
}
if (!cx->encryptedP7CInfo &&
!cx->signedP7CInfo &&
cx->verifyError &&
!cx->decodeError) {
/* Somehow we have the error code backwards */
cx->decodeError = cx->verifyError;
cx->verifyError = 0;
}
cx->encrypted_b = (cx->decodeError ||
(cx->encryptedP7CInfo &&
SEC_PKCS7ContentIsEncrypted(cx->encryptedP7CInfoRes->m_cinfo)) ||
(cx->signedP7CInfo &&
SEC_PKCS7ContentIsEncrypted(cx->signedP7CInfoRes->m_cinfo)));
cx->signed_b = (cx->verifyError ||
(cx->encryptedP7CInfo &&
SEC_PKCS7ContentIsSigned(cx->encryptedP7CInfoRes->m_cinfo)) ||
(cx->signedP7CInfo &&
SEC_PKCS7ContentIsSigned(cx->signedP7CInfoRes->m_cinfo)));
break;
case SSM_BROWSER:
if (cx->resID == 0) {
cx->selectedItemPage = SSM_NAVIGATOR_NO_SEC;
} else {
cx->selectedItemPage = SSM_NAVIGATOR_SSL;
}
break;
default:
cx->selectedItemPage = SSM_NO_INFO;
break;
}
return rv;
loser:
return SSM_FAILURE;
}
SSMStatus sa_noinfo(SSMTextGenContext *cx)
{
SSMStatus rv = SSM_SUCCESS;
SSMResource *target = NULL;
SSMSecurityAdvisorContext* res = NULL;
char *fmt = NULL;
/* get the connection object */
target = SSMTextGen_GetTargetObject(cx);
PR_ASSERT(target != NULL);
res = (SSMSecurityAdvisorContext*)target;
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_noinfo", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
PR_FREEIF(cx->m_result);
cx->m_result = fmt;
return SSM_SUCCESS;
loser:
return SSM_FAILURE;
}
SSMStatus sa_navigator(SSMTextGenContext *cx)
{
SSMStatus rv = SSM_SUCCESS;
SSMResource *target = NULL;
SSMSecurityAdvisorContext* res = NULL;
char *fmt = NULL;
SSMSSLSocketStatus *socketStatusRes = NULL;
char * encryption_level = NULL;
char * serverCN = NULL;
char * issuerName = NULL;
CERTCertificate *issuerCert = NULL;
SSMResourceCert *serverCertRes = NULL, *issuerCertRes = NULL;
int serverCertResID, issuerCertResID;
/* get the connection object */
target = SSMTextGen_GetTargetObject(cx);
PR_ASSERT(target != NULL);
res = (SSMSecurityAdvisorContext*)target;
if (res->resID == 0) {
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_navigator_no_sec", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
PR_FREEIF(cx->m_result);
cx->m_result = PR_smprintf(fmt, res->hostname, res->hostname);
PR_Free(fmt);
return SSM_SUCCESS;
} else {
/* Get the socket status resource */
rv = SSMControlConnection_GetResource(SSMRESOURCE(res)->m_connection, (SSMResourceID)res->resID,
(SSMResource**)&socketStatusRes);
if ((rv != PR_SUCCESS) || (socketStatusRes == NULL)) {
goto loser;
}
/*
* We inherit the client's reference here.
*/
res->socketStatus = socketStatusRes;
/* Do we have an error */
if (!socketStatusRes->m_error) {
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_navigator_ssl", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
#if 0
/* Create a resource for this cert */
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE,
socketStatusRes->m_cert,
SSMRESOURCE(res)->m_connection,
(long *) &serverCertResID,
(SSMResource**)&serverCertRes);
if (rv != PR_SUCCESS) {
goto loser;
}
#else
serverCertResID = socketStatusRes->m_cert->super.m_id;
serverCertRes = socketStatusRes->m_cert;
#endif
issuerName = CERT_NameToAscii(&socketStatusRes->m_cert->cert->issuer);
if (socketStatusRes->m_level == SSL_SECURITY_STATUS_ON_HIGH) {
SSM_GetUTF8Text(cx, "high_grade_encryption", &encryption_level);
} else {
SSM_GetUTF8Text(cx, "low_grade_encryption", &encryption_level);
}
PR_FREEIF(cx->m_result);
cx->m_result = PR_smprintf(fmt, res->hostname, issuerName, target->m_id, serverCertResID,
encryption_level, socketStatusRes->m_cipherName,
socketStatusRes->m_secretKeySize);
PR_Free(issuerName);
PR_Free(encryption_level);
PR_Free(fmt);
SSM_FreeResource(&socketStatusRes->super);
return SSM_SUCCESS;
} else {
if (socketStatusRes->m_error == SEC_ERROR_UNKNOWN_ISSUER ||
socketStatusRes->m_error == SEC_ERROR_CA_CERT_INVALID ) {
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_navigator_ssl_unknown_issuer", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
/* Get the common name of the issuer */
issuerName = CERT_NameToAscii(&socketStatusRes->m_cert->cert->issuer);
if (!issuerName) {
goto loser;
}
/* Get the common name of the server cert */
serverCN = CERT_GetCommonName(&socketStatusRes->m_cert->cert->subject);
if (!serverCN) {
goto loser;
}
#if 0
/* Create resource for the server cert */
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE,
socketStatusRes->m_cert,
SSMRESOURCE(res)->m_connection,
(long *) &serverCertResID,
(SSMResource**)&serverCertRes);
if (rv != PR_SUCCESS) {
goto loser;
}
#else
serverCertRes = socketStatusRes->m_cert;
serverCertResID = serverCertRes->super.m_id;
#endif
if (socketStatusRes->m_level == SSL_SECURITY_STATUS_ON_HIGH) {
SSM_GetUTF8Text(cx, "high_grade_encryption", &encryption_level);
} else {
SSM_GetUTF8Text(cx, "low_grade_encryption", &encryption_level);
}
PR_FREEIF(cx->m_result);
cx->m_result = PR_smprintf(fmt, res->hostname, issuerName, target->m_id, serverCertResID,
encryption_level, socketStatusRes->m_cipherName,
socketStatusRes->m_secretKeySize);
PR_Free(fmt);
PR_Free(issuerName);
PR_Free(serverCN);
PR_Free(encryption_level);
SSM_FreeResource(&socketStatusRes->super);
return SSM_SUCCESS;
} else if(socketStatusRes->m_error == SEC_ERROR_UNTRUSTED_ISSUER) {
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_navigator_ssl_bad_issuer", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
/* Get the common name of the issuer */
issuerName = CERT_NameToAscii(&socketStatusRes->m_cert->cert->issuer);
if (!issuerName) {
goto loser;
}
/* Get the common name of the server cert */
serverCN = CERT_GetCommonName(&socketStatusRes->m_cert->cert->subject);
if (!serverCN) {
goto loser;
}
#if 0
/* Create resource for the server cert */
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE,
socketStatusRes->m_cert,
SSMRESOURCE(res)->m_connection,
(long *) &serverCertResID,
(SSMResource**)&serverCertRes);
if (rv != PR_SUCCESS) {
goto loser;
}
#else
serverCertRes = socketStatusRes->m_cert;
serverCertResID = serverCertRes->super.m_id;
#endif
/* Create a resource for the issuer cert (if it exists) */
issuerCert = CERT_FindCertIssuer(socketStatusRes->m_cert->cert,
PR_Now(), certUsageAnyCA);
if (issuerCert) {
/* Create resource for the issuer cert */
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE,
issuerCert,
SSMRESOURCE(res)->m_connection,
(long *) &issuerCertResID,
(SSMResource**)&issuerCertRes);
if (rv != PR_SUCCESS) {
goto loser;
}
} else {
issuerCertResID = 0;
}
if (socketStatusRes->m_level == SSL_SECURITY_STATUS_ON_HIGH) {
SSM_GetUTF8Text(cx, "high_grade_encryption", &encryption_level);
} else {
SSM_GetUTF8Text(cx, "low_grade_encryption", &encryption_level);
}
PR_FREEIF(cx->m_result);
cx->m_result = PR_smprintf(fmt, res->hostname, issuerName, target->m_id, serverCertResID,
issuerCertResID, encryption_level, socketStatusRes->m_cipherName,
socketStatusRes->m_secretKeySize);
PR_Free(fmt);
PR_Free(issuerName);
PR_Free(serverCN);
PR_Free(encryption_level);
SSM_FreeResource(&socketStatusRes->super);
return SSM_SUCCESS;
} else if (socketStatusRes->m_error == SSL_ERROR_BAD_CERT_DOMAIN) {
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_navigator_ssl_bad_cert_domain", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
/* Get the common name of the server cert */
serverCN = CERT_GetCommonName(&socketStatusRes->m_cert->cert->subject);
if (!serverCN) {
goto loser;
}
if (socketStatusRes->m_level == SSL_SECURITY_STATUS_ON_HIGH) {
SSM_GetUTF8Text(cx, "high_grade_encryption", &encryption_level);
} else {
SSM_GetUTF8Text(cx, "low_grade_encryption", &encryption_level);
}
PR_FREEIF(cx->m_result);
cx->m_result = PR_smprintf(fmt, res->hostname, serverCN, encryption_level, socketStatusRes->m_cipherName,
socketStatusRes->m_secretKeySize);
PR_Free(fmt);
PR_Free(serverCN);
PR_Free(encryption_level);
SSM_FreeResource(&socketStatusRes->super);
return SSM_SUCCESS;
} else {
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_navigator_ssl_unknown_error", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
#if 0
/* Create resource for the server cert */
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE,
socketStatusRes->m_cert,
SSMRESOURCE(res)->m_connection,
(long *) &serverCertResID,
(SSMResource**)&serverCertRes);
if (rv != PR_SUCCESS) {
goto loser;
}
#else
serverCertRes = socketStatusRes->m_cert;
serverCertResID = serverCertRes->super.m_id;
#endif
if (socketStatusRes->m_level == SSL_SECURITY_STATUS_ON_HIGH) {
SSM_GetUTF8Text(cx, "high_grade_encryption", &encryption_level);
} else {
SSM_GetUTF8Text(cx, "low_grade_encryption", &encryption_level);
}
PR_FREEIF(cx->m_result);
cx->m_result = PR_smprintf(fmt, res->hostname, target->m_id, serverCertResID, encryption_level, socketStatusRes->m_cipherName,
socketStatusRes->m_secretKeySize);
PR_Free(fmt);
SSM_FreeResource(&socketStatusRes->super);
return SSM_SUCCESS;
}
}
}
loser:
PR_FREEIF(fmt);
PR_FREEIF(serverCN);
PR_FREEIF(issuerName);
if (socketStatusRes) {
SSM_FreeResource(&socketStatusRes->super);
}
return SSM_FAILURE;
}
static CERTCertificate * get_signer_cert(SSMSecurityAdvisorContext *res)
{
CERTCertificate * cert = NULL;
/* Get the signing cert */
if (res->signedP7CInfoRes ||
res->encryptedP7CInfoRes) {
SEC_PKCS7SignerInfo **signerinfos;
SEC_PKCS7ContentInfo *ci = res->signedP7CInfoRes->m_cinfo;
if (!ci) ci = res->encryptedP7CInfoRes->m_cinfo;
/* Finding the signers cert */
switch(ci->contentTypeTag->offset) {
default:
case SEC_OID_PKCS7_DATA:
case SEC_OID_PKCS7_DIGESTED_DATA:
case SEC_OID_PKCS7_ENVELOPED_DATA:
case SEC_OID_PKCS7_ENCRYPTED_DATA:
/* Could only get here if SEC_PKCS7ContentIsSigned
* is broken. */
{
PORT_Assert (0);
cert=NULL;
}
break;
case SEC_OID_PKCS7_SIGNED_DATA:
{
SEC_PKCS7SignedData *sdp;
sdp = ci->content.signedData;
signerinfos = sdp->signerInfos;
cert = signerinfos[0]->cert;
}
break;
case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
{
SEC_PKCS7SignedAndEnvelopedData *saedp;
saedp = ci->content.signedAndEnvelopedData;
signerinfos = saedp->signerInfos;
cert = signerinfos[0]->cert;
}
break;
} /* finding the signer cert */
}
return cert;
}
char*
SSM_GetOCSPURL(CERTCertificate *cert, PrefSet *prefs)
{
SSMStatus rv;
PRBool boolval = PR_FALSE;
char *responderURL = NULL;
/* Is there a default responder installed */
rv = PREF_GetBoolPref(prefs, "security.OCSP.useDefaultResponder", &boolval);
if (boolval) {
PREF_CopyStringPref(prefs, "security.OCSP.URL", &responderURL);
} else {
responderURL = CERT_GetOCSPAuthorityInfoAccessLocation(cert);
}
return responderURL;
}
static CERTCertificate * get_encryption_cert(SSMSecurityAdvisorContext *res)
{
return NULL;
}
static char *
sa_get_algorithm_string(SEC_PKCS7ContentInfo *cinfo)
{
SECAlgorithmID *algid;
SECOidTag algtag;
const char *alg_name;
int key_size;
if (!cinfo) return 0;
algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);
if (!algid) return 0;
algtag = SECOID_GetAlgorithmTag(algid);
alg_name = SECOID_FindOIDTagDescription(algtag);
key_size = SEC_PKCS7GetKeyLength(cinfo);
if (!alg_name || !*alg_name)
return 0;
else if (key_size > 0)
return PR_smprintf("%d-bits %s",
key_size, alg_name);
else
return PL_strdup(alg_name);
}
PRBool
SSM_IsOCSPEnabled(SSMControlConnection *connection)
{
SSMStatus rv;
PRBool isOCSPEnabled = PR_FALSE;
rv = PREF_GetBoolPref(connection->m_prefs, "security.OCSP.enabled",
&isOCSPEnabled);
return (rv == SSM_SUCCESS) ? isOCSPEnabled : PR_FALSE;
}
char *
SSM_GetGenericOCSPWarning(SSMControlConnection *ctrl,
CERTCertificate *cert)
{
char *retString = NULL;
char *responderURL = NULL;
SSMTextGenContext *cx = NULL;
SSMStatus rv;
retString = PL_strdup("");
if (SSM_IsOCSPEnabled(ctrl)) {
responderURL = SSM_GetOCSPURL(cert, ctrl->m_prefs);
if (responderURL == NULL) {
goto done;
}
rv = SSMTextGen_NewTopLevelContext(NULL, &cx);
if (rv != SSM_SUCCESS) {
goto done;
}
SSM_GetAndExpandTextKeyedByString(cx, "ocsp_fail_message_generic",
&retString);
}
done:
PR_FREEIF(responderURL);
if (cx) {
SSMTextGen_DestroyContext(cx);
}
return retString;
}
SSMStatus sa_message(SSMTextGenContext *cx)
{
SSMStatus rv = SSM_SUCCESS;
SSMResource *target = NULL;
SSMSecurityAdvisorContext* res = NULL;
char *fmt = NULL, *fmtSigned = NULL, *fmtEncrypted = NULL;
char *genericOCSPWarning = NULL;
/* get the connection object */
target = SSMTextGen_GetTargetObject(cx);
PR_ASSERT(target != NULL);
res = (SSMSecurityAdvisorContext*)target;
/* Deal with the signed part first */
if (!res->signed_b) {
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_not_signed", &fmtSigned);
if (rv != SSM_SUCCESS) {
goto loser;
}
} else {
if (res->verifyError == 0) {
char *signer_email;
CERTCertificate *signerCert = NULL;
SSMResourceCert *signerCertRes = NULL;
int signerCertResID;
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_signed", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
signerCert = get_signer_cert(res);
if (!signerCert) {
goto loser;
}
/* Get the signers email address */
if (res->signedP7CInfoRes) {
signer_email = SEC_PKCS7GetSignerEmailAddress(res->signedP7CInfoRes->m_cinfo);
}
if (!signer_email && res->encryptedP7CInfoRes) {
signer_email = SEC_PKCS7GetSignerEmailAddress(res->encryptedP7CInfoRes->m_cinfo);
}
/* Create a cert resource for this certificate */
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE,
signerCert,
SSMRESOURCE(res)->m_connection,
(long *) &signerCertResID,
(SSMResource**)&signerCertRes);
if (rv != PR_SUCCESS) {
goto loser;
}
fmtSigned = PR_smprintf(fmt, signer_email, target->m_id, signerCertResID);
PR_Free(fmt);
} else {
CERTCertificate *signerCert;
/* Get the signing certificate */
signerCert = get_signer_cert(res);
if (!signerCert) {
goto loser;
}
genericOCSPWarning =
SSM_GetGenericOCSPWarning(target->m_connection,
signerCert);
switch(res->verifyError) {
case SEC_ERROR_PKCS7_BAD_SIGNATURE:
{
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_signed_bad_signature", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
fmtSigned = PR_smprintf(fmt, genericOCSPWarning);
PR_FREEIF(fmt);
}
break;
/* This case handles both expired and not yet valid certs */
case SEC_ERROR_EXPIRED_CERTIFICATE:
{
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_signed_expired_signing_cert", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
fmtSigned = PR_smprintf(fmt, genericOCSPWarning);
PR_FREEIF(fmt);
}
break;
case SEC_ERROR_REVOKED_CERTIFICATE:
{
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_signed_revoked_signing_cert", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
fmtSigned = PR_smprintf(fmt, genericOCSPWarning);
PR_FREEIF(fmt);
}
break;
case SEC_ERROR_UNKNOWN_ISSUER:
{
SSMResourceCert *signerCertRes;
PRUint32 signerCertResID;
char *fmt;
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_signed_unknown_issuer", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
/* Create a cert resource for this certificate */
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE,
signerCert,
SSMRESOURCE(res)->m_connection,
(long *) &signerCertResID,
(SSMResource**)&signerCertRes);
if (rv != PR_SUCCESS) {
goto loser;
}
fmtSigned = PR_smprintf(fmt, target->m_id,
signerCertResID,
genericOCSPWarning);
PR_Free(fmt);
}
break;
case SEC_ERROR_CA_CERT_INVALID:
case SEC_ERROR_UNTRUSTED_ISSUER:
{
CERTCertificate *issuerCert;
SSMResourceCert * signerCertRes, issuerCertRes;
PRInt32 signerCertResID, issuerCertResID;
char *fmt = NULL;
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_signed_untrusted_issuer", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
/* Get the isser cert */
issuerCert = CERT_FindCertIssuer(signerCert, PR_Now(), certUsageAnyCA);
if (!issuerCert) {
goto loser;
}
/* Create resources for these certs */
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE,
signerCert,
SSMRESOURCE(res)->m_connection,
(long *) &signerCertResID,
(SSMResource**)&signerCertRes);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE,
issuerCert,
SSMRESOURCE(res)->m_connection,
(long *) &issuerCertResID,
(SSMResource**)&issuerCertRes);
if (rv != SSM_SUCCESS) {
goto loser;
}
fmtSigned = PR_smprintf(fmt, target->m_id,
signerCertResID,
issuerCertResID,
genericOCSPWarning);
PR_Free(fmt);
}
break;
/* This case handles both expired and not yet valid certs */
case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
{
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_signed_expired_issuer_cert", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
fmtSigned = PR_smprintf(fmt, genericOCSPWarning);
PR_FREEIF(fmt);
}
break;
/* Cert address mismatch */
case SEC_ERROR_CERT_ADDR_MISMATCH:
{
char * signer_email = NULL;
char * signerCN = NULL;
CERTCertificate *signerCert = NULL;
SSMResourceCert *signerCertRes = NULL;
PRInt32 signerCertResID;
SECItem * item = NULL;
char *signTime = NULL;
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_signed_addr_mismatch", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
/* Get the signer cert */
signerCert = get_signer_cert(res);
if (!signerCert) {
goto loser;
}
/* Get the signer common name */
signerCN = CERT_GetCommonName(&signerCert->subject);
/* Get the signing time */
item = SEC_PKCS7GetSigningTime(res->signedP7CInfoRes->m_cinfo);
signTime = (item ? DER_UTCTimeToAscii(item) : 0);
/* Create resources for these certs */
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE,
signerCert,
SSMRESOURCE(res)->m_connection,
(long *) &signerCertResID,
(SSMResource**)&signerCertRes);
if (rv != SSM_SUCCESS) {
goto loser;
}
/* Get the signers email address */
if (res->signedP7CInfoRes) {
signer_email = SEC_PKCS7GetSignerEmailAddress(res->signedP7CInfoRes->m_cinfo);
}
if (!signer_email && res->encryptedP7CInfoRes) {
signer_email = SEC_PKCS7GetSignerEmailAddress(res->encryptedP7CInfoRes->m_cinfo);
}
fmtSigned = PR_smprintf(fmt,res->senderAddr,signer_email,signerCN,signTime, target->m_id, signerCertResID);
PR_Free(fmt);
PR_FREEIF(signer_email);
PR_FREEIF(signTime);
}
break;
default:
{
CERTCertificate *signerCert = NULL;
SSMStatus rv = SSM_SUCCESS;
PrefSet* prefs = NULL;
char *responderURL = NULL;
prefs = res->super.m_connection->m_prefs;
if (SSM_IsOCSPEnabled(res->super.m_connection)) {
responderURL = SSM_GetOCSPURL(get_signer_cert(res), prefs);
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_signed_ocsp_error", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
fmtSigned = PR_smprintf(fmt,responderURL,res->verifyError);
PR_Free(fmt);
PR_Free(responderURL);
} else {
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_signed_unknown_error", &fmtSigned);
if (rv != SSM_SUCCESS) {
goto loser;
}
}
}
break;
/* XXX Missing the case where the issuer cert has been revoked XXX */
}
}
}
PR_FREEIF(genericOCSPWarning);
/* Now deal with the encrypted part */
if (!res->encrypted_b) {
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_not_encrypted", &fmtEncrypted);
if (rv != SSM_SUCCESS) {
goto loser;
}
} else {
if (res->decodeError == 0) {
SECAlgorithmID *algid;
SECOidTag algtag;
const char *alg_name;
char *encryption_level;
int key_size;
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_encrypted", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
if (res->encryptedP7CInfoRes == NULL) {
algid = SEC_PKCS7GetEncryptionAlgorithm(res->signedP7CInfoRes->m_cinfo);
} else {
algid = SEC_PKCS7GetEncryptionAlgorithm(res->encryptedP7CInfoRes->m_cinfo);
}
if (!algid) {
goto loser;
}
algtag = SECOID_GetAlgorithmTag(algid);
alg_name = SECOID_FindOIDTagDescription(algtag);
if (res->encryptedP7CInfoRes) {
key_size = SEC_PKCS7GetKeyLength(res->encryptedP7CInfoRes->m_cinfo);
} else {
key_size = SEC_PKCS7GetKeyLength(res->signedP7CInfoRes->m_cinfo);
}
if (key_size == 40) {
SSM_GetUTF8Text(cx, "low_grade_encryption", &encryption_level);
} else if (key_size == 56 || key_size == 64) {
SSM_GetUTF8Text(cx, "medium_grade_encryption", &encryption_level);
} else {
SSM_GetUTF8Text(cx, "high_grade_encryption", &encryption_level);
}
fmtEncrypted = PR_smprintf(fmt, encryption_level, key_size, alg_name);
PR_Free(fmt);
} else {
switch (res->decodeError) {
case SEC_ERROR_NOT_A_RECIPIENT:
{
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_encrypted_no_recipient", &fmtEncrypted);
if (rv != SSM_SUCCESS) {
goto loser;
}
}
break;
case SEC_ERROR_BAD_PASSWORD:
{
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_encrypted_bad_password", &fmtEncrypted);
if (rv != SSM_SUCCESS) {
goto loser;
}
}
break;
/* XXX Missing cases for contents altered and encryption strength mismatch XXX */
default:
{
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_message_encrypted_unknown_error", &fmtEncrypted);
if (rv != SSM_SUCCESS) {
goto loser;
}
}
}
}
}
/* Output the stirngs */
PR_FREEIF(cx->m_result);
cx->m_result = PR_smprintf("%s%s", fmtSigned, fmtEncrypted);
PR_Free(fmtSigned);
PR_Free(fmtEncrypted);
return SSM_SUCCESS;
loser:
PR_FREEIF(fmt);
PR_FREEIF(fmtSigned);
PR_FREEIF(fmtEncrypted);
return SSM_FAILURE;
}
SSMStatus sa_compose(SSMTextGenContext *cx)
{
SSMStatus rv = SSM_SUCCESS;
SSMResource *target = NULL;
SSMSecurityAdvisorContext* res = NULL;
char *fmt = NULL, *fmtSigned = NULL, *fmtEncrypted = NULL;
CERTCertificate *cert = NULL;
char *certNickname = NULL;
int err;
char ** errCerts = NULL;
int numErrCerts, i;
/* get the connection object */
target = SSMTextGen_GetTargetObject(cx);
PR_ASSERT(target != NULL);
res = (SSMSecurityAdvisorContext*)target;
/* Get the default email certificate */
rv = PREF_GetStringPref(target->m_connection->m_prefs, "security.default_mail_cert",
&certNickname);
if (rv != PR_SUCCESS) {
goto loser;
}
/* Deal with the signing part first */
if (!res->signthis) {
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_not_to_be_signed", &fmtSigned);
if (rv != SSM_SUCCESS) {
goto loser;
}
} else {
/* Do we have a default cert installed */
if (!certNickname) {
/* We have no signing cert */
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_sign_no_cert", &fmtSigned);
if (rv != SSM_SUCCESS) {
goto loser;
}
} else {
cert = CERT_FindUserCertByUsage(target->m_connection->m_certdb,
certNickname,
certUsageEmailSigner,
PR_FALSE,
target->m_connection);
if (!cert){
/* We have no signing cert */
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_sign_no_cert", &fmtSigned);
if (rv != SSM_SUCCESS) {
goto loser;
}
} else {
/* Verify the cert */
if (CERT_VerifyCert(target->m_connection->m_certdb,
cert,
PR_TRUE,
certUsageEmailSigner,
PR_Now(),
target->m_connection,
NULL) == SECSuccess) {
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_can_be_signed", &fmtSigned);
if (rv != SSM_SUCCESS) {
goto loser;
}
} else {
err = PR_GetError();
switch (err) {
case SEC_ERROR_EXPIRED_CERTIFICATE:
{
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_sign_expired_cert", &fmtSigned);
if (rv != SSM_SUCCESS) {
goto loser;
}
}
break;
case SEC_ERROR_REVOKED_CERTIFICATE:
{
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_sign_revoked_cert", &fmtSigned);
if (rv != SSM_SUCCESS) {
goto loser;
}
}
break;
case SEC_ERROR_CERT_USAGES_INVALID:
{
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_sign_invalid_cert", &fmtSigned);
if (rv != SSM_SUCCESS) {
goto loser;
}
}
break;
default:
{
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_sign_unknown_error", &fmtSigned);
if (rv != SSM_SUCCESS) {
goto loser;
}
}
}
}
}
}
}
/* Now deal with the encryption part */
if (!res->encryptthis) {
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_not_to_be_encrypted", &fmtEncrypted);
if (rv != SSM_SUCCESS) {
goto loser;
}
} else {
if (!res->numRecipients) {
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_encrypted_no_recipients", &fmtEncrypted);
if (rv != SSM_SUCCESS) {
goto loser;
}
} else {
/* Do we have a default cert installed */
if (!certNickname) {
/* We have no cert */
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_encrypted_no_cert", &fmtEncrypted);
if (rv != SSM_SUCCESS) {
goto loser;
}
} else {
cert = CERT_FindUserCertByUsage(target->m_connection->m_certdb,
certNickname,
certUsageEmailRecipient,
PR_FALSE,
target->m_connection);
if (!cert) {
/* We have no cert */
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_encrypted_no_cert", &fmtEncrypted);
if (rv != SSM_SUCCESS) {
goto loser;
}
} else {
/* Verify the cert */
if (CERT_VerifyCert(target->m_connection->m_certdb,
cert,
PR_TRUE,
certUsageEmailRecipient,
PR_Now(),
target->m_connection,
NULL) == SECSuccess) {
errCerts = (char **) PR_CALLOC(sizeof(char*)*res->numRecipients);
if (!errCerts) {
goto loser;
}
/* Verify the recipient certs */
for (i=0,numErrCerts=0; i<res->numRecipients; i++) {
cert = CERT_FindCertByEmailAddr(target->m_connection->m_certdb, res->recipients[i]);
if (!cert) {
errCerts[numErrCerts++] = PL_strdup(res->recipients[i]);
continue;
}
if (CERT_VerifyCertNow(target->m_connection->m_certdb,
cert,
PR_TRUE,
certUsageEmailRecipient,
target->m_connection) == SECFailure) {
errCerts[numErrCerts++] = PL_strdup(res->recipients[i]);
continue;
}
CERT_DestroyCertificate(cert);
}
if (!numErrCerts) {
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_can_be_encrypted", &fmtEncrypted);
if (rv != SSM_SUCCESS) {
goto loser;
}
} else {
char *option = NULL;
char *out = NULL;
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_encrypted_bad_recipients", &fmt);
if (rv != SSM_SUCCESS) {
goto loser;
}
for (i=0; i < numErrCerts; i++) {
option = PR_smprintf("<option selected>%s</option>\n", errCerts[i]);
SSM_ConcatenateUTF8String(&out, option);
}
fmtEncrypted = PR_smprintf(fmt, target->m_id, numErrCerts, out);
PR_Free(fmt);
}
} else {
err = PR_GetError();
switch (err) {
case SEC_ERROR_EXPIRED_CERTIFICATE:
{
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_encrypted_expired_cert", &fmtEncrypted);
if (rv != SSM_SUCCESS) {
goto loser;
}
}
break;
case SEC_ERROR_REVOKED_CERTIFICATE:
{
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_encrypted_revoked_cert", &fmtEncrypted);
if (rv != SSM_SUCCESS) {
goto loser;
}
}
break;
case SEC_ERROR_CERT_USAGES_INVALID:
{
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_encrypted_invalid_cert", &fmtEncrypted);
if (rv != SSM_SUCCESS) {
goto loser;
}
}
break;
default:
{
rv = SSM_GetAndExpandTextKeyedByString(cx, "sa_compose_encrypted_unknown_error", &fmtEncrypted);
if (rv != SSM_SUCCESS) {
goto loser;
}
}
}
}
}
}
}
}
/* Output the stirngs */
PR_FREEIF(cx->m_result);
cx->m_result = PR_smprintf("%s%s", fmtSigned, fmtEncrypted);
PR_Free(fmtSigned);
PR_Free(fmtEncrypted);
return SSM_SUCCESS;
loser:
PR_FREEIF(fmt);
PR_FREEIF(fmtSigned);
PR_FREEIF(fmtEncrypted);
return SSM_FAILURE;
}
SSMStatus SSMSecurityAdvisorContext_sa_selected_item(SSMTextGenContext* cx)
{
SSMStatus rv = SSM_SUCCESS;
SSMResource *target = NULL;
SSMSecurityAdvisorContext* res = NULL;
/* get the connection object */
target = SSMTextGen_GetTargetObject(cx);
PR_ASSERT(target != NULL);
res = (SSMSecurityAdvisorContext*)target;
/* Load the correct page */
switch (res->infoContext)
{
case SSM_NOINFO:
rv = sa_noinfo(cx);
break;
case SSM_BROWSER:
rv = sa_navigator(cx);
break;
case SSM_SNEWS_MESSAGE:
case SSM_NEWS_MESSAGE:
case SSM_MAIL_MESSAGE:
rv = sa_message(cx);
break;
case SSM_COMPOSE:
rv = sa_compose(cx);
break;
default:
rv = SSM_FAILURE;
break;
}
goto done;
done:
return rv;
}
SSMStatus
SSMSecurityAdvisorContext_GetPrefListKeywordHandler(SSMTextGenContext* cx)
{
SSMStatus rv = SSM_SUCCESS;
SSMSecurityAdvisorContext* adv = NULL;
PrefSet* prefs = NULL;
char* subboolfmt;
char* subfmt;
char* fmt;
PRBool boolval;
char* strval = NULL;
char* str1 = NULL;
char* str2 = NULL;
char* str3 = NULL;
char* str4 = NULL;
char* str5 = NULL;
char* str6 = NULL;
char* str7 = NULL;
char* str8 = NULL;
char* str9 = NULL;
char* str10 = NULL;
char* str11 = NULL;
char* str12 = NULL;
if ((cx == NULL) || (cx->m_request == NULL) || (cx->m_result == NULL)) {
goto loser;
}
adv = (SSMSecurityAdvisorContext*)SSMTextGen_GetTargetObject(cx);
if ((adv == NULL) ||
!SSM_IsA((SSMResource*)adv, SSM_RESTYPE_SECADVISOR_CONTEXT)) {
goto loser;
}
/* get the prefs object */
if ((adv->super.m_connection == NULL) ||
(adv->super.m_connection->m_prefs == NULL)) {
goto loser;
}
prefs = adv->super.m_connection->m_prefs;
/* strings and formats */
subboolfmt = "var %1$s = %2$s;\n";
subfmt = "var %1$s = \"%2$s\";\n";
/* since nickname may contain ', I really should use " for quotes */
fmt = "%1$s%2$s%3$s%4$s%5$s%6$s%7$s%8$s%9$s%10$s%11$s%12$s";
/* make sure all the right default values are enforced */
rv = PREF_GetBoolPref(prefs, "security.enable_ssl2", &boolval);
if ((rv == SSM_SUCCESS) && (boolval == PR_FALSE)) {
str1 = PR_smprintf(subboolfmt, SSL2_SPK, "false");
}
else { /* default */
str1 = PR_smprintf(subboolfmt, SSL2_SPK, "true");
}
rv = PREF_GetBoolPref(prefs, "security.enable_ssl3", &boolval);
if ((rv == SSM_SUCCESS) && (boolval == PR_FALSE)) {
str2 = PR_smprintf(subboolfmt, SSL3_SPK, "false");
}
else { /* default */
str2 = PR_smprintf(subboolfmt, SSL3_SPK, "true");
}
rv = PREF_GetStringPref(prefs, "security.default_personal_cert", &strval);
if ((strval != NULL) && (PL_strcmp(strval, "Select Automatically") == 0)) {
str3 = PR_smprintf(subboolfmt, CLIENT_AUTH_SPK, "true");
}
else { /* default */
str3 = PR_smprintf(subboolfmt, CLIENT_AUTH_SPK, "false");
}
rv = PREF_GetStringPref(prefs, "security.default_mail_cert", &strval);
if (strval != NULL) {
str4 = PR_smprintf(subfmt, EMAIL_CERT_SPK, strval);
}
else {
str4 = PR_smprintf(subfmt, EMAIL_CERT_SPK, "");
}
rv = PREF_GetBoolPref(prefs, "security.warn_entering_secure", &boolval);
if ((rv == SSM_SUCCESS) && (boolval == PR_FALSE)) {
str5 = PR_smprintf(subboolfmt, WARN_ENTER_SECURE_SPK, "false");
}
else { /* default */
str5 = PR_smprintf(subboolfmt, WARN_ENTER_SECURE_SPK, "true");
}
rv = PREF_GetBoolPref(prefs, "security.warn_leaving_secure", &boolval);
if ((rv == SSM_SUCCESS) && (boolval == PR_FALSE)) {
str6 = PR_smprintf(subboolfmt, WARN_LEAVE_SECURE_SPK, "false");
}
else { /* default */
str6 = PR_smprintf(subboolfmt, WARN_LEAVE_SECURE_SPK, "true");
}
rv = PREF_GetBoolPref(prefs, "security.warn_viewing_mixed", &boolval);
if ((rv == SSM_SUCCESS) && (boolval == PR_FALSE)) {
str7 = PR_smprintf(subboolfmt, WARN_VIEW_MIXED_SPK, "false");
}
else { /* default */
str7 = PR_smprintf(subboolfmt, WARN_VIEW_MIXED_SPK, "true");
}
rv = PREF_GetBoolPref(prefs, "security.warn_submit_insecure", &boolval);
if ((rv == SSM_SUCCESS) && (boolval == PR_FALSE)) {
str8 = PR_smprintf(subboolfmt, WARN_SUBMIT_INSECURE_SPK, "false");
}
else { /* default */
str8 = PR_smprintf(subboolfmt, WARN_SUBMIT_INSECURE_SPK, "true");
}
rv = PREF_GetBoolPref(prefs, "mail.encrypt_outgoing_mail", &boolval);
if ((rv == SSM_SUCCESS) && (boolval == PR_TRUE)) {
str9 = PR_smprintf(subboolfmt, ENCRYPT_MAIL_SPK, "true");
}
else { /* default */
str9 = PR_smprintf(subboolfmt, ENCRYPT_MAIL_SPK, "false");
}
rv = PREF_GetBoolPref(prefs, "mail.crypto_sign_outgoing_mail", &boolval);
if ((rv == SSM_SUCCESS) && (boolval == PR_TRUE)) {
str10 = PR_smprintf(subboolfmt, SIGN_MAIL_SPK, "true");
}
else { /* default */
str10 = PR_smprintf(subboolfmt, SIGN_MAIL_SPK, "false");
}
rv = PREF_GetBoolPref(prefs, "mail.crypto_sign_outgoing_news", &boolval);
if ((rv == SSM_SUCCESS) && (boolval == PR_TRUE)) {
str11 = PR_smprintf(subboolfmt, SIGN_NEWS_SPK, "true");
}
else { /* default */
str11 = PR_smprintf(subboolfmt, SIGN_NEWS_SPK, "false");
}
rv = PREF_GetBoolPref(prefs, "security.enable_tls", &boolval);
if ((rv == SSM_SUCCESS) && (boolval == PR_FALSE)) {
str12 = PR_smprintf(subboolfmt, TLS_SPK, "false");
}
else { /* default */
str12 = PR_smprintf(subboolfmt, TLS_SPK, "true");
}
PR_FREEIF(cx->m_result);
cx->m_result = PR_smprintf(fmt, str1, str2, str3, str4, str5, str6, str7,
str8, str9, str10, str11, str12);
SSM_DebugUTF8String("security advisor prefs list", cx->m_result);
goto done;
loser:
if (rv == SSM_SUCCESS) {
rv = SSM_FAILURE;
}
done:
PR_FREEIF(str1);
PR_FREEIF(str2);
PR_FREEIF(str3);
PR_FREEIF(str4);
PR_FREEIF(str5);
PR_FREEIF(str6);
PR_FREEIF(str7);
PR_FREEIF(str8);
PR_FREEIF(str9);
PR_FREEIF(str10);
PR_FREEIF(str11);
return SSM_SUCCESS;
}
SSMStatus
SSM_FreeTarget(SSMTextGenContext *cx)
{
SSMResource *res = NULL;
res = SSMTextGen_GetTargetObject(cx);
if (res != NULL) {
SSM_FreeResource(res);
}
return SSM_SUCCESS;
}
#if 0
/*---- Functions for handling Java principal certs ----*/
static SSMStatus ssm_parse_token(char* start, char** dest)
{
char* openQuote = NULL;
char* closeQuote = NULL;
*dest = NULL;
openQuote = strchr(start, '\"');
if (openQuote == NULL) {
return SSM_FAILURE;
}
closeQuote = strchr(openQuote+1, '\"');
if (closeQuote == NULL) {
return SSM_FAILURE;
}
*dest = (char*)PR_Calloc(closeQuote-openQuote, sizeof(char));
if (*dest == NULL) {
return SSM_FAILURE;
}
/* copy the string */
memcpy(*dest, openQuote+1, closeQuote-openQuote-1);
return SSM_SUCCESS;
}
static SSMStatus ssm_parse_principals(char* principalsData,
char*** principals, PRIntn* size)
{
SSMStatus rv;
PRIntn i = 1;
char* start = NULL;
*principals = NULL;
/* first check whether the data is empty */
if (*principalsData == '\0') {
/* this is not a failure */
*size = 0;
return SSM_SUCCESS;
}
/* data looks like "\"Netscape\", \"AOL\"": tokenize the string */
/* first determine the number of tokens */
start = principalsData;
while ((start = strchr(start+1, ',')) != NULL) {
i++;
}
*principals = (char**)PR_Calloc(i, sizeof(char*));
if (*principals == NULL) {
return SSM_FAILURE;
}
*size = i;
/* parse the tokens and store them in principals */
for (start = principalsData, i = 0; start != NULL;
start = strchr(start, ','), i++) {
rv = ssm_parse_token(start, &((*principals)[i]));
if (rv != SSM_SUCCESS) {
goto loser;
}
}
return SSM_SUCCESS;
loser:
for (i = 0; i < *size; i++) {
PR_FREEIF((*principals)[i]);
}
return SSM_FAILURE;
}
static SSMStatus ssm_retrieve_principals(SSMSecurityAdvisorContext* adv,
char*** principals, PRIntn* size)
{
SSMStatus rv;
SingleNumMessage request;
CMTItem message;
/* first, clear data */
PR_FREEIF(adv->m_principalsData);
/* pack the request */
request.value = (PRIntn)adv->super.m_id;
if (CMT_EncodeMessage(SingleNumMessageTemplate, &message, &request) !=
CMTSuccess) {
return SSM_FAILURE;
}
message.type = SSM_EVENT_MESSAGE | SSM_GET_JAVA_PRINCIPALS_EVENT;
/* send the message through the control out queue */
SSM_SendQMessage(adv->super.m_connection->m_controlOutQ,
SSM_PRIORITY_NORMAL, message.type, message.len,
(char*)message.data, PR_TRUE);
/* awkward way of blocking, but can't be helped */
SSM_LockUIEvent(SSMRESOURCE(adv));
while (adv->m_principalsData == NULL) {
SSM_WaitUIEvent(SSMRESOURCE(adv), PR_INTERVAL_NO_TIMEOUT);
}
SSM_UnlockUIEvent(SSMRESOURCE(adv));
/* parse the date that came from the plugin */
rv = ssm_parse_principals(adv->m_principalsData, principals, size);
return rv;
}
SSMStatus SSM_JavaPrincipalsKeywordHandler(SSMTextGenContext* cx)
{
SSMStatus rv;
SSMSecurityAdvisorContext* adv = NULL;
char* prefix = NULL;
char* wrapper = NULL;
char* suffix = NULL;
char* prefixKey = NULL;
char* wrapperKey = NULL;
char* suffixKey = NULL;
char* tmpStr = NULL;
char* finalStr = NULL;
const PRIntn CERT_PREFIX = 0;
const PRIntn CERT_WRAPPER = 1;
const PRIntn CERT_SUFFIX = 2;
PRIntn i;
#if 0
char* principals[5] = {"Macromedia", "NetCenter", "Sun Microsystems",
"MindSpring", "Hong Kong Telecom"};
#else
char** principals = NULL;
PRIntn size;
#endif
if ((cx == NULL) || (cx->m_result == NULL)) {
goto loser;
}
cx->m_result = NULL; /* in case we fail */
adv = (SSMSecurityAdvisorContext*)SSMTextGen_GetTargetObject(cx);
if ((adv == NULL) ||
!SSM_IsA((SSMResource*)adv, SSM_RESTYPE_SECADVISOR_CONTEXT)) {
goto loser;
}
/* retrieve the principals in string form from the plugin */
rv = ssm_retrieve_principals(adv, &principals, &size);
if (rv != SSM_SUCCESS) {
goto loser;
}
prefixKey = (char*)SSM_At(cx->m_params, CERT_PREFIX);
wrapperKey = (char*)SSM_At(cx->m_params, CERT_WRAPPER);
suffixKey = (char*)SSM_At(cx->m_params, CERT_SUFFIX);
rv = SSM_GetAndExpandTextKeyedByString(cx, prefixKey, &prefix);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSM_GetAndExpandTextKeyedByString(cx, suffixKey, &suffix);
if (rv != SSM_SUCCESS) {
goto loser;
}
finalStr = PL_strdup(prefix);
if (finalStr == NULL) {
goto loser;
}
/* add individual certs */
if (principals != NULL) {
rv = SSM_GetAndExpandTextKeyedByString(cx, wrapperKey, &wrapper);
if (rv != SSM_SUCCESS) {
goto loser;
}
for (i = 0; i < size; i++) {
tmpStr = PR_smprintf(wrapper, principals[i]);
if (SSM_ConcatenateUTF8String(&finalStr, tmpStr) != SSM_SUCCESS) {
goto loser;
}
PR_Free(tmpStr);
tmpStr = NULL;
}
}
rv = SSM_ConcatenateUTF8String(&finalStr, suffix);
if (rv != SSM_SUCCESS) {
goto loser;
}
cx->m_result = finalStr;
goto done;
loser:
if (rv == SSM_SUCCESS) {
rv = SSM_FAILURE;
}
PR_FREEIF(finalStr);
PR_FREEIF(tmpStr);
done:
PR_FREEIF(prefix);
PR_FREEIF(wrapper);
PR_FREEIF(suffix);
return rv;
}
void SSM_HandleGetJavaPrincipalsReply(SSMControlConnection* ctrl,
SECItem* message)
{
SSMStatus rv;
GetJavaPrincipalsReply reply;
SSMResource* res = NULL;
SSMSecurityAdvisorContext* adv = NULL;
if (CMT_DecodeMessage(GetJavaPrincipalsReplyTemplate, &reply,
(CMTItem*)message) != CMTSuccess) {
goto loser;
}
rv = SSMControlConnection_GetResource(ctrl, reply.resID, &res);
if (rv != PR_SUCCESS || res == NULL) {
goto loser;
}
/* make sure it is a Security Advisor context */
if (!SSM_IsA(res, SSM_RESTYPE_SECADVISOR_CONTEXT)) {
goto loser;
}
adv = (SSMSecurityAdvisorContext*)res;
SSM_LockUIEvent(res);
adv->m_principalsData = reply.principals;
/* it will be freed by the Security Advisor */
if (adv->m_principalsData == NULL) {
adv->m_principalsData = PL_strdup("");
}
SSM_NotifyUIEvent(res);
SSM_UnlockUIEvent(res);
return;
loser:
/* XXX we can't really wake up the waiting Security Advisor object
* because we don't know which resource to wake up. Bad.
*/
PR_FREEIF(reply.principals);
return;
}
#endif
/* platform-dependent names for signed.db */
#ifdef XP_UNIX
#define SIGNED "/signedapplet.db"
#else
#ifdef XP_MAC
#define SIGNED ":SignedAppletDB"
#else
#define SIGNED "\\signed.db"
#endif
#endif
SSMStatus SSM_RemovePrivilegesHandler(HTTPRequest* req)
{
SSMResource* res = NULL;
char* buttonValue;
SSMStatus rv;
res = (req->target) ? req->target : (SSMResource*)req->ctrlconn;
rv = SSM_HTTPParamValue(req, "OK", &buttonValue);
if (rv == SSM_SUCCESS) {
/* do action */
char* signeddb;
signeddb = PR_smprintf("%s%s", req->ctrlconn->m_dirRoot, SIGNED);
/* XXX we delete the signed.db file here, but we do not actively
* check the return value. There may be failures (file does
* not exist, file may be already open, etc.) but we do not
* have other recourses. Sigh.
*/
PR_Delete(signeddb);
PR_Free(signeddb);
}
else {
rv = SSM_HTTPParamValue(req, "Cancel", &buttonValue);
}
if (rv != SSM_SUCCESS) {
rv = SSM_ERR_NO_BUTTON;
goto done;
}
done:
rv = SSM_HTTPDefaultCommandHandler(req);
return rv;
}
static PRBool
ocsplist_is_default_signer(CERTCertificate *cert,
SSMDefaultOCSPRespondersList *potResponders)
{
if (!cert->nickname) {
return PR_FALSE;
}
return (PL_strcmp(cert->nickname, potResponders->defaultSigner) == 0) ?
PR_TRUE : PR_FALSE;
}
static PRBool ocsplist_include_cert(CERTCertificate *cert)
{
CERTCertTrust *trust;
char *nickname;
trust = cert->trust;
nickname = cert->nickname;
if ( ( ( trust->sslFlags & CERTDB_INVISIBLE_CA ) ||
(trust->emailFlags & CERTDB_INVISIBLE_CA ) ||
(trust->objectSigningFlags & CERTDB_INVISIBLE_CA ) ) ||
nickname == NULL) {
return PR_FALSE;
}
if ((trust->sslFlags & CERTDB_VALID_CA) ||
(trust->emailFlags & CERTDB_VALID_CA) ||
(trust->objectSigningFlags & CERTDB_VALID_CA)) {
return PR_TRUE;
}
return PR_FALSE;
}
static SECStatus ssm_get_potential_ocsp_signers(CERTCertificate *cert,
SECItem *dbKey,
void *arg)
{
SSMDefaultOCSPRespondersList *potResponders;
char *serviceURL, *nickname;
potResponders = (SSMDefaultOCSPRespondersList*)arg;
if (!ocsplist_include_cert(cert) ||
ocsplist_is_default_signer(cert, potResponders)) {
goto done;
}
/*
* We've got a CA cert, now we need to figure out if it has the AIA
* extension that points to a responder somewhere. Get our own copy
* of the nickname.
*/
nickname = PL_strdup(cert->nickname);
serviceURL = CERT_GetOCSPAuthorityInfoAccessLocation(cert);
if (serviceURL != NULL) {
/*
* This CA has an AIA extension so we'll bundle it with the group
* certs that have the
*/
SSMSortedList_Insert(potResponders->respondersWithAIA,
nickname, serviceURL);
} else {
/*
* This CA doesn't have an AIA extension so we lump with the
* rest of the CA's.
*/
SSMSortedList_Insert(potResponders->respondersWithoutAIA,
nickname, NULL);
}
done:
return SECSuccess;
}
static void
ocsplist_freedata(void *data)
{
if (data) {
PR_Free(data);
}
}
static void
ocsplist_freekey(void *data)
{
ocsplist_freedata(data);
}
static SSMStatus
ocsplist_aiacerts_enumerator(PRIntn index, void * arg, void *key,
void *data)
{
SSMDefaultOCSPRespondersList *potResps;
char *nextChunk;
SSMStatus rv;
potResps = (SSMDefaultOCSPRespondersList*)arg;
nextChunk = PR_smprintf(potResps->wrapper, (char*)key,
(data == NULL) ? "http://" : (char*)data);
rv = SSM_ConcatenateUTF8String(&potResps->cx->m_result, nextChunk);
PR_Free(nextChunk);
return rv;
}
static SSMStatus
ocsplist_cacerts_enumerator(PRIntn index, void * arg, void *key,
void *data)
{
return ocsplist_aiacerts_enumerator(index, arg, key, data);
}
SSMStatus
SSM_OCSPResponderList(SSMTextGenContext *cx)
{
SECStatus srv;
SSMDefaultOCSPRespondersList potentialResponders = {NULL, NULL,
NULL, NULL, NULL};
SSMSortedListFn funcs;
char *prefix, *suffix, *tmpStr, *prefService, *prefSigner;
SSMStatus rv;
PR_ASSERT(cx != NULL);
funcs.keyCompare = certlist_compare_strings;
funcs.freeListItemData = ocsplist_freedata;
funcs.freeListItemKey = ocsplist_freekey;
potentialResponders.respondersWithAIA = SSMSortedList_New(&funcs);
potentialResponders.respondersWithoutAIA = SSMSortedList_New(&funcs);
PREF_GetStringPref(cx->m_request->ctrlconn->m_prefs,
"security.OCSP.signingCA",
&potentialResponders.defaultSigner);
srv = SEC_TraversePermCerts(cx->m_request->ctrlconn->m_certdb,
ssm_get_potential_ocsp_signers,
&potentialResponders);
if (srv == SECSuccess) {
srv = PK11_TraverseSlotCerts(ssm_get_potential_ocsp_signers,
&potentialResponders,
cx->m_request->ctrlconn);
}
if (srv != SECSuccess) {
goto loser;
}
prefix = (char*)SSM_At(cx->m_params, 0);
suffix = (char*)SSM_At(cx->m_params, 1);
PR_ASSERT(prefix);
PR_ASSERT(suffix);
if (prefix == NULL || suffix == NULL) {
goto loser;
}
rv = SSM_GetAndExpandTextKeyedByString(cx, prefix, &tmpStr);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSM_ConcatenateUTF8String(&cx->m_result, tmpStr);
PR_Free(tmpStr);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSM_GetAndExpandTextKeyedByString(cx, "ocsp_list_wrapper",
&potentialResponders.wrapper);
if (rv != SSM_SUCCESS) {
goto loser;
}
potentialResponders.cx = cx;
/*
* Now it's time to build the list of potential OCSP Responders.
*/
SSMSortedList_Enumerate(potentialResponders.respondersWithAIA,
ocsplist_aiacerts_enumerator,
&potentialResponders);
SSMSortedList_Enumerate(potentialResponders.respondersWithoutAIA,
ocsplist_cacerts_enumerator,
&potentialResponders);
/*
* If there was a default responder enabled, let's over-ride whatever
* the cert said with what the user entered as the appropriate value.
*/
if (PREF_GetStringPref(cx->m_request->ctrlconn->m_prefs,
"security.OCSP.URL", &prefService) == SSM_SUCCESS) {
if (PREF_GetStringPref(cx->m_request->ctrlconn->m_prefs,
"security.OCSP.signingCA", &prefSigner) == SSM_SUCCESS) {
tmpStr = PR_smprintf("addNewServiceURL(\"%1$s\",\"%2$s\");\n",
prefSigner, prefService);
rv = SSM_ConcatenateUTF8String(&cx->m_result, tmpStr);
if (rv != SSM_SUCCESS) {
goto loser;
}
PR_Free(tmpStr);
}
}
rv = SSM_GetAndExpandTextKeyedByString(cx, suffix, &tmpStr);
if (rv != SSM_SUCCESS) {
goto loser;
}
rv = SSM_ConcatenateUTF8String(&cx->m_result, tmpStr);
PR_Free(tmpStr);
if (rv != SSM_SUCCESS) {
goto loser;
}
PR_Free(potentialResponders.wrapper);
SSMSortedList_Destroy(potentialResponders.respondersWithAIA);
SSMSortedList_Destroy(potentialResponders.respondersWithoutAIA);
return SSM_SUCCESS;
loser:
PR_FREEIF(potentialResponders.wrapper);
if (potentialResponders.respondersWithAIA) {
SSMSortedList_Destroy(potentialResponders.respondersWithAIA);
}
if (potentialResponders.respondersWithoutAIA) {
SSMSortedList_Destroy(potentialResponders.respondersWithoutAIA);
}
return SSM_FAILURE;
}
SSMStatus
SSM_DisplayCRLButton(SSMTextGenContext *cx)
{
SSMControlConnection *ctrl;
char *crlHTML = NULL;
SSMStatus rv;
ctrl = SSMTextGen_GetControlConnection(cx);
if (ctrl == NULL) {
goto loser;
}
if (SSM_IsCRLPresent(ctrl)) {
rv = SSM_GetAndExpandTextKeyedByString(cx, "crlButtonHTML", &crlHTML);
if (rv == SSM_SUCCESS) {
PR_FREEIF(cx->m_result);
cx->m_result = crlHTML;
}
}
return SSM_SUCCESS;
loser:
return SSM_FAILURE;
}
SSMStatus
SSM_ListCRLs(SSMTextGenContext *cx)
{
SECStatus srv;
CERTCrlHeadNode *head = NULL;
CERTCrlNode *node;
SSMControlConnection *ctrl;
char *retString = NULL;
char *currString ;
char *emptyString = "";
char *currCRLName = NULL;
char *name = NULL;
char *b64Name = NULL, *b64HTMLName;
ctrl = SSMTextGen_GetControlConnection(cx);
srv = SEC_LookupCrls(ctrl->m_certdb, &head, -1);
if (srv != SECSuccess || head == NULL) {
goto loser;
}
currString = emptyString;
for (node=head->first; node != NULL; node = node->next) {
name = CERT_GetCommonName(&(node->crl->crl.name));
b64Name = BTOA_ConvertItemToAscii(&node->crl->crl.derName);
b64HTMLName = ssm_packb64_name(b64Name);
retString = PR_smprintf("%1$s\n<option value=\"%4$d%2$s\">%3$s",
currString, b64HTMLName, name, node->type);
PR_Free(name);
PR_Free(b64Name);
PR_Free(b64HTMLName);
if (currString != emptyString)
PR_Free(currString);
currString = retString;
}
PR_FREEIF(cx->m_result);
cx->m_result = retString;
return SSM_SUCCESS;
loser:
return SSM_FAILURE;
}
SSMStatus
ssm_getStringForAbleAgent(SSMTextGenContext *cx, const char *agents[])
{
int i;
SSMStatus rv;
char *key;
key = SSM_At(cx->m_params, 0);
for (i=0; agents[i] != NULL; i++) {
if (PL_strstr(cx->m_request->agent, agents[i]) != NULL) {
PR_FREEIF(cx->m_result);
rv = SSM_GetAndExpandText(cx, key, &cx->m_result);
if (rv != SSM_SUCCESS) {
return rv;
}
break;
}
}
return SSM_SUCCESS;
}
SSMStatus SSM_LayoutSMIMETab(SSMTextGenContext *cx)
{
return ssm_getStringForAbleAgent(cx, kSMimeApps);
}
SSMStatus SSM_LayoutJavaJSTab(SSMTextGenContext *cx)
{
return ssm_getStringForAbleAgent(cx, kJavaJSApps);
}
SSMStatus SSM_LayoutOthersTab(SSMTextGenContext *cx)
{
return ssm_getStringForAbleAgent(cx, kSMimeApps);
}