Skip to content
This repository was archived by the owner on Apr 13, 2026. It is now read-only.

Managing containers

Marten Rebane edited this page Jun 8, 2021 · 9 revisions

Creating container

Before you can sign documents, you need to add them to a container.
Use createContainer method. Make sure you include container name and .asice extension in container path.

NSString *containerPath = @"path/to/container.asice";
NSString *filePaths = @[@"path/to/file"];
MoppLibContainerActions *sharedInstance = [MoppLibContainerActions sharedInstance];

[sharedInstance createContainerWithPath:containerPath withDataFilePaths:filePaths success:^(MoppLibContainer *container) {
  NSLog(@"Container created");
} failure:^(NSError *error) {
  NSLog(@"Failed to create container: %@", error);
}];

Adding and removing files

Files can be added to existing container or removed, but only if container has not been signed by anyone yet.

To add files to container use addDataFilesToContainer method:

NSString *containerPath = @"path/to/container.asice";
NSString *filePaths = @[@"path/to/file"];
MoppLibContainerActions *sharedInstance = [MoppLibContainerActions sharedInstance];

[sharedInstance addDataFilesToContainerWithPath:containerPath withDataFilePaths:filePaths success:^(MoppLibContainer *container) {
  NSLog(@"Files added");
} failure:^(NSError *error) {
  NSLog(@"Failed to add files: %@", error);
}];

To remove files from container use removeDataFileFromContainer method:

NSString *containerPath = @"path/to/container.asice";
MoppLibContainerActions *sharedInstance = [MoppLibContainerActions sharedInstance];

[sharedInstance removeDataFileFromContainerWithPath:containerPath atIndex:1 success:^(MoppLibContainer *container) {
  NSLog(@"File removed");
} failure:^(NSError *error) {
  NSLog(@"Failed to remove file: %@", error);
}];

Adding and removing signatures

Signatures can be added to containers only. Add all documents to container before signing it. Additional files can't be added to already signed container. If you still need to add files to signed container, you need to remove all signatures from it first and have all parties sign updated container again.

There are two options for signing - with Mobile-ID or with physical ID-card. You should let user choose between those two methods. MoppLib has separate methods for both cases.

Adding signature with a physical ID-card

For signing with a physical ID-card, user must have a card reader, that they can connect to their device.
MoppLib currently supports one card reader:

In order to add a signature to the container with ID-card or acquiring ID-card information you must first start discovering supported card readers by using startDiscoveringReaders method.
When finished working with ID-card related functionality, stopDiscoveringReaders method should be called.
Implement MoppLibCardReaderManagerDelegate protocol to receive status about the card reader state.

Set the delegate by calling MoppLibCardReaderManager's method setDelegate:

[[MoppLibCardReaderManager sharedInstance] setDelegate:self];

where 'self' being the object implementing MoppLibCardReaderManagerDelegate protocol.

ID-card related methods can be used only when state CardConnected has been returned from moppLibCardReaderStatusDidChange method.

To add signature with ID-card, use addSignature method:

NSString *containerPath = @"path/to/container.asice";
MoppLibContainerActions *sharedInstance = [MoppLibContainerActions sharedInstance];

[sharedInstance addSignature:containerPath controller:self success:^(MoppLibContainer *container, BOOL signatureWasAdded) {
  // Adding signature complete
} failure:^(NSError *error) {
  NSLog(@"Failed to add signature: %@", error);
}];

Adding signature with Mobile-ID

For signing with Mobile-ID, you must provide some data about the person that is providing signature. ID code and phone number are required to verify, that SIM card is allowed to give signature.

Mobile-ID signing is in SkSigningLib framework and uses Mobile-ID REST API. SkSigningLib framework is written in Swift programming language.

Mobile-ID Wiki documentation

To get the certificate use getCertificate method:

func getCertificate(baseUrl: String, requestParameters: CertificateRequestParameters, trustedCertificates: [String]?, completionHandler: @escaping (Result<CertificateResponse, SigningError>) -> Void)
import SkSigningLib

let baseUrl: String = "https://dd-mid.ria.ee/mid-api"
let uuid: String = "00000000-0000-0000-0000-000000000000"
let relyingPartyName: String = "My Service"
let phoneNumber = "+37255555555"
let nationalIdentityNumber = "47101010033"
let trustedCertificates: [String] = [] // For certificate pinning

RequestSignature.shared.getCertificate(baseUrl: baseUrl, requestParameters: CertificateRequestParameters(relyingPartyUUID: uuid, relyingPartyName: relyingPartyName, phoneNumber: phoneNumber, nationalIdentityNumber: nationalIdentityNumber), trustedCertificates: trustedCertificates) { (result) in
    switch result {
    case .success(let response):
        // Certificate received successfully
    case .failure(let error):
        // Failed with error
    }
}

After getting the certificate, you need to get the session ID. Use the getSession method:

