new files for 106507

NOT PART OF THE BUILD
This commit is contained in:
mscott%netscape.com 2001-11-02 01:59:55 +00:00
Родитель 1b6cfe2225
Коммит 43b2a7ad1e
6 изменённых файлов: 2068 добавлений и 0 удалений

Просмотреть файл

@ -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_ */