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 )