LogoSignature Service
Remote Signing Service SDK

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.

  • tokenType
  • access_token
  • id_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

ErrorDescriptionAndroidiOS
Session errorSession with server is no more available, a new one must be established.ch.sysmosoft.sense.common.server.exception.SessionExceptionch.sysmosoft.sense.framework.ErrorDomain Code = 407
Access denied errorThe 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.AccessDeniedExceptionch.sysmosoft.sense.framework.ErrorDomain Code = 404
User authentication errorFailed to authenticate user with the provided secret.ch.sysmosoft.sense.common.server.exception.AuthenticationExceptionch.sysmosoft.sense.framework.ErrorDomain Code = 401
Account locked errorAccount 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.AccountLockedExceptionch.sysmosoft.sense.framework.ErrorDomain Code=403
User disenrolled errorUser is no longer enrolled server-side and has been disenrolled client-side as well.ch.sysmosoft.sense.client.exception.UserDisenrolledExceptionch.sysmosoft.sense.framework.ErrorDomain Code = 102
Server errorUnexpected server errorch.sysmosoft.sense.common.server.exception.ServerExceptionch.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:

ResultMeaning
.deviceCompliantDevice meets the biometric prerequisites.
.errNoHardwareRequired hardware is unavailable.
.errPinCodeNotSetA device passcode is not configured.
.errNoBiometricSetBiometric 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 requests
  • name: A human-readable name of the profile (not translated)
  • The jurisdiction: Jurisdiction applicable to the profile
    • ZERTES: Swiss regulation for Electronic Signatures
    • EIDAS: EU regulation for Electronic Signatures
    • NONE: The profile is not applicable to a specific regulation
  • signatureLevel: Signature level applicable to the profile
    • QES: Qualified Electronic Signature
    • AES: Advanced Electronic Signature
    • SES: Simple Electronic Signature
  • registrationStatus: Registration status of the profile for the current device
    • REGISTERED: The profile can be used for signature
    • NOT_REGISTERED: The profile is not registered yet
    • REGISTERED_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 profile
    • VALID: Identification is current and valid
    • IDENTIFICATION_REQUIRED: Identification is required to use the profile
    • IDENTIFICATION_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: Constant registration indicating the type of the notification
  • username: Username of the user (sub attribute 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 request
  • digestId: A unique identifier representing the digest
  • dssProfileId: Identifier of the DSS Profile
  • documentHash: Content to be signed
  • documentMetaData: Additional meta data for the pending request
    • documentName: Name of the document to be signed
    • documentDescription: Name of the sender of the document
    • transactionNumber: 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: Constant keyunlock indicating the type of the notification
  • requestId: Unique identifier of the pending request
  • username: Username of the user (sub attribute 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.

ErrorDescriptionAndroidiOS
Session errorSession with server is not more available, a new one must be establishedch.sysmosoft.sense.common.server.exception.SessionExceptionch.sysmosoft.sense.framework.ErrorDomain Code = 407
DSS errorError during operation with the DSS, refer to the code provided for reason (see next section)com.swisssign.rss.sdk.mobile.exception.DssExceptioncom.swisssign.rss.sdk.DssException
Authentication errorError while authenticating user with biometric datach.sysmosoft.sense.common.server.exception.AuthenticationExceptioncom.apple.LocalAuthentication References
Key invalidation errorKey permanently invalidated by OS, profile needs to be activated againandroid.security.keystore.KeyPermanentlyInvalidatedExceptionMay 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 contract
  • type: The type of the contract, typically PDF
  • date: The timestamp representing the creation date of the contract
  • state: State of the contract always PENDING when returned by the getPendingContracts API
  • metaData: Dictionary of metadata that have been added by the server workflow or by the sender of the contract
  • payload: 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 in signature attribute
    • PENDING: Signature is awaiting user authentication. Authentication hint may be provided in authenticationUrl attribute and the app should start polling signature status using requestId attribute
    • CANCEL: The request was canceled by the server or the user
    • TIMEOUT: The signature status has timed out
  • signature: The CMS CAdES signature. Only available when status is SUCCESS
  • requestId: The unique id of the signature request that can be used to retrieve signature status. Only available in requestSignature response when status is PENDING
  • authenticationUrl: Optional hint to be displayed to the user into a webview for the authentication. Only available in requestSignature response when status is PENDING
  • error: Error type. Only available when status is ERROR:
    • NotAllowed: User is not allowed to use the signing service
    • ServiceFailure: An unexpected error occurred on the server while retrieving the signature, request must be tried again later
    • UnrecoverableFailure: 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 response attribute
  • The payload to be signed
  • Whether the provided payload must 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 response attribute is the decision of the user and must be either accepted or refused (case sensitive)
  • The payload attribute value depend on the response attribute:
    • If response equals to accepted, it must be the signed payload (typically signed PDF)
    • If response equals to refused, it must be the original paylaod sent from getContractPayload API
  • The data must be attached only if response equals to accepted

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.

ErrorDescriptionAndroidiOS
API errorRequest to SmartContract service failed, see exception message for detailsjava.io.IOExceptionch.sysmosoft.sense.framework.ErrorDomain Code = 408

On this page