From b6da8d0ff12a4d5f4fe271e820249a957e9381e9 Mon Sep 17 00:00:00 2001 From: "Hoa V. DINH" Date: Tue, 23 Sep 2014 22:20:51 -0700 Subject: Provided helpers for OpenPGP encryption and signature --- src/core/rfc822/MCMessageBuilder.cc | 171 +++++++++++++++++++++++++++++++---- src/core/rfc822/MCMessageBuilder.h | 4 + src/objc/rfc822/MCOMessageBuilder.h | 15 +++ src/objc/rfc822/MCOMessageBuilder.mm | 10 ++ 4 files changed, 180 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/core/rfc822/MCMessageBuilder.cc b/src/core/rfc822/MCMessageBuilder.cc index 933a022b..b81daed8 100644 --- a/src/core/rfc822/MCMessageBuilder.cc +++ b/src/core/rfc822/MCMessageBuilder.cc @@ -37,6 +37,28 @@ static struct mailmime * get_multipart_related(const char * boundary_prefix) return mime; } +static struct mailmime * get_multipart_signed_pgp(const char * boundary_prefix) +{ + struct mailmime * mime; + + mime = part_multiple_new("multipart/signed", boundary_prefix); + struct mailmime_parameter * param = mailmime_param_new_with_data((char *) "protocol", (char *) "application/pgp-signature"); + clist_append(mime->mm_content_type->ct_parameters, param); + + return mime; +} + +static struct mailmime * get_multipart_encrypted_pgp(const char * boundary_prefix) +{ + struct mailmime * mime; + + mime = part_multiple_new("multipart/encrypted", boundary_prefix); + struct mailmime_parameter * param = mailmime_param_new_with_data((char *) "protocol", (char *) "application/pgp-encrypted"); + clist_append(mime->mm_content_type->ct_parameters, param); + + return mime; +} + static int add_attachment(struct mailmime * mime, struct mailmime * mime_sub, const char * boundary_prefix) @@ -662,43 +684,39 @@ String * MessageBuilder::boundaryPrefix() return mBoundaryPrefix; } -Data * MessageBuilder::dataAndFilterBccAndForEncryption(bool filterBcc, bool forEncryption) +struct mailmime * MessageBuilder::mimeAndFilterBccAndForEncryption(bool filterBcc, bool forEncryption) { - Data * data; - MMAPString * str; - int col; - struct mailmime * htmlPart; struct mailmime * textPart; struct mailmime * altPart; struct mailmime * mainPart; - + htmlPart = NULL; textPart = NULL; altPart = NULL; mainPart = NULL; - + if (htmlBody() != NULL) { Attachment * htmlAttachment; - + htmlAttachment = Attachment::attachmentWithHTMLString(htmlBody()); htmlPart = multipart_related_from_attachments(htmlAttachment, mRelatedAttachments, - MCUTF8(mBoundaryPrefix), forEncryption); + MCUTF8(mBoundaryPrefix), forEncryption); } - + if (textBody() != NULL) { Attachment * textAttachment; - + textAttachment = Attachment::attachmentWithText(textBody()); textPart = mime_from_attachment(textAttachment, forEncryption); } else if (htmlBody() != NULL) { Attachment * textAttachment; - + textAttachment = Attachment::attachmentWithText(htmlBody()->flattenHTML()); textPart = mime_from_attachment(textAttachment, forEncryption); } - + if ((textPart != NULL) && (htmlPart != NULL)) { altPart = get_multipart_alternative(MCUTF8(mBoundaryPrefix)); mailmime_smart_add_part(altPart, textPart); @@ -711,38 +729,55 @@ Data * MessageBuilder::dataAndFilterBccAndForEncryption(bool filterBcc, bool for else if (htmlPart != NULL) { mainPart = htmlPart; } - + struct mailimf_fields * fields; unsigned int i; struct mailmime * mime; - + fields = header()->createIMFFieldsAndFilterBcc(filterBcc); - + mime = mailmime_new_message_data(NULL); mailmime_set_imf_fields(mime, fields); - + if (mainPart != NULL) { add_attachment(mime, mainPart, MCUTF8(mBoundaryPrefix)); } - + if (attachments() != NULL) { for(i = 0 ; i < attachments()->count() ; i ++) { Attachment * attachment; struct mailmime * submime; - + attachment = (Attachment *) attachments()->objectAtIndex(i); submime = mime_from_attachment(attachment, forEncryption); add_attachment(mime, submime, MCUTF8(mBoundaryPrefix)); } } + struct mailmime * result = mime; + if (forEncryption) { + result = mime->mm_data.mm_message.mm_msg_mime; + mime->mm_data.mm_message.mm_msg_mime = NULL; + mailmime_free(mime); + } + + return result; +} + +Data * MessageBuilder::dataAndFilterBccAndForEncryption(bool filterBcc, bool forEncryption) +{ + Data * data; + MMAPString * str; + int col; + str = mmap_string_new(""); col = 0; + struct mailmime * mime = mimeAndFilterBccAndForEncryption(filterBcc, forEncryption); mailmime_write_mem(str, &col, mime); data = Data::dataWithBytes(str->str, (unsigned int) str->len); mmap_string_free(str); mailmime_free(mime); - + return data; } @@ -780,3 +815,99 @@ String * MessageBuilder::plainTextBodyRendering(bool stripWhitespace) return message->plainTextBodyRendering(stripWhitespace); } +struct mailmime * get_signature_part(Data * signature) +{ + struct mailmime * mime; + struct mailmime_content * content; + + content = mailmime_content_new_with_str("application/pgp-signature"); + struct mailmime_fields * mime_fields = mailmime_fields_new_empty(); + mime = part_new_empty(content, mime_fields, NULL, 1); + mailmime_set_body_text(mime, signature->bytes(), signature->length()); + + return mime; +} + +Data * MessageBuilder::openPGPSignedMessageDataWithSignatureData(Data * signature) +{ + struct mailimf_fields * fields; + struct mailmime * mime; + + fields = header()->createIMFFieldsAndFilterBcc(false); + + mime = mailmime_new_message_data(NULL); + mailmime_set_imf_fields(mime, fields); + + struct mailmime * multipart = get_multipart_signed_pgp(MCUTF8(boundaryPrefix())); + add_attachment(mime, multipart, MCUTF8(boundaryPrefix())); + struct mailmime * part_to_sign = mimeAndFilterBccAndForEncryption(false, true); + add_attachment(multipart, part_to_sign, MCUTF8(boundaryPrefix())); + struct mailmime * signature_part = get_signature_part(signature); + add_attachment(multipart, signature_part, MCUTF8(boundaryPrefix())); + + MMAPString * str = mmap_string_new(""); + int col = 0; + + mailmime_write_mem(str, &col, mime); + Data * data = Data::dataWithBytes(str->str, (unsigned int) str->len); + mmap_string_free(str); + mailmime_free(mime); + + return data; +} + +static struct mailmime * get_pgp_version_part(void) +{ + struct mailmime * mime; + struct mailmime_content * content; + + content = mailmime_content_new_with_str("application/pgp-encrypted"); + struct mailmime_fields * mime_fields = mailmime_fields_new_empty(); + mime = part_new_empty(content, mime_fields, NULL, 1); + const char * version = "Version: 1\r\n"; + mailmime_set_body_text(mime, (char *) version, strlen(version)); + + return mime; +} + +static struct mailmime * get_encrypted_part(Data * encryptedData) +{ + struct mailmime * mime; + struct mailmime_content * content; + + content = mailmime_content_new_with_str("application/octet-stream"); + struct mailmime_fields * mime_fields = mailmime_fields_new_empty(); + mime = part_new_empty(content, mime_fields, NULL, 1); + mailmime_set_body_text(mime, encryptedData->bytes(), encryptedData->length()); + + return mime; +} + +Data * MessageBuilder::openPGPEncryptedMessageDataWithEncryptedData(Data * encryptedData) +{ + struct mailimf_fields * fields; + struct mailmime * mime; + + fields = header()->createIMFFieldsAndFilterBcc(false); + + mime = mailmime_new_message_data(NULL); + mailmime_set_imf_fields(mime, fields); + + struct mailmime * multipart = get_multipart_encrypted_pgp(MCUTF8(boundaryPrefix())); + add_attachment(mime, multipart, MCUTF8(boundaryPrefix())); + + struct mailmime * version_part = get_pgp_version_part(); + add_attachment(multipart, version_part, MCUTF8(boundaryPrefix())); + struct mailmime * encrypted_part = get_encrypted_part(encryptedData); + add_attachment(multipart, encrypted_part, MCUTF8(boundaryPrefix())); + + MMAPString * str = mmap_string_new(""); + int col = 0; + + mailmime_write_mem(str, &col, mime); + Data * data = Data::dataWithBytes(str->str, (unsigned int) str->len); + mmap_string_free(str); + mailmime_free(mime); + + return data; +} diff --git a/src/core/rfc822/MCMessageBuilder.h b/src/core/rfc822/MCMessageBuilder.h index d3b32a4f..482fe07c 100644 --- a/src/core/rfc822/MCMessageBuilder.h +++ b/src/core/rfc822/MCMessageBuilder.h @@ -47,6 +47,9 @@ namespace mailcore { virtual String * plainTextRendering(); virtual String * plainTextBodyRendering(bool stripWhitespace); + virtual Data * openPGPSignedMessageDataWithSignatureData(Data * signature); + virtual Data * openPGPEncryptedMessageDataWithEncryptedData(Data * encryptedData); + public: // subclass behavior MessageBuilder(MessageBuilder * other); virtual String * description(); @@ -60,6 +63,7 @@ namespace mailcore { String * mBoundaryPrefix; void init(); Data * dataAndFilterBccAndForEncryption(bool filterBcc, bool forEncryption); + struct mailmime * mimeAndFilterBccAndForEncryption(bool filterBcc, bool forEncryption); }; }; diff --git a/src/objc/rfc822/MCOMessageBuilder.h b/src/objc/rfc822/MCOMessageBuilder.h index 93e2a387..1663d6f7 100644 --- a/src/objc/rfc822/MCOMessageBuilder.h +++ b/src/objc/rfc822/MCOMessageBuilder.h @@ -61,6 +61,21 @@ /** RFC 822 formatted message for encryption.*/ - (NSData *) dataForEncryption; +/** + Returns an OpenPGP signed message with a given signature. + The signature needs to be computed on the data returned by -dataForEncryption + before calling this method. + You could use http://www.netpgp.com to generate it. + */ +- (NSData *) openPGPSignedMessageDataWithSignatureData:(NSData *)signature; + +/** + Returns an OpenPGP encrypted message with a given encrypted data. + The encrypted data needs to be computed before calling this method. + You could use http://www.netpgp.com to generate it. + */ +- (NSData *) openPGPEncryptedMessageDataWithEncryptedData:(NSData *)encryptedData; + /** HTML rendering of the message to be displayed in a web view. The delegate can be nil.*/ - (NSString *) htmlRenderingWithDelegate:(id )delegate; diff --git a/src/objc/rfc822/MCOMessageBuilder.mm b/src/objc/rfc822/MCOMessageBuilder.mm index 023697e3..c122ab14 100644 --- a/src/objc/rfc822/MCOMessageBuilder.mm +++ b/src/objc/rfc822/MCOMessageBuilder.mm @@ -100,4 +100,14 @@ MCO_OBJC_SYNTHESIZE_STRING(setBoundaryPrefix, boundaryPrefix) return MCO_TO_OBJC(MCO_NATIVE_INSTANCE->plainTextBodyRendering(stripWhitespace)); } +- (NSData *) openPGPSignedMessageDataWithSignatureData:(NSData *)signature +{ + return MCO_TO_OBJC(MCO_NATIVE_INSTANCE->openPGPSignedMessageDataWithSignatureData(MCO_FROM_OBJC(mailcore::Data, signature))); +} + +- (NSData *) openPGPEncryptedMessageDataWithEncryptedData:(NSData *)encryptedData +{ + return MCO_TO_OBJC(MCO_NATIVE_INSTANCE->openPGPEncryptedMessageDataWithEncryptedData(MCO_FROM_OBJC(mailcore::Data, encryptedData))); +} + @end -- cgit v1.2.3