glasslock/testing

Helpers for generating WebAuthn/FIDO2 test data in unit and integration tests. Exposes high-level builders for common scenarios and low-level building blocks for edge cases.

This module is for testing only. It should not be used in production code.

Build a valid response, then use record update syntax to introduce the flaw under test:

testing.to_registration_json(
  testing.RegistrationResponse(..response, credential_type: "invalid-type"),
)

Values the authenticator signs over — the credential ID and public key inside attestation_object, and authenticator_data with its signature — are not reachable this way; rebuild them with the lower-level builders.

Example

For a simple registration test:

import glasslock/registration
import glasslock/testing

pub fn registration_test() {
  let #(_, challenge) =
    registration.new(
      relying_party: registration.RelyingParty(id: "example.com", name: "Test"),
      user: registration.User(id: <<1, 2, 3>>, name: "test", display_name: "Test"),
      origin: "https://example.com",
    )
    |> registration.build()

  let response = testing.build_registration_response(challenge: challenge)
  let response_json = testing.to_registration_json(response)

  let assert Ok(credential) = registration.verify_json(response_json:, challenge:)
}

Types

Complete response data for an authentication ceremony.

pub type AuthenticationResponse {
  AuthenticationResponse(
    id: String,
    credential_id: BitArray,
    credential_type: String,
    authenticator_data: BitArray,
    client_data_json: BitArray,
    signature: BitArray,
    user_handle: option.Option(BitArray),
  )
}

Constructors

  • AuthenticationResponse(
      id: String,
      credential_id: BitArray,
      credential_type: String,
      authenticator_data: BitArray,
      client_data_json: BitArray,
      signature: BitArray,
      user_handle: option.Option(BitArray),
    )

    Arguments

    id

    Emitted as id. Base64url of credential_id in a real response.

    credential_id

    Emitted as rawId.

    credential_type

    Emitted as type. "public-key" for a real credential.

    client_data_json

    UTF-8 encoded client data JSON.

    signature

    Signature over authenticator_data || SHA-256(client_data_json).

Authenticator flags for building authenticator data.

pub type AuthenticatorFlags {
  AuthenticatorFlags(user_present: Bool, user_verified: Bool)
}

Constructors

  • AuthenticatorFlags(user_present: Bool, user_verified: Bool)

    Arguments

    user_present

    WebAuthn UP (user presence) flag: the user touched or interacted with the authenticator.

    user_verified

    WebAuthn UV (user verification) flag: the authenticator performed biometric or PIN verification.

A COSE key pair for testing WebAuthn flows.

Construct with generate_es256_keypair, generate_ed25519_keypair, or generate_rs256_keypair.

pub opaque type KeyPair

Complete response data for a registration ceremony.

pub type RegistrationResponse {
  RegistrationResponse(
    id: String,
    credential_id: BitArray,
    credential_type: String,
    client_data_json: BitArray,
    attestation_object: BitArray,
    transports: List(glasslock.Transport),
  )
}

Constructors

  • RegistrationResponse(
      id: String,
      credential_id: BitArray,
      credential_type: String,
      client_data_json: BitArray,
      attestation_object: BitArray,
      transports: List(glasslock.Transport),
    )

    Arguments

    id

    Emitted as id. Base64url of credential_id in a real response.

    credential_id

    Emitted as rawId. Matches the attested credential ID inside attestation_object in a real response.

    credential_type

    Emitted as type. "public-key" for a real credential.

    client_data_json

    UTF-8 encoded client data JSON.

    attestation_object

    CBOR-encoded attestation object.

    transports

    Omitted from the envelope when empty.

Values

pub fn build_attestation_object(
  format format: String,
  authenticator_data authenticator_data: BitArray,
  attestation_statement attestation_statement: List(
    #(String, Int),
  ),
) -> BitArray

Build an attestation object. glasslock accepts only "none" with an empty statement.

pub fn build_authentication_authenticator_data(
  relying_party_id relying_party_id: String,
  flags flags: AuthenticatorFlags,
  sign_count sign_count: Int,
) -> BitArray

Build authenticator data for authentication (no attested credential).

