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
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

@interface DigiDocContainerWrapper ()
+ (DigiDocSignatureStatus)determineSignatureStatus:(int)status;
+ (DigiDocSignatureWarning)determineSignatureWarning:(digidoc::Exception::ExceptionCode)code;
@end

struct DigiDocContainerOpenCB: public digidoc::ContainerOpenCB {
Expand Down Expand Up @@ -148,6 +149,25 @@ + (DigiDocSignatureStatus)determineSignatureStatus:(int)status {
}
}

+ (DigiDocSignatureWarning)determineSignatureWarning:(digidoc::Exception::ExceptionCode)code {
switch (code) {
case digidoc::Exception::ReferenceDigestWeak:
return DigiDocSignatureWarningReferenceDigestWeak;
case digidoc::Exception::SignatureDigestWeak:
return DigiDocSignatureWarningSignatureDigestWeak;
case digidoc::Exception::DataFileNameSpaceWarning:
return DigiDocSignatureWarningDataFileNameSpace;
case digidoc::Exception::IssuerNameSpaceWarning:
return DigiDocSignatureWarningIssuerNameSpace;
case digidoc::Exception::ProducedATLateWarning:
return DigiDocSignatureWarningProducedATLate;
case digidoc::Exception::MimeTypeWarning:
return DigiDocSignatureWarningMimeType;
default:
return DigiDocSignatureWarningOther;
}
}

