-
Notifications
You must be signed in to change notification settings - Fork 12
Managing containers
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);
}];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);
}];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.
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);
}];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
})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
})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);
}];