Authen-WebAuthn
view release on metacpan or search on metacpan
lib/Authen/WebAuthn.pm view on Meta::CPAN
return $res;
}
sub check_length {
my ( $data, $name, $expected_len ) = @_;
my $len = length($data);
if ( $len < $expected_len ) {
croak("$name has incorrect length $len (min: $expected_len)");
}
}
sub getAuthData {
my ($ad) = @_;
my $res = {};
check_length( $ad, "Authenticator data", 37 );
$res->{rpIdHash} = substr( $ad, 0, 32 );
$res->{flags} = resolveFlags( unpack( 'C', substr( $ad, 32, 1 ) ) );
$res->{signCount} = unpack( 'N', substr( $ad, 33, 4 ) );
my $attestedCredentialDataLength = 0;
if ( $res->{flags}->{atIncluded} ) {
my $attestedCredentialData =
getAttestedCredentialData( substr( $ad, 37 ) );
$res->{attestedCredentialData} = $attestedCredentialData;
$attestedCredentialDataLength =
18 + $attestedCredentialData->{credentialIdLength} +
$attestedCredentialData->{credentialPublicKeyLength};
}
if ( $res->{flags}->{edIncluded} ) {
my $ext = substr( $ad, 37 + $attestedCredentialDataLength );
if ($ext) {
$res->{extensions} = decode_cbor($ext);
}
}
else {
# Check for trailing bytes
croak("Trailing bytes in authenticator data")
if ( length($ad) > ( 37 + $attestedCredentialDataLength ) );
}
return $res;
}
sub resolveFlags {
my ($bits) = @_;
return {
userPresent => ( ( $bits & 1 ) == 1 ),
userVerified => ( ( $bits & 4 ) == 4 ),
atIncluded => ( ( $bits & 64 ) == 64 ),
edIncluded => ( ( $bits & 128 ) == 128 ),
};
}
sub getAttestationObject {
my ($dat) = @_;
my $decoded = decode_base64url($dat);
my $res = {};
my $h = decode_cbor($decoded);
$res->{authData} = getAuthData( $h->{authData} );
$res->{authDataRaw} = $h->{authData};
$res->{attStmt} = $h->{attStmt};
$res->{fmt} = $h->{fmt};
return $res;
}
# https://www.w3.org/TR/webauthn-2/#sctn-none-attestation
sub attest_none {
my (
$attestation_statement, $auhenticator_data,
$authenticator_data_raw, $client_data_hash
) = @_;
return {
success => 1,
type => "None",
trust_path => [],
};
}
# https://www.w3.org/TR/webauthn-2/#sctn-packed-attestation
sub attest_packed {
my (
$attestation_statement, $authenticator_data,
$authenticator_data_raw, $client_data_hash
) = @_;
# Verify that attStmt is valid CBOR conforming to the syntax defined above
# and perform CBOR decoding on it to extract the contained fields.
croak "Missing algorithm field in attestation statement"
unless ( $attestation_statement->{alg} );
croak "Missing signature field in attestation statement"
unless ( $attestation_statement->{sig} );
my $signed_value = $authenticator_data_raw . $client_data_hash;
#If x5c is present:
if ( $attestation_statement->{x5c} ) {
return attest_packed_x5c( $attestation_statement, $authenticator_data,
$signed_value );
#If x5c is not present, self attestation is in use.
}
else {
return attest_packed_self( $attestation_statement, $authenticator_data,
$signed_value );
}
}
sub attest_packed_x5c {
my ( $attestation_statement, $authenticator_data, $signed_value ) = @_;
my $x5c_der = $attestation_statement->{x5c}->[0];
my $sig_alg = $attestation_statement->{alg};
my $sig = $attestation_statement->{sig};
my ( $x5c, $key, $key_alg );
eval {
( run in 1.604 second using v1.01-cache-2.11-cpan-d06a3f9ecfd )