feat(accounts): Add parameter to encrypt/decrypt auxiliary account's password

This commit is contained in:
Hivert Quentin
2024-02-01 16:55:41 +01:00
parent f0010afef4
commit e6bfab7ee1
11 changed files with 841 additions and 16 deletions
+36 -2
View File
@@ -29,10 +29,11 @@
#import <NGImap4/NGSieveClient.h>
#import <SOPE/NGCards/iCalRecurrenceRule.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSObject+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/NSString+Crypto.h>
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoSieveManager.h>
#import <SOGo/SOGoUser.h>
@@ -493,8 +494,10 @@ static SoProduct *preferencesProduct = nil;
if ([accounts count])
{
int i;
NSDictionary *security;
NSDictionary *security, *accountPassword;
NSMutableDictionary *auxAccount, *limitedSecurity;
NSString *password, *encryptedPassword, *sogoSecret, *iv, *tag;
NSException* exception = nil;
for (i = 0; i < [accounts count]; i++)
{
@@ -510,6 +513,37 @@ static SoProduct *preferencesProduct = nil;
}
[auxAccount setObject: limitedSecurity forKey: @"security"];
}
//Decrypt password if needed
sogoSecret = [[SOGoSystemDefaults sharedSystemDefaults] sogoSecretValue];
if (sogoSecret)
{
if(![[auxAccount objectForKey: @"password"] isKindOfClass: [NSDictionary class]])
{
[self errorWithFormat:@"Can't decrypt the password for auxiliary account %@, is not a dictionnary",
[auxAccount objectForKey: @"name"]];
continue;
}
accountPassword = [auxAccount objectForKey: @"password"];
encryptedPassword = [accountPassword objectForKey: @"cypher"];
iv = [accountPassword objectForKey: @"iv"];
tag = [accountPassword objectForKey: @"tag"];
if([encryptedPassword length] > 0)
{
NS_DURING
password = [encryptedPassword decryptAES256GCM: sogoSecret iv: iv tag: tag exception:&exception];
NS_HANDLER
[self errorWithFormat:@"Can't decrypt the password for auxiliary account %@, probably not encrypted.",
[auxAccount objectForKey: @"name"]];
password = [auxAccount objectForKey: @"password"];
NS_ENDHANDLER
if(exception)
[self errorWithFormat:@"Can't decrypt the password for auxiliary account %@: %@",
[auxAccount objectForKey: @"name"], [exception reason]];
else
[auxAccount setObject: password forKey: @"password"];
}
}
}
}
// We inject our default mail account
+73 -5
View File
@@ -35,6 +35,7 @@
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/NSString+Crypto.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserSettings.h>
#import <SOGo/SOGoSieveManager.h>
@@ -1532,6 +1533,7 @@ static NSArray *reminderValues = nil;
int count, max;
NSMutableArray *auxAccounts;
NSMutableDictionary *account;
NSString *sogoSecret, *password;
max = [accounts count];
auxAccounts = [NSMutableArray arrayWithCapacity: max];
@@ -1542,6 +1544,24 @@ static NSArray *reminderValues = nil;
if ([self _validateAccount: account])
{
[self _updateAuxiliaryAccount: account];
//Encrypt password if needed
sogoSecret = [[SOGoSystemDefaults sharedSystemDefaults] sogoSecretValue];
//Note that password here will always be a string and not a dictionnary of gcm encryption as it comes from the saveAction Request
password = [account objectForKey: @"password"];
if(sogoSecret && [password length] > 0)
{
NSDictionary* newPassword;
NSException* exception = nil;
newPassword = [password encryptAES256GCM: sogoSecret exception:&exception];
if(exception)
[self errorWithFormat:@"Can't encrypt the password: %@", [exception reason]];
else
[account setObject: newPassword forKey: @"password"];
}
else
[self warnWithFormat:@"Password for auxiliary accounts are not stored encrypted see SOGoSecretType"];
[auxAccounts addObject: account];
}
}
@@ -1556,7 +1576,7 @@ static NSArray *reminderValues = nil;
NSDictionary *oldAccount, *oldSecurity;
NSEnumerator *comparisonAttributesList;
NSMutableDictionary *newSecurity;
NSString *comparisonAttribute, *password, *certificate;
NSString *comparisonAttribute, *password, *certificate, *sogoSecret, *decryptedPassword;
comparisonAttributes = [NSArray arrayWithObjects: @"serverName", @"userName", nil];
oldAccounts = [user mailAccounts];
@@ -1580,11 +1600,59 @@ static NSArray *reminderValues = nil;
// Use previous password if none is provided
password = [newAccount objectForKey: @"password"];
if (!password)
password = [oldAccount objectForKey: @"password"];
if (!password)
password = @"";
[newAccount setObject: password forKey: @"password"];
{
if([oldAccount objectForKey: @"password"])
{
if([[oldAccount objectForKey: @"password"] isKindOfClass: [NSDictionary class]])
{
//Old password is encrypted, decrypt it first as it will be encrypt again after
NSDictionary *accountPassword;
NSString *encryptedPassword, *iv, *tag;
accountPassword = [oldAccount objectForKey: @"password"];
encryptedPassword = [accountPassword objectForKey: @"cypher"];
iv = [accountPassword objectForKey: @"iv"];
tag = [accountPassword objectForKey: @"tag"];
sogoSecret = [[SOGoSystemDefaults sharedSystemDefaults] sogoSecretValue];
if(sogoSecret)
{
NSException* exception = nil;
NS_DURING
decryptedPassword = [encryptedPassword decryptAES256GCM: sogoSecret iv: iv tag: tag exception:&exception];
if(exception)
{
[self errorWithFormat:@"Can't decrypt the password for auxiliary account %@: %@",
[oldAccount objectForKey: @"name"], [exception reason]];
decryptedPassword = @"";
}
else
password = decryptedPassword;
NS_HANDLER
[self errorWithFormat:@"Can't decrypt the password for auxiliary account %@, probably wrong key",
[oldAccount objectForKey: @"name"]];
decryptedPassword = @"";
NS_ENDHANDLER
[newAccount setObject: decryptedPassword forKey: @"password"];
}
else
{
[self errorWithFormat:@"Password currently stored for account %@ is encrypted but there is a no secret SOGoSecretValue to decrypt with",
[newAccount objectForKey: @"name"]];
[newAccount setObject: @"" forKey: @"password"];
}
}
else
{
//Old password is not encrypted, nothing to do
[newAccount setObject: [oldAccount objectForKey: @"password"] forKey: @"password"];
}
}
else {
//No password for this account, weird choice but possible
[newAccount setObject: @"" forKey: @"password"];
}
}
// Keep previous certificate
oldSecurity = [oldAccount objectForKey: @"security"];
if (oldSecurity)