mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-10-12 23:37:15 +00:00
(feat) added support for S/MIME opaque signing (fixes #4582)
This commit is contained in:
1 parent
b52abfcbea
commit
676d2e6790
15 files changed
+569
-33
No files matched your search
@@ -31,6 +31,8 @@
|
||||
- (NSData *) encryptUsingCertificate: (NSData *) theData;
|
||||
- (NSData *) decryptUsingCertificate: (NSData *) theData;
|
||||
- (NGMimeMessage *) messageFromEncryptedDataAndCertificate: (NSData *) theCertificate;
|
||||
- (NSData *) embeddedContent;
|
||||
- (NGMimeMessage *) messageFromOpaqueSignedData;
|
||||
- (NSData *) convertPKCS12ToPEMUsingPassword: (NSString *) thePassword;
|
||||
- (NSData *) signersFromPKCS7;
|
||||
- (NSDictionary *) certificateDescription;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* NSData+SMIME.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2017-2018 Inverse inc.
|
||||
* Copyright (C) 2017-2019 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -296,10 +296,86 @@
|
||||
NGMimeMessageParser *parser;
|
||||
NGMimeMessage *message;
|
||||
NSData *decryptedData;
|
||||
NGMimeType *contentType;
|
||||
NSString *type, *subtype, *smimetype;
|
||||
|
||||
decryptedData = [self decryptUsingCertificate: theCertificate];
|
||||
parser = [[NGMimeMessageParser alloc] init];
|
||||
message = [parser parsePartFromData: decryptedData];
|
||||
|
||||
// Extract contents if the encrypted messages contains opaque signed data
|
||||
contentType = [message contentType];
|
||||
type = [[contentType type] lowercaseString];
|
||||
subtype = [[contentType subType] lowercaseString];
|
||||
if ([type isEqualToString: @"application"])
|
||||
{
|
||||
if ([subtype isEqualToString: @"x-pkcs7-mime"] ||
|
||||
[subtype isEqualToString: @"pkcs7-mime"])
|
||||
{
|
||||
smimetype = [[contentType valueOfParameter: @"smime-type"] lowercaseString];
|
||||
if ([smimetype isEqualToString: @"signed-data"])
|
||||
{
|
||||
message = [decryptedData messageFromOpaqueSignedData];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RELEASE(parser);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
- (NSData *) embeddedContent
|
||||
{
|
||||
NSData *output = NULL;
|
||||
|
||||
BIO *sbio, *obio;
|
||||
BUF_MEM *bptr;
|
||||
PKCS7 *p7 = NULL;
|
||||
|
||||
sbio = BIO_new_mem_buf((void *)[self bytes], [self length]);
|
||||
|
||||
p7 = SMIME_read_PKCS7(sbio, NULL);
|
||||
|
||||
if (!p7)
|
||||
{
|
||||
NSLog(@"FATAL: could not read the signature");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// We output the S/MIME encrypted message
|
||||
obio = BIO_new(BIO_s_mem());
|
||||
|
||||
if (!PKCS7_verify(p7, NULL, NULL, NULL, obio, PKCS7_NOVERIFY|PKCS7_NOSIGS))
|
||||
{
|
||||
NSLog(@"FATAL: could not extract content");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
BIO_get_mem_ptr(obio, &bptr);
|
||||
|
||||
output = [NSData dataWithBytes: bptr->data length: bptr->length];
|
||||
|
||||
cleanup:
|
||||
PKCS7_free(p7);
|
||||
BIO_free(sbio);
|
||||
BIO_free(obio);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (NGMimeMessage *) messageFromOpaqueSignedData
|
||||
{
|
||||
NGMimeMessageParser *parser;
|
||||
NGMimeMessage *message;
|
||||
NSData *extractedData;
|
||||
|
||||
extractedData = [self embeddedContent];
|
||||
parser = [[NGMimeMessageParser alloc] init];
|
||||
message = [parser parsePartFromData: extractedData];
|
||||
RELEASE(parser);
|
||||
|
||||
return message;
|
||||
|
||||
@@ -872,6 +872,18 @@ static NSString *userAgent = nil;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) _fetchAttachmentsFromOpaqueSignedMail: (SOGoMailObject *) sourceMail
|
||||
{
|
||||
NGMimeMessage *m;
|
||||
|
||||
m = [[sourceMail content] messageFromOpaqueSignedData];
|
||||
[self _fileAttachmentsFromPart: [m body]];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
@@ -1007,6 +1019,8 @@ static NSString *userAgent = nil;
|
||||
[self setText: [sourceMail contentForInlineForward]];
|
||||
if ([sourceMail isEncrypted])
|
||||
[self _fetchAttachmentsFromEncryptedMail: sourceMail];
|
||||
else if ([sourceMail isOpaqueSigned])
|
||||
[self _fetchAttachmentsFromOpaqueSignedMail: sourceMail];
|
||||
else
|
||||
[self _fetchAttachmentsFromMail: sourceMail];
|
||||
}
|
||||
|
||||
@@ -197,9 +197,7 @@
|
||||
- (NGImap4Connection *) imap4Connection
|
||||
{
|
||||
NSString *cacheKey, *login;
|
||||
|
||||
SOGoCache *sogoCache;
|
||||
|
||||
|
||||
if (!imap4)
|
||||
{
|
||||
|
||||
@@ -210,6 +210,28 @@ static BOOL debugOn = NO;
|
||||
inContext: localContext];
|
||||
obj = [clazz objectWithName:key inContainer: self];
|
||||
}
|
||||
else if ([o isOpaqueSigned])
|
||||
{
|
||||
NGMimeMessage *m;
|
||||
id part;
|
||||
|
||||
int i;
|
||||
|
||||
m = [[o content] messageFromOpaqueSignedData];
|
||||
part = [m body];
|
||||
|
||||
for (i = 0; i < [[self bodyPartPath] count]; i++)
|
||||
{
|
||||
nbr = [[[self bodyPartPath] objectAtIndex: i] intValue]-1;
|
||||
part = [[part parts] objectAtIndex: nbr];;
|
||||
}
|
||||
|
||||
part = [[part parts] objectAtIndex: ([key intValue]-1)];
|
||||
mimeType = [[part contentType] stringValue];
|
||||
clazz = [SOGoMailBodyPart bodyPartClassForMimeType: mimeType
|
||||
inContext: localContext];
|
||||
obj = [clazz objectWithName:key inContainer: self];
|
||||
}
|
||||
else
|
||||
{
|
||||
infos = [self partInfo];
|
||||
@@ -353,6 +375,24 @@ static BOOL debugOn = NO;
|
||||
m = [[o content] messageFromEncryptedDataAndCertificate: certificate];
|
||||
part = [m body];
|
||||
|
||||
for (i = 0; i < [[self bodyPartPath] count]; i++)
|
||||
{
|
||||
nbr = [[[self bodyPartPath] objectAtIndex: i] intValue]-1;
|
||||
part = [[part parts] objectAtIndex: nbr];;
|
||||
}
|
||||
|
||||
return [part body];
|
||||
}
|
||||
else if ([o isOpaqueSigned])
|
||||
{
|
||||
NGMimeMessage *m;
|
||||
id part;
|
||||
|
||||
unsigned int i, nbr;
|
||||
|
||||
m = [[o content] messageFromOpaqueSignedData];
|
||||
part = [m body];
|
||||
|
||||
for (i = 0; i < [[self bodyPartPath] count]; i++)
|
||||
{
|
||||
nbr = [[[self bodyPartPath] objectAtIndex: i] intValue]-1;
|
||||
|
||||
@@ -238,6 +238,24 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (NSString *) _contentForEditingFromOpaqueSignedMail
|
||||
{
|
||||
SOGoUserDefaults *ud;
|
||||
NGMimeMessage *m;
|
||||
|
||||
m = [[self content] messageFromOpaqueSignedData];
|
||||
ud = [[context activeUser] userDefaults];
|
||||
|
||||
return [self _preferredContentFromPart: [m body]
|
||||
favorHTML: [[ud mailComposeMessageType] isEqualToString: @"html"]];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
@@ -250,6 +268,8 @@
|
||||
|
||||
if ([self isEncrypted])
|
||||
output = [self _contentForEditingFromEncryptedMail];
|
||||
else if ([self isOpaqueSigned])
|
||||
output = [self _contentForEditingFromOpaqueSignedMail];
|
||||
|
||||
// If not encrypted or if decryption failed, we fallback
|
||||
// to the normal content fetching code.
|
||||
|
||||
@@ -124,7 +124,8 @@ NSArray *SOGoMailCoreInfoKeys;
|
||||
- (BOOL) replied; /* \Answered */
|
||||
- (BOOL) forwarded; /* $forwarded */
|
||||
- (BOOL) deleted; /* \Deleted */
|
||||
- (BOOL) isSigned; /* S/MIME signed message */
|
||||
- (BOOL) isSigned; /* S/MIME signed message (detached signature) */
|
||||
- (BOOL) isOpaqueSigned; /* S/MIME signed message (embedded content) */
|
||||
- (BOOL) isEncrypted; /* S/MIME encrypted message */
|
||||
|
||||
/* deletion */
|
||||
|
||||
@@ -1201,6 +1201,19 @@ static BOOL debugSoParts = NO;
|
||||
return [clazz objectWithName:_key inContainer: self];
|
||||
}
|
||||
}
|
||||
else if ([self isOpaqueSigned])
|
||||
{
|
||||
NGMimeMessage *m;
|
||||
id part;
|
||||
|
||||
m = [[self content] messageFromOpaqueSignedData];
|
||||
|
||||
part = [[[m body] parts] objectAtIndex: ([_key intValue]-1)];
|
||||
mimeType = [[part contentType] stringValue];
|
||||
clazz = [SOGoMailBodyPart bodyPartClassForMimeType: mimeType
|
||||
inContext: _ctx];
|
||||
return [clazz objectWithName:_key inContainer: self];
|
||||
}
|
||||
|
||||
parts = [[self bodyStructure] objectForKey: @"parts"];
|
||||
|
||||
@@ -1738,18 +1751,47 @@ static BOOL debugSoParts = NO;
|
||||
[protocol isEqualToString: @"application/pkcs7-signature"]));
|
||||
}
|
||||
|
||||
- (BOOL) isEncrypted
|
||||
- (BOOL) isOpaqueSigned
|
||||
{
|
||||
NSString *type, *subtype;
|
||||
NSString *type, *subtype, *smimetype;
|
||||
NGMimeType *contentType;
|
||||
|
||||
type = [[[[self mailHeaders] objectForKey: @"content-type"] type] lowercaseString];
|
||||
subtype = [[[[self mailHeaders] objectForKey: @"content-type"] subType] lowercaseString];
|
||||
contentType = [[self mailHeaders] objectForKey: @"content-type"];
|
||||
type = [[contentType type] lowercaseString];
|
||||
subtype = [[contentType subType] lowercaseString];
|
||||
|
||||
if ([type isEqualToString: @"application"])
|
||||
{
|
||||
if ([subtype isEqualToString: @"x-pkcs7-mime"] ||
|
||||
[subtype isEqualToString: @"pkcs7-mime"])
|
||||
return YES;
|
||||
{
|
||||
smimetype = [[contentType valueOfParameter: @"smime-type"] lowercaseString];
|
||||
if ([smimetype isEqualToString: @"signed-data"])
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL) isEncrypted
|
||||
{
|
||||
NSString *type, *subtype, *smimetype;
|
||||
NGMimeType *contentType;
|
||||
|
||||
contentType = [[self mailHeaders] objectForKey: @"content-type"];
|
||||
type = [[contentType type] lowercaseString];
|
||||
subtype = [[contentType subType] lowercaseString];
|
||||
|
||||
if ([type isEqualToString: @"application"])
|
||||
{
|
||||
if ([subtype isEqualToString: @"x-pkcs7-mime"] ||
|
||||
[subtype isEqualToString: @"pkcs7-mime"])
|
||||
{
|
||||
smimetype = [[contentType valueOfParameter: @"smime-type"] lowercaseString];
|
||||
if ([smimetype isEqualToString: @"enveloped-data"])
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
Reference in new issue
Block a user