Services
Session Service
An instance of SessionService can be retrieved directly after SDK initialisation using the Rss.getSessionService API. This API takes an OIDC token response as a parameter so that it is initialised for a specific user, uniquely identified by the sub attribute present in the id_token.
The provided OIDC token response must contain at least the following attributes in order to be validated by the server.
tokenTypeaccess_tokenid_token
As the token must remain valid for each request to the DssService, obtain a new SessionService with the updated token response after a token refresh. On iOS, getSessionService(token:) takes the JSON-encoded response and returns an optional service. Obtain fresh RssService and DssService wrappers from it; existing wrappers retain their original token. Check the session validity before using the new wrappers and reopen the session when required.
Establishing a session
Before using any of the RSS Mobile SDK services, a session must be established with the Mobile Gateway.
This session can be opened using the openSession API, which takes a secret as a parameter.
This is used to encrypt a shared secret between the RSS Mobile SDK and the Mobile Gateway.
This secret must not be hardcoded in the app but should be securely provided to the RSS Mobile SDK.
There are multiple ways to manage this secret, some of them are listed below:
- Raw or derived PIN code obtained from user input.
- Random secret stored in operating system keychain / keystore, preferably secured with user authentication
- Symmetric encryption key securely exchanged from a third-party backend service
The openSession API internally handles whether the user needs to be enrolled (first time) or an if a session from a previous enrollment needs to be opened.
Once the session is established, all available services can be used.
The secret must remain the same from the first call to openSession and all subsequent calls until user is disenrolled.
Entering an incorrect secret multiple times when opening a session will result in the account being locked by the server.
Disenrolling the user
The disenroll API can be used to clear all information about the user on the client side.
After calling it, a re-enrollment is required to use the services again.
This API doesn't call the Mobile Gateway, so the user is still considered to be enrolled in the backend.
If the user has been disenrolled on the server, a specific error will be thrown the next time a session is attempted to be established.
Error handling
The list of following exception may happen while opening a session
| Error | Description | Android | iOS |
|---|---|---|---|
| Session error | Session with server is no more available, a new one must be established. | ch.sysmosoft.sense.common.server.exception.SessionException | ch.sysmosoft.sense.framework.ErrorDomain Code = 407 |
| Access denied error | The app is not authorized to open a session, most likely because the app has not been authorized in the security group to which the user belongs. | ch.sysmosoft.sense.common.server.exception.AccessDeniedException | ch.sysmosoft.sense.framework.ErrorDomain Code = 404 |
| User authentication error | Failed to authenticate user with the provided secret. | ch.sysmosoft.sense.common.server.exception.AuthenticationException | ch.sysmosoft.sense.framework.ErrorDomain Code = 401 |
| Account locked error | Account has been locked server-side due to several authentication attempts or by a manual operation in the Mobile Gateway. | ch.sysmosoft.sense.common.server.exception.AccountLockedException | ch.sysmosoft.sense.framework.ErrorDomain Code=403 |
| User disenrolled error | User is no longer enrolled server-side and has been disenrolled client-side as well. | ch.sysmosoft.sense.client.exception.UserDisenrolledException | ch.sysmosoft.sense.framework.ErrorDomain Code = 102 |
| Server error | Unexpected server error | ch.sysmosoft.sense.common.server.exception.ServerException | ch.sysmosoft.sense.framework.ErrorDomain Codes range = 500/503 |
Rss Service
This service holds the various services provided by the RSS Mobile SDK:
- Dynamic configuration properties
- Push notification registration APIs
- Dss Service
- SmartContract service
An instance of the RssService can be retrieved using the SessionService.getRssService API after the session is established.
On iOS, first check session.isSessionValid(), then unwrap session.getRssService(). Calling getRssService() with an invalid session triggers an assertion in debug builds. getDssService() only retrieves a wrapper; it does not revalidate the session. Handle session errors from subsequent operations as well.
Dynamic configuration properties
The server can provide dynamic configuration for an app. This feature can be useful to change
the behaviour and configuration without having to update the mobile app. The getConfigProperties API allows you to retrieve the properties.
The values have must be cast to the expected types (e.g String, int, etc.). Complex data objects can be casted to a Map object.
Properties are statically defined on the server in the deployment configuration file and can vary depending on the bundle id and the operating system.
Get Firebase configuration
Available on Android only, this API allows the app integrating the SDK to retrieve the Firebase options that have been configured server-side and dynamically configure a FirebaseApp instance.
This feature is optional and not mandatory if Firebase is configured at compile time using a local configuration as recommended by Google.
Register Push Notification Token
To receive signing notifications, register the device's notification token with the server. Android uses registerPushNotificationToken; iOS uses RssService.registerRemoteNotificationToken(_:), which accepts Data and returns a Bool.
On Android, the Firebase token must be retrieved using the Firebase APIs and provided to the RSS Mobile SDK.
On iOS, obtain the APNs token through the application's notification flow. Register it once both the token and a valid session are available, and check RssService.isAvailable() before registration. See the iOS example.
The Mobile Gateway may remove the client token if multiple notification delivery failure occur. We recommend sending the notification token after each session establishment to ensure that is always up-to-date on the server.
DSS Service
An instance of this service can be obtained from the RssService once a session is established with the Mobile Gateway.
This service is used for interactions with the DSS server component which allow to manage the signature profiles available for the user and unlock signature requests for different jurisdiction (e.g ZertES, eIDAS) and signature types (e.g QES, AES, SES).
Verifying device compliance
The DSS Service requires a device with a biometric hardware available and correctly configured in the OS settings.
The Rss.isDeviceCompliant API allows the application to verify the device status. The Android results are:
DeviceCompliance.Compliant: Device is compliant and correctly configured to use the SDK.DeviceCompliance.ErrNoHardware: Required biometric hardware is unavailable. SDK cannot be used on the device.DeviceCompliance.ErrBiometricNotEnrolled: The user does not have biometrics enrolled. User must configure biometrics in the system settings.
On iOS, the API returns Rss.RssDeviceCompliance:
| Result | Meaning |
|---|---|
.deviceCompliant | Device meets the biometric prerequisites. |
.errNoHardware | Required hardware is unavailable. |
.errPinCodeNotSet | A device passcode is not configured. |
.errNoBiometricSet | Biometric authentication cannot currently be evaluated, for example because no biometrics are enrolled. |
Only begin DSS activation or signing when the device is compliant.
Managing DSS Profiles
A DSS profile is a signature profile characterised by the following properties:
id: An identifier of the profile which is used as identification in all requestsname: A human-readable name of the profile (not translated)- The
jurisdiction: Jurisdiction applicable to the profileZERTES: Swiss regulation for Electronic SignaturesEIDAS: EU regulation for Electronic SignaturesNONE: The profile is not applicable to a specific regulation
signatureLevel: Signature level applicable to the profileQES: Qualified Electronic SignatureAES: Advanced Electronic SignatureSES: Simple Electronic Signature
registrationStatus: Registration status of the profile for the current deviceREGISTERED: The profile can be used for signatureNOT_REGISTERED: The profile is not registered yetREGISTERED_ON_OTHER_DEVICE: The profile is registered on a different device. It must be disabled before it can be enabled on the current device
identificationStatus: Identification status of the profileVALID: Identification is current and validIDENTIFICATION_REQUIRED: Identification is required to use the profileIDENTIFICATION_RENEWAL_REQUIRED: Identification renewal is required to use the profile
The list of available profiles can be retrieved with the API getAvailableProfiles, which return all the profiles the user is allowed to register and use for signing.
Additionally, the getAllProfiles API retrieves all profiles configured for the user's domain, including profiles whose identificationStatus does not yet allow activation.
In iOS 2.6.0, the Swift model uses identifier for the profile ID and signatureJurisdiction for its jurisdiction. The remaining properties include name, signatureLevel, registrationStatus and identificationStatus. getProfile(_:errorBlock:) looks up the profile through getAllProfiles; handle a missing result even when the error is nil.
It's possible to retrieve information and registration status about a specific profile using API getProfile.
Activating a profile
When a profile is activated, a key pair is generated in the device's secure hardware. The private key remains on the device; the public key is registered on the server. To do so, a registration token needs to be signed and requires biometric authentication of the user. The SDK handles all the complexity and will simply prompt the user to authenticate when the activateProfile API is called.
A profile can be registered only on one device at a time. In case the registration status of the profile is REGISTERED_ON_OTHER_DEVICE, it must be disabled first (see next section).
Disabling a profile
When a profile is not needed anymore or if it needs to be disabled from a different device, the disableProfile API has to be called.
This API does not need user authentication and will permanently remove the key registration server-side and client-side.
Checking Biometric Integrity
The isBiometricIntegrityValid API allows developers to verify if the biometric state (like fingerprints or Face ID) remains consistent with the state when the profile was originally registered.
Use this check before reusing an activated profile, and also handle errors from the subsequent signing operation.
iOS: isBiometricIntegrityValid(_:) compares the current biometric domain state with the state saved for the profile. It returns false when biometrics are unavailable or the saved state is missing or different. This check does not prove that a private-key operation will succeed. Keys are protected with BiometryCurrentSet; do not rely on removing an added fingerprint to restore an invalidated key. Handle failures from activation and signing, refresh the profile state, and have the application guide the user through disabling and reactivating the profile when the key has been invalidated.
Push notification for profile activation
When a third-party system requests a signature for a profile that has not been activated by the user yet, a silent push notification is sent to the device.
The app should initiate the profile activation flow to notify the user of the pending request.
The notification contains the following attributes:
type: Constantregistrationindicating the type of the notificationusername: Username of the user (subattribute of the idToken)dssProfileId: Unique identifier of the DSS Profile
Example of Android Firebase notification payload
{
"from":224813428171,
"notification":null,
"sentTime":1683704635941,
"data":{
"dssProfileId":"PROFILE-X",
"server-timestamp":1683702514164,
"type":"registration",
"username":"UhOb5ZUX21c9KKifNImBvZj8Zd337miNAcyfi35xlwA="
}
}Example of iOS APNS notification payload
{
"username":"UhOb5ZUX21c9KKifNImBvZj8Zd337miNAcyfi35xlwA=",
"aps":{
"content-available":1
},
"dssProfileId":"PROFILE-X",
"type":"registration",
"server-timestamp":1683702514164
}The user will need to trigger a new signature request from the third-party system after the profile is activated.
Retrieving and sign pending requests
A pending request represents a signing request. Its document fields depend on the SDK version. Versions using the single-digest model expose the following properties:
requestId: A unique identifier representing the pending requestdigestId: A unique identifier representing the digestdssProfileId: Identifier of the DSS ProfiledocumentHash: Content to be signeddocumentMetaData: Additional meta data for the pending requestdocumentName: Name of the document to be signeddocumentDescription: Name of the sender of the documenttransactionNumber: Human-readable representation of the requestId
The list of pending requests can be retrieved with the getPendingRequests API, which returns all pending requests for a given profile.
In iOS 2.6.0, a PendingRequest represents a batch and has requestId, dssProfileId, digests, documentMetaData and transactionNumber. Each element in digests contains digestId and documentHash. Read transactionNumber directly from the pending request; use getDocumentName() and getDocumentDescription() for optional display metadata. Pass the complete PendingRequest to signPendingRequest(_:errorBlock:) so that all its digests are processed.
It's possible to retrieve information about a specific request using the getPendingRequest API. A pending request is valid only for a short period of time (usually 90 seconds) and disappears after expiration. On iOS, the lookup can return both a nil request and a nil error when no matching request is found; treat this as an absent or expired request.
When a pending request is retrieved, the user must be prompted to sign and unlock the signing request.
In the case the signature request has been initiated from a different application, the transaction number shall be displayed to the user to identify and confirm the request being currently signed.
The signature can be unlocked by calling the signPendingRequest API, which requires a user biometric's authentication.
Push notification for signature request
When a third-party system requests a signature for a profile that has been already activated by the user, a silent push notification is sent to the device.
The notification contains the following attributes:
type: Constantkeyunlockindicating the type of the notificationrequestId: Unique identifier of the pending requestusername: Username of the user (subattribute of the idToken)dssProfileId: Unique identifier of the DSS Profile
Example of Android Firebase notification payload
{
"from":224813428171,
"notification":null,
"sentTime":1683704393174,
"data":{
"dssProfileId":"PROFILE-X",
"requestId":"4ae6719b-fb20-462b-a7b1-b60b81f8919c",
"server-timestamp":1683704392856,
"type":"keyunlock",
"username":"UhOb5ZUX21c9KKifNImBvZj8Zd337miNAcyfi35xlwA="
}
}Example of iOS APNS notification payload
{
"type":"keyunlock",
"server-timestamp":1683704392856,
"dssProfileId":"PROFILE-X",
"requestId":"4ae6719b-fb20-462b-a7b1-b60b81f8919c",
"aps":{
"content-available":1
},
"username":"UhOb5ZUX21c9KKifNImBvZj8Zd337miNAcyfi35xlwA="
}This notification might be received by a device that is not registered to the DSS. It is strongly advised to retrieve the registrationStatus of the profile and verify that the registrationStatus does not match REGISTERED_ON_OTHER_DEVICE before unlocking the signature.
Error handling
The following errors may be raised using DssService APIs.
| Error | Description | Android | iOS |
|---|---|---|---|
| Session error | Session with server is not more available, a new one must be established | ch.sysmosoft.sense.common.server.exception.SessionException | ch.sysmosoft.sense.framework.ErrorDomain Code = 407 |
| DSS error | Error during operation with the DSS, refer to the code provided for reason (see next section) | com.swisssign.rss.sdk.mobile.exception.DssException | com.swisssign.rss.sdk.DssException |
| Authentication error | Error while authenticating user with biometric data | ch.sysmosoft.sense.common.server.exception.AuthenticationException | com.apple.LocalAuthentication References |
| Key invalidation error | Key permanently invalidated by OS, profile needs to be activated again | android.security.keystore.KeyPermanentlyInvalidatedException | May surface through NSOSStatusErrorDomain or com.apple.LocalAuthentication; inspect the operation error and refresh profile state. |
On iOS, inspect both the NSError domain and code. The wrappers also return com.swisssign.rss.sdk.RssSdkException with code -1 when a required wrapper or session is unavailable. Keychain and Secure Enclave failures can use NSOSStatusErrorDomain. Batch signing can return ConsentTokenError with code -1 or -2 for consent-token parsing or signing failures. A biometric cancellation or temporary lockout alone does not establish permanent key invalidation.
SmartContract Service
This service is used to interact with the workflow engine component that allows contracts to be retrieved and signed contracts from the device.
This service is only available if the workflow engine is installed on your premises. The SwissSign Signature Service environment does not currently offer workflow engine functionality.
Retrieving pending contracts
The getPendingContracts API returns a list of contracts waiting to be signed by the current user.
A contract is characterised by the following properties:
id: A unique identifier for the contracttype: The type of the contract, typicallyPDFdate: The timestamp representing the creation date of the contractstate: State of the contract alwaysPENDINGwhen returned by thegetPendingContractsAPImetaData: Dictionary of metadata that have been added by the server workflow or by the sender of the contractpayload: Raw payload of the contract, typically the PDF content
For performance reasons the payload is always null for contracts returned by the getPendingContracts API.
Retrieving a contract payload
The contract payload must be explicitly retrieved using the getPayload API, passing the expected contract id as a parameter.
The raw data returned by the API is typically the PDF content.
Requesting an external signature
The SDK provides an API to request a CAdES signature for a digest to a wide range of signing services.
The signing service to be used is selected by the workflow and must be transparent to the app. There are two types of signing service:
- Synchronous services, that do not require an user authentication, such as Simple Electronic Signature (SES) or Seals
- Asynchronous services, that do require an user authentication, such as Advanced Electronic Signature (AES) or Qualified Electronic Signature (QES)
When requesting a signature, the contract id and the SHA-256 digest to be signed must be provided.
The digest to be sent does not correspond to the raw PDF but the Data To Be Signed (DTBS) which is the data object that will be covered by the signature value (including thus the document(s) and attributes to be signed).
The CAdES signatures returned by the API can be embedded directly into a PDF signature container for a compliant PAdES signature.
The complexity of preparing a document for signing, extracting the Data To Be Signed and embedding back the signature into the document can be addressed by an additional WYSIWYS SDK provided by SwissSign AG.
The requestSignature API returns a SignatureStatus which is characterised by the following properties:
status: Status of the request, can be either:SUCCESS: Signature request is successful, signature is available insignatureattributePENDING: Signature is awaiting user authentication. Authentication hint may be provided inauthenticationUrlattribute and the app should start polling signature status usingrequestIdattributeCANCEL: The request was canceled by the server or the userTIMEOUT: The signature status has timed out
signature: The CMS CAdES signature. Only available when status isSUCCESSrequestId: The unique id of the signature request that can be used to retrieve signature status. Only available inrequestSignatureresponse when status isPENDINGauthenticationUrl: Optional hint to be displayed to the user into a webview for the authentication. Only available inrequestSignatureresponse when status isPENDINGerror: Error type. Only available when status isERROR:NotAllowed: User is not allowed to use the signing serviceServiceFailure: An unexpected error occurred on the server while retrieving the signature, request must be tried again laterUnrecoverableFailure: An unrecovarable error occured on the server while retrieving the signature. The contract has moved to an error state and cannot be signed by the user anymore
errorInfo: Optional hint to be displayed to the user when an error occurs
When using an asynchronous signing service that requires an user authentication, the app can retrieve the status of the signature request using the getSignatureStatus API, passing the contract id and the requestId as parameters. If the implementation of a polling mechanism is required, the API must not be called more than once per second.
Sending a response
The final step in processing a contract on the client-side is to send the response to the backend.
The sendResponse API takes the following attributes:
- The
responseattribute - The
payloadto be signed - Whether the provided
payloadmust be attached to the response to the server
The digest of the payload to be signed and some contextual information such as OS version, application UID and username are signed locally by the SDK using a certificate issued at enrolment time. The resulting CMS signature is appended to the response in order to be stored server-side in an audit trail.
The values to be used when sending a response depend on the server-side workflow that the contract is associated with. If the workflow is one of the built-in workflows provided by the solution, the following values are expected:
- The
responseattribute is the decision of the user and must be eitheracceptedorrefused(case sensitive) - The
payloadattribute value depend on theresponseattribute:- If
responseequals toaccepted, it must be the signed payload (typically signed PDF) - If
responseequals torefused, it must be the original paylaod sent fromgetContractPayloadAPI
- If
- The data must be attached only if
responseequals toaccepted
Once a response has been sent, the status of the contract changes and is no longer available from pending contracts list.
Error handling
The SmartContract mainly acts as a gateway to the SmartContract REST APIs. In case a request fails server-side the issue is forwarded to the client app.
| Error | Description | Android | iOS |
|---|---|---|---|
| API error | Request to SmartContract service failed, see exception message for details | java.io.IOException | ch.sysmosoft.sense.framework.ErrorDomain Code = 408 |