func getSession(baseUrl: String, requestParameters: SessionRequestParameters, trustedCertificates: [String]?, completionHandler: @escaping (Result<SessionResponse, SigningError>) -> Void)
import SkSigningLib

let baseUrl: String = "https://dd-mid.ria.ee/mid-api"
let relyingPartyName: String = "My Service"
let uuid: String = "00000000-0000-0000-0000-000000000000"
let phoneNumber = "+37255555555"
let nationalIdentityNumber = "47101010033"
let hash: String = "aGFzaA=="
let hashType: String = "SHA256" // Eg. SHA256, SHA512
let language: String = "EST" // EST, ENG, RUS
let trustedCertificates: [String] = []
let displayText: String = "Sign with My Service"
let displayTextFormat: String = "GSM-7" // GSM-7 or UCS-2

RequestSession.shared.getSession(baseUrl: baseUrl, requestParameters: SessionRequestParameters(relyingPartyName: relyingPartyName, relyingPartyUUID: uuid, phoneNumber: phoneNumber, nationalIdentityNumber: nationalIdentityNumber, hash: hash, hashType: hashType, language: language, displayText: displayText, displayTextFormat: displayTextFormat), trustedCertificates: trustedCertificates) { (sessionResult) in
    switch sessionResult {
    case .success(let response):
        // Session ID received successfully
    case .failure(let sessionError):
        // Failed with error
    }
}

NOTE: To get the hash, use the "prepareSignature" method in MoppLib framework:

let hash: String = MoppLibManager.prepareSignature(cert, containerPath: containerPath)

You need to display challenge ID in your application, so user can verify, that signature is given with correct device.

After getting the session ID, you need to poll the session status. This is method is used to poll as long as Mobile-ID signing service responds. Use the getSessionStatus method:

func getSessionStatus(baseUrl: String, process: PollingProcess, requestParameters: SessionStatusRequestParameters, trustedCertificates: [String]?, completionHandler: @escaping (Result<SessionStatusResponse, SigningError>) -> Void)
import SkSigningLib

let baseUrl: String = "https://dd-mid.ria.ee/mid-api"
let process: PollingProcess = PollingProcess.SIGNING
let sessionId: String = "sessionId" // From "getSession" completionHandler
let timeoutMs: Int? = 5000 // Poll every 5 seconds
let trustedCertificates: [String] = []

RequestSession.shared.getSessionStatus(baseUrl: baseUrl, process: process, requestParameters: SessionStatusRequestParameters(sessionId: sessionId, timeoutMs: timeoutMs), trustedCertificates: trustedCertificates) { (sessionStatusResult: Result<SessionStatusResponse, SigningError>) in
    switch sessionStatusResult {
    case .success(let sessionStatus):
        timer.invalidate()
        // Successfully retrieved result
    case .failure(let sessionError):
        timer.invalidate()
        // Failed with error
    }
}

Obtaining signature can take some time. It is up to you if you want to block user actions until everything is finished, but it is not required. If you want to allow user to interact with application, make sure completion and status blocks are not deallocated before everything is completed.

Success callback will be called with updated container when signature is successfully added. After that, you don't need to expect any more block calls from this method. Alternatively, failure block can be called with error. That also indicates, that method has finished working and no further calls will be made.

To validate signature, use the isSignatureValid method in MoppLib framework:

+ (void)isSignatureValid:(NSString *)cert signatureValue:(NSString *)signatureValue success:(BoolBlock)success failure:(FailureBlock)failure;
let cert: String = "Y2VydA==" // Cert from "getCertificate" method completionHandler
let signatureValue: String = "c2lnbmF0dXJl" // Signature value from "getSessionStatus" method completionHandler

MoppLibManager.isSignatureValid(cert, signatureValue: signatureValue, success: { (_) in
    // Signature successfully validated
}, failure: { (error: Error?) in
    // Failed with error
})

Adding signature with Smart-ID

For signing with Smart-ID, you must provide some data about the person that is providing signature. Country and ID code are required to sign with Smart-ID.

Smart-ID signing is in SkSigningLib framework and uses Smart-ID REST API. SkSigningLib framework is written in Swift programming language.

Smart-ID Wiki documentation

To get the certificate use getCertificate method:

func getCertificate(baseUrl: String, country: String, nationalIdentityNumber: String, requestParameters: SIDCertificateRequestParameters, trustedCertificates: [String]?, completionHandler: @escaping (Result<SIDSessionResponse, SigningError>) -> Void)
import SkSigningLib

let baseUrl: String = "https://rp-api.smart-id.com/v1"
let uuid: String = "00000000-0000-0000-000000000000"
let certBundle: [String] = [] // For certificate pinning
let backgroundTask = UIApplication.shared.beginBackgroundTask(withName: "Smart-ID")
let certparams = SIDCertificateRequestParameters(relyingPartyName: "My Service", relyingPartyUUID: uuid)
let errorHandler: (SigningError, String) -> Void = { error, log in
    UIApplication.shared.endBackgroundTask(backgroundTask)
}

