@nevis-security/nevis-mobile-authentication-sdk-react
Version:
React Native plugin for Nevis Mobile Authentication SDK. Supports only mobile.
353 lines (326 loc) • 14.3 kB
text/typescript
/**
* Copyright © 2025 Nevis Security AG. All rights reserved.
*/
import type { CertificateChainValidationResult } from './CertificateChainValidationResult';
import type { SecurityLevel } from './SecurityLevel';
enum FidoUafAttestationInformationType {
OnlySurrogateBasicSupported,
OnlyDefaultMode,
StrictMode,
StrictStrongBoxMode,
}
/**
* The interface informing about whether the device supports {@link https://docs.nevis.net/configurationguide/mobile-auth-concept-and-integration-guide/use-cases-and-best-practices/uaf-surrogate-full-basic-comparison | Full Basic Attestations}.
*
* If full basic is required by the backend during registration, and this device does not support it,
* registration will fail. This information can be used to preemptively inform the user that the device
* is not supported.
*
* Note that it is guaranteed that the only type of instances that the {@link AndroidDeviceCapabilities.fidoUafAttestationInformationGetter}
* returns are either {@link OnlySurrogateBasicSupported}, {@link OnlyDefaultMode}, {@link StrictMode} or {@link StrictStrongBoxMode}.
*
* @see
* - {@link MobileAuthenticationClient.deviceCapabilities}
* - {@link AndroidDeviceCapabilities.fidoUafAttestationInformationGetter}
* - {@link FidoUafAttestationInformationGetter}
*/
export abstract class FidoUafAttestationInformation {
/**
* The {@link SecurityLevel} of the environment where the FIDO UAF keys are stored.
* This provides information about the security of the environment where the keys are stored.
*/
abstract keymasterSecurityLevel: SecurityLevel;
/**
* The {@link https://source.android.com/docs/security/features/keystore/attestation#keydescription-fields | keymaster} version.
*/
abstract keymasterVersion: number;
/**
* Returns `true` if the {@link https://source.android.com/docs/security/features/keystore/attestation#rootoftrust-fields | device's bootloader}
* is locked, and `false` otherwise.
*/
abstract isDeviceBootloaderLocked: boolean;
/**
* Returns `true` if the {@link https://source.android.com/docs/security/features/keystore/attestation#verifiedbootstate-values | boot
* state} is `Verified`. Compromised devices (such as some root devices) do not have a valid
* boot state.
*/
abstract isVerifiedBootStateValid: boolean;
/**
* The result of the certificate chain validation.
*
* In devices supporting full basic attestation ({@link OnlyDefaultMode}, {@link StrictMode} or
* {@link StrictStrongBoxMode}), when a new key is created the device must generate an associated
* certificate chain (or certification path) that fulfills the following criteria:
* <ul>
* <li>The root certificate is a known {@link https://developer.android.com/privacy-and-security/security-key-attestation#root_certificate | Google
* root certificate}.</li>
* <li>The certificate chain is valid: it does not contain a certificate in the CRL, no certificate
* is expired, the certificates in the chain are signed with the previous one, etc.</li>
* </ul>
* So, when a device supports full basic, returns {@link CertificateChainValidationResult.Success}.
*/
abstract certificateChainValidationResult: CertificateChainValidationResult;
/**
* Alternate constructor that creates a {@link FidoUafAttestationInformation} from a json.
*
* @param json contains the source for instance creation.
* @returns a {@link FidoUafAttestationInformation} instance.
*/
static fromJson(json: any): FidoUafAttestationInformation {
const subtype =
FidoUafAttestationInformationType[
json.type as keyof typeof FidoUafAttestationInformationType
];
switch (subtype) {
case FidoUafAttestationInformationType.OnlySurrogateBasicSupported:
return OnlySurrogateBasicSupported.fromJson(json.data);
case FidoUafAttestationInformationType.OnlyDefaultMode:
return OnlyDefaultMode.fromJson(json.data);
case FidoUafAttestationInformationType.StrictMode:
return StrictMode.fromJson(json.data);
case FidoUafAttestationInformationType.StrictStrongBoxMode:
return StrictStrongBoxMode.fromJson(json.data);
default:
throw new Error(`Unknown FIDO UAF attestation information (${json.type}).`);
}
}
}
/**
* Only the surrogate basic attestation is supported.
*
* So, neither the `default`, the `strict` nor the `strict-strongbox` modes of full basic attestation
* are supported (see the {@link https://docs.nevis.net/configurationguide/patterns-reference#basic-full-attestation | nevisFIDO documentation}
* for details regarding the different modes).
*
* Supporting only surrogate basic attestation implies that the certificate chain of the device could
* not be successfully validated (see {@link certificateChainValidationResult}). This occurs typically
* in old devices, and devices that do not contain a Google root certificate (like some Huawei models).
*/
export abstract class OnlySurrogateBasicSupported extends FidoUafAttestationInformation {
/**
* The error that occurred while checking if the full basic attestation is supported.
*
* Its message provides information about why the device does not support full basic attestation.
*/
abstract cause?: string;
/**
* Alternate constructor that creates an {@link OnlySurrogateBasicSupported} from a json.
*
* @param json contains the source for instance creation.
* @returns the created {@link OnlySurrogateBasicSupported} instance.
*/
static fromJson(json: any): OnlySurrogateBasicSupported {
return OnlySurrogateBasicSupportedImpl.fromJson(json);
}
}
export class OnlySurrogateBasicSupportedImpl extends OnlySurrogateBasicSupported {
keymasterSecurityLevel: SecurityLevel;
keymasterVersion: number;
isDeviceBootloaderLocked: boolean;
isVerifiedBootStateValid: boolean;
certificateChainValidationResult: CertificateChainValidationResult;
cause: string | undefined;
constructor(
keymasterSecurityLevel: SecurityLevel,
keymasterVersion: number,
isDeviceBootloaderLocked: boolean,
isVerifiedBootStateValid: boolean,
certificateChainValidationResult: CertificateChainValidationResult,
cause: string | undefined
) {
super();
this.keymasterSecurityLevel = keymasterSecurityLevel;
this.keymasterVersion = keymasterVersion;
this.isDeviceBootloaderLocked = isDeviceBootloaderLocked;
this.isVerifiedBootStateValid = isVerifiedBootStateValid;
this.certificateChainValidationResult = certificateChainValidationResult;
this.cause = cause;
}
static fromJson(json: any): OnlySurrogateBasicSupportedImpl {
return new OnlySurrogateBasicSupportedImpl(
json.keymasterSecurityLevel,
json.keymasterVersion,
json.isDeviceBootloaderLocked,
json.isVerifiedBootStateValid,
json.certificateChainValidationResult,
json.cause
);
}
}
/**
* The device supports the `default` full basic attestation mode as described in the {@link https://docs.nevis.net/configurationguide/patterns-reference#basic-full-attestation | nevisFIDO documentation}.
*
* It supports surrogate basic attestation, but it does not support neither the `strict` nor the
* `strict-strongbox` modes.
*
* This means that the certificate chain was successfully validated, and thus {@link certificateChainValidationResult}
* returns {@link CertificateChainValidationResult.Success}. The device contains hardware using a known
* Google root certificate, but does not fulfill at least one of the other criteria required to be
* compatible with {@link StrictMode} or {@link StrictStrongBoxMode}.
*/
export abstract class OnlyDefaultMode extends FidoUafAttestationInformation {
/**
* The error that occurred while checking if the strict mode of the full basic attestation is
* supported.
*
* Its message provides information about why the device does not support the full basic attestation
* strict mode.
*/
abstract cause?: string;
/**
* Alternate constructor that creates an {@link OnlyDefaultMode} from a json.
*
* @param json contains the source for instance creation.
* @returns the created {@link OnlyDefaultMode} instance.
*/
static fromJson(json: any): OnlyDefaultMode {
return OnlyDefaultModeImpl.fromJson(json);
}
}
export class OnlyDefaultModeImpl extends OnlyDefaultMode {
keymasterSecurityLevel: SecurityLevel;
keymasterVersion: number;
isDeviceBootloaderLocked: boolean;
isVerifiedBootStateValid: boolean;
certificateChainValidationResult: CertificateChainValidationResult;
cause: string | undefined;
constructor(
keymasterSecurityLevel: SecurityLevel,
keymasterVersion: number,
isDeviceBootloaderLocked: boolean,
isVerifiedBootStateValid: boolean,
certificateChainValidationResult: CertificateChainValidationResult,
cause: string | undefined
) {
super();
this.keymasterSecurityLevel = keymasterSecurityLevel;
this.keymasterVersion = keymasterVersion;
this.isDeviceBootloaderLocked = isDeviceBootloaderLocked;
this.isVerifiedBootStateValid = isVerifiedBootStateValid;
this.certificateChainValidationResult = certificateChainValidationResult;
this.cause = cause;
}
static fromJson(json: any): OnlyDefaultModeImpl {
return new OnlyDefaultModeImpl(
json.keymasterSecurityLevel,
json.keymasterVersion,
json.isDeviceBootloaderLocked,
json.isVerifiedBootStateValid,
json.certificateChainValidationResult,
json.cause
);
}
}
/**
* The device supports the `default` and `strict` full basic attestation modes as described in the
* {@link https://docs.nevis.net/configurationguide/component-installation-guides/nevisFido/fido-uaf-configuration#full-basic-attestation | nevisFIDO documentation}.
* It also supports surrogate basic.
*
* However, since it does not have a StrongBox that the SDK can use to store the FIDO UAF credentials,
* the `strict-strongbox` mode is not supported.
*
* If the device supports this mode, then:
* - The FIDO UAF keys will be stored in a Trusted Execution Environment (TEE), and thus {@link keymasterSecurityLevel}
* will be {@link SecurityLevel.TrustedEnvironment}.
* - The certificate chain was successfully validated, and thus {@link certificateChainValidationResult}
* returns {@link CertificateChainValidationResult.Success}.
* - The value of {@link keymasterVersion} is 2 or higher.
* - The verified boot state is valid ({@link isVerifiedBootStateValid} returns `true`).
* - The device bootloader is locked ({@link isDeviceBootloaderLocked} returns `true`).
*/
export abstract class StrictMode extends FidoUafAttestationInformation {
/**
* Alternate constructor that creates a {@link StrictMode} from a json.
*
* @param json contains the source for instance creation.
* @returns the created {@link StrictMode} instance.
*/
static fromJson(json: any): StrictMode {
return StrictModeImpl.fromJson(json);
}
}
export class StrictModeImpl extends StrictMode {
keymasterSecurityLevel: SecurityLevel;
keymasterVersion: number;
isDeviceBootloaderLocked: boolean;
isVerifiedBootStateValid: boolean;
certificateChainValidationResult: CertificateChainValidationResult;
constructor(
keymasterSecurityLevel: SecurityLevel,
keymasterVersion: number,
isDeviceBootloaderLocked: boolean,
isVerifiedBootStateValid: boolean,
certificateChainValidationResult: CertificateChainValidationResult
) {
super();
this.keymasterSecurityLevel = keymasterSecurityLevel;
this.keymasterVersion = keymasterVersion;
this.isDeviceBootloaderLocked = isDeviceBootloaderLocked;
this.isVerifiedBootStateValid = isVerifiedBootStateValid;
this.certificateChainValidationResult = certificateChainValidationResult;
}
static fromJson(json: any): StrictModeImpl {
return new StrictModeImpl(
json.keymasterSecurityLevel,
json.keymasterVersion,
json.isDeviceBootloaderLocked,
json.isVerifiedBootStateValid,
json.certificateChainValidationResult
);
}
}
/**
* The device supports the `default`, `strict` and `strict-strongbox` full basic attestation modes as
* described in the {@link https://docs.nevis.net/configurationguide/component-installation-guides/nevisFido/fido-uaf-configuration#full-basic-attestation | nevisFIDO documentation}.
* It also supports surrogate basic.
*
* If the device supports this mode, then:
* - The FIDO UAF keys will be stored in the StrongBox, and thus {@link keymasterSecurityLevel} will
* be {@link SecurityLevel.StrongBox}.
* - The certificate chain was successfully validated, and thus {@link certificateChainValidationResult}
* returns {@link CertificateChainValidationResult.Success}.
* - The value of {@link keymasterVersion} is 2 or higher.
* - The verified boot state is valid ({@link isVerifiedBootStateValid} returns `true`).
* - The device bootloader is locked ({@link isDeviceBootloaderLocked} returns `true`).
*/
export abstract class StrictStrongBoxMode extends FidoUafAttestationInformation {
/**
* Alternate constructor that creates a {@link StrictStrongBoxMode} from a json.
*
* @param json contains the source for instance creation.
* @returns the created {@link StrictStrongBoxMode} instance.
*/
static fromJson(json: any): StrictStrongBoxMode {
return StrictStrongBoxModeImpl.fromJson(json);
}
}
export class StrictStrongBoxModeImpl extends StrictStrongBoxMode {
keymasterSecurityLevel: SecurityLevel;
keymasterVersion: number;
isDeviceBootloaderLocked: boolean;
isVerifiedBootStateValid: boolean;
certificateChainValidationResult: CertificateChainValidationResult;
constructor(
keymasterSecurityLevel: SecurityLevel,
keymasterVersion: number,
isDeviceBootloaderLocked: boolean,
isVerifiedBootStateValid: boolean,
certificateChainValidationResult: CertificateChainValidationResult
) {
super();
this.keymasterSecurityLevel = keymasterSecurityLevel;
this.keymasterVersion = keymasterVersion;
this.isDeviceBootloaderLocked = isDeviceBootloaderLocked;
this.isVerifiedBootStateValid = isVerifiedBootStateValid;
this.certificateChainValidationResult = certificateChainValidationResult;
}
static fromJson(json: any): StrictStrongBoxModeImpl {
return new StrictStrongBoxModeImpl(
json.keymasterSecurityLevel,
json.keymasterVersion,
json.isDeviceBootloaderLocked,
json.isVerifiedBootStateValid,
json.certificateChainValidationResult
);
}
}