This commit is contained in:
+1322
@@ -0,0 +1,1322 @@
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Fetch creates a new HTTP client and gets the production metadata, decodes it, and parses it. This is an
|
||||
// instrumentation simplification that makes it easier to either just grab the latest metadata or for implementers to
|
||||
// see the rough process of retrieving it to implement any of their own logic.
|
||||
func Fetch() (metadata *Metadata, err error) {
|
||||
var (
|
||||
decoder *Decoder
|
||||
payload *PayloadJSON
|
||||
resp *http.Response
|
||||
)
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
if resp, err = client.Get(ProductionMDSURL); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = resp.Body.Close()
|
||||
}()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("error occurred fetching metadata: status code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
if decoder, err = NewDecoder(WithIgnoreEntryParsingErrors()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if payload, err = decoder.Decode(resp.Body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return decoder.Parse(payload)
|
||||
}
|
||||
|
||||
// Metadata represents a FIDO Metadata Service BLOB in either a fully parsed or partially parsed state.
|
||||
type Metadata struct {
|
||||
// Parsed contains the successfully parsed BLOB payload entries.
|
||||
Parsed Parsed
|
||||
|
||||
// Unparsed contains entries that failed to parse, along with their errors.
|
||||
Unparsed []EntryError
|
||||
}
|
||||
|
||||
func (m *Metadata) ToMap() (metadata map[uuid.UUID]*Entry) {
|
||||
metadata = make(map[uuid.UUID]*Entry)
|
||||
|
||||
for _, entry := range m.Parsed.Entries {
|
||||
if entry.AaGUID != uuid.Nil {
|
||||
metadata[entry.AaGUID] = &entry
|
||||
}
|
||||
}
|
||||
|
||||
return metadata
|
||||
}
|
||||
|
||||
// Parsed is a structure representing the Metadata BLOB Payload dictionary.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-service-v3.1.1-rd-20251016.html#sctn-mds-blob-payload
|
||||
type Parsed struct {
|
||||
// The legalHeader, which MUST be in each BLOB, is an indication of the acceptance of the relevant legal agreement
|
||||
// for using the MDS.
|
||||
LegalHeader string
|
||||
|
||||
// The serial number of this Metadata BLOB Payload. This serial number MUST be incremented whenever the contents
|
||||
// of the BLOB changes. Serial numbers MUST be consecutive and strictly monotonic, i.e. the successor BLOB will
|
||||
// have a no value exactly incremented by one.
|
||||
Number int
|
||||
|
||||
// ISO-8601 formatted date when the next update will be provided at latest. The use of this field is discouraged
|
||||
// and may be removed in a future version of the spec.
|
||||
NextUpdate time.Time
|
||||
|
||||
// List of zero or more MetadataBLOBPayloadEntry objects.
|
||||
Entries []Entry
|
||||
}
|
||||
|
||||
// PayloadJSON is an intermediary JSON/JWT representation of the Metadata BLOB Payload dictionary and the JSON
|
||||
// representation of the [Parsed] struct.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-service-v3.1.1-rd-20251016.html#sctn-mds-blob-payload
|
||||
type PayloadJSON struct {
|
||||
// LegalHeader is an indication of the acceptance of the relevant legal agreement for using the MDS.
|
||||
LegalHeader string `json:"legalHeader"`
|
||||
|
||||
// Number is the serial number of this Metadata BLOB Payload.
|
||||
Number int `json:"no"`
|
||||
|
||||
// NextUpdate is an ISO-8601 formatted date when the next update will be provided at latest.
|
||||
NextUpdate string `json:"nextUpdate"`
|
||||
|
||||
// Entries is a list of zero or more MetadataBLOBPayloadEntry objects.
|
||||
Entries []EntryJSON `json:"entries"`
|
||||
}
|
||||
|
||||
func (j PayloadJSON) Parse() (payload Parsed, err error) {
|
||||
var update time.Time
|
||||
|
||||
if update, err = time.Parse(time.DateOnly, j.NextUpdate); err != nil {
|
||||
return payload, fmt.Errorf("error occurred parsing next update value '%s': %w", j.NextUpdate, err)
|
||||
}
|
||||
|
||||
n := len(j.Entries)
|
||||
|
||||
entries := make([]Entry, n)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
if entries[i], err = j.Entries[i].Parse(); err != nil {
|
||||
return payload, fmt.Errorf("error occurred parsing entry %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
return Parsed{
|
||||
LegalHeader: j.LegalHeader,
|
||||
Number: j.Number,
|
||||
NextUpdate: update,
|
||||
Entries: entries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Entry is a structure representing the Metadata BLOB Payload Entry dictionary.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-service-v3.1.1-rd-20251016.html#sctn-mds-blob-pe
|
||||
type Entry struct {
|
||||
// Aaid is the AAID of the authenticator this metadata BLOB payload entry relates to. This field MUST be set if
|
||||
// the authenticator implements FIDO UAF.
|
||||
Aaid string
|
||||
|
||||
// AaGUID is the Authenticator Attestation GUID. This field MUST be set if the authenticator implements FIDO2.
|
||||
AaGUID uuid.UUID
|
||||
|
||||
// AttestationCertificateKeyIdentifiers is a list of the attestation certificate public key identifiers encoded as
|
||||
// hex string. This field MUST be set if neither aaid nor aaguid are set.
|
||||
AttestationCertificateKeyIdentifiers []string
|
||||
|
||||
// MetadataStatement is the metadataStatement JSON object as defined in FIDOMetadataStatement.
|
||||
MetadataStatement Statement
|
||||
|
||||
// BiometricStatusReports is the status of the FIDO Biometric Certification of one or more biometric components of
|
||||
// the Authenticator.
|
||||
BiometricStatusReports []BiometricStatusReport
|
||||
|
||||
// StatusReports is an array of status reports applicable to this authenticator.
|
||||
StatusReports []StatusReport
|
||||
|
||||
// TimeOfLastStatusChange is an ISO-8601 formatted date since when the status report array was set to the current
|
||||
// value.
|
||||
TimeOfLastStatusChange time.Time
|
||||
|
||||
// RogueListURL is a URL of a list of rogue (i.e. untrusted) individual authenticators.
|
||||
RogueListURL *url.URL
|
||||
|
||||
// RogueListHash is the hash value computed over the Base64url encoding of the UTF-8 representation of the JSON
|
||||
// encoded rogueList available at rogueListURL (with type rogueListEntry[]). This hash value MUST be present and
|
||||
// non-empty whenever rogueListURL is present.
|
||||
RogueListHash string
|
||||
}
|
||||
|
||||
// EntryJSON is an intermediary JSON/JWT structure representing the Metadata BLOB Payload Entry dictionary and
|
||||
// the JSON representation of the [Entry] struct.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-service-v3.1.1-rd-20251016.html#sctn-mds-blob-pe
|
||||
type EntryJSON struct {
|
||||
// Aaid is the AAID of the authenticator. Set if the authenticator implements FIDO UAF.
|
||||
Aaid string `json:"aaid"`
|
||||
|
||||
// AaGUID is the Authenticator Attestation GUID. Set if the authenticator implements FIDO2.
|
||||
AaGUID string `json:"aaguid"`
|
||||
|
||||
// AttestationCertificateKeyIdentifiers is a list of attestation certificate public key identifiers (hex).
|
||||
AttestationCertificateKeyIdentifiers []string `json:"attestationCertificateKeyIdentifiers"`
|
||||
|
||||
// MetadataStatement is the metadataStatement JSON object as defined in FIDOMetadataStatement.
|
||||
MetadataStatement StatementJSON `json:"metadataStatement"`
|
||||
|
||||
// BiometricStatusReports is the biometric certification status of one or more biometric components.
|
||||
BiometricStatusReports []BiometricStatusReportJSON `json:"biometricStatusReports"`
|
||||
|
||||
// StatusReports is an array of status reports applicable to this authenticator.
|
||||
StatusReports []StatusReportJSON `json:"statusReports"`
|
||||
|
||||
// TimeOfLastStatusChange is an ISO-8601 formatted date since when the status report array was set.
|
||||
TimeOfLastStatusChange string `json:"timeOfLastStatusChange"`
|
||||
|
||||
// RogueListURL is a URL of a list of rogue (i.e. untrusted) individual authenticators.
|
||||
RogueListURL string `json:"rogueListURL"`
|
||||
|
||||
// RogueListHash is the hash value computed over the Base64url encoding of the rogueList at rogueListURL.
|
||||
RogueListHash string `json:"rogueListHash"`
|
||||
}
|
||||
|
||||
func (j EntryJSON) Parse() (entry Entry, err error) {
|
||||
var aaguid uuid.UUID
|
||||
|
||||
if len(j.AaGUID) != 0 {
|
||||
if aaguid, err = uuid.Parse(j.AaGUID); err != nil {
|
||||
return entry, fmt.Errorf("error occurred parsing metadata entry with AAGUID '%s': error parsing AAGUID: %w", j.AaGUID, err)
|
||||
}
|
||||
}
|
||||
|
||||
var statement Statement
|
||||
|
||||
if statement, err = j.MetadataStatement.Parse(); err != nil {
|
||||
return entry, fmt.Errorf("error occurred parsing metadata entry with AAGUID '%s': %w", j.AaGUID, err)
|
||||
}
|
||||
|
||||
var i, n int
|
||||
|
||||
n = len(j.BiometricStatusReports)
|
||||
|
||||
bsrs := make([]BiometricStatusReport, n)
|
||||
|
||||
for i = 0; i < n; i++ {
|
||||
if bsrs[i], err = j.BiometricStatusReports[i].Parse(); err != nil {
|
||||
return entry, fmt.Errorf("error occurred parsing metadata entry with AAGUID '%s': error occurred parsing biometric status report %d: %w", j.AaGUID, i, err)
|
||||
}
|
||||
}
|
||||
|
||||
n = len(j.StatusReports)
|
||||
|
||||
srs := make([]StatusReport, n)
|
||||
|
||||
for i = 0; i < n; i++ {
|
||||
if srs[i], err = j.StatusReports[i].Parse(); err != nil {
|
||||
return entry, fmt.Errorf("error occurred parsing metadata entry with AAGUID '%s': error occurred parsing status report %d: %w", j.AaGUID, i, err)
|
||||
}
|
||||
}
|
||||
|
||||
var change time.Time
|
||||
|
||||
if change, err = time.Parse(time.DateOnly, j.TimeOfLastStatusChange); err != nil {
|
||||
return entry, fmt.Errorf("error occurred parsing metadata entry with AAGUID '%s': error occurred parsing time of last status change value: %w", j.AaGUID, err)
|
||||
}
|
||||
|
||||
var rogues *url.URL
|
||||
|
||||
if len(j.RogueListURL) != 0 {
|
||||
if rogues, err = url.ParseRequestURI(j.RogueListURL); err != nil {
|
||||
return entry, fmt.Errorf("error occurred parsing metadata entry with AAGUID '%s': error occurred parsing rogue list URL value: %w", j.AaGUID, err)
|
||||
}
|
||||
|
||||
if len(j.RogueListHash) == 0 {
|
||||
return entry, fmt.Errorf("error occurred parsing metadata entry with AAGUID '%s': error occurred validating rogue list URL value: the rogue list hash was absent", j.AaGUID)
|
||||
}
|
||||
}
|
||||
|
||||
return Entry{
|
||||
Aaid: j.Aaid,
|
||||
AaGUID: aaguid,
|
||||
AttestationCertificateKeyIdentifiers: j.AttestationCertificateKeyIdentifiers,
|
||||
MetadataStatement: statement,
|
||||
BiometricStatusReports: bsrs,
|
||||
StatusReports: srs,
|
||||
TimeOfLastStatusChange: change,
|
||||
RogueListURL: rogues,
|
||||
RogueListHash: j.RogueListHash,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Statement is a structure representing the Metadata Statement dictionary. Authenticator metadata statements are used
|
||||
// directly by the FIDO server at a relying party, but the information contained in the authoritative statement is used
|
||||
// in several other places.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.1-ps-20250521.html#sctn-md-keys
|
||||
type Statement struct {
|
||||
// The LegalHeader, if present, contains a legal guide for accessing and using metadata, which itself MAY contain
|
||||
// URL(s) pointing to further information, such as a full Terms and Conditions statement.
|
||||
LegalHeader string
|
||||
|
||||
// Aaid is the Authenticator Attestation ID.
|
||||
Aaid string
|
||||
|
||||
// AaGUID is the Authenticator Attestation GUID.
|
||||
AaGUID uuid.UUID
|
||||
|
||||
// AttestationCertificateKeyIdentifiers is a list of the attestation certificate public key identifiers encoded as
|
||||
// hex string.
|
||||
AttestationCertificateKeyIdentifiers []string
|
||||
|
||||
// FriendlyNames contains friendly names (i.e., public trade name) of the authenticator in multiple languages.
|
||||
FriendlyNames map[string]string
|
||||
|
||||
// Description is a human-readable, short description of the authenticator, in English.
|
||||
Description string
|
||||
|
||||
// AlternativeDescriptions is a list of human-readable short descriptions of the authenticator in different
|
||||
// languages.
|
||||
AlternativeDescriptions map[string]string
|
||||
|
||||
// AuthenticatorVersion is the earliest (i.e. lowest) trustworthy authenticatorVersion meeting the requirements
|
||||
// specified in this metadata statement.
|
||||
AuthenticatorVersion uint32
|
||||
|
||||
// ProtocolFamily is the FIDO protocol family. The values "uaf", "u2f", and "fido2" are supported.
|
||||
ProtocolFamily string
|
||||
|
||||
// Schema is the Metadata Schema version.
|
||||
Schema uint16
|
||||
|
||||
// Upv is the FIDO unified protocol version(s) (related to the specific protocol family) supported by this
|
||||
// authenticator.
|
||||
Upv []Version
|
||||
|
||||
// AuthenticationAlgorithms is the list of authentication algorithms supported by the authenticator.
|
||||
AuthenticationAlgorithms []AuthenticationAlgorithm
|
||||
|
||||
// PublicKeyAlgAndEncodings is the list of public key formats supported by the authenticator during registration
|
||||
// operations.
|
||||
PublicKeyAlgAndEncodings []PublicKeyAlgAndEncoding
|
||||
|
||||
// AttestationTypes is the supported attestation type(s).
|
||||
AttestationTypes AuthenticatorAttestationTypes
|
||||
|
||||
// UserVerificationDetails is a list of alternative VerificationMethodANDCombinations.
|
||||
UserVerificationDetails [][]VerificationMethodDescriptor
|
||||
|
||||
// KeyProtection is a 16-bit number representing the bit fields defined by the KEY_PROTECTION constants in the FIDO
|
||||
// Registry of Predefined Values.
|
||||
KeyProtection []string
|
||||
|
||||
// IsKeyRestricted is set to true or it is omitted, if the Uauth private key is restricted by the authenticator to
|
||||
// only sign valid FIDO signature assertions. This entry is set to false, if the authenticator doesn't restrict the
|
||||
// Uauth key to only sign valid FIDO signature assertions.
|
||||
IsKeyRestricted bool
|
||||
|
||||
// IsFreshUserVerificationRequired is set to true or it is omitted, if Uauth key usage always requires a fresh user
|
||||
// verification. This entry is set to false, if the Uauth key can be used without requiring a fresh user
|
||||
// verification, i.e. without any additional user interaction, if the user was verified a (potentially configurable)
|
||||
// caching time ago.
|
||||
IsFreshUserVerificationRequired bool
|
||||
|
||||
// MatcherProtection is a 16-bit number representing the bit fields defined by the MATCHER_PROTECTION constants in
|
||||
// the FIDO Registry of Predefined Values.
|
||||
MatcherProtection []string
|
||||
|
||||
// CryptoStrength is the authenticator's overall claimed cryptographic strength in bits (sometimes also called
|
||||
// security strength or security level).
|
||||
CryptoStrength uint16
|
||||
|
||||
// AttachmentHint is a 32-bit number representing the bit fields defined by the ATTACHMENT_HINT constants in the
|
||||
// FIDO Registry of Predefined Values.
|
||||
AttachmentHint []string
|
||||
|
||||
// TcDisplay is a 16-bit number representing a combination of the bit flags defined by the
|
||||
// TRANSACTION_CONFIRMATION_DISPLAY constants in the FIDO Registry of Predefined Values.
|
||||
TcDisplay []string
|
||||
|
||||
// TcDisplayContentType is the supported MIME content type [RFC2049] for the transaction confirmation display, such
|
||||
// as text/plain or image/png.
|
||||
TcDisplayContentType string
|
||||
|
||||
// TcDisplayPNGCharacteristics is a list of alternative [DisplayPNGCharacteristicsDescriptor]. Each of these entries
|
||||
// is one alternative of supported image characteristics for displaying a PNG image.
|
||||
TcDisplayPNGCharacteristics []DisplayPNGCharacteristicsDescriptor
|
||||
|
||||
// AttestationRootCertificates is a list of root certificates. Each element of this array represents a PKIX
|
||||
// [RFC5280] X.509 certificate that is a valid trust anchor for this authenticator model.
|
||||
// Multiple certificates might be used for different batches of the same model.
|
||||
// The array does not represent a certificate chain, but only the trust anchor of that chain.
|
||||
// A trust anchor can be a root certificate, an intermediate CA certificate, or even the attestation certificate
|
||||
// itself.
|
||||
AttestationRootCertificates []*x509.Certificate
|
||||
|
||||
// EcdaaTrustAnchors is a list of trust anchors used for ECDAA attestation. This entry MUST be present if and only
|
||||
// if attestationType includes ATTESTATION_ECDAA.
|
||||
EcdaaTrustAnchors []EcdaaTrustAnchor
|
||||
|
||||
// Icon is a 'data:' url [RFC2397] encoded [PNG] or [SVG11] (light mode) icon for the Authenticator (i.e., depicting
|
||||
// the security key). This icon is intended to be shown to users by RPs. Use of [SVG11] format is mandatory if any
|
||||
// of the iconDark, providerLogoLight and/or providerLogoDark is used in addition to icon. Use of [SVG11] is
|
||||
// recommended if only icon is used. The icon is more specific than the provider logo and should be shown if
|
||||
// present.
|
||||
Icon *url.URL
|
||||
|
||||
// IconDark is a 'data:' url [RFC2397] encoded [SVG11] dark mode icon for the Authenticator (i.e., depicting the
|
||||
// security key). This icon is intended to be shown to users by RPs. The icon is more specific than the provider
|
||||
// logo and should be shown if present.
|
||||
IconDark *url.URL
|
||||
|
||||
// ProviderLogoLight is a 'data:' url [RFC2397] encoded [SVG11] light mode icon for the provider (i.e., logomark of
|
||||
// the passkey provider). The SVG MUST meet all of the requirements defined in § 4.1 SVG requirements. This icon
|
||||
// is intended to be shown to users by RPs.
|
||||
ProviderLogoLight *url.URL
|
||||
|
||||
// ProviderLogoDark is a 'data:' url [RFC2397] encoded [SVG11] dark mode icon for the provider (i.e., logomark of
|
||||
// the passkey provider). The SVG MUST meet all of the requirements defined in § 4.1 SVG requirements. This icon
|
||||
// is intended to be shown to users by RPs.
|
||||
ProviderLogoDark *url.URL
|
||||
|
||||
// SupportedExtensions is a list of extensions supported by the authenticator.
|
||||
SupportedExtensions []ExtensionDescriptor
|
||||
|
||||
// KeyScope of keys generated and maintained by this authenticator model.
|
||||
KeyScope KeyScope
|
||||
|
||||
// MultiDeviceCredentialSupport describes the support for multi-device credentials.
|
||||
MultiDeviceCredentialSupport MultiDeviceCredentialSupport
|
||||
|
||||
// AuthenticatorGetInfo describes supported versions, extensions, AAGUID of the device and its capabilities.
|
||||
AuthenticatorGetInfo AuthenticatorGetInfo
|
||||
|
||||
// CredentialExportProtocolConfigURL specifies the URL for retrieving the configuration details for the credential
|
||||
// export protocol (CXP).
|
||||
CredentialExportProtocolConfigURL *url.URL
|
||||
}
|
||||
|
||||
func (s *Statement) Verifier(x5cis []*x509.Certificate) (opts x509.VerifyOptions) {
|
||||
roots := x509.NewCertPool()
|
||||
|
||||
for _, root := range s.AttestationRootCertificates {
|
||||
roots.AddCert(root)
|
||||
}
|
||||
|
||||
var intermediates *x509.CertPool
|
||||
|
||||
if len(x5cis) > 0 {
|
||||
intermediates = x509.NewCertPool()
|
||||
|
||||
for _, x5c := range x5cis {
|
||||
intermediates.AddCert(x5c)
|
||||
}
|
||||
}
|
||||
|
||||
return x509.VerifyOptions{
|
||||
Roots: roots,
|
||||
Intermediates: intermediates,
|
||||
}
|
||||
}
|
||||
|
||||
// StatementJSON is the JSON representation of the [Statement] struct.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.1-ps-20250521.html#sctn-md-keys
|
||||
type StatementJSON struct {
|
||||
// LegalHeader contains a legal guide for accessing and using metadata.
|
||||
LegalHeader string `json:"legalHeader"`
|
||||
|
||||
// Aaid is the Authenticator Attestation ID. Set if the authenticator implements FIDO UAF.
|
||||
Aaid string `json:"aaid"`
|
||||
|
||||
// AaGUID is the Authenticator Attestation GUID. Set if the authenticator implements FIDO2.
|
||||
AaGUID string `json:"aaguid"`
|
||||
|
||||
// AttestationCertificateKeyIdentifiers is a list of attestation certificate public key identifiers (hex).
|
||||
AttestationCertificateKeyIdentifiers []string `json:"attestationCertificateKeyIdentifiers"`
|
||||
|
||||
// FriendlyNames contains friendly names of the authenticator in multiple languages.
|
||||
FriendlyNames map[string]string `json:"friendlyNames"`
|
||||
|
||||
// Description is a human-readable, short description of the authenticator, in English.
|
||||
Description string `json:"description"`
|
||||
|
||||
// AlternativeDescriptions is a list of human-readable short descriptions in different languages.
|
||||
AlternativeDescriptions map[string]string `json:"alternativeDescriptions"`
|
||||
|
||||
// AuthenticatorVersion is the earliest trustworthy authenticatorVersion meeting the requirements in this statement.
|
||||
AuthenticatorVersion uint32 `json:"authenticatorVersion"`
|
||||
|
||||
// ProtocolFamily is the FIDO protocol family. The values "uaf", "u2f", and "fido2" are supported.
|
||||
ProtocolFamily string `json:"protocolFamily"`
|
||||
|
||||
// Schema is the Metadata Schema version.
|
||||
Schema uint16 `json:"schema"`
|
||||
|
||||
// Upv is the FIDO unified protocol version(s) supported by this authenticator.
|
||||
Upv []Version `json:"upv"`
|
||||
|
||||
// AuthenticationAlgorithms is the list of authentication algorithms supported by the authenticator.
|
||||
AuthenticationAlgorithms []AuthenticationAlgorithm `json:"authenticationAlgorithms"`
|
||||
|
||||
// PublicKeyAlgAndEncodings is the list of public key formats supported during registration operations.
|
||||
PublicKeyAlgAndEncodings []PublicKeyAlgAndEncoding `json:"publicKeyAlgAndEncodings"`
|
||||
|
||||
// AttestationTypes is the supported attestation type(s).
|
||||
AttestationTypes []AuthenticatorAttestationType `json:"attestationTypes"`
|
||||
|
||||
// UserVerificationDetails is a list of alternative VerificationMethodANDCombinations.
|
||||
UserVerificationDetails [][]VerificationMethodDescriptor `json:"userVerificationDetails"`
|
||||
|
||||
// KeyProtection is the key protection type(s).
|
||||
KeyProtection []string `json:"keyProtection"`
|
||||
|
||||
// IsKeyRestricted indicates if the Uauth private key is restricted to only sign valid FIDO signature assertions.
|
||||
IsKeyRestricted bool `json:"isKeyRestricted"`
|
||||
|
||||
// IsFreshUserVerificationRequired indicates if Uauth key usage always requires a fresh user verification.
|
||||
IsFreshUserVerificationRequired bool `json:"isFreshUserVerificationRequired"`
|
||||
|
||||
// MatcherProtection is the matcher protection type(s).
|
||||
MatcherProtection []string `json:"matcherProtection"`
|
||||
|
||||
// CryptoStrength is the authenticator's overall claimed cryptographic strength in bits.
|
||||
CryptoStrength uint16 `json:"cryptoStrength"`
|
||||
|
||||
// AttachmentHint is the attachment hint(s).
|
||||
AttachmentHint []string `json:"attachmentHint"`
|
||||
|
||||
// TcDisplay is the transaction confirmation display type(s).
|
||||
TcDisplay []string `json:"tcDisplay"`
|
||||
|
||||
// TcDisplayContentType is the supported MIME content type for the transaction confirmation display.
|
||||
TcDisplayContentType string `json:"tcDisplayContentType"`
|
||||
|
||||
// TcDisplayPNGCharacteristics is a list of alternative DisplayPNGCharacteristicsDescriptor.
|
||||
TcDisplayPNGCharacteristics []DisplayPNGCharacteristicsDescriptor `json:"tcDisplayPNGCharacteristics"`
|
||||
|
||||
// AttestationRootCertificates is a list of base64-encoded trust anchor certificates for this authenticator model.
|
||||
AttestationRootCertificates []string `json:"attestationRootCertificates"`
|
||||
|
||||
// EcdaaTrustAnchors is a list of trust anchors used for ECDAA attestation.
|
||||
EcdaaTrustAnchors []EcdaaTrustAnchor `json:"ecdaaTrustAnchors"`
|
||||
|
||||
// Icon is a data: URL encoded PNG or SVG (light mode) icon for the Authenticator.
|
||||
Icon string `json:"icon"`
|
||||
|
||||
// IconDark is a data: URL encoded SVG dark mode icon for the Authenticator.
|
||||
IconDark string `json:"iconDark"`
|
||||
|
||||
// ProviderLogoLight is a data: URL encoded SVG light mode icon for the provider.
|
||||
ProviderLogoLight string `json:"providerLogoLight"`
|
||||
|
||||
// ProviderLogoDark is a data: URL encoded SVG dark mode icon for the provider.
|
||||
ProviderLogoDark string `json:"providerLogoDark"`
|
||||
|
||||
// SupportedExtensions is a list of extensions supported by the authenticator.
|
||||
SupportedExtensions []ExtensionDescriptor `json:"supportedExtensions"`
|
||||
|
||||
// KeyScope of keys generated and maintained by this authenticator model.
|
||||
KeyScope KeyScope `json:"keyScope"`
|
||||
|
||||
// MultiDeviceCredentialSupport describes the support for multi-device credentials.
|
||||
MultiDeviceCredentialSupport MultiDeviceCredentialSupport `json:"multiDeviceCredentialSupport"`
|
||||
|
||||
// AuthenticatorGetInfo describes supported versions, extensions, AAGUID of the device and its capabilities.
|
||||
AuthenticatorGetInfo AuthenticatorGetInfoJSON `json:"authenticatorGetInfo"`
|
||||
|
||||
// CredentialExportProtocolConfigURL specifies the URL for the credential export protocol (CXP) configuration.
|
||||
CredentialExportProtocolConfigURL string `json:"cxpConfigURL"`
|
||||
}
|
||||
|
||||
// Parse converts StatementJSON into a [Statement] object, validating and parsing its fields. Returns an error on failure.
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func (j StatementJSON) Parse() (statement Statement, err error) {
|
||||
var aaguid uuid.UUID
|
||||
|
||||
if len(j.AaGUID) != 0 {
|
||||
if aaguid, err = uuid.Parse(j.AaGUID); err != nil {
|
||||
return statement, fmt.Errorf("error occurred parsing statement with description '%s': error occurred parsing AAGUID value: %w", j.Description, err)
|
||||
}
|
||||
}
|
||||
|
||||
n := len(j.AttestationRootCertificates)
|
||||
|
||||
certificates := make([]*x509.Certificate, n)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
if certificates[i], err = mdsParseX509Certificate(j.AttestationRootCertificates[i]); err != nil {
|
||||
return statement, fmt.Errorf("error occurred parsing statement with description '%s': error occurred parsing attestation root certificate %d value: %w", j.Description, i, err)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
icon, iconDark *url.URL
|
||||
|
||||
logoLight, logoDark *url.URL
|
||||
|
||||
cxpConfigURL *url.URL
|
||||
)
|
||||
|
||||
if len(j.Icon) != 0 {
|
||||
if icon, err = url.ParseRequestURI(j.Icon); err != nil {
|
||||
return statement, fmt.Errorf("error occurred parsing statement with description '%s': error occurred parsing icon value: %w", j.Description, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(j.IconDark) != 0 {
|
||||
if iconDark, err = url.ParseRequestURI(j.IconDark); err != nil {
|
||||
return statement, fmt.Errorf("error occurred parsing statement with description '%s': error occurred parsing icon dark value: %w", j.Description, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(j.ProviderLogoLight) != 0 {
|
||||
if logoLight, err = url.ParseRequestURI(j.ProviderLogoLight); err != nil {
|
||||
return statement, fmt.Errorf("error occurred parsing statement with description '%s': error occurred parsing provider logo light value: %w", j.Description, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(j.ProviderLogoDark) != 0 {
|
||||
if logoDark, err = url.ParseRequestURI(j.ProviderLogoDark); err != nil {
|
||||
return statement, fmt.Errorf("error occurred parsing statement with description '%s': error occurred parsing provider logo dark value: %w", j.Description, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(j.CredentialExportProtocolConfigURL) != 0 {
|
||||
if cxpConfigURL, err = url.ParseRequestURI(j.CredentialExportProtocolConfigURL); err != nil {
|
||||
return statement, fmt.Errorf("error occurred parsing statement with description '%s': error occurred parsing cxp config url value: %w", j.Description, err)
|
||||
}
|
||||
}
|
||||
|
||||
var info AuthenticatorGetInfo
|
||||
|
||||
if info, err = j.AuthenticatorGetInfo.Parse(); err != nil {
|
||||
return statement, fmt.Errorf("error occurred parsing statement with description '%s': error occurred parsing authenticator get info value: %w", j.Description, err)
|
||||
}
|
||||
|
||||
return Statement{
|
||||
LegalHeader: j.LegalHeader,
|
||||
Aaid: j.Aaid,
|
||||
AaGUID: aaguid,
|
||||
AttestationCertificateKeyIdentifiers: j.AttestationCertificateKeyIdentifiers,
|
||||
FriendlyNames: j.FriendlyNames,
|
||||
Description: j.Description,
|
||||
AlternativeDescriptions: j.AlternativeDescriptions,
|
||||
AuthenticatorVersion: j.AuthenticatorVersion,
|
||||
ProtocolFamily: j.ProtocolFamily,
|
||||
Schema: j.Schema,
|
||||
Upv: j.Upv,
|
||||
AuthenticationAlgorithms: j.AuthenticationAlgorithms,
|
||||
PublicKeyAlgAndEncodings: j.PublicKeyAlgAndEncodings,
|
||||
AttestationTypes: j.AttestationTypes,
|
||||
UserVerificationDetails: j.UserVerificationDetails,
|
||||
KeyProtection: j.KeyProtection,
|
||||
IsKeyRestricted: j.IsKeyRestricted,
|
||||
IsFreshUserVerificationRequired: j.IsFreshUserVerificationRequired,
|
||||
MatcherProtection: j.MatcherProtection,
|
||||
CryptoStrength: j.CryptoStrength,
|
||||
AttachmentHint: j.AttachmentHint,
|
||||
TcDisplay: j.TcDisplay,
|
||||
TcDisplayContentType: j.TcDisplayContentType,
|
||||
TcDisplayPNGCharacteristics: j.TcDisplayPNGCharacteristics,
|
||||
AttestationRootCertificates: certificates,
|
||||
EcdaaTrustAnchors: j.EcdaaTrustAnchors,
|
||||
Icon: icon,
|
||||
IconDark: iconDark,
|
||||
ProviderLogoLight: logoLight,
|
||||
ProviderLogoDark: logoDark,
|
||||
SupportedExtensions: j.SupportedExtensions,
|
||||
KeyScope: j.KeyScope,
|
||||
MultiDeviceCredentialSupport: j.MultiDeviceCredentialSupport,
|
||||
AuthenticatorGetInfo: info,
|
||||
CredentialExportProtocolConfigURL: cxpConfigURL,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// BiometricStatusReport is a structure representing the BiometricStatusReport dictionary. Contains the current
|
||||
// BiometricStatusReport of one of the authenticator's biometric component.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-service-v3.1.1-rd-20251016.html#sctn-bio-stat-rep
|
||||
type BiometricStatusReport struct {
|
||||
// CertLevel is the achieved level of the biometric certification of this biometric component of the authenticator.
|
||||
CertLevel uint16
|
||||
|
||||
// Modality is a single USER_VERIFY short form case-sensitive string name constant, representing biometric modality.
|
||||
Modality string
|
||||
|
||||
// EffectiveDate is an ISO-8601 formatted date since when the certLevel achieved, if applicable. If no date is
|
||||
// given, the status is assumed to be effective while present.
|
||||
EffectiveDate time.Time
|
||||
|
||||
// CertificationDescriptor describes the externally visible aspects of the Biometric Certification evaluation.
|
||||
CertificationDescriptor string
|
||||
|
||||
// CertificateNumber is the unique identifier for the issued Biometric Certification.
|
||||
CertificateNumber string
|
||||
|
||||
// CertificationPolicyVersion is the version of the Biometric Certification Policy the implementation is Certified
|
||||
// to, i.e. "1.0.0".
|
||||
CertificationPolicyVersion string
|
||||
|
||||
// CertificationRequirementsVersion is the version of the Biometric Requirements [FIDOBiometricsRequirements] the
|
||||
// implementation is certified to, i.e. "1.0.0".
|
||||
CertificationRequirementsVersion string
|
||||
}
|
||||
|
||||
// BiometricStatusReportJSON is the JSON representation of the [BiometricStatusReport] struct.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-service-v3.1.1-rd-20251016.html#sctn-bio-stat-rep
|
||||
type BiometricStatusReportJSON struct {
|
||||
// CertLevel is the achieved level of the biometric certification of this biometric component.
|
||||
CertLevel uint16 `json:"certLevel"`
|
||||
|
||||
// Modality is a single USER_VERIFY short form string constant representing the biometric modality.
|
||||
Modality string `json:"modality"`
|
||||
|
||||
// EffectiveDate is an ISO-8601 formatted date since when the certLevel was achieved.
|
||||
EffectiveDate string `json:"effectiveDate"`
|
||||
|
||||
// CertificationDescriptor describes the externally visible aspects of the Biometric Certification evaluation.
|
||||
CertificationDescriptor string `json:"certificationDescriptor"`
|
||||
|
||||
// CertificateNumber is the unique identifier for the issued Biometric Certification.
|
||||
CertificateNumber string `json:"certificateNumber"`
|
||||
|
||||
// CertificationPolicyVersion is the version of the Biometric Certification Policy, i.e. "1.0.0".
|
||||
CertificationPolicyVersion string `json:"certificationPolicyVersion"`
|
||||
|
||||
// CertificationRequirementsVersion is the version of the Biometric Requirements, i.e. "1.0.0".
|
||||
CertificationRequirementsVersion string `json:"certificationRequirementsVersion"`
|
||||
}
|
||||
|
||||
func (j BiometricStatusReportJSON) Parse() (report BiometricStatusReport, err error) {
|
||||
var effective time.Time
|
||||
|
||||
if effective, err = time.Parse(time.DateOnly, j.EffectiveDate); err != nil {
|
||||
return report, fmt.Errorf("error occurred parsing effective date value: %w", err)
|
||||
}
|
||||
|
||||
return BiometricStatusReport{
|
||||
CertLevel: j.CertLevel,
|
||||
Modality: j.Modality,
|
||||
EffectiveDate: effective,
|
||||
CertificationDescriptor: j.CertificationDescriptor,
|
||||
CertificateNumber: j.CertificateNumber,
|
||||
CertificationPolicyVersion: j.CertificationPolicyVersion,
|
||||
CertificationRequirementsVersion: j.CertificationRequirementsVersion,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// StatusReport is a structure representing the StatusReport dictionary. Contains an [AuthenticatorStatus] and additional
|
||||
// data associated with it, if any.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-service-v3.1.1-rd-20251016.html#sctn-stat-rep
|
||||
type StatusReport struct {
|
||||
// Status of the authenticator. Additional fields MAY be set depending on this value.
|
||||
Status AuthenticatorStatus
|
||||
|
||||
// EffectiveDate is an ISO-8601 formatted date since when the status code was set, if applicable. If no date is
|
||||
// given, the status is assumed to be effective while present.
|
||||
EffectiveDate time.Time
|
||||
|
||||
// AuthenticatorVersion is the authenticator version (firmware version) that this status report relates to. In the
|
||||
// case of FIDO_CERTIFIED* status values, the status applies to higher authenticatorVersions until there is a new
|
||||
// statusReport.
|
||||
AuthenticatorVersion uint32
|
||||
|
||||
// BatchCertificate is a Base64-encoded [RFC4648] (not base64url!) DER [ITU-X690-2008] PKIX certificate value
|
||||
// related to the current status, if applicable.
|
||||
BatchCertificate *x509.Certificate
|
||||
|
||||
// Certificate is a Base64-encoded [RFC4648] (not base64url!) DER [ITU-X690-2008] PKIX certificate value related to
|
||||
// the current status, if applicable. This field will typically not be present if field batchCertificate is present.
|
||||
Certificate *x509.Certificate
|
||||
|
||||
// URL is a HTTPS URL where additional information may be found related to the current status, if applicable.
|
||||
URL *url.URL
|
||||
|
||||
// CertificationDescriptor describes the externally visible aspects of the Authenticator Certification evaluation.
|
||||
CertificationDescriptor string
|
||||
|
||||
// CertificateNumber is the unique identifier for the issued Certification.
|
||||
CertificateNumber string
|
||||
|
||||
// CertificationPolicyVersion is the version of the Authenticator Certification Policy the implementation is
|
||||
// Certified to, i.e. "1.0.0".
|
||||
CertificationPolicyVersion string
|
||||
|
||||
// CertificationProfiles is a list of certification profile strings. Each entry represents a supported
|
||||
// certification profile, i.e. "consumer" or "enterprise".
|
||||
CertificationProfiles []string
|
||||
|
||||
// CertificationRequirementsVersion is the Document Version of the Authenticator Security Requirements (DV)
|
||||
// [FIDOAuthenticatorSecurityRequirements] the implementation is certified to, i.e. "1.2.0".
|
||||
CertificationRequirementsVersion string
|
||||
|
||||
// SunsetDate is an ISO-8601 formatted date since when the status will expire, if applicable. If no date is given,
|
||||
// the status is assumed to not have a scheduled expiry.
|
||||
SunsetDate *time.Time
|
||||
|
||||
// FIPSRevision is the revision number of the FIPS 140 specification, i.e. "3" in the case of FIPS 140-3. This
|
||||
// entry MUST be present if and only if the status entry is one of FIPS140_CERTIFIED_L*.
|
||||
FIPSRevision uint32
|
||||
|
||||
// FIPSPhysicalSecurityLevel is the "physical security level" of the FIPS certification. This entry MUST be present
|
||||
// if and only if the status entry is one of FIPS140_CERTIFIED_L*. It MUST reflect the physical security level
|
||||
// which might deviate from the overall level.
|
||||
FIPSPhysicalSecurityLevel uint32
|
||||
}
|
||||
|
||||
// StatusReportJSON is the JSON representation of the [StatusReport] struct.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-service-v3.1.1-rd-20251016.html#sctn-stat-rep
|
||||
type StatusReportJSON struct {
|
||||
// Status of the authenticator. Additional fields MAY be set depending on this value.
|
||||
Status AuthenticatorStatus `json:"status"`
|
||||
|
||||
// EffectiveDate is an ISO-8601 formatted date since when the status code was set.
|
||||
EffectiveDate string `json:"effectiveDate"`
|
||||
|
||||
// AuthenticatorVersion is the authenticator version (firmware version) that this status report relates to.
|
||||
AuthenticatorVersion uint32 `json:"authenticatorVersion"`
|
||||
|
||||
// BatchCertificate is a Base64-encoded DER PKIX certificate related to the current status.
|
||||
BatchCertificate string `json:"batchCertificate"`
|
||||
|
||||
// Certificate is a Base64-encoded DER PKIX certificate related to the current status.
|
||||
Certificate string `json:"certificate"`
|
||||
|
||||
// URL is a HTTPS URL where additional information may be found related to the current status.
|
||||
URL string `json:"url"`
|
||||
|
||||
// CertificationDescriptor describes the externally visible aspects of the Authenticator Certification evaluation.
|
||||
CertificationDescriptor string `json:"certificationDescriptor"`
|
||||
|
||||
// CertificateNumber is the unique identifier for the issued Certification.
|
||||
CertificateNumber string `json:"certificateNumber"`
|
||||
|
||||
// CertificationPolicyVersion is the version of the Authenticator Certification Policy, i.e. "1.0.0".
|
||||
CertificationPolicyVersion string `json:"certificationPolicyVersion"`
|
||||
|
||||
// CertificationProfiles is a list of supported certification profiles, i.e. "consumer" or "enterprise".
|
||||
CertificationProfiles []string `json:"certificationProfiles"`
|
||||
|
||||
// CertificationRequirementsVersion is the Document Version of the Authenticator Security Requirements, i.e. "1.2.0".
|
||||
CertificationRequirementsVersion string `json:"certificationRequirementsVersion"`
|
||||
|
||||
// SunsetDate is an ISO-8601 formatted date when the status will expire.
|
||||
SunsetDate string `json:"sunsetDate"`
|
||||
|
||||
// FIPSRevision is the revision number of the FIPS 140 specification, i.e. "3" for FIPS 140-3.
|
||||
FIPSRevision uint32 `json:"fipsRevision"`
|
||||
|
||||
// FIPSPhysicalSecurityLevel is the physical security level of the FIPS certification.
|
||||
FIPSPhysicalSecurityLevel uint32 `json:"fipsPhysicalSecurityLevel"`
|
||||
}
|
||||
|
||||
func (j StatusReportJSON) Parse() (report StatusReport, err error) {
|
||||
var (
|
||||
certificate, batchCertificate *x509.Certificate
|
||||
)
|
||||
|
||||
if len(j.Certificate) != 0 {
|
||||
if certificate, err = mdsParseX509Certificate(j.Certificate); err != nil {
|
||||
return report, fmt.Errorf("error occurred parsing certificate value: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(j.BatchCertificate) != 0 {
|
||||
if batchCertificate, err = mdsParseX509Certificate(j.BatchCertificate); err != nil {
|
||||
return report, fmt.Errorf("error occurred parsing batch certificate value: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
effective time.Time
|
||||
sunset *time.Time
|
||||
)
|
||||
|
||||
if effective, err = time.Parse(time.DateOnly, j.EffectiveDate); err != nil {
|
||||
return report, fmt.Errorf("error occurred parsing effective date value: %w", err)
|
||||
}
|
||||
|
||||
if sunset, err = mdsParseTimePointer(time.DateOnly, j.SunsetDate); err != nil {
|
||||
return report, fmt.Errorf("error occurred parsing sunset date value: %w", err)
|
||||
}
|
||||
|
||||
var uri *url.URL
|
||||
|
||||
if len(j.URL) != 0 {
|
||||
if uri, err = url.ParseRequestURI(j.URL); err != nil {
|
||||
if !strings.HasPrefix(j.URL, "http") {
|
||||
var e error
|
||||
if uri, e = url.ParseRequestURI(fmt.Sprintf("https://%s", j.URL)); e != nil {
|
||||
return report, fmt.Errorf("error occurred parsing URL value: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return StatusReport{
|
||||
Status: j.Status,
|
||||
EffectiveDate: effective,
|
||||
AuthenticatorVersion: j.AuthenticatorVersion,
|
||||
BatchCertificate: batchCertificate,
|
||||
Certificate: certificate,
|
||||
URL: uri,
|
||||
CertificationDescriptor: j.CertificationDescriptor,
|
||||
CertificateNumber: j.CertificateNumber,
|
||||
CertificationPolicyVersion: j.CertificationPolicyVersion,
|
||||
CertificationProfiles: j.CertificationProfiles,
|
||||
CertificationRequirementsVersion: j.CertificationRequirementsVersion,
|
||||
SunsetDate: sunset,
|
||||
FIPSRevision: j.FIPSRevision,
|
||||
FIPSPhysicalSecurityLevel: j.FIPSPhysicalSecurityLevel,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RogueListEntry is a structure representing the RogueListEntry dictionary.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-service-v3.1.1-rd-20251016.html#sctn-rogue-list-entry
|
||||
type RogueListEntry struct {
|
||||
// Sk is the base64url encoding of the rogue authenticator's secret key.
|
||||
Sk string `json:"sk"`
|
||||
|
||||
// Data is the ISO-8601 formatted date since when this entry is effective.
|
||||
Date string `json:"date"`
|
||||
}
|
||||
|
||||
// CodeAccuracyDescriptor is a structure representing the CodeAccuracyDescriptor dictionary.
|
||||
// It describes the relevant accuracy/complexity aspects of passcode user verification methods.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.1-ps-20250521.html#sctn-type-cad
|
||||
type CodeAccuracyDescriptor struct {
|
||||
// Base is the numeric system base (radix) of the code, i.e. 10 in the case of decimal digits.
|
||||
Base uint16 `json:"base"`
|
||||
|
||||
// MinLength is the minimum number of digits of the given base required for that code, i.e. 4 in the case of 4
|
||||
// digits.
|
||||
MinLength uint16 `json:"minLength"`
|
||||
|
||||
// MaxRetries is the maximum number of false attempts before the authenticator will block this method (at least for
|
||||
// some time). 0 means it will never block.
|
||||
MaxRetries uint16 `json:"maxRetries"`
|
||||
|
||||
// BlockSlowdown is the enforced minimum number of seconds wait time after blocking (i.e. due to forced reboot or
|
||||
// similar). 0 means this user verification method will be blocked, either permanently, or until an alternative user
|
||||
// verification method method succeeded. All alternative user verification methods MUST be specified appropriately
|
||||
// in the Metadata in userVerificationDetails.
|
||||
BlockSlowdown uint16 `json:"blockSlowdown"`
|
||||
}
|
||||
|
||||
// BiometricAccuracyDescriptor is a structure representing the BiometricAccuracyDescriptor dictionary.
|
||||
// It describes relevant accuracy/complexity aspects in the case of a biometric user verification method.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.1-ps-20250521.html#sctn-type-bad
|
||||
type BiometricAccuracyDescriptor struct {
|
||||
// SelfAttestedFRR is the false rejection rate [ISO19795-1] for a single template, i.e. the percentage of
|
||||
// verification transactions with truthful claims of identity that are incorrectly denied.
|
||||
SelfAttestedFRR float64 `json:"selfAttestedFRR"`
|
||||
|
||||
// SelfAttestedFAR is the false acceptance rate [ISO19795-1] for a single template, i.e. the percentage of
|
||||
// verification transactions with wrongful claims of identity that are incorrectly confirmed.
|
||||
SelfAttestedFAR float64 `json:"selfAttestedFAR"`
|
||||
|
||||
// ImposterAttackPresentationAcceptRateThreshold is the threshold for Impostor Attack Presentation Accept Rate
|
||||
// (IAPAR) is the proportion of impostor attack presentations using the same presentation attack instrument (PAI)
|
||||
// species that result in accept [isoiec-30107-3]. For biometric certification requirements
|
||||
// [FIDOBiometricsRequirements], certification can be achieved for an IAPAR threshold of less than 7% OR less than
|
||||
// 15% for each of the PAI species tested.
|
||||
ImposterAttackPresentationAcceptRateThreshold float64 `json:"iAPARThreshold"`
|
||||
|
||||
// MaxTemplates is the maximum number of alternative templates from different fingers allowed.
|
||||
MaxTemplates uint16 `json:"maxTemplates"`
|
||||
|
||||
// MaxRetries is the maximum number of false attempts before the authenticator will block this method (at least for
|
||||
// some time). 0 means it will never block.
|
||||
MaxRetries uint16 `json:"maxRetries"`
|
||||
|
||||
// BlockSlowdown is the enforced minimum number of seconds wait time after blocking (i.e. due to forced reboot or
|
||||
// similar).0 means that this user verification method will be blocked either permanently or until an alternative
|
||||
// user verification method succeeded. All alternative user verification methods MUST be specified appropriately in
|
||||
// the metadata in userVerificationDetails.
|
||||
BlockSlowdown uint16 `json:"blockSlowdown"`
|
||||
}
|
||||
|
||||
// PatternAccuracyDescriptor is a structure representing the PatternAccuracyDescriptor dictionary.
|
||||
// It describes relevant accuracy/complexity aspects in the case that a pattern is used as the user verification method.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.1-ps-20250521.html#sctn-type-pad
|
||||
type PatternAccuracyDescriptor struct {
|
||||
// MinComplexity is the number of possible patterns (having the minimum length) out of which exactly one would be
|
||||
// the right one, i.e. 1/probability in the case of equal distribution.
|
||||
MinComplexity uint32 `json:"minComplexity"`
|
||||
|
||||
// MaxRetries is the maximum number of false attempts before the authenticator will block authentication using this
|
||||
// method (at least temporarily). 0 means it will never block.
|
||||
MaxRetries uint16 `json:"maxRetries"`
|
||||
|
||||
// BlockSlowdown is the enforced minimum number of seconds wait time after blocking (due to forced reboot or similar
|
||||
// mechanism). 0 means this user verification method will be blocked, either permanently, or until an alternative
|
||||
// user verification method method succeeded. All alternative user verification methods MUST be specified
|
||||
// appropriately in the metadata under userVerificationDetails.
|
||||
BlockSlowdown uint16 `json:"blockSlowdown"`
|
||||
}
|
||||
|
||||
// VerificationMethodDescriptor is a structure representing the VerificationMethodDescriptor dictionary.
|
||||
// It describes a descriptor for a specific base user verification method as implemented by the authenticator.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.1-ps-20250521.html#sctn-type-vmd
|
||||
type VerificationMethodDescriptor struct {
|
||||
// UserVerificationMethod is a single USER_VERIFY constant (see [FIDORegistry]), not a bit flag combination. This
|
||||
// value MUST be non-zero.
|
||||
UserVerificationMethod string `json:"userVerificationMethod"`
|
||||
|
||||
// CaDesc nay optionally be used in the case of method USER_VERIFY_PASSCODE.
|
||||
CaDesc CodeAccuracyDescriptor `json:"caDesc"`
|
||||
|
||||
// BaDesc may optionally be used in the case of method USER_VERIFY_FINGERPRINT, USER_VERIFY_VOICEPRINT,
|
||||
// USER_VERIFY_FACEPRINT, USER_VERIFY_EYEPRINT, or USER_VERIFY_HANDPRINT.
|
||||
BaDesc BiometricAccuracyDescriptor `json:"baDesc"`
|
||||
|
||||
// PaDesc may optionally be used in case of method USER_VERIFY_PATTERN.
|
||||
PaDesc PatternAccuracyDescriptor `json:"paDesc"`
|
||||
}
|
||||
|
||||
// RGBPaletteEntry is a structure representing the RGBPaletteEntry dictionary.
|
||||
// It describes an RGB three-sample tuple palette entry.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.1-ps-20250521.html#sctn-type-rgbpe
|
||||
type RGBPaletteEntry struct {
|
||||
// R is the red channel sample value.
|
||||
R uint16 `json:"r"`
|
||||
|
||||
// G is the green channel sample value.
|
||||
G uint16 `json:"g"`
|
||||
|
||||
// B is the blue channel sample value.
|
||||
B uint16 `json:"b"`
|
||||
}
|
||||
|
||||
// DisplayPNGCharacteristicsDescriptor is a structure representing the DisplayPNGCharacteristicsDescriptor MDS3.1
|
||||
// dictionary. It describes a PNG image characteristics as defined in the PNG [PNG] spec for IHDR (image header) and
|
||||
// PLTE (palette table).
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.1-ps-20250521.html#sctn-type-dpngcd
|
||||
type DisplayPNGCharacteristicsDescriptor struct {
|
||||
// Width of the image.
|
||||
Width uint32 `json:"width"`
|
||||
|
||||
// Height of the image.
|
||||
Height uint32 `json:"height"`
|
||||
|
||||
// BitDepth is bits per sample or per palette index.
|
||||
BitDepth byte `json:"bitDepth"`
|
||||
|
||||
// ColorType defines the PNG image type.
|
||||
ColorType byte `json:"colorType"`
|
||||
|
||||
// Compression method used to compress the image data.
|
||||
Compression byte `json:"compression"`
|
||||
|
||||
// Filter method is the preprocessing method applied to the image data before compression.
|
||||
Filter byte `json:"filter"`
|
||||
|
||||
// Interlace method is the transmission order of the image data.
|
||||
Interlace byte `json:"interlace"`
|
||||
|
||||
// Plte is a number 1 to 256 representing palette entries.
|
||||
Plte []RGBPaletteEntry `json:"plte"`
|
||||
}
|
||||
|
||||
// EcdaaTrustAnchor is a structure representing the EcdaaTrustAnchor dictionary.
|
||||
// In the case of ECDAA attestation, the ECDAA-Issuer's trust anchor MUST be specified in this field.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.1-ps-20250521.html#sctn-type-ecdaata
|
||||
type EcdaaTrustAnchor struct {
|
||||
// X is the base64url encoding of the result of ECPoint2ToB of the ECPoint2 X.
|
||||
X string `json:"X"`
|
||||
|
||||
// Y is the base64url encoding of the result of ECPoint2ToB of the ECPoint2 Y.
|
||||
Y string `json:"Y"`
|
||||
|
||||
// C is the base64url encoding of the result of BigNumberToB(c).
|
||||
C string `json:"c"`
|
||||
|
||||
// SX is the base64url encoding of the result of BigNumberToB(sx).
|
||||
SX string `json:"sx"`
|
||||
|
||||
// SY is the base64url encoding of the result of BigNumberToB(sy).
|
||||
SY string `json:"sy"`
|
||||
|
||||
// G1Curve is the name of the Barreto-Naehrig elliptic curve for G1. "BN_P256", "BN_P638", "BN_ISOP256", and
|
||||
// "BN_ISOP512" are supported.
|
||||
G1Curve string `json:"G1Curve"`
|
||||
}
|
||||
|
||||
// ExtensionDescriptor is a structure representing the ExtensionDescriptor dictionary.
|
||||
// This descriptor contains an extension supported by the authenticator.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.1-ps-20250521.html#sctn-type-ed
|
||||
type ExtensionDescriptor struct {
|
||||
// ID identifies the extension.
|
||||
ID string `json:"id"`
|
||||
|
||||
// Tag of the extension if this was assigned. TAGs are assigned to extensions if they could appear in an assertion.
|
||||
Tag uint16 `json:"tag"`
|
||||
|
||||
// Data contains arbitrary data further describing the extension and/or data needed to correctly process the
|
||||
// extension.
|
||||
Data string `json:"data"`
|
||||
|
||||
// FailIfUnknown indicates whether unknown extensions must be ignored (false) or must lead to an error (true) when
|
||||
// the extension is to be processed by the FIDO Server, FIDO Client, ASM, or FIDO Authenticator.
|
||||
FailIfUnknown bool `json:"fail_if_unknown"`
|
||||
}
|
||||
|
||||
// Version is a structure representing the Version FIDO UAF Protocol 1.2 dictionary and represents a generic version
|
||||
// with major and minor fields.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/fido-uaf-v1.2-ps-20201020/fido-uaf-protocol-v1.2-ps-20201020.html#version-interface
|
||||
type Version struct {
|
||||
// Major version.
|
||||
Major uint16 `json:"major"`
|
||||
|
||||
// Minor version.
|
||||
Minor uint16 `json:"minor"`
|
||||
}
|
||||
|
||||
// AuthenticatorGetInfo is a structure representing the AuthenticatorGetInfo dictionary.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.1-ps-20250521.html#sctn-type-agid
|
||||
type AuthenticatorGetInfo struct {
|
||||
// Versions is a list of supported versions.
|
||||
Versions []string
|
||||
|
||||
// Extensions is a list of supported extensions.
|
||||
Extensions []string
|
||||
|
||||
// AaGUID is the claimed AAGUID.
|
||||
AaGUID uuid.UUID
|
||||
|
||||
// Options is a list of supported options.
|
||||
Options map[string]bool
|
||||
|
||||
// MaxMsgSize is the maximum message size supported by the authenticator.
|
||||
MaxMsgSize uint
|
||||
|
||||
// PivUvAuthProtocols is a list of supported PIN/UV auth protocols in order of decreasing authenticator preference.
|
||||
PivUvAuthProtocols []uint
|
||||
|
||||
// MaxCredentialCountInList is the maximum number of credentials supported in credentialID list at a time by the
|
||||
// authenticator.
|
||||
MaxCredentialCountInList uint
|
||||
|
||||
// MaxCredentialIdLength is the maximum Credential ID Length supported by the authenticator.
|
||||
MaxCredentialIdLength uint
|
||||
|
||||
// Transports is the list of supported transports.
|
||||
Transports []string
|
||||
|
||||
// Algorithms is the list of supported algorithms for credential generation, as specified in WebAuthn.
|
||||
Algorithms []PublicKeyCredentialParameters
|
||||
|
||||
// MaxSerializedLargeBlobArray is the maximum size, in bytes, of the serialized large-blob array that this
|
||||
// authenticator can store.
|
||||
MaxSerializedLargeBlobArray uint
|
||||
|
||||
// ForcePINChange indicates if the PIN must be changed.
|
||||
ForcePINChange bool
|
||||
|
||||
// MinPINLength specifies the current minimum PIN length, in Unicode code points, the authenticator enforces for ClientPIN.
|
||||
MinPINLength uint
|
||||
|
||||
// FirmwareVersion indicates the firmware version of the authenticator model identified by AAGUID.
|
||||
FirmwareVersion uint
|
||||
|
||||
// MaxCredBlobLength indicates the maximum credential blob length in bytes supported by the authenticator.
|
||||
MaxCredBlobLength uint
|
||||
|
||||
// MaxRPIDsForSetMinPINLength specifies the max number of RP IDs that authenticator can set via setMinPINLength
|
||||
// subcommand.
|
||||
MaxRPIDsForSetMinPINLength uint
|
||||
|
||||
// PreferredPlatformUvAttempts specifies the preferred number of invocations of the
|
||||
// getPinUvAuthTokenUsingUvWithPermissions subCommand the platform may attempt before falling back to the
|
||||
// getPinUvAuthTokenUsingPinWithPermissions subCommand or displaying an error.
|
||||
PreferredPlatformUvAttempts uint
|
||||
|
||||
// UvModality specifies the user verification modality supported by the authenticator via authenticatorClientPIN's
|
||||
// getPinUvAuthTokenUsingUvWithPermissions subcommand.
|
||||
UvModality uint
|
||||
|
||||
// Certifications specifies a list of authenticator certifications.
|
||||
Certifications map[string]float64
|
||||
|
||||
// RemainingDiscoverableCredentials if present indicates the estimated number of additional discoverable credentials
|
||||
// that can be stored.
|
||||
RemainingDiscoverableCredentials uint
|
||||
|
||||
// VendorPrototypeConfigCommands if present the authenticator supports the authenticatorConfig vendorPrototype
|
||||
// subcommand, and its value is a list of authenticatorConfig vendorCommandId values supported, which MAY be empty.
|
||||
VendorPrototypeConfigCommands []uint
|
||||
}
|
||||
|
||||
// AuthenticatorGetInfoJSON is the JSON representation of the [AuthenticatorGetInfo] struct. The members mirror the
|
||||
// fields returned by the CTAP authenticatorGetInfo command.
|
||||
//
|
||||
// See: https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.1-ps-20250521.html#sctn-type-agid
|
||||
type AuthenticatorGetInfoJSON struct {
|
||||
// Versions is a list of supported CTAP versions.
|
||||
Versions []string `json:"versions"`
|
||||
|
||||
// Extensions is a list of supported extensions.
|
||||
Extensions []string `json:"extensions"`
|
||||
|
||||
// AaGUID is the claimed AAGUID.
|
||||
AaGUID string `json:"aaguid"`
|
||||
|
||||
// Options is a map of supported options.
|
||||
Options map[string]bool `json:"options"`
|
||||
|
||||
// MaxMsgSize is the maximum message size supported by the authenticator.
|
||||
MaxMsgSize uint `json:"maxMsgSize"`
|
||||
|
||||
// PivUvAuthProtocols is a list of supported PIN/UV auth protocols in order of decreasing authenticator preference.
|
||||
PivUvAuthProtocols []uint `json:"pinUvAuthProtocols"`
|
||||
|
||||
// MaxCredentialCountInList is the maximum number of credentials supported in credentialID list at a time.
|
||||
MaxCredentialCountInList uint `json:"maxCredentialCountInList"`
|
||||
|
||||
// MaxCredentialIdLength is the maximum Credential ID Length supported by the authenticator.
|
||||
MaxCredentialIdLength uint `json:"maxCredentialIdLength"`
|
||||
|
||||
// Transports is the list of supported transports.
|
||||
Transports []string `json:"transports"`
|
||||
|
||||
// Algorithms is the list of supported algorithms for credential generation.
|
||||
Algorithms []PublicKeyCredentialParameters `json:"algorithms"`
|
||||
|
||||
// MaxSerializedLargeBlobArray is the maximum size, in bytes, of the serialized large-blob array.
|
||||
MaxSerializedLargeBlobArray uint `json:"maxSerializedLargeBlobArray"`
|
||||
|
||||
// ForcePINChange indicates if the PIN must be changed.
|
||||
ForcePINChange bool `json:"forcePINChange"`
|
||||
|
||||
// MinPINLength specifies the current minimum PIN length, in Unicode code points.
|
||||
MinPINLength uint `json:"minPINLength"`
|
||||
|
||||
// FirmwareVersion indicates the firmware version of the authenticator model identified by AAGUID.
|
||||
FirmwareVersion uint `json:"firmwareVersion"`
|
||||
|
||||
// MaxCredBlobLength indicates the maximum credential blob length in bytes.
|
||||
MaxCredBlobLength uint `json:"maxCredBlobLength"`
|
||||
|
||||
// MaxRPIDsForSetMinPINLength specifies the max number of RP IDs that can be set via setMinPINLength subcommand.
|
||||
MaxRPIDsForSetMinPINLength uint `json:"maxRPIDsForSetMinPINLength"`
|
||||
|
||||
// PreferredPlatformUvAttempts specifies the preferred number of UV attempts before falling back to PIN.
|
||||
PreferredPlatformUvAttempts uint `json:"preferredPlatformUvAttempts"`
|
||||
|
||||
// UvModality specifies the user verification modality supported by the authenticator.
|
||||
UvModality uint `json:"uvModality"`
|
||||
|
||||
// Certifications specifies a map of authenticator certifications.
|
||||
Certifications map[string]float64 `json:"certifications"`
|
||||
|
||||
// RemainingDiscoverableCredentials indicates the estimated number of additional discoverable credentials that
|
||||
// can be stored.
|
||||
RemainingDiscoverableCredentials uint `json:"remainingDiscoverableCredentials"`
|
||||
|
||||
// VendorPrototypeConfigCommands is a list of supported authenticatorConfig vendorCommandId values.
|
||||
VendorPrototypeConfigCommands []uint `json:"vendorPrototypeConfigCommands"`
|
||||
}
|
||||
|
||||
func (j AuthenticatorGetInfoJSON) Parse() (info AuthenticatorGetInfo, err error) {
|
||||
var aaguid uuid.UUID
|
||||
|
||||
if len(j.AaGUID) != 0 {
|
||||
if aaguid, err = uuid.Parse(j.AaGUID); err != nil {
|
||||
return info, fmt.Errorf("error occurred parsing AAGUID value: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return AuthenticatorGetInfo{
|
||||
Versions: j.Versions,
|
||||
Extensions: j.Extensions,
|
||||
AaGUID: aaguid,
|
||||
Options: j.Options,
|
||||
MaxMsgSize: j.MaxMsgSize,
|
||||
PivUvAuthProtocols: j.PivUvAuthProtocols,
|
||||
MaxCredentialCountInList: j.MaxCredentialCountInList,
|
||||
MaxCredentialIdLength: j.MaxCredentialIdLength,
|
||||
Transports: j.Transports,
|
||||
Algorithms: j.Algorithms,
|
||||
MaxSerializedLargeBlobArray: j.MaxSerializedLargeBlobArray,
|
||||
ForcePINChange: j.ForcePINChange,
|
||||
MinPINLength: j.MinPINLength,
|
||||
FirmwareVersion: j.FirmwareVersion,
|
||||
MaxCredBlobLength: j.MaxCredBlobLength,
|
||||
MaxRPIDsForSetMinPINLength: j.MaxRPIDsForSetMinPINLength,
|
||||
PreferredPlatformUvAttempts: j.PreferredPlatformUvAttempts,
|
||||
UvModality: j.UvModality,
|
||||
Certifications: j.Certifications,
|
||||
RemainingDiscoverableCredentials: j.RemainingDiscoverableCredentials,
|
||||
VendorPrototypeConfigCommands: j.VendorPrototypeConfigCommands,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MDSGetEndpointsRequest is the request sent to the conformance metadata getEndpoints endpoint.
|
||||
type MDSGetEndpointsRequest struct {
|
||||
// Endpoint is the URL of the local server endpoint, i.e. https://webauthn.io/
|
||||
Endpoint string `json:"endpoint"`
|
||||
}
|
||||
|
||||
// MDSGetEndpointsResponse is the response received from a conformance metadata getEndpoints request.
|
||||
type MDSGetEndpointsResponse struct {
|
||||
// Status is the status of the response.
|
||||
Status string `json:"status"`
|
||||
|
||||
// Result is an array of urls, each pointing to a MetadataTOCPayload.
|
||||
Result []string `json:"result"`
|
||||
}
|
||||
|
||||
// DefaultUndesiredAuthenticatorStatuses returns a copy of the defaultUndesiredAuthenticatorStatus slice.
|
||||
func DefaultUndesiredAuthenticatorStatuses() []AuthenticatorStatus {
|
||||
undesired := make([]AuthenticatorStatus, len(defaultUndesiredAuthenticatorStatus))
|
||||
|
||||
copy(undesired, defaultUndesiredAuthenticatorStatus[:])
|
||||
|
||||
return undesired
|
||||
}
|
||||
|
||||
// EntryError represents an [EntryJSON] that failed to parse, along with the error that occurred.
|
||||
type EntryError struct {
|
||||
// Error is the parsing error that occurred.
|
||||
Error error
|
||||
|
||||
// EntryJSON is the raw JSON entry that failed to parse.
|
||||
EntryJSON
|
||||
}
|
||||
Reference in New Issue
Block a user