SIDRequest.shared.getCertificate(baseUrl: baseUrl, country: country, nationalIdentityNumber: nationalIdentityNumber, requestParameters: requestParameters, trustedCertificates: trustedCertificates) { result in
    switch result {
    case .success(let response):
        self.getSessionStatus(baseUrl: baseUrl, sessionId: response.sessionID, trustedCertificates: trustedCertificates, notification: self.selectAccount) { result in
            switch result {
            case .success(let sessionStatus):
                // Successful result
            case .failure(let error):
                // Failed with error
            }
        }
    case .failure(let error):
        // Failed with error
    }
}

After getting the certificate, you need to get the session ID. Use the getSignature method:

func getSignature(baseUrl: String, documentNumber: String, requestParameters: SIDSignatureRequestParameters, trustedCertificates: [String]?, completionHandler: @escaping (Result<SIDSessionResponse, SigningError>) -> Void)
import SkSigningLib

let baseUrl: String = "https://rp-api.smart-id.com/v1"
let documentNumber: String = "PNOEE-372" // Document number from "getCertificate" completionHandler
let relyingPartyName: String = "My Service"
let uuid: String = "00000000-0000-0000-0000-000000000000"
let hash: String = "aGFzaA=="
let hashType: String = "SHA256" // Eg. SHA256, SHA512
let displayText: String = "Sign with My Service"

let signparams = SIDSignatureRequestParameters(relyingPartyName: relyingPartyName, relyingPartyUUID: uuid, hash: hash, hashType: hashType, displayText: displayText, vcChoice: true)

SIDRequest.shared.getSignature(baseUrl: baseUrl, documentNumber: documentNumber, requestParameters: requestParameters, trustedCertificates: trustedCertificates) { result in
    switch result {
    case .success(let response):
        // Successful response
    case .failure(let error):
        // Failed with error
    }
}

NOTE: To get the hash, use the "prepareSignature" method in MoppLib framework:

let hash: String = MoppLibManager.prepareSignature(cert, containerPath: containerPath)

You need to display challenge ID in your application, so user can verify, that signature is given with correct device.

After getting the session ID, you need to poll the session status. This is method is used to poll as long as Smart-ID signing service responds. Use the getSessionStatus method:

func getSessionStatus(baseUrl: String, sessionId: String, timeoutMs: Int?, trustedCertificates: [String]?, completionHandler: @escaping (Result<SIDSessionStatusResponse, SigningError>) -> Void)
let baseUrl: String = "https://rp-api.smart-id.com/v1"
let sessionId: String = "sessionId" // From "getSignature" completionHandler
let timeoutMs: Int? = 5000
let trustedCertificates: [String] = []

SIDRequest.shared.getSessionStatus(baseUrl: baseUrl, sessionId: sessionId, timeoutMs: timeoutMs, trustedCertificates: trustedCertificates) { result in
    switch result {
    case .success(let sessionStatus):
        switch sessionStatus.state {
        case .RUNNING:
            // Session status state is "RUNNING""
        case .COMPLETE:
            // Session status state is "COMPLETED"
            // Session status result may include errors
        }
    case .failure(let error):
        // Failed with error
    }
}

To validate signature, use the isSignatureValid method in MoppLib framework:

+ (void)isSignatureValid:(NSString *)cert signatureValue:(NSString *)signatureValue success:(BoolBlock)success failure:(FailureBlock)failure;
let cert: String = "Y2VydA==" // Cert from "getCertificate" method completionHandler
let signatureValue: String = "c2lnbmF0dXJl" // Signature value from "getSessionStatus" method completionHandler

MoppLibManager.isSignatureValid(cert, signatureValue: signatureValue, success: { (_) in
    // Signature successfully validated
}, failure: { (error: Error?) in
    // Failed with error
})

Container contents

MoppLibContainer object gives you basic information about contents of container. If you don't have MoppLibContainer object, you can let MoppLib to create it with method openContainer like this:

NSString *containerPath = @"path/to/container.asice";
MoppLibContainerActions *sharedInstance = [MoppLibContainerActions sharedInstance];

[sharedInstance openContainerWithPath:containerPath success:^(MoppLibContainer *container) {
  // Got container
} failure:^(NSError *error) {
  NSLog(@"Failed to get container: %@", error);
}];

MoppLibContainer will give you a list of signatures and file attached to container. If you need to access one of the files in it, you need to export it somewhere where your application has access.

To extract data file from container and save it use saveDataFile method:

NSString *containerPath = @"path/to/container.asice";
NSString *filePath = @"path/to/file/in/container";
NSString *savePath = @"path/where/to/save";
MoppLibContainerActions *sharedInstance = [MoppLibContainerActions sharedInstance];

[sharedInstance container:containerPath saveDataFile:filePath to:savePath success:^{
  // File was saved
} failure:^(NSError *error) {
  NSLog(@"Failed to save: %@", error);
}];

Clone this wiki locally