+ (DigiDocSignature *)getSignature:(digidoc::Signature *)signature pos:(int)pos mediaType:(const std::string&)mediaType dataFileCount:(NSInteger)dataFileCount {

digidoc::X509Cert signingCert = signature->signingCertificate();
Expand Down Expand Up @@ -209,7 +229,14 @@ + (DigiDocSignature *)getSignature:(digidoc::Signature *)signature pos:(int)pos
digidoc::Signature::Validator::Status status = validator.status();
digiDocSignature.diagnosticsInfo = [NSString stringWithUTF8String:validator.diagnostics().c_str()];
digiDocSignature.status = [DigiDocContainerWrapper determineSignatureStatus:status];
digiDocSignature.diagnosticsInfo = [NSString stringWithUTF8String:validator.diagnostics().c_str()];

std::vector<digidoc::Exception::ExceptionCode> validatorWarnings = validator.warnings();
NSMutableArray<NSNumber *> *warnings = [NSMutableArray arrayWithCapacity:validatorWarnings.size()];
for (digidoc::Exception::ExceptionCode warning : validatorWarnings) {
[warnings addObject:@([DigiDocContainerWrapper determineSignatureWarning:warning])];
}
digiDocSignature.warnings = warnings;

return digiDocSignature;

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@

#import <Foundation/Foundation.h>

typedef NS_ENUM(int, DigiDocSignatureWarning) {
DigiDocSignatureWarningReferenceDigestWeak,
DigiDocSignatureWarningSignatureDigestWeak,
DigiDocSignatureWarningDataFileNameSpace,
DigiDocSignatureWarningIssuerNameSpace,
DigiDocSignatureWarningProducedATLate,
DigiDocSignatureWarningMimeType,
DigiDocSignatureWarningOther
};

typedef NS_ENUM(int, DigiDocSignatureStatus) {
Valid,
Warning,
Expand Down Expand Up @@ -51,6 +61,7 @@ typedef NS_ENUM(int, DigiDocSignatureStatus) {

@property (nonatomic, assign) DigiDocSignatureStatus status;
@property (nonatomic, strong) NSString *diagnosticsInfo;
@property (nonatomic, strong) NSArray<NSNumber *> *warnings;

@property (nonatomic, strong) NSString *archiveTimestampTime;
@property (nonatomic, strong) NSData *archiveTimestampCert;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,25 @@ public actor ContainerWrapper: ContainerWrapperProtocol, Loggable {
}
}

private static func signatureWarningToDigiDocWarning(_ warning: DigiDocSignatureWarning) -> SignatureWarning {
switch warning {
case .referenceDigestWeak:
return .referenceDigestWeak
case .signatureDigestWeak:
return .signatureDigestWeak
case .dataFileNameSpace:
return .dataFileNameSpace
case .issuerNameSpace:
return .issuerNameSpace
case .producedATLate:
return .producedATLate
case .mimeType:
return .mimeType
default:
return .other
}
}

@discardableResult
private func updateContainer(
datafiles: [DataFileWrapper],
Expand Down Expand Up @@ -414,7 +433,12 @@ public actor ContainerWrapper: ContainerWrapperProtocol, Loggable {
messageImprint: signature.messageImprint,
diagnosticsInfo: signature.diagnosticsInfo,
archiveTimestampTime: signature.archiveTimestampTime,
archiveTimestampCert: signature.archiveTimestampCert
archiveTimestampCert: signature.archiveTimestampCert,
warnings: signature.warnings?.map { warning in
signatureWarningToDigiDocWarning(
DigiDocSignatureWarning(rawValue: warning.int32Value) ?? .other
)
} ?? []
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@

import Foundation

public enum SignatureWarning: Sendable, Hashable {
case referenceDigestWeak
case signatureDigestWeak
case dataFileNameSpace
case issuerNameSpace
case producedATLate
case mimeType
case other
}

public enum SignatureStatus: String, Sendable {
case valid
case warning
Expand Down Expand Up @@ -55,6 +65,17 @@ public struct SignatureWrapper: Sendable, Identifiable, Hashable {
public var archiveTimestampTime: String
public var archiveTimestampCert: Data

private static let weakDigestWarnings: Set<SignatureWarning> = [
.referenceDigestWeak,
.signatureDigestWeak
]

public var warnings: [SignatureWarning]

public var hasOnlyWeakDigestWarnings: Bool {
!warnings.isEmpty && warnings.allSatisfy { SignatureWrapper.weakDigestWarnings.contains($0) }
}

public var isLTAExtended: Bool {
!archiveTimestampCert.isEmpty
}
Expand All @@ -80,7 +101,8 @@ public struct SignatureWrapper: Sendable, Identifiable, Hashable {
messageImprint: Data,
diagnosticsInfo: String,
archiveTimestampTime: String = "",
archiveTimestampCert: Data = Data()) {
archiveTimestampCert: Data = Data(),
warnings: [SignatureWarning] = []) {
self.pos = pos
self.signingCert = signingCert
self.timestampCert = timestampCert
Expand All @@ -103,5 +125,6 @@ public struct SignatureWrapper: Sendable, Identifiable, Hashable {
self.diagnosticsInfo = diagnosticsInfo
self.archiveTimestampTime = archiveTimestampTime
self.archiveTimestampCert = archiveTimestampCert
self.warnings = warnings
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public actor SignedContainer: SignedContainerProtocol, Loggable {

private static let signedContainerLogTag: String = "SignedContainer"

private static let weakDigestExemptionTime = "2018-07-01T00:00:00Z"

private var containerFile: URL?
private let isExistingContainer: Bool
private let container: ContainerWrapperProtocol
Expand Down Expand Up @@ -55,7 +57,24 @@ public actor SignedContainer: SignedContainerProtocol, Loggable {
}

public func getSignatures() async -> [SignatureWrapper] {
return await container.getSignatures()
let signatures = await container.getSignatures()

guard isExemptFromWeakDigestWarning else { return signatures }

return signatures.map { signature in
guard signature.status == .warning, signature.hasOnlyWeakDigestWarnings else { return signature }

var validSignature = signature
validSignature.status = .valid
return validSignature
}
}

private var isExemptFromWeakDigestWarning: Bool {
guard let trustedSigningTime = timestamps.first?.trustedSigningTime,
!trustedSigningTime.isEmpty else { return false }

return trustedSigningTime < SignedContainer.weakDigestExemptionTime
}

public func getTimestamps() async -> [SignatureWrapper] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,97 @@ final class SignedContainerTests {
#expect(timestamps.first == timestamp)
}

private func containerTimestamped(at trustedSigningTime: String) -> SignedContainer {
SignedContainer(
containerFile: URL(fileURLWithPath: "/mock/path/container.asics"),
isExistingContainer: true,
container: mockContainerWrapper,
timestamps: [MockSignatureWrapper.mockSignatureWrapper(trustedSigningTime: trustedSigningTime)],
fileManager: mockFileManager,
containerUtil: mockContainerUtil
)
}

@Test
func getSignatures_dropWeakDigestWarningWhenTimestampedBefore2018() async {
mockContainerWrapper.getSignaturesHandler = {
[MockSignatureWrapper.mockSignatureWrapper(status: .warning, warnings: [.referenceDigestWeak])]
}

let signatures = await containerTimestamped(at: "2016-05-11T10:20:30Z").getSignatures()

#expect(signatures.first?.status == .valid)
}

@Test
func getSignatures_keepWeakDigestWarningWhenTimestampedAfter2018() async {
mockContainerWrapper.getSignaturesHandler = {
[MockSignatureWrapper.mockSignatureWrapper(status: .warning, warnings: [.referenceDigestWeak])]
}

let signatures = await containerTimestamped(at: "2019-05-11T10:20:30Z").getSignatures()

#expect(signatures.first?.status == .warning)
}

@Test
func getSignatures_keepWeakDigestWarningAtExemptionTime() async {
mockContainerWrapper.getSignaturesHandler = {
[MockSignatureWrapper.mockSignatureWrapper(status: .warning, warnings: [.signatureDigestWeak])]
}

let signatures = await containerTimestamped(at: "2018-07-01T00:00:00Z").getSignatures()

#expect(signatures.first?.status == .warning)
}

@Test
func getSignatures_keepOtherWarningsWhenTimestampedBefore2018() async {
mockContainerWrapper.getSignaturesHandler = {
[MockSignatureWrapper.mockSignatureWrapper(
status: .warning,
warnings: [.referenceDigestWeak, .dataFileNameSpace]
)]
}

let signatures = await containerTimestamped(at: "2016-05-11T10:20:30Z").getSignatures()

#expect(signatures.first?.status == .warning)
}

@Test
func getSignatures_keepWarningWhenValidatorReportsNoWarningCodes() async {
mockContainerWrapper.getSignaturesHandler = {
[MockSignatureWrapper.mockSignatureWrapper(status: .warning, warnings: [])]
}

let signatures = await containerTimestamped(at: "2016-05-11T10:20:30Z").getSignatures()

#expect(signatures.first?.status == .warning)
}

@Test
func getSignatures_keepWeakDigestWarningWhenContainerIsNotTimestamped() async {
mockContainerWrapper.getSignaturesHandler = {
[MockSignatureWrapper.mockSignatureWrapper(status: .warning, warnings: [.referenceDigestWeak])]
}

let signatures = await signedContainer.getSignatures()

#expect(signatures.first?.status == .warning)
}

@Test
func getSignatures_leaveInvalidSignatureUntouchedWhenTimestampedBefore2018() async {
mockContainerWrapper.getSignaturesHandler = {
[MockSignatureWrapper.mockSignatureWrapper(status: .invalid, warnings: [.referenceDigestWeak])]
}

let signatures = await containerTimestamped(at: "2016-05-11T10:20:30Z").getSignatures()

#expect(signatures.first?.status == .invalid)
}

@Test
func isExistingContainer_returnTrue() async {
let existingSignedContainer = SignedContainer(
Expand Down
6 changes: 4 additions & 2 deletions Modules/LibdigidocLib/Tests/Mocks/MockSignatureWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ public struct MockSignatureWrapper {
status: SignatureStatus = .valid,
format: String = "BES/time-stamp",
messageImprint: Data = Data(),
diagnosticsInfo: String = ""
diagnosticsInfo: String = "",
warnings: [SignatureWarning] = []
) -> SignatureWrapper {
SignatureWrapper(
pos: pos,
Expand All @@ -63,7 +64,8 @@ public struct MockSignatureWrapper {
status: status,
format: format,
messageImprint: messageImprint,
diagnosticsInfo: diagnosticsInfo
diagnosticsInfo: diagnosticsInfo,
warnings: warnings
)
}
}
11 changes: 8 additions & 3 deletions RIADigiDoc/ViewModel/SigningViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -498,11 +498,15 @@ class SigningViewModel: SigningViewModelProtocol, Loggable {
let isEmptyFileInContainer = await signedContainer?.isEmptyFileInContainer() ?? false

return signedContainer != nil &&
(!Constants.MimeType.UnsignableContainers.contains(mimetype)) &&
(!Constants.Extension.UnsignableContainerExtensions.contains((name as NSString).pathExtension)) &&
!isUnsignableContainer(mimetype: mimetype, name: name) &&
!isNestedContainer && !isEmptyFileInContainer && !isCadesContainer && !isXadesContainer
}

private func isUnsignableContainer(mimetype: String, name: String) -> Bool {
return Constants.MimeType.UnsignableContainers.contains(mimetype.lowercased()) ||
Constants.Extension.UnsignableContainerExtensions.contains((name as NSString).pathExtension.lowercased())
}

func isEncryptButtonShown(
signedContainer: SignedContainerProtocol?,
isNestedContainer: Bool,
Expand All @@ -513,7 +517,8 @@ class SigningViewModel: SigningViewModelProtocol, Loggable {
}

func isSignatureRemoveButtonShown() -> Bool {
return !isNestedContainer() && !isCadesContainer && !isXadesContainer
return !isNestedContainer() && !isCadesContainer && !isXadesContainer &&
!isUnsignableContainer(mimetype: containerMimetype, name: containerName)
}

func isTimestampedContainer() async -> Bool {
Expand Down
Loading
Loading