import { SpkiHexString } from "../model/specializations/SpkiHexString.mjs"; import { DataOwnerWithType } from "../model/DataOwnerWithType.mjs"; import { KeypairFingerprintV1String } from "../model/specializations/KeypairFingerprintV1String.mjs"; import { CryptoActorStubWithType } from "../model/CryptoActorStubWithType.mjs"; import { RecoveryResult } from "./entities/RecoveryResult.mjs"; import { RecoveryDataKey } from "./entities/RecoveryDataKey.mjs"; import { RsaAlgorithm, RsaEncryptionAlgorithm, XCryptoService, XRsaKeypair } from "./CryptoService.mjs"; import { CardinalApis } from "../sdk/CardinalSdk.mjs"; /** * Allows customizing the behavior of the crypto api to better suit your needs. * * An important task which should be done in these crypto strategies is public key verification: in general there is no guarantee that the public keys * stored in the iCure database are authentic, i.e. created by the data owner they are associated to. This is because the database admins or a * malicious attacker may have added his own public keys to the data owner's public keys. * Sharing any kind of data using unverified public keys could potentially cause a data leak: this is why when creating new exchange keys or when * creating recovery data only verified keys will be considered. For decrypting existing data instead unverified keys will be used without issues. */ export declare class CryptoStrategies { /** * Method called during initialization of the crypto API to validate keys recovered through iCure's recovery methods and/or to allow recovery of * missing keys using means external to iCure. * On startup the iCure sdk will try to load all keys for the current data owner and its parent hierarchy: if the sdk can't find some of the keys * for any of the data owners (according to the public keys for the data owner in the iCure server) and/or the sdk could recover some private keys * but can't verify the authenticity of the key pairs this method will be called. * The recovered and verified keys will automatically be cached using the current api {@link KeyStorageFacade} and {@link StorageFacade} * * `currentDataOwnerId` is the id of the current data owner; use it to tell it apart from its parents in * `keysData`, instead of relying on its position in the map (map entries have no defined order). `keysData` * associates to the id of each data owner part of the current data owner's parent hierarchy (including the * current data owner itself) the corresponding recovery request. * * The returned value must be an object associating to each data owner id an object with: * - `recoveredKeys`: * - `keyAuthenticity`: an object * @param currentDataOwnerId the id of the current data owner. * @param keysData all information on unknown and unavailable keys for each data owner part of the current data owner's parent hierarchy, by id. * @param cryptoPrimitives cryptographic primitives you can use to support the process. * @param keyPairRecoverer a key pair recoverer you can use to support the process * @return a map that associates to each given data owner id the recovered data. */ recoverAndVerifySelfHierarchyKeys(currentDataOwnerId: string, keysData: { [dataOwnerId: string]: CryptoStrategies.KeyDataRecoveryRequest; }, cryptoPrimitives: XCryptoService, keyPairRecoverer: KeyPairRecoverer): Promise<{ [dataOwnerId: string]: CryptoStrategies.RecoveredKeyData; }>; /** * The correct initialisation of the crypto API requires that at least 1 verified (or device) key pair is available for each data owner part of the * current data owner hierarchy. If no verified key is available for any of the data owner parents the api initialisation will automatically fail, * however if there is no verified key for the current data owner you can instead create a new crypto key. * @param self the current data owner. * @param cryptoPrimitives cryptographic primitives you can use to support the process. * @return an instance of {@link CryptoStrategies.KeyGenerationRequestResult} specifying how the SDK should behave. * @throws Exception you can throw any exception, and it will simply propagate to the api initialisation method. */ generateNewKeyForDataOwner(self: DataOwnerWithType, cryptoPrimitives: XCryptoService): Promise; /** * Verifies if the public keys of a data owner which will be the delegate of new exchange data do actually belong to * the person the data owner represents; if you do not override this method the public keys of the delegate are * obtained from the cardinal backend and are fully trusted. * * Note that this method is not called when: * - The delegate id the current SDK delegator actor * - The delegate is a parent type data owner linked from the current SDK delegator actor. * - The SDK is creating exchange data to a simple-type group of data owners (in that case [getDelegatesPublicKeys] is used) * * There are two approaches you can use for verification of public keys: a separate service not controlled by iCure, * or interaction with the end user. * * For example this method may ask the end user to compare the public keys with verified public keys of the delegate * obtained from out of iCure, such as an email, the personal website of the other user, or by scanning verification * qr codes at the doctor office. * * As long as one of the public keys is verified the creation of a new exchange key will succeed. * * If no public key is verified the operation will fail. * * @param delegate the potential data owner delegate. * @param publicKeys public keys requiring verification, in spki hex-encoded format. * @param cryptoPrimitives cryptographic primitives you can use to support the process. * @param groupId the id of the delegate data owner's group, or null if the data owner is in the same group as the current user * @return all verified public keys, in spki hex-encoded format. */ verifyDelegatePublicKeys(delegate: CryptoActorStubWithType, publicKeys: Array, cryptoPrimitives: XCryptoService, groupId: string | undefined): Promise>; /** * Similarly to [verifyDelegatePublicKeys] this method can be used if you don't want the SDK to fully trust the * public keys coming from the cardinal backend, however this method is only called when creating exchange data for * a simple-type data owner group, which may require to get validated public keys for many data owners. * * In that case interaction with the end-user is undesired, and it would be better instead to have a dedicated * service separated from cardinal that provides the public keys of your cardinal data owners. * * Note that: * - Returning null means the SDK will retrieve public keys from the cardinal backend and fully trust them. * - If this method does not return null, it must provide at least a key for each delegate * - Unlike [verifyDelegatePublicKeys] this method might be called even for delegates that are parent of the current * SDK delegator actor. * - The keys returned by this method will not be checked against the cardinal backend; if there are any * inconsistencies the SDK might create invalid exchange data. * * @param delegates delegates for which the public keys are required. * @param groupId the id of the delegate data owners' group, or null if their group is the same as the current user */ getDelegatesPublicKeys(delegates: Array, groupId: string | undefined): Promise<{ [delegateId: string]: { [publicKey: SpkiHexString]: RsaEncryptionAlgorithm; }; } | undefined>; /** * Specifies if a data owner requires anonymous delegations, i.e. his id should not appear unencrypted in new secure * delegations. * This should always be the case for patient data owners. * @param dataOwner a data owner. * @param groupId the id of the data owner's group, or null if the data owner is in the same group as the current user * @return true if the delegations for the provided data owner should be anonymous. */ dataOwnerRequiresAnonymousDelegation(dataOwner: CryptoActorStubWithType, groupId: string | undefined): Promise; /** * Notifies that a new key for the current data owner was created. * This method is called after the initialization of the other SDK apis. * @param apis the initialized cardinal apis. * @param key the newly created key. * @param cryptoPrimitives cryptographic primitives you can use to support the process. */ notifyNewKeyCreated(apis: CardinalApis, key: XRsaKeypair, cryptoPrimitives: XCryptoService): Promise; } export declare namespace CryptoStrategies { /** * Specifies how the SDK should behave when a new key pair is required for a data owner. */ namespace KeyGenerationRequestResult { /** * Allows the SDK to generate a new key pair for the current data owner. */ const Allow: { readonly kind: "Allow"; }; /** * The SDK must not generate a new key for the data owner. The SDK initialisation should fail with a predefined * error. */ const Deny: { readonly kind: "Deny"; }; /** * The SDK must not generate a new key for the data owner. * The SDK initialisation will continue, but the initialised SDK will run in keyless mode. * In keyless mode, exchange data has to be created explicitly before data can be shared. */ const Keyless: { readonly kind: "Keyless"; }; /** * The SDK must not generate a new key for the data owner. * Instead, whenever a delegator is needed for an action (creating new encrypted data, or sharing existing data) * the SDK will use the provided parent data owner and its key as delegator. * This option is only available if the data owner has at least a parent and the SDK was initialized using * hierarchical data owners. * Note that this will not have an effect on the author/responsible fields of created data, the only observable * effect is on the created exchange data and delegations. */ class ParentDelegator { /** * The id of a parent of the current data owner that should be used as delegator instead of the current * delegator when needed. */ readonly parentId: string; readonly kind = "ParentDelegator"; constructor( /** * The id of a parent of the current data owner that should be used as delegator instead of the current * delegator when needed. */ parentId: string); } /** * The SDK should use the provided key pair as a new key for the data owner. */ class Use { readonly keyPair: XRsaKeypair; readonly kind = "Use"; constructor(keyPair: XRsaKeypair); } } type KeyGenerationRequestResult = typeof KeyGenerationRequestResult.Allow | typeof KeyGenerationRequestResult.Deny | typeof KeyGenerationRequestResult.Keyless | KeyGenerationRequestResult.ParentDelegator | KeyGenerationRequestResult.Use; /** * A request to recover key data that was not found for a user. */ interface KeyDataRecoveryRequest { /** * The data owner for which the key data should be recovered. */ readonly dataOwnerDetails: DataOwnerWithType; /** * All public keys (in hex-encoded spki format) of `dataOwner` for which the authenticity status (verified or unverified) is * unknown (no result was cached from a previous api instantiation and the key was not generated on the current device). * This could include keys that were recovered automatically by the sdk and may have overlap with `unavailableKeys`. */ readonly unknownKeys: Array; /** * All public keys (in hex-encoded spki format) of `dataOwner` for which the sdk could not recover a private key. May overlap * (partially or completely) with `unknownKeys`. */ readonly unavailableKeys: Array; } /** * Data recovered for a data owner. */ interface RecoveredKeyData { /** * All keys recovered for the data owner, by fingerprint. * Recovered keys are by default considered as verified, unless explicitly marked as unverified in * `keyAuthenticity`. */ readonly recoveredKeys: { [fp: KeypairFingerprintV1String | SpkiHexString]: XRsaKeypair; }; /** * Marks if the user has recognized any public key associated to him as authentic / verified. * The key of the object should be a public key in hex-encoded spki format or its fingerprint (last 32 characters of * the hex-encoded spki representation). * If any of the keys from `unknownKeys` is completely missing from this object the key will be considered as * unverified in this api instance (same as false). However, in this case the unverified status of the key won't be * saved: next time that an api is instantiated, even if the storage was not reset sdk will ask again to verify the * authenticity of that key. */ readonly keyAuthenticity: { [fp: KeypairFingerprintV1String | SpkiHexString]: boolean; }; } interface UnavailableKeyInfo { /** * The public key */ readonly publicKey: SpkiHexString; /** * The algorithm of the keypair */ readonly keyAlgorithm: RsaAlgorithm; } } /** * Allows to recover user keypairs using builtin recovery mechanisms. * This interface includes recovery methods that require some input from your application (e.g. a recovery key created from a different device). * Other recovery methods (such as transfer keys) are used automatically by the sdk when available and don't require any input from your application. */ export interface KeyPairRecoverer { /** * Recover a keypair using a recovery key created in the past using the {@link RecoveryApi.createRecoveryInfoForAvailableKeyPairs} method. * @param recoveryKey the result of a past call to {@link RecoveryApi.createRecoveryInfoForAvailableKeyPairs}. * @param autoDelete if true, the recovery data will be deleted from the server after it could be used successfully. * This will prevent the recovery key from being used again. * @return a recovery result, which, if successful, contains a map dataOwnerId -> publicKeySpki -> keyPair, where: * - The `dataOwnerId` keys are the ids of the data owner which created the recovery data and his parents, if the recovery data contains also the * parents keys * - The `publicKeySpki` keys are all recovered public key pairs for the data owner, in hex-encoded spki format (full, no fingerprint). Usually * these are all the keys if the recovery data was created after the latest key for the user. * - The `keyPair` is the imported privateKey + publicKey. */ recoverWithRecoveryKey(recoveryKey: RecoveryDataKey, autoDelete: boolean): Promise>; /** * Get information on which keys the SDK will be able to recover autonomously through transfer keys or shamir * shares using the provided {@link recoveredKeys} plus any already available keys (i.e. keys that were already in the * storage or recovered using transfer keys and/or shamir from the keys already in the storage). * * When prompting the user to recover more of his keys you can ignore any key that are returned by this method, as * those keys will be automatically recovered by the SDK if you return {@link recoveredKeys}. */ getRecoverableWithEncryptionKeys(dataOwner: DataOwnerWithType, recoveredKeys: XRsaKeypair[]): Promise; }