pub fn build_authentication_response(
  challenge challenge: authentication.Challenge,
  credential_id credential_id: BitArray,
  keypair keypair: KeyPair,
  sign_count sign_count: Int,
) -> AuthenticationResponse

Build a complete authentication response for the given challenge.

Uses the keypair to generate a valid signature.

pub fn build_client_data(
  type_ type_: String,
  challenge challenge: BitArray,
  origin origin: String,
  cross_origin cross_origin: Bool,
  top_origin top_origin: option.Option(String),
) -> BitArray

Build client data JSON with a caller-supplied type field.

Parameters allow constructing invalid data for error testing:

  • Use a different origin to test origin mismatch
  • Use a different challenge to test challenge mismatch
  • Set cross_origin: True with a challenge that disallows it
pub fn build_client_data_create(
  challenge challenge: BitArray,
  origin origin: String,
  cross_origin cross_origin: Bool,
) -> BitArray

Build webauthn.create client data JSON for registration.

pub fn build_client_data_get(
  challenge challenge: BitArray,
  origin origin: String,
  cross_origin cross_origin: Bool,
) -> BitArray

Build webauthn.get client data JSON for authentication.

pub fn build_registration_authenticator_data(
  relying_party_id relying_party_id: String,
  credential_id credential_id: BitArray,
  cose_key_cbor cose_key_cbor: BitArray,
  flags flags: AuthenticatorFlags,
  sign_count sign_count: Int,
) -> BitArray

Build authenticator data for registration (includes attested credential). Pass cose_key(keypair) for the cose_key_cbor parameter.

pub fn build_registration_response(
  challenge challenge: registration.Challenge,
) -> RegistrationResponse

Build a complete registration response for the given challenge.

Generates a fresh ES256 keypair and credential ID. The generated keypair is not part of the returned response; use build_registration_response_with_keypair to supply a keypair of a different algorithm, or to keep the keypair for a follow-on authentication response.

pub fn build_registration_response_with_keypair(
  challenge challenge: registration.Challenge,
  keypair keypair: KeyPair,
) -> RegistrationResponse

Build a complete registration response using a caller-supplied keypair.

Useful when the test needs to exercise an algorithm other than ES256. The keypair determines the COSE algorithm embedded in the attested credential.

pub fn cose_key(keypair: KeyPair) -> BitArray

Get the public key in COSE CBOR format. This is the format embedded in authenticator data during registration.

pub const default_flags: AuthenticatorFlags

User present, not user verified.

pub fn generate_ed25519_keypair() -> KeyPair

Generate a new random Ed25519 key pair.

pub fn generate_es256_keypair() -> KeyPair

Generate a new random ES256 (P-256) key pair.

pub fn generate_rs256_keypair() -> KeyPair

Generate a new random RS256 (RSA 2048-bit) key pair.

pub fn public_key(keypair: KeyPair) -> glasslock.PublicKey

Get the public key as a parsed glasslock.PublicKey. Use to construct a stored Credential in tests.

pub fn sign(
  keypair keypair: KeyPair,
  message message: BitArray,
) -> BitArray

Sign a message using the algorithm stamped on the keypair.

Dispatches to ECDSA, EdDSA, RSA PKCS#1 v1.5, or RSA PSS based on the COSE alg label assigned when the keypair was generated. Returns the wire-format signature bytes a real WebAuthn authenticator would produce: ASN.1 DER for ECDSA, raw for EdDSA, and raw PKCS#1 v1.5 or PSS bytes for RSA.

pub fn sign_authentication_message(
  keypair keypair: KeyPair,
  authenticator_data authenticator_data: BitArray,
  client_data_json client_data_json: BitArray,
) -> BitArray

Sign an authentication message the same way a real authenticator would: ECDSA/EdDSA/RSA over authenticator_data || SHA-256(client_data_json).

pub fn to_authentication_json(
  response: AuthenticationResponse,
) -> String

Convert an authentication response to an AuthenticationResponseJSON string.

pub fn to_registration_json(
  response: RegistrationResponse,
) -> String

Convert a registration response to a RegistrationResponseJSON string.

Search Document