Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ build-cdoc-debug/
Packages/
xcuserdata

# Module lockfiles
Modules/**/Package.resolved
# Module lockfiles (SPM packages and the Xcode workspace's own copy)
**/Package.resolved

# Mockolo
**/Mocks/**
Expand Down
20 changes: 19 additions & 1 deletion Modules/CryptoLib/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ let package = Package(
.library(
name: "CryptoLib",
targets: ["CryptoSwift"]
)
),
.library(name: "CryptoLibMocks", targets: ["CryptoLibMocks"])
],
dependencies: [
.package(url: "https://github.com/filom/ASN1Decoder", exact: .init(1, 10, 0)),
Expand Down Expand Up @@ -87,6 +88,23 @@ let package = Package(
.enableUpcomingFeature("NonisolatedNonsendingByDefault"),
.enableUpcomingFeature("InferIsolatedConformances")
]
),
.target(
name: "CryptoLibMocks",
dependencies: ["CryptoSwift"],
path: "Tests/Mocks"
),
.testTarget(
name: "CryptoSwiftTests",
dependencies: [
"ConfigLib",
"CryptoLibMocks",
"CryptoObjCWrapper",
"CommonsLib",
"UtilsLib",
.product(name: "FactoryTesting", package: "Factory"),
.product(name: "CommonsLibMocks", package: "commonslib")
]
)
]
)
74 changes: 54 additions & 20 deletions Modules/CryptoLib/Sources/CryptoObjC/include/Decrypt.mm
Original file line number Diff line number Diff line change
Expand Up @@ -27,40 +27,56 @@
#include <cdoc/CdocReader.h>
#include <cdoc/Lock.h>

static CertType certTypeFromLabel(NSString * _Nullable type) {
if (type == nil) return CertTypeESealType;
if ([type isEqualToString:@"ID-card"] ||
[type isEqualToString:@"cert"]) return CertTypeIDCardType;
if ([type isEqualToString:@"Digi-ID"]) return CertTypeDigiIDType;
if ([type isEqualToString:@"Digi-ID E-RESIDENT"]) return CertTypeEResidentType;
return CertTypeUnknownType;
}

@implementation Addressee (label)

- (instancetype)initWithLabel:(const std::string &)label pub:(NSData*)pub concatKDFAlgorithmURI:(NSString *)concatKDFAlgorithmURI {
std::map<std::string, std::string> info = libcdoc::Lock::parseLabel(label);
id cn = info.contains("cn") ? [NSString stringWithStdString:info["cn"]] : [NSString stringWithStdString:label];
id type = info.contains("type") ? [NSString stringWithStdString:info["type"]] : nil;
id serial = info.contains("serial_number") ? [NSString stringWithStdString:info["serial_number"]] : nil;
CertType certType = CertTypeUnknownType;
NSString *cn = info.contains("cn") ? [NSString stringWithStdString:info["cn"]] : [NSString stringWithStdString:label];
NSString *type = info.contains("type") ? [NSString stringWithStdString:info["type"]] : nil;
NSString *serial = info.contains("serial_number") ? [NSString stringWithStdString:info["serial_number"]] : nil;

// A single-segment CN with no explicit last_name key is an e-seal, not a person.
NSArray<NSString *> *split = [cn componentsSeparatedByString:@","];
if (!info.contains("last_name") && split.count == 1) {
type = nil;
}

if ([type isEqualToString:@"ID-card"] || [type isEqualToString:@"cert"]) {
certType = CertTypeIDCardType;
} else if ([type isEqualToString:@"Digi-ID"]) {
certType = CertTypeDigiIDType;
} else if ([type isEqualToString:@"Digi-ID E-RESIDENT"]) {
certType = CertTypeEResidentType;
} else if (type == nil) {
certType = CertTypeESealType;
}
id validTo = nil;

NSDate *validTo = nil;
if (info.contains("server_exp")) {
long long epochTime = [[NSString stringWithStdString:info["server_exp"]] longLongValue];
validTo = [NSDate dateWithTimeIntervalSince1970:epochTime];
}
if (self = [self initWithCnVal:cn serialNumber:serial certType:certType validTo:validTo data:pub concatKDFAlgorithmURI:concatKDFAlgorithmURI]) {

if (self = [self initWithCnVal:cn serialNumber:serial certType:certTypeFromLabel(type) validTo:validTo data:pub concatKDFAlgorithmURI:concatKDFAlgorithmURI lockLabel:@"" lockType:@""]) {
}
return self;
}

@end

static NSString *lockTypeName(libcdoc::Lock::Type type) {
switch (type) {
case libcdoc::Lock::Type::PASSWORD: return @"PASSWORD";
case libcdoc::Lock::Type::SYMMETRIC_KEY: return @"SYMMETRIC_KEY";
case libcdoc::Lock::Type::PUBLIC_KEY: return @"PUBLIC_KEY";
case libcdoc::Lock::Type::CDOC1: return @"CDOC1";
case libcdoc::Lock::Type::SERVER: return @"SERVER";
#ifdef HAS_KEYSHARES
case libcdoc::Lock::Type::SHARE_SERVER: return @"SHARE_SERVER";
#endif
default: return @"UNKNOWN";
}
}

@implementation Decrypt

+ (void)setCerts:(nullable NSArray<NSData *> *)certs {
Expand Down Expand Up @@ -114,13 +130,16 @@ + (CdocInfo*)cdocInfo:(NSString *)fullPath error:(NSError**)error {
NSString *cnVal = info.contains("label")
? [NSString stringWithStdString:info["label"]]
: @"";
NSString *rawLockLabel = [NSString stringWithStdString:lock.label] ?: @"";
[addressees addObject:[[Addressee alloc]
initWithCnVal:cnVal
serialNumber:nil
certType:CertTypePasswordType
validTo:nil
data:[NSData data]
concatKDFAlgorithmURI:@""]];
concatKDFAlgorithmURI:@""
lockLabel:rawLockLabel
lockType:lockTypeName(lock.type)]];
} else {
[addressees addObject:[[Addressee alloc] initWithData:[NSData data] cnVal:@"Unknown capsule"]];
}
Expand Down Expand Up @@ -198,12 +217,27 @@ + (void)decryptFile:(NSString *)fullPath withCert:(NSData *)certData withToken:(
}
} crypto {password};
std::unique_ptr<libcdoc::CDocReader> reader(libcdoc::CDocReader::createReader(fullPath.UTF8String, nullptr, &crypto, nullptr));
if (!reader) {
return [NSError cryptoError:@"Failed to create CDocReader" error:error];
}

auto idx = 0; // TODO: reader->getLockForCert(network.cert);
if(idx < 0)
int idx = -1;
const auto& locks = reader->getLocks();
for (size_t i = 0; i < locks.size(); i++) {
if (locks[i].type == libcdoc::Lock::Type::PASSWORD) {
idx = (int)i;
break;
}
}
if (idx < 0) {
return [NSError cryptoError:@"Decrypting failed" error:error];
}
std::vector<uint8_t> fmk;
if(reader->getFMK(fmk, unsigned(idx)) != 0 || fmk.empty()) {
auto fmkResult = reader->getFMK(fmk, unsigned(idx));
if (fmkResult == libcdoc::WRONG_KEY) {
return [NSError cryptoWrongKeyError:error];
}
if (fmkResult != libcdoc::OK || fmk.empty()) {
return [NSError cryptoError:@"Decrypting failed" error:error];
}
return [self decryptReader:*reader withFMK:fmk error:error];
Expand Down
10 changes: 6 additions & 4 deletions Modules/CryptoLib/Sources/CryptoObjC/include/Encrypt.mm
Original file line number Diff line number Diff line change
Expand Up @@ -213,12 +213,14 @@ + (void)encryptFile:(NSString *)fullPath withDataFiles:(NSArray<CryptoDataFile*>
return completion([NSError cryptoError:@"Failed to create writer"]);
}

if (writer->beginEncryption() != 0) {
return completion([NSError cryptoError:@"Failed to start encryption"]);
auto passwordRecipient = libcdoc::Recipient::makeSymmetric("", 65536);
passwordRecipient.setLabelValue("label", std::string(label.UTF8String));
if (writer->addRecipient(passwordRecipient) != 0) {
return completion([NSError cryptoError:@"Failed to create key"]);
}

if (writer->addRecipient(libcdoc::Recipient::makeSymmetric(label.UTF8String, 65536))) {
return completion([NSError cryptoError:@"Failed to create key"]);
if (writer->beginEncryption() != 0) {
return completion([NSError cryptoError:@"Failed to start encryption"]);
}

for (CryptoDataFile *dataFile in dataFiles) {
Expand Down
12 changes: 12 additions & 0 deletions Modules/CryptoLib/Sources/CryptoObjC/include/Extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@
#include <string>
#include <vector>

static const NSInteger CryptoLibWrongKeyErrorCode = -109; // libcdoc::WRONG_KEY

@interface NSError (CryptoLib)
+ (NSError*)cryptoError:(NSString*)msg;
+ (id)cryptoError:(NSString*)msg error:(NSError**)error;
+ (id)cryptoWrongKeyError:(NSError**)error;
@end

@interface NSString (std_string)
Expand Down Expand Up @@ -77,4 +80,13 @@
}
return nil;
}

+ (id)cryptoWrongKeyError:(NSError**)error {
if (error) {
*error = [[NSError alloc] initWithDomain:@"ee.ria.digidoc.CryptoLib"
code:CryptoLibWrongKeyErrorCode
userInfo:@{NSLocalizedDescriptionKey: @"Wrong password"}];
}
return nil;
}
@end
16 changes: 14 additions & 2 deletions Modules/CryptoLib/Sources/CryptoObjCWrapper/Domain/Addressee.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import Foundation
public let validTo: Date?
@MainActor
@objc public var concatKDFAlgorithmURI: String
@objc public let lockLabel: String
@objc public let lockType: String

@objc public init(
data: Data,
Expand All @@ -39,7 +41,9 @@ import Foundation
serialNumber: String?,
certType: CertType,
validTo: Date?,
concatKDFAlgorithmURI: String = ""
concatKDFAlgorithmURI: String = "",
lockLabel: String = "",
lockType: String = ""
) {
self.identifier = cnVal
self.data = data
Expand All @@ -49,6 +53,8 @@ import Foundation
self.certType = certType
self.validTo = validTo
self.concatKDFAlgorithmURI = concatKDFAlgorithmURI
self.lockLabel = lockLabel
self.lockType = lockType
}

@objc public convenience init(data: Data, cnVal: String) {
Expand All @@ -69,7 +75,9 @@ import Foundation
certType: CertType,
validTo: Date?,
data: Data,
concatKDFAlgorithmURI: String = ""
concatKDFAlgorithmURI: String = "",
lockLabel: String = "",
lockType: String = ""
) {
let split = cnVal.split(separator: ",").map { String($0) }
if split.count >= 3 {
Expand All @@ -86,6 +94,8 @@ import Foundation
self.validTo = validTo
self.data = data
self.concatKDFAlgorithmURI = concatKDFAlgorithmURI
self.lockLabel = lockLabel
self.lockType = lockType
}

public init(cert: Data, x509: X509Certificate?) {
Expand All @@ -105,6 +115,8 @@ import Foundation
certType = x509?.certType() ?? .unknownType
validTo = x509?.notAfter
concatKDFAlgorithmURI = ""
lockLabel = ""
lockType = ""
}

convenience public init(cert: Data) {
Expand Down
Loading
Loading