зеркало из https://github.com/mozilla/pjs.git
NOT PART OF THE BUILD
new files for 106507 NOT PART OF THE BUILD
This commit is contained in:
Родитель
1b6cfe2225
Коммит
43b2a7ad1e
|
@ -0,0 +1,654 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape 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/NPL/
|
||||
*
|
||||
* 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 mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Drinan <ddrinan@netscape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsICMS.h"
|
||||
#include "mimecms.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nspr.h"
|
||||
#include "nsEscape.h"
|
||||
#include "mimemsg.h"
|
||||
#include "nsIWindowWatcher.h"
|
||||
#include "nsIPrompt.h"
|
||||
|
||||
|
||||
#define MIME_SUPERCLASS mimeEncryptedClass
|
||||
MimeDefClass(MimeEncryptedCMS, MimeEncryptedCMSClass,
|
||||
mimeEncryptedCMSClass, &MIME_SUPERCLASS);
|
||||
|
||||
static void *MimeCMS_init(MimeObject *,
|
||||
int (*output_fn) (const char *, PRInt32, void *),
|
||||
void *);
|
||||
static int MimeCMS_write (const char *, PRInt32, void *);
|
||||
static int MimeCMS_eof (void *, PRBool);
|
||||
static char * MimeCMS_generate (void *);
|
||||
static void MimeCMS_free (void *);
|
||||
static void MimeCMS_get_content_info (MimeObject *,
|
||||
nsICMSMessage **,
|
||||
char **, PRInt32 *, PRInt32 *, PRBool *);
|
||||
|
||||
extern int SEC_ERROR_CERT_ADDR_MISMATCH;
|
||||
|
||||
static int
|
||||
MimeEncryptedCMSClassInitialize(MimeEncryptedCMSClass *clazz)
|
||||
{
|
||||
MimeObjectClass *oclass = (MimeObjectClass *) clazz;
|
||||
MimeEncryptedClass *eclass = (MimeEncryptedClass *) clazz;
|
||||
|
||||
PR_ASSERT(!oclass->class_initialized);
|
||||
|
||||
eclass->crypto_init = MimeCMS_init;
|
||||
eclass->crypto_write = MimeCMS_write;
|
||||
eclass->crypto_eof = MimeCMS_eof;
|
||||
eclass->crypto_generate_html = MimeCMS_generate;
|
||||
eclass->crypto_free = MimeCMS_free;
|
||||
|
||||
clazz->get_content_info = MimeCMS_get_content_info;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
typedef struct MimeCMSdata {
|
||||
int (*output_fn) (const char *buf, PRInt32 buf_size, void *output_closure);
|
||||
void *output_closure;
|
||||
nsCOMPtr<nsICMSDecoder> decoder_context;
|
||||
nsCOMPtr<nsICMSMessage> content_info;
|
||||
PRBool ci_is_encrypted;
|
||||
char *sender_addr;
|
||||
PRInt32 decode_error;
|
||||
PRInt32 verify_error;
|
||||
MimeObject *self;
|
||||
PRBool parent_is_encrypted_p;
|
||||
PRBool parent_holds_stamp_p;
|
||||
} MimeCMSdata;
|
||||
|
||||
|
||||
static void
|
||||
MimeCMS_get_content_info(MimeObject *obj,
|
||||
nsICMSMessage **content_info_ret,
|
||||
char **sender_email_addr_return,
|
||||
PRInt32 *decode_error_ret,
|
||||
PRInt32 *verify_error_ret,
|
||||
PRBool *ci_is_encrypted)
|
||||
{
|
||||
MimeEncrypted *enc = (MimeEncrypted *) obj;
|
||||
if (enc && enc->crypto_closure)
|
||||
{
|
||||
MimeCMSdata *data = (MimeCMSdata *) enc->crypto_closure;
|
||||
|
||||
*decode_error_ret = data->decode_error;
|
||||
*verify_error_ret = data->verify_error;
|
||||
*content_info_ret = data->content_info;
|
||||
*ci_is_encrypted = data->ci_is_encrypted;
|
||||
|
||||
if (sender_email_addr_return)
|
||||
*sender_email_addr_return = (data->sender_addr
|
||||
? nsCRT::strdup(data->sender_addr)
|
||||
: 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* SEC_PKCS7DecoderContentCallback for SEC_PKCS7DecoderStart() */
|
||||
static void
|
||||
MimeCMS_content_callback (void *arg, const char *buf, unsigned long length)
|
||||
{
|
||||
int status;
|
||||
MimeCMSdata *data = (MimeCMSdata *) arg;
|
||||
PR_ASSERT(data);
|
||||
if (!data) return;
|
||||
|
||||
PR_ASSERT(data->output_fn);
|
||||
if (!data->output_fn)
|
||||
return;
|
||||
|
||||
PR_SetError(0,0);
|
||||
status = data->output_fn (buf, length, data->output_closure);
|
||||
if (status < 0)
|
||||
{
|
||||
PR_SetError(status, 0);
|
||||
data->output_fn = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
MimeEncryptedCMS_encrypted_p (MimeObject *obj)
|
||||
{
|
||||
PRBool encrypted;
|
||||
|
||||
PR_ASSERT(obj);
|
||||
if (!obj) return PR_FALSE;
|
||||
if (mime_typep(obj, (MimeObjectClass *) &mimeEncryptedCMSClass))
|
||||
{
|
||||
MimeEncrypted *enc = (MimeEncrypted *) obj;
|
||||
MimeCMSdata *data = (MimeCMSdata *) enc->crypto_closure;
|
||||
if (!data || !data->content_info) return PR_FALSE;
|
||||
data->content_info->ContentIsEncrypted(&encrypted);
|
||||
return encrypted;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// extern MimeMessageClass mimeMessageClass; /* gag */
|
||||
extern MimeObjectClass mimeMultipartSignedClass; /* double gag */
|
||||
|
||||
extern int ParseRFC822Addresses (const char *line,
|
||||
char **names, char **addresses);
|
||||
|
||||
extern char *IMAP_CreateReloadAllPartsUrl(const char *url);
|
||||
|
||||
|
||||
PRBool
|
||||
MimeCMSHeadersAndCertsMatch(MimeObject *obj,
|
||||
nsICMSMessage *content_info,
|
||||
char **sender_email_addr_return)
|
||||
{
|
||||
MimeHeaders *msg_headers = 0;
|
||||
char *from_addr = 0;
|
||||
char *from_name = 0;
|
||||
char *sender_addr = 0;
|
||||
char *sender_name = 0;
|
||||
char *cert_name = 0;
|
||||
char *cert_addr = 0;
|
||||
PRBool match = PR_TRUE;
|
||||
|
||||
/* Find the name and address in the cert.
|
||||
*/
|
||||
PR_ASSERT(content_info);
|
||||
if (content_info)
|
||||
{
|
||||
content_info->GetSignerCommonName (&cert_name);
|
||||
content_info->GetSignerEmailAddress (&cert_addr);
|
||||
}
|
||||
if (!cert_name && !cert_addr) goto DONE;
|
||||
|
||||
|
||||
/* Find the headers of the MimeMessage which is the parent (or grandparent)
|
||||
of this object (remember, crypto objects nest.) */
|
||||
{
|
||||
MimeObject *o2 = obj;
|
||||
msg_headers = o2->headers;
|
||||
while (o2 &&
|
||||
o2->parent &&
|
||||
!mime_typep(o2->parent, (MimeObjectClass *) &mimeMessageClass))
|
||||
{
|
||||
o2 = o2->parent;
|
||||
msg_headers = o2->headers;
|
||||
}
|
||||
}
|
||||
|
||||
PR_ASSERT(msg_headers);
|
||||
if (!msg_headers) goto DONE;
|
||||
|
||||
/* Find the names and addresses in the From and/or Sender fields.
|
||||
*/
|
||||
{
|
||||
char *s;
|
||||
|
||||
/* Extract the name and address of the "From:" field. */
|
||||
s = MimeHeaders_get(msg_headers, HEADER_FROM, PR_FALSE, PR_FALSE);
|
||||
if (s)
|
||||
{
|
||||
int n = ParseRFC822Addresses(s, &from_name, &from_addr);
|
||||
PR_ASSERT(n <= 1);
|
||||
PR_FREEIF(s);
|
||||
}
|
||||
|
||||
/* Extract the name and address of the "Sender:" field. */
|
||||
s = MimeHeaders_get(msg_headers, HEADER_SENDER, PR_FALSE, PR_FALSE);
|
||||
if (s)
|
||||
{
|
||||
int n = ParseRFC822Addresses(s, &sender_name, &sender_addr);
|
||||
PR_ASSERT(n <= 1);
|
||||
PR_FREEIF(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now compare them --
|
||||
consider it a match if the address in the cert matches either the
|
||||
address in the From or Sender field; and if the name in the cert
|
||||
matches either the name in the From or Sender field.
|
||||
|
||||
Consider it a match if the cert does not contain a name (address.)
|
||||
But do not consider it a match if the cert contains a name (address)
|
||||
but the message headers do not.
|
||||
*/
|
||||
|
||||
PR_ASSERT(match == PR_TRUE);
|
||||
match = PR_TRUE;
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
First check the addresses.
|
||||
*/
|
||||
|
||||
/* If there is no addr in the cert, then consider it a match. */
|
||||
if (!cert_addr)
|
||||
match = PR_TRUE;
|
||||
|
||||
/* If there is both a from and sender address, and if neither of
|
||||
them match, then error. */
|
||||
else if (from_addr && *from_addr &&
|
||||
sender_addr && *sender_addr)
|
||||
{
|
||||
if (!!nsCRT::strcasecmp(cert_addr, from_addr) &&
|
||||
!!nsCRT::strcasecmp(cert_addr, sender_addr))
|
||||
match = PR_FALSE;
|
||||
}
|
||||
/* If there is a from but no sender, and it doesn't match, then error. */
|
||||
else if (from_addr && *from_addr)
|
||||
{
|
||||
if (!!nsCRT::strcasecmp(cert_addr, from_addr))
|
||||
match = PR_FALSE;
|
||||
}
|
||||
/* If there is a sender but no from, and it doesn't match, then error. */
|
||||
else if (sender_addr && *sender_addr)
|
||||
{
|
||||
if (!!nsCRT::strcasecmp(cert_addr, sender_addr))
|
||||
match = PR_FALSE;
|
||||
}
|
||||
/* Else there are no addresses at all -- error. */
|
||||
else
|
||||
{
|
||||
match = PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
if (sender_email_addr_return)
|
||||
{
|
||||
if (match && cert_addr)
|
||||
*sender_email_addr_return = nsCRT::strdup(cert_addr);
|
||||
else if (from_addr && *from_addr)
|
||||
*sender_email_addr_return = nsCRT::strdup(from_addr);
|
||||
else if (sender_addr && *sender_addr)
|
||||
*sender_email_addr_return = nsCRT::strdup(sender_addr);
|
||||
else
|
||||
*sender_email_addr_return = 0;
|
||||
}
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
Next, check the names.
|
||||
*/
|
||||
#if 0
|
||||
/* No, don't check the names, that's a nightmare that just won't end. */
|
||||
|
||||
if (match == PR_FALSE)
|
||||
; /* nevermind */
|
||||
|
||||
/* If there is no name in the cert, then consider it a match. */
|
||||
else if (!cert_name)
|
||||
match = PR_TRUE;
|
||||
/* If there is both a from and sender name, and if neither of
|
||||
them match, then error. */
|
||||
else if (from_name && *from_name &&
|
||||
sender_name && *sender_name)
|
||||
{
|
||||
if (!!strcasecomp(cert_name, from_name) &&
|
||||
!!strcasecomp(cert_name, sender_name))
|
||||
match = PR_FALSE;
|
||||
}
|
||||
/* If there is a from but no sender, and it doesn't match, then error. */
|
||||
else if (from_name && *from_name)
|
||||
{
|
||||
if (!!strcasecomp(cert_name, from_name))
|
||||
match = PR_FALSE;
|
||||
}
|
||||
/* If there is a sender but no from, and it doesn't match, then error. */
|
||||
else if (sender_name && *sender_name)
|
||||
{
|
||||
if (!!strcasecomp(cert_name, sender_name))
|
||||
match = PR_FALSE;
|
||||
}
|
||||
/* Else there are no names at all -- consider that a match. */
|
||||
#endif /* 0 */
|
||||
|
||||
|
||||
DONE:
|
||||
PR_FREEIF(from_addr);
|
||||
PR_FREEIF(from_name);
|
||||
PR_FREEIF(sender_addr);
|
||||
PR_FREEIF(sender_name);
|
||||
PR_FREEIF(cert_addr);
|
||||
PR_FREEIF(cert_name);
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
static void *
|
||||
MimeCMS_init(MimeObject *obj,
|
||||
int (*output_fn) (const char *buf, PRInt32 buf_size,
|
||||
void *output_closure),
|
||||
void *output_closure)
|
||||
{
|
||||
MimeCMSdata *data;
|
||||
MimeDisplayOptions *opts;
|
||||
nsresult rv;
|
||||
|
||||
PR_ASSERT(obj && obj->options && output_fn);
|
||||
if (!(obj && obj->options && output_fn)) return 0;
|
||||
|
||||
opts = obj->options;
|
||||
data = (MimeCMSdata *) PR_MALLOC(sizeof(*data));
|
||||
if (!data) return 0;
|
||||
|
||||
nsCRT::memset(data, 0, sizeof(*data));
|
||||
|
||||
data->self = obj;
|
||||
data->output_fn = output_fn;
|
||||
data->output_closure = output_closure;
|
||||
PR_SetError(0, 0);
|
||||
data->decoder_context = do_CreateInstance(NS_CMSDECODER_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) return 0;
|
||||
|
||||
rv = data->decoder_context->Start(MimeCMS_content_callback, data);
|
||||
if (NS_FAILED(rv)) return 0;
|
||||
|
||||
// XXX Fix later XXX //
|
||||
#if 0
|
||||
data->parent_holds_stamp_p =
|
||||
(obj->parent &&
|
||||
(mime_crypto_stamped_p(obj->parent) ||
|
||||
mime_typep(obj->parent, (MimeObjectClass *) &mimeEncryptedClass)));
|
||||
|
||||
data->parent_is_encrypted_p =
|
||||
(obj->parent && MimeEncryptedCMS_encrypted_p (obj->parent));
|
||||
|
||||
/* If the parent of this object is a crypto-blob, then it's the grandparent
|
||||
who would have written out the headers and prepared for a stamp...
|
||||
(This shit sucks.)
|
||||
*/
|
||||
if (data->parent_is_encrypted_p &&
|
||||
!data->parent_holds_stamp_p &&
|
||||
obj->parent && obj->parent->parent)
|
||||
data->parent_holds_stamp_p =
|
||||
mime_crypto_stamped_p (obj->parent->parent);
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int
|
||||
MimeCMS_write (const char *buf, PRInt32 buf_size, void *closure)
|
||||
{
|
||||
MimeCMSdata *data = (MimeCMSdata *) closure;
|
||||
nsresult rv;
|
||||
|
||||
PR_ASSERT(data && data->output_fn && data->decoder_context);
|
||||
if (!data || !data->output_fn || !data->decoder_context) return -1;
|
||||
|
||||
PR_SetError(0, 0);
|
||||
rv = data->decoder_context->Update(buf, buf_size);
|
||||
if (NS_FAILED(rv)) {
|
||||
data->verify_error = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
MimeCMS_eof (void *crypto_closure, PRBool abort_p)
|
||||
{
|
||||
MimeCMSdata *data = (MimeCMSdata *) crypto_closure;
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService("@mozilla.org/embedcomp/window-watcher;1"));
|
||||
nsCOMPtr<nsIPrompt> prompter;
|
||||
wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
|
||||
|
||||
PR_ASSERT(data && data->output_fn && data->decoder_context);
|
||||
if (!data || !data->output_fn || !data->decoder_context)
|
||||
return -1;
|
||||
|
||||
/* Hand an EOF to the crypto library. It may call data->output_fn.
|
||||
(Today, the crypto library has no flushing to do, but maybe there
|
||||
will be someday.)
|
||||
|
||||
We save away the value returned and will use it later to emit a
|
||||
blurb about whether the signature validation was cool.
|
||||
*/
|
||||
|
||||
PR_SetError(0, 0);
|
||||
rv = data->decoder_context->Finish(getter_AddRefs(data->content_info));
|
||||
if (NS_FAILED(rv)) {
|
||||
data->verify_error = PR_GetError();
|
||||
nsString msg(NS_LITERAL_STRING("Error decrypted message that was encrypted by the sender").get());
|
||||
prompter->Alert(0, msg.get());
|
||||
} else {
|
||||
nsString msg(NS_LITERAL_STRING("Successfully decrypted message that was encrypted by the sender").get());
|
||||
prompter->Alert(0, msg.get());
|
||||
}
|
||||
data->decoder_context = 0;
|
||||
|
||||
/* Is the content info encrypted? */
|
||||
if (data->content_info) {
|
||||
data->ci_is_encrypted = PR_TRUE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
MimeCMS_free (void *crypto_closure)
|
||||
{
|
||||
MimeCMSdata *data = (MimeCMSdata *) crypto_closure;
|
||||
PR_ASSERT(data);
|
||||
if (!data) return;
|
||||
|
||||
PR_ASSERT(!data->decoder_context);
|
||||
|
||||
PR_FREEIF(data->sender_addr);
|
||||
|
||||
if (data->content_info)
|
||||
{
|
||||
// Free reference to nsICMSMessage //
|
||||
data->content_info = 0;
|
||||
}
|
||||
|
||||
// Do an orderly release of nsICMSDecoder and nsICMSMessage //
|
||||
if (data->decoder_context)
|
||||
{
|
||||
nsCOMPtr<nsICMSMessage> cinfo;
|
||||
data->decoder_context->Finish(getter_AddRefs(cinfo));
|
||||
data->decoder_context = 0;
|
||||
}
|
||||
|
||||
PR_FREEIF(data);
|
||||
}
|
||||
|
||||
char *
|
||||
MimeCMS_MakeSAURL(MimeObject *obj)
|
||||
{
|
||||
char *stamp_url = 0;
|
||||
|
||||
/* Skip over any crypto objects which lie between us and a message/rfc822.
|
||||
But if we reach an object that isn't a crypto object or a message/rfc822
|
||||
then stop on the crypto object *before* it. That is, leave `obj' set to
|
||||
either a crypto object, or a message/rfc822, but leave it set to the
|
||||
innermost message/rfc822 above a consecutive run of crypto objects.
|
||||
*/
|
||||
while (1)
|
||||
{
|
||||
if (!obj->parent)
|
||||
break;
|
||||
else if (mime_typep (obj->parent, (MimeObjectClass *) &mimeMessageClass))
|
||||
{
|
||||
obj = obj->parent;
|
||||
break;
|
||||
}
|
||||
#if 0 // XXX Fix later XXX //
|
||||
else if (!mime_typep (obj->parent,
|
||||
(MimeObjectClass *) &mimeEncryptedClass) &&
|
||||
!mime_typep (obj->parent,
|
||||
(MimeObjectClass *) &mimeMultipartSignedClass))
|
||||
#endif
|
||||
else if (!mime_typep (obj->parent,
|
||||
(MimeObjectClass *) &mimeEncryptedClass))
|
||||
{
|
||||
break;
|
||||
}
|
||||
obj = obj->parent;
|
||||
PR_ASSERT(obj);
|
||||
}
|
||||
|
||||
|
||||
if (obj->options)
|
||||
{
|
||||
const char *base_url = obj->options->url;
|
||||
char *id = (base_url ? mime_part_address (obj) : 0);
|
||||
char *url = (id && base_url
|
||||
? mime_set_url_part(base_url, id, PR_TRUE)
|
||||
: 0);
|
||||
char *url2 = (url ? nsEscape(url, url_XAlphas) : 0);
|
||||
PR_FREEIF(id);
|
||||
PR_FREEIF(url);
|
||||
|
||||
stamp_url = (char *) PR_MALLOC(nsCRT::strlen(url2) + 50);
|
||||
if (stamp_url)
|
||||
{
|
||||
PL_strcpy(stamp_url, "about:security?advisor=");
|
||||
PL_strcat(stamp_url, url2);
|
||||
}
|
||||
PR_FREEIF(url2);
|
||||
}
|
||||
return stamp_url;
|
||||
}
|
||||
|
||||
static char *
|
||||
MimeCMS_generate (void *crypto_closure)
|
||||
{
|
||||
MimeCMSdata *data = (MimeCMSdata *) crypto_closure;
|
||||
PRBool self_signed_p = PR_FALSE;
|
||||
PRBool self_encrypted_p = PR_FALSE;
|
||||
PRBool union_encrypted_p = PR_FALSE;
|
||||
PRBool good_p = PR_TRUE;
|
||||
PRBool unverified_p = PR_FALSE;
|
||||
|
||||
PR_ASSERT(data && data->output_fn);
|
||||
if (!data || !data->output_fn) return 0;
|
||||
|
||||
if (data->content_info)
|
||||
{
|
||||
data->content_info->ContentIsSigned(&self_signed_p);
|
||||
data->content_info->ContentIsEncrypted(&self_encrypted_p);
|
||||
union_encrypted_p = (self_encrypted_p || data->parent_is_encrypted_p);
|
||||
|
||||
if (self_signed_p)
|
||||
{
|
||||
PR_SetError(0, 0);
|
||||
good_p = data->content_info->VerifySignature();
|
||||
#if 0 // XXX Fix this XXX //
|
||||
good_p = SEC_PKCS7VerifySignature(data->content_info,
|
||||
0, /*certUsageEmailSigner */ /* #### */
|
||||
PR_TRUE); /* #### keepcerts */
|
||||
#endif
|
||||
if (!good_p)
|
||||
{
|
||||
if (!data->verify_error)
|
||||
data->verify_error = PR_GetError();
|
||||
PR_ASSERT(data->verify_error < 0);
|
||||
if (data->verify_error >= 0)
|
||||
data->verify_error = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
good_p = MimeCMSHeadersAndCertsMatch(data->self,
|
||||
data->content_info,
|
||||
&data->sender_addr);
|
||||
if (!good_p && !data->verify_error)
|
||||
// data->verify_error = SEC_ERROR_CERT_ADDR_MISMATCH; XXX Fix later XXX //
|
||||
data->verify_error = -1;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (SEC_PKCS7ContainsCertsOrCrls(data->content_info))
|
||||
{
|
||||
/* #### call libsec telling it to import the certs */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Don't free these yet -- keep them around for the lifetime of the
|
||||
MIME object, so that we can get at the security info of sub-parts
|
||||
of the currently-displayed message. */
|
||||
#if 0
|
||||
SEC_PKCS7DestroyContentInfo(data->content_info);
|
||||
data->content_info = 0;
|
||||
#endif /* 0 */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No content info? Something's horked. Guess. */
|
||||
self_encrypted_p = PR_TRUE;
|
||||
union_encrypted_p = PR_TRUE;
|
||||
good_p = PR_FALSE;
|
||||
if (!data->decode_error && !data->verify_error)
|
||||
data->decode_error = -1;
|
||||
}
|
||||
|
||||
unverified_p = data->self->options->missing_parts;
|
||||
|
||||
PR_ASSERT(data->self);
|
||||
if (data->self && data->self->parent)
|
||||
// mime_set_crypto_stamp(data->self->parent, self_signed_p, self_encrypted_p); XXX Fix later XXX //
|
||||
|
||||
|
||||
{
|
||||
char *stamp_url = 0, *result = nsnull;
|
||||
if (data->self)
|
||||
{
|
||||
if (unverified_p && data->self->options)
|
||||
// stamp_url = IMAP_CreateReloadAllPartsUrl(data->self->options->url); XXX Fix later XXX //
|
||||
stamp_url = nsnull;
|
||||
else
|
||||
stamp_url = MimeCMS_MakeSAURL(data->self);
|
||||
}
|
||||
|
||||
#if 0 // XXX Fix this later XXX //
|
||||
result =
|
||||
MimeHeaders_make_crypto_stamp (union_encrypted_p,
|
||||
self_signed_p,
|
||||
good_p,
|
||||
unverified_p,
|
||||
data->parent_holds_stamp_p,
|
||||
stamp_url);
|
||||
#endif
|
||||
PR_FREEIF(stamp_url);
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape 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/NPL/
|
||||
*
|
||||
* 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 mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Drinan <ddrinan@netscape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MIMECMS_H_
|
||||
#define _MIMECMS_H_
|
||||
|
||||
#include "mimecryp.h"
|
||||
#include "nsICMS.h"
|
||||
|
||||
/* The MimeEncryptedCMS class implements a type of MIME object where the
|
||||
object is passed through a CMS decryption engine to decrypt or verify
|
||||
signatures. That module returns a new MIME object, which is then presented
|
||||
to the user. See mimecryp.h for details of the general mechanism on which
|
||||
this is built.
|
||||
*/
|
||||
|
||||
typedef struct MimeEncryptedCMSClass MimeEncryptedCMSClass;
|
||||
typedef struct MimeEncryptedCMS MimeEncryptedCMS;
|
||||
|
||||
struct MimeEncryptedCMSClass {
|
||||
MimeEncryptedClass encrypted;
|
||||
|
||||
/* Callback used to access the SEC_PKCS7ContentInfo of this object. */
|
||||
void (*get_content_info) (MimeObject *self,
|
||||
nsICMSMessage **content_info_ret,
|
||||
char **sender_email_addr_return,
|
||||
PRInt32 *decode_error_ret,
|
||||
PRInt32 *verify_error_ret,
|
||||
PRBool * ci_is_encrypted);
|
||||
};
|
||||
|
||||
extern MimeEncryptedCMSClass mimeEncryptedCMSClass;
|
||||
|
||||
struct MimeEncryptedCMS {
|
||||
MimeEncrypted encrypted; /* superclass variables */
|
||||
};
|
||||
|
||||
#endif /* _MIMEPKCS_H_ */
|
|
@ -0,0 +1,601 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape 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/NPL/
|
||||
*
|
||||
* 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 mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Drinan <ddrinan@netscape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "mimecryp.h"
|
||||
#include "mimemoz2.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsMimeStringResources.h"
|
||||
#include "mimebuf.h"
|
||||
#include "prmem.h"
|
||||
#include "plstr.h"
|
||||
#include "prlog.h"
|
||||
#include "nsCRT.h"
|
||||
#include "mimemult.h"
|
||||
|
||||
|
||||
#define MIME_SUPERCLASS mimeContainerClass
|
||||
MimeDefClass(MimeEncrypted, MimeEncryptedClass, mimeEncryptedClass,
|
||||
&MIME_SUPERCLASS);
|
||||
|
||||
static int MimeEncrypted_initialize (MimeObject *);
|
||||
static void MimeEncrypted_finalize (MimeObject *);
|
||||
static int MimeEncrypted_parse_begin (MimeObject *);
|
||||
static int MimeEncrypted_parse_buffer (char *, PRInt32, MimeObject *);
|
||||
static int MimeEncrypted_parse_line (char *, PRInt32, MimeObject *);
|
||||
static int MimeEncrypted_parse_decoded_buffer (char *, PRInt32, MimeObject *);
|
||||
static int MimeEncrypted_parse_eof (MimeObject *, PRBool);
|
||||
static int MimeEncrypted_parse_end (MimeObject *, PRBool);
|
||||
static int MimeEncrypted_add_child (MimeObject *, MimeObject *);
|
||||
|
||||
static int MimeHandleDecryptedOutput (const char *, PRInt32, void *);
|
||||
static int MimeHandleDecryptedOutputLine (char *, PRInt32, MimeObject *);
|
||||
static int MimeEncrypted_close_headers (MimeObject *);
|
||||
static int MimeEncrypted_emit_buffered_child(MimeObject *);
|
||||
|
||||
static int
|
||||
MimeEncryptedClassInitialize(MimeEncryptedClass *clazz)
|
||||
{
|
||||
MimeObjectClass *oclass = (MimeObjectClass *) clazz;
|
||||
MimeContainerClass *cclass = (MimeContainerClass *) clazz;
|
||||
|
||||
PR_ASSERT(!oclass->class_initialized);
|
||||
oclass->initialize = MimeEncrypted_initialize;
|
||||
oclass->finalize = MimeEncrypted_finalize;
|
||||
oclass->parse_begin = MimeEncrypted_parse_begin;
|
||||
oclass->parse_buffer = MimeEncrypted_parse_buffer;
|
||||
oclass->parse_line = MimeEncrypted_parse_line;
|
||||
oclass->parse_eof = MimeEncrypted_parse_eof;
|
||||
oclass->parse_end = MimeEncrypted_parse_end;
|
||||
|
||||
cclass->add_child = MimeEncrypted_add_child;
|
||||
|
||||
clazz->parse_decoded_buffer = MimeEncrypted_parse_decoded_buffer;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
MimeEncrypted_initialize (MimeObject *obj)
|
||||
{
|
||||
return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(obj);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
MimeEncrypted_parse_begin (MimeObject *obj)
|
||||
{
|
||||
MimeEncrypted *enc = (MimeEncrypted *) obj;
|
||||
MimeDecoderData *(*fn) (nsresult (*) (const char*, PRInt32, void*), void*) = 0;
|
||||
|
||||
PR_ASSERT(!enc->crypto_closure);
|
||||
if (enc->crypto_closure)
|
||||
return -1;
|
||||
|
||||
enc->crypto_closure = (((MimeEncryptedClass *) obj->clazz)->crypto_init) (obj, MimeHandleDecryptedOutput, obj);
|
||||
if (!enc->crypto_closure)
|
||||
return -1;
|
||||
|
||||
|
||||
/* (Mostly duplicated from MimeLeaf, see comments in mimecryp.h.)
|
||||
Initialize a decoder if necessary.
|
||||
*/
|
||||
if (!obj->encoding)
|
||||
;
|
||||
else if (!nsCRT::strcasecmp(obj->encoding, ENCODING_BASE64))
|
||||
fn = &MimeB64DecoderInit;
|
||||
else if (!nsCRT::strcasecmp(obj->encoding, ENCODING_QUOTED_PRINTABLE))
|
||||
fn = &MimeQPDecoderInit;
|
||||
else if (!nsCRT::strcasecmp(obj->encoding, ENCODING_UUENCODE) ||
|
||||
!nsCRT::strcasecmp(obj->encoding, ENCODING_UUENCODE2) ||
|
||||
!nsCRT::strcasecmp(obj->encoding, ENCODING_UUENCODE3) ||
|
||||
!nsCRT::strcasecmp(obj->encoding, ENCODING_UUENCODE4))
|
||||
fn = &MimeUUDecoderInit;
|
||||
if (fn)
|
||||
{
|
||||
enc->decoder_data =
|
||||
fn (/* The (int (*) ...) cast is to turn the `void' argument
|
||||
into `MimeObject'. */
|
||||
((nsresult (*) (const char *, PRInt32, void *))
|
||||
((MimeEncryptedClass *)obj->clazz)->parse_decoded_buffer),
|
||||
obj);
|
||||
|
||||
if (!enc->decoder_data)
|
||||
return MIME_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
MimeEncrypted_parse_buffer (char *buffer, PRInt32 size, MimeObject *obj)
|
||||
{
|
||||
/* (Duplicated from MimeLeaf, see comments in mimecryp.h.)
|
||||
*/
|
||||
|
||||
MimeEncrypted *enc = (MimeEncrypted *) obj;
|
||||
|
||||
PR_ASSERT(!obj->closed_p);
|
||||
if (obj->closed_p) return -1;
|
||||
|
||||
/* Don't consult output_p here, since at this point we're behaving as a
|
||||
simple container object -- the output_p decision should be made by
|
||||
the child of this object. */
|
||||
|
||||
if (enc->decoder_data)
|
||||
return MimeDecoderWrite (enc->decoder_data, buffer, size);
|
||||
else
|
||||
return ((MimeEncryptedClass *)obj->clazz)->parse_decoded_buffer (buffer,
|
||||
size,
|
||||
obj);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
MimeEncrypted_parse_line (char *line, PRInt32 length, MimeObject *obj)
|
||||
{
|
||||
PR_ASSERT(0);
|
||||
/* This method shouldn't ever be called. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
MimeEncrypted_parse_decoded_buffer (char *buffer, PRInt32 size, MimeObject *obj)
|
||||
{
|
||||
MimeEncrypted *enc = (MimeEncrypted *) obj;
|
||||
return
|
||||
((MimeEncryptedClass *) obj->clazz)->crypto_write (buffer, size,
|
||||
enc->crypto_closure);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
MimeEncrypted_parse_eof (MimeObject *obj, PRBool abort_p)
|
||||
{
|
||||
int status = 0;
|
||||
MimeEncrypted *enc = (MimeEncrypted *) obj;
|
||||
|
||||
if (obj->closed_p) return 0;
|
||||
PR_ASSERT(!obj->parsed_p);
|
||||
|
||||
/* (Duplicated from MimeLeaf, see comments in mimecryp.h.)
|
||||
Close off the decoder, to cause it to give up any buffered data that
|
||||
it is still holding.
|
||||
*/
|
||||
if (enc->decoder_data)
|
||||
{
|
||||
int status = MimeDecoderDestroy(enc->decoder_data, PR_FALSE);
|
||||
enc->decoder_data = 0;
|
||||
if (status < 0) return status;
|
||||
}
|
||||
|
||||
|
||||
/* If there is still data in the ibuffer, that means that the last
|
||||
*decrypted* line of this part didn't end in a newline; so push it out
|
||||
anyway (this means that the parse_line method will be called with a
|
||||
string with no trailing newline, which isn't the usual case.) */
|
||||
if (!abort_p &&
|
||||
obj->ibuffer_fp > 0)
|
||||
{
|
||||
int status = MimeHandleDecryptedOutputLine (obj->ibuffer,
|
||||
obj->ibuffer_fp, obj);
|
||||
obj->ibuffer_fp = 0;
|
||||
if (status < 0)
|
||||
{
|
||||
obj->closed_p = PR_TRUE;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Now run the superclass's parse_eof, which (because we've already taken
|
||||
care of ibuffer in a way appropriate for this class, immediately above)
|
||||
will ony set closed_p to true.
|
||||
*/
|
||||
status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof (obj, abort_p);
|
||||
if (status < 0) return status;
|
||||
|
||||
|
||||
/* Now close off the underlying crypto module. At this point, the crypto
|
||||
module has all of the input. (DecoderDestroy called parse_decoded_buffer
|
||||
which called crypto_write, with the last of the data.)
|
||||
*/
|
||||
if (enc->crypto_closure)
|
||||
{
|
||||
status =
|
||||
((MimeEncryptedClass *) obj->clazz)->crypto_eof (enc->crypto_closure,
|
||||
abort_p);
|
||||
if (status < 0 && !abort_p)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Now we have the entire child part in the part buffer.
|
||||
We are now able to verify its signature, emit a blurb, and then
|
||||
emit the part.
|
||||
*/
|
||||
if (abort_p)
|
||||
return 0;
|
||||
else
|
||||
return MimeEncrypted_emit_buffered_child (obj);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
MimeEncrypted_parse_end (MimeObject *obj, PRBool abort_p)
|
||||
{
|
||||
MimeEncrypted *enc = (MimeEncrypted *) obj;
|
||||
|
||||
/* Don't free these yet -- keep them around for the lifetime of the
|
||||
MIME object, so that we can get at the security info of sub-parts
|
||||
of the currently-displayed message. */
|
||||
#if 0
|
||||
if (enc->crypto_closure)
|
||||
{
|
||||
((MimeEncryptedClass *) obj->class)->crypto_free (enc->crypto_closure);
|
||||
enc->crypto_closure = 0;
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
return ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_end (obj, abort_p);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
MimeEncrypted_cleanup (MimeObject *obj, PRBool finalizing_p)
|
||||
{
|
||||
MimeEncrypted *enc = (MimeEncrypted *) obj;
|
||||
|
||||
if (enc->part_buffer)
|
||||
{
|
||||
MimePartBufferDestroy(enc->part_buffer);
|
||||
enc->part_buffer = 0;
|
||||
}
|
||||
|
||||
if (finalizing_p && enc->crypto_closure)
|
||||
{
|
||||
/* Don't free these until this object is really going away -- keep them
|
||||
around for the lifetime of the MIME object, so that we can get at the
|
||||
security info of sub-parts of the currently-displayed message. */
|
||||
((MimeEncryptedClass *) obj->clazz)->crypto_free (enc->crypto_closure);
|
||||
enc->crypto_closure = 0;
|
||||
}
|
||||
|
||||
/* (Duplicated from MimeLeaf, see comments in mimecryp.h.)
|
||||
Free the decoder data, if it's still around. */
|
||||
if (enc->decoder_data)
|
||||
{
|
||||
MimeDecoderDestroy(enc->decoder_data, PR_TRUE);
|
||||
enc->decoder_data = 0;
|
||||
}
|
||||
|
||||
if (enc->hdrs)
|
||||
{
|
||||
MimeHeaders_free(enc->hdrs);
|
||||
enc->hdrs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
MimeEncrypted_finalize (MimeObject *obj)
|
||||
{
|
||||
MimeEncrypted_cleanup (obj, PR_TRUE);
|
||||
((MimeObjectClass*)&MIME_SUPERCLASS)->finalize (obj);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
MimeHandleDecryptedOutput (const char *buf, PRInt32 buf_size,
|
||||
void *output_closure)
|
||||
{
|
||||
/* This method is invoked by the underlying decryption module.
|
||||
The module is assumed to return a MIME object, and its associated
|
||||
headers. For example, if a text/plain document was encrypted,
|
||||
the encryption module would return the following data:
|
||||
|
||||
Content-Type: text/plain
|
||||
|
||||
Decrypted text goes here.
|
||||
|
||||
This function will then extract a header block (up to the first
|
||||
blank line, as usual) and will then handle the included data as
|
||||
appropriate.
|
||||
*/
|
||||
MimeObject *obj = (MimeObject *) output_closure;
|
||||
|
||||
/* Is it truly safe to use ibuffer here? I think so... */
|
||||
return mime_LineBuffer (buf, buf_size,
|
||||
&obj->ibuffer, &obj->ibuffer_size, &obj->ibuffer_fp,
|
||||
PR_TRUE,
|
||||
((int (*PR_CALLBACK) (char *, PRInt32, void *))
|
||||
/* This cast is to turn void into MimeObject */
|
||||
MimeHandleDecryptedOutputLine),
|
||||
obj);
|
||||
}
|
||||
|
||||
static int
|
||||
MimeHandleDecryptedOutputLine (char *line, PRInt32 length, MimeObject *obj)
|
||||
{
|
||||
/* Largely the same as MimeMessage_parse_line (the other MIME container
|
||||
type which contains exactly one child.)
|
||||
*/
|
||||
MimeEncrypted *enc = (MimeEncrypted *) obj;
|
||||
int status = 0;
|
||||
|
||||
PR_ASSERT(line && *line);
|
||||
if (!line || !*line) return -1;
|
||||
|
||||
/* If we're supposed to write this object, but aren't supposed to convert
|
||||
it to HTML, simply pass it through unaltered. */
|
||||
if (obj->output_p &&
|
||||
obj->options &&
|
||||
!obj->options->write_html_p &&
|
||||
obj->options->output_fn)
|
||||
return MimeObject_write(obj, line, length, PR_TRUE);
|
||||
|
||||
/* If we already have a child object in the buffer, then we're done parsing
|
||||
headers, and all subsequent lines get passed to the inferior object
|
||||
without further processing by us. (Our parent will stop feeding us
|
||||
lines when this MimeMessage part is out of data.)
|
||||
*/
|
||||
if (enc->part_buffer)
|
||||
return MimePartBufferWrite (enc->part_buffer, line, length);
|
||||
|
||||
/* Otherwise we don't yet have a child object in the buffer, which means
|
||||
we're not done parsing our headers yet.
|
||||
*/
|
||||
if (!enc->hdrs)
|
||||
{
|
||||
enc->hdrs = MimeHeaders_new();
|
||||
if (!enc->hdrs) return MIME_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
status = MimeHeaders_parse_line(line, length, enc->hdrs);
|
||||
if (status < 0) return status;
|
||||
|
||||
/* If this line is blank, we're now done parsing headers, and should
|
||||
examine our content-type to create our "body" part.
|
||||
*/
|
||||
if (*line == nsCRT::CR || *line == nsCRT::LF)
|
||||
{
|
||||
status = MimeEncrypted_close_headers(obj);
|
||||
if (status < 0) return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
MimeEncrypted_close_headers (MimeObject *obj)
|
||||
{
|
||||
MimeEncrypted *enc = (MimeEncrypted *) obj;
|
||||
|
||||
PR_ASSERT(!enc->part_buffer);
|
||||
if (enc->part_buffer) return -1;
|
||||
enc->part_buffer = MimePartBufferCreate();
|
||||
if (!enc->part_buffer)
|
||||
return MIME_OUT_OF_MEMORY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
MimeEncrypted_add_child (MimeObject *parent, MimeObject *child)
|
||||
{
|
||||
MimeContainer *cont = (MimeContainer *) parent;
|
||||
PR_ASSERT(parent && child);
|
||||
if (!parent || !child) return -1;
|
||||
|
||||
/* Encryption containers can only have one child. */
|
||||
PR_ASSERT(cont->nchildren == 0);
|
||||
if (cont->nchildren != 0) return -1;
|
||||
|
||||
return ((MimeContainerClass*)&MIME_SUPERCLASS)->add_child (parent, child);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
MimeEncrypted_emit_buffered_child(MimeObject *obj)
|
||||
{
|
||||
MimeEncrypted *enc = (MimeEncrypted *) obj;
|
||||
int status = 0;
|
||||
char *ct = 0;
|
||||
MimeObject *body;
|
||||
|
||||
PR_ASSERT(enc->crypto_closure);
|
||||
|
||||
/* Emit some HTML saying whether the signature was cool.
|
||||
But don't emit anything if in FO_QUOTE_MESSAGE mode.
|
||||
|
||||
Also, don't emit anything if the enclosed object is itself a signed
|
||||
object -- in the case of an encrypted object which contains a signed
|
||||
object, we only emit the HTML once (since the normal way of encrypting
|
||||
and signing is to nest the signature inside the crypto envelope.)
|
||||
*/
|
||||
if (enc->crypto_closure &&
|
||||
obj->options &&
|
||||
obj->options->headers != MimeHeadersCitation &&
|
||||
obj->options->write_html_p &&
|
||||
obj->options->output_fn)
|
||||
// && !mime_crypto_object_p(enc->hdrs, PR_TRUE)) // XXX fix later XXX //
|
||||
{
|
||||
char *html;
|
||||
#if 0 // XXX Fix this later XXX //
|
||||
char *html = (((MimeEncryptedClass *) obj->clazz)->crypto_generate_html
|
||||
(enc->crypto_closure));
|
||||
if (!html) return -1; /* MK_OUT_OF_MEMORY? */
|
||||
|
||||
status = MimeObject_write(obj, html, nsCRT::strlen(html), PR_FALSE);
|
||||
PR_FREEIF(html);
|
||||
if (status < 0) return status;
|
||||
#endif
|
||||
|
||||
/* Now that we have written out the crypto stamp, the outermost header
|
||||
block is well and truly closed. If this is in fact the outermost
|
||||
message, then run the post_header_html_fn now.
|
||||
*/
|
||||
if (obj->options &&
|
||||
obj->options->state &&
|
||||
obj->options->generate_post_header_html_fn &&
|
||||
!obj->options->state->post_header_html_run_p)
|
||||
{
|
||||
MimeHeaders *outer_headers;
|
||||
MimeObject *p;
|
||||
for (p = obj; p->parent; p = p->parent)
|
||||
outer_headers = p->headers;
|
||||
PR_ASSERT(obj->options->state->first_data_written_p);
|
||||
html = obj->options->generate_post_header_html_fn(NULL,
|
||||
obj->options->html_closure,
|
||||
outer_headers);
|
||||
obj->options->state->post_header_html_run_p = PR_TRUE;
|
||||
if (html)
|
||||
{
|
||||
status = MimeObject_write(obj, html, nsCRT::strlen(html), PR_FALSE);
|
||||
PR_FREEIF(html);
|
||||
if (status < 0) return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (enc->crypto_closure &&
|
||||
obj->options &&
|
||||
obj->options->decrypt_p)
|
||||
{
|
||||
/* Do this just to cause `mime_set_crypto_stamp' to be called, and to
|
||||
cause the various `decode_error' and `verify_error' slots to be set:
|
||||
we don't actually use the returned HTML, because we're not emitting
|
||||
HTML. It's maybe not such a good thing that the determination of
|
||||
whether it was encrypted or not is tied up with generating HTML,
|
||||
but oh well. */
|
||||
char *html = (((MimeEncryptedClass *) obj->clazz)->crypto_generate_html
|
||||
(enc->crypto_closure));
|
||||
PR_FREEIF(html);
|
||||
}
|
||||
|
||||
if (enc->hdrs)
|
||||
ct = MimeHeaders_get (enc->hdrs, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE);
|
||||
body = mime_create((ct ? ct : TEXT_PLAIN), enc->hdrs, obj->options);
|
||||
|
||||
#ifdef MIME_DRAFTS
|
||||
if (obj->options->decompose_file_p) {
|
||||
if (mime_typep (body, (MimeObjectClass*) &mimeMultipartClass) )
|
||||
obj->options->is_multipart_msg = PR_TRUE;
|
||||
else if (obj->options->decompose_file_init_fn)
|
||||
obj->options->decompose_file_init_fn(obj->options->stream_closure,
|
||||
enc->hdrs);
|
||||
}
|
||||
#endif /* MIME_DRAFTS */
|
||||
|
||||
PR_FREEIF(ct);
|
||||
|
||||
if (!body) return MIME_OUT_OF_MEMORY;
|
||||
status = ((MimeContainerClass *) obj->clazz)->add_child (obj, body);
|
||||
if (status < 0)
|
||||
{
|
||||
mime_free(body);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Now that we've added this new object to our list of children,
|
||||
start its parser going. */
|
||||
status = body->clazz->parse_begin(body);
|
||||
if (status < 0) return status;
|
||||
|
||||
/* If this object (or the parent) is being output, then by definition
|
||||
the child is as well. (This is only necessary because this is such
|
||||
a funny sort of container...)
|
||||
*/
|
||||
if (!body->output_p &&
|
||||
(obj->output_p ||
|
||||
(obj->parent && obj->parent->output_p)))
|
||||
body->output_p = PR_TRUE;
|
||||
|
||||
/* If the body is being written raw (not as HTML) then make sure to
|
||||
write its headers as well. */
|
||||
if (body->output_p && obj->output_p && !obj->options->write_html_p)
|
||||
{
|
||||
status = MimeObject_write(body, "", 0, PR_FALSE); /* initialize */
|
||||
if (status < 0) return status;
|
||||
status = MimeHeaders_write_raw_headers(body->headers, obj->options,
|
||||
PR_FALSE);
|
||||
if (status < 0) return status;
|
||||
}
|
||||
|
||||
if (enc->part_buffer) /* part_buffer is 0 for 0-length encrypted data. */
|
||||
|
||||
#ifdef MIME_DRAFTS
|
||||
if (obj->options->decompose_file_p && !obj->options->is_multipart_msg)
|
||||
status = MimePartBufferRead(enc->part_buffer,
|
||||
/* The (nsresult (*) ...) cast is to turn the `void'
|
||||
argument into `MimeObject'. */
|
||||
((nsresult (*) (char *, PRInt32, void *))
|
||||
obj->options->decompose_file_output_fn),
|
||||
obj->options->stream_closure);
|
||||
else
|
||||
#endif /* MIME_DRAFTS */
|
||||
|
||||
status = MimePartBufferRead(enc->part_buffer,
|
||||
/* The (nsresult (*) ...) cast is to turn the `void'
|
||||
argument into `MimeObject'. */
|
||||
((nsresult (*) (char *, PRInt32, void *))
|
||||
body->clazz->parse_buffer),
|
||||
body);
|
||||
if (status < 0) return status;
|
||||
|
||||
/* The child has been fully processed. Close it off.
|
||||
*/
|
||||
status = body->clazz->parse_eof(body, PR_FALSE);
|
||||
if (status < 0) return status;
|
||||
|
||||
status = body->clazz->parse_end(body, PR_FALSE);
|
||||
if (status < 0) return status;
|
||||
|
||||
#ifdef MIME_DRAFTS
|
||||
if (obj->options->decompose_file_p && !obj->options->is_multipart_msg)
|
||||
obj->options->decompose_file_close_fn(obj->options->stream_closure);
|
||||
#endif /* MIME_DRAFTS */
|
||||
|
||||
/* Put out a separator after every encrypted object. */
|
||||
status = MimeObject_write_separator(obj);
|
||||
if (status < 0) return status;
|
||||
|
||||
MimeEncrypted_cleanup (obj, PR_FALSE);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape 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/NPL/
|
||||
*
|
||||
* 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 mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Drinan <ddrinan@netscape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MIMECRYP_H_
|
||||
#define _MIMECRYP_H_
|
||||
|
||||
#include "mimecont.h"
|
||||
// #include "mimeenc.h"
|
||||
#include "modmimee.h"
|
||||
#include "mimepbuf.h"
|
||||
|
||||
/* The MimeEncrypted class implements a type of MIME object where the object
|
||||
is passed to some other routine, which then returns a new MIME object.
|
||||
This is the basis of a decryption module.
|
||||
|
||||
Oddly, this class behaves both as a container and as a leaf: it acts as a
|
||||
container in that it parses out data in order to eventually present a
|
||||
contained object; however, it acts as a leaf in that this container may
|
||||
itself have a Content-Transfer-Encoding applied to its body. This violates
|
||||
the cardinal rule of MIME containers, which is that encodings don't nest,
|
||||
and therefore containers can't have encodings. But, the fact that the
|
||||
S/MIME spec doesn't follow the groundwork laid down by previous MIME specs
|
||||
isn't something we can do anything about at this point...
|
||||
|
||||
Therefore, this class duplicates some of the work done by the MimeLeaf
|
||||
class, to meet its dual goals of container-hood and leaf-hood. (We could
|
||||
alternately have made this class be a subclass of leaf, and had it duplicate
|
||||
the effort of MimeContainer, but that seemed like the harder approach.)
|
||||
|
||||
The MimeEncrypted class provides the following methods:
|
||||
|
||||
void *crypto_init(MimeObject *obj,
|
||||
int (*output_fn) (const char *data, int32 data_size,
|
||||
void *output_closure),
|
||||
void *output_closure)
|
||||
|
||||
This is called with the MimeObject representing the encrypted data.
|
||||
The obj->headers should be used to initialize the decryption engine.
|
||||
NULL indicates failure; otherwise, an opaque closure object should
|
||||
be returned.
|
||||
|
||||
output_fn is what the decryption module should use to write a new MIME
|
||||
object (the decrypted data.) output_closure should be passed along to
|
||||
every call to the output routine.
|
||||
|
||||
The data sent to output_fn should begin with valid MIME headers indicating
|
||||
the type of the data. For example, if decryption resulted in a text
|
||||
document, the data fed through to the output_fn might minimally look like
|
||||
|
||||
Content-Type: text/plain
|
||||
|
||||
This is the decrypted data.
|
||||
It is only two lines long.
|
||||
|
||||
Of course, the data may be of any MIME type, including multipart/mixed.
|
||||
Any returned MIME object will be recursively processed and presented
|
||||
appropriately. (This also imples that encrypted objects may nest, and
|
||||
thus that the underlying decryption module must be reentrant.)
|
||||
|
||||
int crypto_write (const char *data, int32 data_size, void *crypto_closure)
|
||||
|
||||
This is called with the raw encrypted data. This data might not come
|
||||
in line-based chunks: if there was a Content-Transfer-Encoding applied
|
||||
to the data (base64 or quoted-printable) then it will have been decoded
|
||||
first (handing binary data to the filter_fn.) `crypto_closure' is the
|
||||
object that `crypto_init' returned. This may return negative on error.
|
||||
|
||||
int crypto_eof (void *crypto_closure, PRBool abort_p)
|
||||
|
||||
This is called when no more data remains. It may call `output_fn' again
|
||||
to flush out any buffered data. If `abort_p' is true, then it may choose
|
||||
to discard any data rather than processing it, as we're terminating
|
||||
abnormally.
|
||||
|
||||
char * crypto_generate_html (void *crypto_closure)
|
||||
|
||||
This is called after `crypto_eof' but before `crypto_free'. The crypto
|
||||
module should return a newly-allocated string of HTML code which
|
||||
explains the status of the decryption to the user (whether the signature
|
||||
checked out, etc.)
|
||||
|
||||
void crypto_free (void *crypto_closure)
|
||||
|
||||
This will be called when we're all done, after `crypto_eof' and
|
||||
`crypto_emit_html'. It is intended to free any data represented
|
||||
by the crypto_closure. output_fn may not be called.
|
||||
|
||||
|
||||
int (*parse_decoded_buffer) (char *buf, int32 size, MimeObject *obj)
|
||||
|
||||
This method, of the same name as one in MimeLeaf, is a part of the
|
||||
afforementioned leaf/container hybridization. This method is invoked
|
||||
with the content-transfer-decoded body of this part (without line
|
||||
buffering.) The default behavior of this method is to simply invoke
|
||||
`crypto_write' on the data with which it is called. It's unlikely that
|
||||
a subclass will need to specialize this.
|
||||
*/
|
||||
|
||||
typedef struct MimeEncryptedClass MimeEncryptedClass;
|
||||
typedef struct MimeEncrypted MimeEncrypted;
|
||||
|
||||
struct MimeEncryptedClass {
|
||||
MimeContainerClass container;
|
||||
|
||||
/* Duplicated from MimeLeaf, see comments above.
|
||||
This is the callback that is handed to the decoder. */
|
||||
int (*parse_decoded_buffer) (char *buf, PRInt32 size, MimeObject *obj);
|
||||
|
||||
|
||||
/* Callbacks used by decryption module. */
|
||||
void * (*crypto_init) (MimeObject *obj,
|
||||
int (*output_fn) (const char *data, PRInt32 data_size,
|
||||
void *output_closure),
|
||||
void *output_closure);
|
||||
int (*crypto_write) (const char *data, PRInt32 data_size,
|
||||
void *crypto_closure);
|
||||
int (*crypto_eof) (void *crypto_closure, PRBool abort_p);
|
||||
char * (*crypto_generate_html) (void *crypto_closure);
|
||||
void (*crypto_free) (void *crypto_closure);
|
||||
};
|
||||
|
||||
extern MimeEncryptedClass mimeEncryptedClass;
|
||||
|
||||
struct MimeEncrypted {
|
||||
MimeContainer container; /* superclass variables */
|
||||
void *crypto_closure; /* Opaque data used by decryption module. */
|
||||
MimeDecoderData *decoder_data; /* Opaque data for the Transfer-Encoding
|
||||
decoder. */
|
||||
MimeHeaders *hdrs; /* Headers of the enclosed object (including
|
||||
the type of the *decrypted* data.) */
|
||||
MimePartBufferData *part_buffer; /* The data of the decrypted enclosed
|
||||
object (see mimepbuf.h) */
|
||||
};
|
||||
|
||||
#endif /* _MIMECRYP_H_ */
|
|
@ -0,0 +1,498 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape 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/NPL/
|
||||
*
|
||||
* 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 mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Drinan <ddrinan@netscape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "mimemcms.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nspr.h"
|
||||
#include "nsMimeStringResources.h"
|
||||
#include "nsIWindowWatcher.h"
|
||||
#include "nsIPrompt.h"
|
||||
|
||||
#define MIME_SUPERCLASS mimeMultipartSignedClass
|
||||
MimeDefClass(MimeMultipartSignedCMS, MimeMultipartSignedCMSClass,
|
||||
mimeMultipartSignedCMSClass, &MIME_SUPERCLASS);
|
||||
|
||||
static int MimeMultipartSignedCMS_initialize (MimeObject *);
|
||||
|
||||
static void *MimeMultCMS_init (MimeObject *);
|
||||
static int MimeMultCMS_data_hash (char *, PRInt32, void *);
|
||||
static int MimeMultCMS_sig_hash (char *, PRInt32, void *);
|
||||
static int MimeMultCMS_data_eof (void *, PRBool);
|
||||
static int MimeMultCMS_sig_eof (void *, PRBool);
|
||||
static int MimeMultCMS_sig_init (void *, MimeObject *, MimeHeaders *);
|
||||
static char * MimeMultCMS_generate (void *);
|
||||
static void MimeMultCMS_free (void *);
|
||||
static void MimeMultCMS_get_content_info (MimeObject *,
|
||||
nsICMSMessage **,
|
||||
char **, PRInt32 *, PRInt32 *, PRBool *);
|
||||
|
||||
extern int SEC_ERROR_CERT_ADDR_MISMATCH;
|
||||
|
||||
static int
|
||||
MimeMultipartSignedCMSClassInitialize(MimeMultipartSignedCMSClass *clazz)
|
||||
{
|
||||
MimeObjectClass *oclass = (MimeObjectClass *) clazz;
|
||||
MimeMultipartSignedClass *sclass = (MimeMultipartSignedClass *) clazz;
|
||||
|
||||
oclass->initialize = MimeMultipartSignedCMS_initialize;
|
||||
|
||||
sclass->crypto_init = MimeMultCMS_init;
|
||||
sclass->crypto_data_hash = MimeMultCMS_data_hash;
|
||||
sclass->crypto_data_eof = MimeMultCMS_data_eof;
|
||||
sclass->crypto_signature_init = MimeMultCMS_sig_init;
|
||||
sclass->crypto_signature_hash = MimeMultCMS_sig_hash;
|
||||
sclass->crypto_signature_eof = MimeMultCMS_sig_eof;
|
||||
sclass->crypto_generate_html = MimeMultCMS_generate;
|
||||
sclass->crypto_free = MimeMultCMS_free;
|
||||
|
||||
clazz->get_content_info = MimeMultCMS_get_content_info;
|
||||
|
||||
PR_ASSERT(!oclass->class_initialized);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
MimeMultipartSignedCMS_initialize (MimeObject *object)
|
||||
{
|
||||
return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object);
|
||||
}
|
||||
|
||||
|
||||
typedef struct MimeMultCMSdata {
|
||||
PRInt16 hash_type;
|
||||
nsCOMPtr<nsIHash> data_hash_context;
|
||||
nsCOMPtr<nsICMSDecoder> sig_decoder_context;
|
||||
nsCOMPtr<nsICMSMessage> content_info;
|
||||
char *sender_addr;
|
||||
PRInt32 decode_error;
|
||||
PRInt32 verify_error;
|
||||
unsigned char* item_data;
|
||||
PRUint32 item_len;
|
||||
MimeObject *self;
|
||||
PRBool parent_is_encrypted_p;
|
||||
PRBool parent_holds_stamp_p;
|
||||
} MimeMultCMSdata;
|
||||
|
||||
|
||||
static void
|
||||
MimeMultCMS_get_content_info(MimeObject *obj,
|
||||
nsICMSMessage **content_info_ret,
|
||||
char **sender_email_addr_return,
|
||||
PRInt32 *decode_error_ret,
|
||||
PRInt32 *verify_error_ret,
|
||||
PRBool *ci_is_encrypted)
|
||||
{
|
||||
MimeMultipartSigned *msig = (MimeMultipartSigned *) obj;
|
||||
if (msig && msig->crypto_closure)
|
||||
{
|
||||
MimeMultCMSdata *data = (MimeMultCMSdata *) msig->crypto_closure;
|
||||
|
||||
*decode_error_ret = data->decode_error;
|
||||
*verify_error_ret = data->verify_error;
|
||||
*content_info_ret = data->content_info;
|
||||
*ci_is_encrypted = PR_FALSE;
|
||||
|
||||
if (sender_email_addr_return)
|
||||
*sender_email_addr_return = (data->sender_addr
|
||||
? nsCRT::strdup(data->sender_addr)
|
||||
: 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* #### MimeEncryptedCMS and MimeMultipartSignedCMS have a sleazy,
|
||||
incestuous, dysfunctional relationship. */
|
||||
extern PRBool MimeEncryptedCMS_encrypted_p (MimeObject *obj);
|
||||
extern PRBool MimeCMSHeadersAndCertsMatch(MimeObject *obj,
|
||||
nsICMSMessage *,
|
||||
char **);
|
||||
extern char *MimeCMS_MakeSAURL(MimeObject *obj);
|
||||
extern char *IMAP_CreateReloadAllPartsUrl(const char *url);
|
||||
|
||||
static void *
|
||||
MimeMultCMS_init (MimeObject *obj)
|
||||
{
|
||||
MimeHeaders *hdrs = obj->headers;
|
||||
MimeMultCMSdata *data = 0;
|
||||
char *ct, *micalg;
|
||||
PRInt16 hash_type;
|
||||
nsresult rv;
|
||||
|
||||
ct = MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
|
||||
if (!ct) return 0; /* #### bogus message? out of memory? */
|
||||
micalg = MimeHeaders_get_parameter (ct, PARAM_MICALG, NULL, NULL);
|
||||
PR_Free(ct);
|
||||
ct = 0;
|
||||
if (!micalg) return 0; /* #### bogus message? out of memory? */
|
||||
|
||||
if (!nsCRT::strcasecmp(micalg, PARAM_MICALG_MD5))
|
||||
hash_type = nsIHash::HASH_AlgMD5;
|
||||
else if (!nsCRT::strcasecmp(micalg, PARAM_MICALG_SHA1) ||
|
||||
!nsCRT::strcasecmp(micalg, PARAM_MICALG_SHA1_2) ||
|
||||
!nsCRT::strcasecmp(micalg, PARAM_MICALG_SHA1_3) ||
|
||||
!nsCRT::strcasecmp(micalg, PARAM_MICALG_SHA1_4) ||
|
||||
!nsCRT::strcasecmp(micalg, PARAM_MICALG_SHA1_5))
|
||||
hash_type = nsIHash::HASH_AlgSHA1;
|
||||
else if (!nsCRT::strcasecmp(micalg, PARAM_MICALG_MD2))
|
||||
hash_type = nsIHash::HASH_AlgMD2;
|
||||
else
|
||||
hash_type = nsIHash::HASH_AlgNULL;
|
||||
|
||||
PR_Free(micalg);
|
||||
micalg = 0;
|
||||
|
||||
if (hash_type == nsIHash::HASH_AlgNULL) return 0; /* #### bogus message? */
|
||||
|
||||
data = (MimeMultCMSdata *) PR_MALLOC(sizeof(*data));
|
||||
if (!data) return 0;
|
||||
|
||||
nsCRT::memset(data, 0, sizeof(*data));
|
||||
|
||||
data->self = obj;
|
||||
data->hash_type = hash_type;
|
||||
|
||||
PR_ASSERT(!data->data_hash_context);
|
||||
PR_ASSERT(!data->sig_decoder_context);
|
||||
|
||||
data->data_hash_context = do_CreateInstance(NS_HASH_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) return 0;
|
||||
|
||||
rv = data->data_hash_context->Create(data->hash_type);
|
||||
if (NS_FAILED(rv)) return 0;
|
||||
|
||||
PR_SetError(0,0);
|
||||
data->data_hash_context->Begin();
|
||||
if (!data->decode_error)
|
||||
{
|
||||
data->decode_error = PR_GetError();
|
||||
if (data->decode_error)
|
||||
{
|
||||
PR_Free(data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
data->parent_holds_stamp_p =
|
||||
(obj->parent && mime_crypto_stamped_p(obj->parent));
|
||||
|
||||
data->parent_is_encrypted_p =
|
||||
(obj->parent && MimeEncryptedCMS_encrypted_p (obj->parent));
|
||||
|
||||
/* If the parent of this object is a crypto-blob, then it's the grandparent
|
||||
who would have written out the headers and prepared for a stamp...
|
||||
(This s##t s$%#s.)
|
||||
*/
|
||||
if (data->parent_is_encrypted_p &&
|
||||
!data->parent_holds_stamp_p &&
|
||||
obj->parent && obj->parent->parent)
|
||||
data->parent_holds_stamp_p =
|
||||
mime_crypto_stamped_p (obj->parent->parent);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int
|
||||
MimeMultCMS_data_hash (char *buf, PRInt32 size, void *crypto_closure)
|
||||
{
|
||||
MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure;
|
||||
PR_ASSERT(data && data->data_hash_context);
|
||||
if (!data || !data->data_hash_context) return -1;
|
||||
|
||||
PR_ASSERT(!data->sig_decoder_context);
|
||||
|
||||
PR_SetError(0, 0);
|
||||
data->data_hash_context->Update((unsigned char *) buf, size);
|
||||
if (!data->verify_error)
|
||||
data->verify_error = PR_GetError();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
MimeMultCMS_data_eof (void *crypto_closure, PRBool abort_p)
|
||||
{
|
||||
MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure;
|
||||
PR_ASSERT(data && data->data_hash_context);
|
||||
if (!data || !data->data_hash_context) return -1;
|
||||
|
||||
PR_ASSERT(!data->sig_decoder_context);
|
||||
|
||||
data->data_hash_context->ResultLen(data->hash_type, &data->item_len);
|
||||
data->item_data = (unsigned char *) PR_MALLOC(data->item_len);
|
||||
if (!data->item_data) return MIME_OUT_OF_MEMORY;
|
||||
|
||||
PR_SetError(0, 0);
|
||||
data->data_hash_context->End(data->item_data, &data->item_len, data->item_len);
|
||||
if (!data->verify_error)
|
||||
data->verify_error = PR_GetError();
|
||||
|
||||
// Release our reference to nsIHash //
|
||||
data->data_hash_context = 0;
|
||||
|
||||
/* At this point, data->item.data contains a digest for the first part.
|
||||
When we process the signature, the security library will compare this
|
||||
digest to what's in the signature object. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
MimeMultCMS_sig_init (void *crypto_closure,
|
||||
MimeObject *multipart_object,
|
||||
MimeHeaders *signature_hdrs)
|
||||
{
|
||||
MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure;
|
||||
MimeDisplayOptions *opts = multipart_object->options;
|
||||
char *ct;
|
||||
int status = 0;
|
||||
nsresult rv;
|
||||
|
||||
PR_ASSERT(!data->data_hash_context);
|
||||
PR_ASSERT(!data->sig_decoder_context);
|
||||
|
||||
PR_ASSERT(signature_hdrs);
|
||||
if (!signature_hdrs) return -1;
|
||||
|
||||
ct = MimeHeaders_get (signature_hdrs, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE);
|
||||
|
||||
/* Verify that the signature object is of the right type. */
|
||||
if (!ct || (nsCRT::strcasecmp(ct, APPLICATION_XPKCS7_SIGNATURE))) {
|
||||
status = -1; /* #### error msg about bogus message */
|
||||
}
|
||||
PR_FREEIF(ct);
|
||||
if (status < 0) return status;
|
||||
|
||||
data->sig_decoder_context = do_CreateInstance(NS_CMSDECODER_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) return 0;
|
||||
|
||||
rv = data->sig_decoder_context->Start(nsnull, nsnull);
|
||||
if (NS_FAILED(rv)) {
|
||||
status = PR_GetError();
|
||||
PR_ASSERT(status < 0);
|
||||
if (status >= 0) status = -1;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
MimeMultCMS_sig_hash (char *buf, PRInt32 size, void *crypto_closure)
|
||||
{
|
||||
MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure;
|
||||
nsresult rv;
|
||||
|
||||
PR_ASSERT(data && data->sig_decoder_context);
|
||||
if (!data || !data->sig_decoder_context) return -1;
|
||||
|
||||
PR_ASSERT(!data->data_hash_context);
|
||||
|
||||
rv = data->sig_decoder_context->Update(buf, size);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (!data->verify_error)
|
||||
data->verify_error = PR_GetError();
|
||||
PR_ASSERT(data->verify_error < 0);
|
||||
if (data->verify_error >= 0)
|
||||
data->verify_error = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
MimeMultCMS_sig_eof (void *crypto_closure, PRBool abort_p)
|
||||
{
|
||||
MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure;
|
||||
|
||||
if (!data) return -1;
|
||||
|
||||
PR_ASSERT(!data->data_hash_context);
|
||||
|
||||
/* Hand an EOF to the crypto library.
|
||||
|
||||
We save away the value returned and will use it later to emit a
|
||||
blurb about whether the signature validation was cool.
|
||||
*/
|
||||
|
||||
PR_ASSERT(!data->content_info);
|
||||
|
||||
if (data->sig_decoder_context)
|
||||
{
|
||||
data->sig_decoder_context->Finish(getter_AddRefs(data->content_info));
|
||||
|
||||
// Release our reference to nsICMSDecoder //
|
||||
data->sig_decoder_context = 0;
|
||||
|
||||
if (!data->content_info && !data->verify_error)
|
||||
data->verify_error = PR_GetError();
|
||||
|
||||
PR_ASSERT(data->content_info ||
|
||||
data->verify_error || data->decode_error);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
MimeMultCMS_free (void *crypto_closure)
|
||||
{
|
||||
MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure;
|
||||
PR_ASSERT(data);
|
||||
if (!data) return;
|
||||
|
||||
PR_FREEIF(data->sender_addr);
|
||||
|
||||
if (data->data_hash_context)
|
||||
{
|
||||
// Release our reference to nsIHash //
|
||||
data->data_hash_context = 0;
|
||||
}
|
||||
|
||||
// Do a graceful shutdown of the nsICMSDecoder and release the nsICMSMessage //
|
||||
if (data->sig_decoder_context)
|
||||
{
|
||||
nsCOMPtr<nsICMSMessage> cinfo;
|
||||
data->sig_decoder_context->Finish(getter_AddRefs(cinfo));
|
||||
}
|
||||
|
||||
if (data->content_info)
|
||||
{
|
||||
// Release our reference to nsICMSMessage //
|
||||
data->content_info = 0;
|
||||
}
|
||||
|
||||
PR_FREEIF(data->item_data);
|
||||
PR_FREEIF(data);
|
||||
}
|
||||
|
||||
static char *
|
||||
MimeMultCMS_generate (void *crypto_closure)
|
||||
{
|
||||
MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure;
|
||||
PRBool signed_p = PR_TRUE;
|
||||
PRBool good_p = PR_TRUE;
|
||||
PRBool encrypted_p;
|
||||
PRBool unverified_p = PR_FALSE;
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService("@mozilla.org/embedcomp/window-watcher;1"));
|
||||
nsCOMPtr<nsIPrompt> prompter;
|
||||
wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
|
||||
|
||||
PR_ASSERT(data);
|
||||
if (!data) return 0;
|
||||
encrypted_p = data->parent_is_encrypted_p;
|
||||
|
||||
if (data->content_info)
|
||||
{
|
||||
rv = data->content_info->VerifyDetachedSignature(data->item_data, data->item_len);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (!data->verify_error)
|
||||
data->verify_error = PR_GetError();
|
||||
PR_ASSERT(data->verify_error < 0);
|
||||
if (data->verify_error >= 0)
|
||||
data->verify_error = -1;
|
||||
} else {
|
||||
good_p = MimeCMSHeadersAndCertsMatch(data->self,
|
||||
data->content_info,
|
||||
&data->sender_addr);
|
||||
if (!good_p && !data->verify_error) {
|
||||
data->verify_error = -1;
|
||||
// XXX Fix this data->verify_error = SEC_ERROR_CERT_ADDR_MISMATCH; XXX //
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 // XXX Fix this. What do we do here? //
|
||||
if (SEC_CMSContainsCertsOrCrls(data->content_info))
|
||||
{
|
||||
/* #### call libsec telling it to import the certs */
|
||||
|
||||
#endif
|
||||
|
||||
/* Don't free these yet -- keep them around for the lifetime of the
|
||||
MIME object, so that we can get at the security info of sub-parts
|
||||
of the currently-displayed message. */
|
||||
#if 0
|
||||
SEC_CMSDestroyContentInfo(data->content_info);
|
||||
data->content_info = 0;
|
||||
#endif /* 0 */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No content_info at all -- since we're inside a multipart/signed,
|
||||
that means that we've either gotten a message that was truncated
|
||||
before the signature part, or we ran out of memory, or something
|
||||
awful has happened. Anyway, it sure ain't good_p.
|
||||
*/
|
||||
good_p = PR_FALSE;
|
||||
}
|
||||
|
||||
// XXX Temporary hack until we write out to the chrome XXX //
|
||||
if (good_p) {
|
||||
nsString msg(NS_LITERAL_STRING("This is a signed message with a valid signature").get());
|
||||
prompter->Alert(0, msg.get());
|
||||
} else {
|
||||
nsString msg(NS_LITERAL_STRING("This is a signed message with an invalid signature").get());
|
||||
prompter->Alert(0, msg.get());
|
||||
}
|
||||
|
||||
unverified_p = data->self->options->missing_parts;
|
||||
|
||||
PR_ASSERT(data->self);
|
||||
if (data->self && data->self->parent)
|
||||
mime_set_crypto_stamp(data->self->parent, signed_p, encrypted_p);
|
||||
|
||||
|
||||
{
|
||||
char *stamp_url = 0, *result;
|
||||
if (data->self)
|
||||
{
|
||||
if (unverified_p && data->self->options) {
|
||||
// XXX Fix this stamp_url = IMAP_CreateReloadAllPartsUrl(data->self->options->url); XXX //
|
||||
} else {
|
||||
stamp_url = MimeCMS_MakeSAURL(data->self);
|
||||
}
|
||||
}
|
||||
|
||||
result =
|
||||
MimeHeaders_make_crypto_stamp (encrypted_p, signed_p, good_p,
|
||||
unverified_p,
|
||||
data->parent_holds_stamp_p,
|
||||
stamp_url);
|
||||
PR_FREEIF(stamp_url);
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape 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/NPL/
|
||||
*
|
||||
* 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 mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Drinan <ddrinan@netscape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MIMEMPKC_H_
|
||||
#define _MIMEMPKC_H_
|
||||
|
||||
#include "nsICMS.h"
|
||||
#include "mimemsig.h"
|
||||
|
||||
/* The MimeMultipartSignedCMS class implements a multipart/signed MIME
|
||||
container with protocol=application/x-CMS-signature, which passes the
|
||||
signed object through CMS code to verify the signature. See mimemsig.h
|
||||
for details of the general mechanism on which this is built.
|
||||
*/
|
||||
|
||||
typedef struct MimeMultipartSignedCMSClass MimeMultipartSignedCMSClass;
|
||||
typedef struct MimeMultipartSignedCMS MimeMultipartSignedCMS;
|
||||
|
||||
struct MimeMultipartSignedCMSClass {
|
||||
MimeMultipartSignedClass msigned;
|
||||
|
||||
/* Callback used to access the SEC_CMSContentInfo of this object. */
|
||||
void (*get_content_info) (MimeObject *self,
|
||||
nsICMSMessage **content_info_ret,
|
||||
char **sender_email_addr_return,
|
||||
PRInt32 *decode_error_ret,
|
||||
PRInt32 *verify_error_ret,
|
||||
PRBool * ci_is_encrypted);
|
||||
};
|
||||
|
||||
extern MimeMultipartSignedCMSClass mimeMultipartSignedCMSClass;
|
||||
|
||||
struct MimeMultipartSignedCMS {
|
||||
MimeMultipartSigned msigned;
|
||||
};
|
||||
|
||||
#endif /* _MIMEMPKC_H_ */
|
Загрузка…
Ссылка в новой задаче