Net-API-REST

 view release on metacpan or  search on metacpan

lib/Net/API/REST/JWT.pm  view on Meta::CPAN

            return( $j->encode( $token ) );
        }
        else 
        {
            die( "JWT: unsupported JWS serialization '$ser'" );
        }
    }
    else 
    {
        ### JWE
        my( $b64u_header, $b64u_ecek, $b64u_iv, $b64u_ct, $b64u_tag, $b64u_aad ) = _encode_jwe( %args );
        # https://tools.ietf.org/html/rfc7516#section-7.1
        if( $ser eq 'compact' )
        {
            die( "JWT: cannot use 'aad' with compact serialization" ) if( defined( $args{aad} ) );
            die( "JWT: cannot use 'unprotected_headers' with compact serialization" ) if( defined( $args{unprotected_headers} ) );
            die( "JWT: cannot use 'shared_unprotected_headers' with compact serialization" ) if( defined( $args{shared_unprotected_headers} ) );
            return( "$b64u_header.$b64u_ecek.$b64u_iv.$b64u_ct.$b64u_tag" );
        }
        # https://tools.ietf.org/html/rfc7516#section-7.2.2
        elsif( $ser eq 'flattened' ) 
        {
            my $token = {
            protected     => $b64u_header,
            encrypted_key => $b64u_ecek,
            iv            => $b64u_iv,
            ciphertext    => $b64u_ct,
            tag           => $b64u_tag,
            };
            # header: JWE Per-Recipient Unprotected Header when the JWE Per-Recipient Unprotected Header
            $token->{header} = \%{$args{unprotected_headers}} if( ref( $args{unprotected_headers} ) eq 'HASH' );
            # unprotected: JWE Shared Unprotected Header
            $token->{unprotected} = \%{$args{shared_unprotected_headers}} if( ref( $args{shared_unprotected_headers} ) eq 'HASH' );
            # aad: Additional Authenticated Data (AAD)
            $token->{aad} = $b64u_aad if( defined( $b64u_aad ) );
            # return( encode_json( $token ) );
            my $j = JSON->new->allow_nonref->allow_blessed->convert_blessed;
            return( $j->encode( $token ) );
        }
        else 
        {
            die( "JWT: unsupported JWE serialization '$ser'" );
        }
    }
}

sub _prepare_rsa_key 
{
    my( $key ) = @_;
    die( "JWT: undefined RSA key" ) unless( defined( $key ) );
    die( "JWT: invalid RSA key (cannot be scalar)" ) unless( ref( $key ) );
    # we need Crypt::PK::RSA object
    return( $key )                         if( ref( $key ) eq 'Crypt::PK::RSA' );
    return( Crypt::PK::RSA->new( $key ) )  if( ref( $key ) eq 'HASH' || ref( $key ) eq 'SCALAR' );
    return( Crypt::PK::RSA->new( @$key ) ) if( ref( $key ) eq 'ARRAY' );
    # handle also: Crypt::OpenSSL::RSA, Crypt::X509, Crypt::OpenSSL::X509
    my $str;
    if( ref( $key ) eq 'Crypt::OpenSSL::RSA' ) 
    {
        # https://metacpan.org/pod/Crypt::OpenSSL::RSA
        $str = $key->is_private ? $key->get_private_key_string : $key->get_public_key_string;
    }
    elsif( ref( $key ) =~ /^Crypt::(X509|OpenSSL::X509)$/ ) 
    {
        # https://metacpan.org/pod/Crypt::X509
        # https://metacpan.org/pod/Crypt::OpenSSL::X509
        $str = $key->pubkey;
    }
    return( Crypt::PK::RSA->new( \$str ) ) if( defined( $str ) && !ref( $str ) );
    die( "JWT: invalid RSA key" );
}

sub _prepare_ecc_key 
{
    my( $key ) = @_;
    die( "JWT: undefined ECC key" ) unless( defined( $key ) );
    die( "JWT: invalid ECC key (cannot be scalar)" ) unless( ref( $key ) );
    # we need Crypt::PK::ECC object
    return( $key )                         if( ref( $key ) eq 'Crypt::PK::ECC' );
    return( Crypt::PK::ECC->new( $key ) )  if( ref( $key ) eq 'HASH' || ref( $key ) eq 'SCALAR' );
    return( Crypt::PK::ECC->new( @$key ) ) if( ref( $key ) eq 'ARRAY' );
    die( "JWT: invalid ECC key" );
}

sub _prepare_oct_key 
{
    my( $key ) = @_;
    die( "JWT: undefined oct key" ) unless( defined( $key ) );
    if( ref( $key ) eq 'HASH' && $key->{k} && $key->{kty} && $key->{kty} eq 'oct' ) 
    {
        return( decode_b64u( $key->{k} ) );
    }
    elsif( !ref( $key ) )
    {
        return( $key );
    }
    die( "JWT: invalid oct key" );
}

sub _kid_lookup 
{
    my( $kid, $kid_keys, $alg ) = @_;
    return( undef() ) if( !defined( $kid ) || !defined( $alg ) );
    $kid_keys = eval{ decode_json( $kid_keys ) } if( $kid_keys && !ref( $kid_keys ) );
    die( "JWT: kid_keys must be a HASHREF or a valid JSON/HASH" ) if( ref( $kid_keys ) ne 'HASH' );
    my $found;
    if( exists( $kid_keys->{keys} ) && ref( $kid_keys->{keys} ) eq 'ARRAY' ) 
    {
        #FORMAT: { keys => [ {kid=>'A', kty=>?, ...}, {kid=>'B', kty=>?, ...} ] }
        for( @{$kid_keys->{keys}} ) 
        {
            if( $_->{kid} && $_->{kty} && $_->{kid} eq $kid ) 
            {
                $found = $_;
                last;
            }
        }
    }
    else 
    {
        #FORMAT: { hexadec1 => "----BEGIN CERTIFICATE-----...", hexadec2 => "----BEGIN CERTIFICATE-----..." }

lib/Net/API/REST/JWT.pm  view on Meta::CPAN

 dir                 string (raw octects) or perl HASH ref with JWK, kty=>'oct', length depends on 'enc' algorithm
 A128KW              string (raw octects) 16 bytes (or perl HASH ref with JWK, kty=>'oct')
 A192KW              string (raw octects) 24 bytes (or perl HASH ref with JWK, kty=>'oct')
 A256KW              string (raw octects) 32 bytes (or perl HASH ref with JWK, kty=>'oct')
 A128GCMKW           string (raw octects) 16 bytes (or perl HASH ref with JWK, kty=>'oct')
 A192GCMKW           string (raw octects) 24 bytes (or perl HASH ref with JWK, kty=>'oct')
 A256GCMKW           string (raw octects) 32 bytes (or perl HASH ref with JWK, kty=>'oct')
 PBES2-HS256+A128KW  string (raw octects) of any length (or perl HASH ref with JWK, kty=>'oct')
 PBES2-HS384+A192KW  string (raw octects) of any length (or perl HASH ref with JWK, kty=>'oct')
 PBES2-HS512+A256KW  string (raw octects) of any length (or perl HASH ref with JWK, kty=>'oct')
 RSA-OAEP            private RSA key, perl HASH ref with JWK key structure,
                     a reference to SCALAR string with PEM or DER or JSON/JWK data,
                     an instance of Crypt::PK::RSA or Crypt::OpenSSL::RSA
 RSA-OAEP-256        private RSA key, see RSA-OAEP
 RSA1_5              private RSA key, see RSA-OAEP
 ECDH-ES             private ECC key, perl HASH ref with JWK key structure,
                     a reference to SCALAR string with PEM or DER or JSON/JWK data,
                     an instance of Crypt::PK::ECC
 ECDH-ES+A128KW      private ECC key, see ECDH-ES
 ECDH-ES+A192KW      private ECC key, see ECDH-ES
 ECDH-ES+A256KW      private ECC key, see ECDH-ES

Example using the key from C<jwk> token header:

 my $data = decode_jwt(token=>$t, key_from_jwk_header=>1);
 my ($header, $data) = decode_jwt(token=>$t, decode_header=>1, key_from_jwk_header=>1);

Examples with raw octet keys:

 #string
 my $data = decode_jwt(token=>$t, key=>'secretkey');
 #binary key
 my $data = decode_jwt(token=>$t, key=>pack("H*", "788A6E38F36B7596EF6A669E94"));
 #perl HASH ref with JWK structure (key type 'oct')
 my $data = decode_jwt(token=>$t, key=>{kty=>'oct', k=>"GawgguFyGrWKav7AX4VKUg"});

Examples with RSA keys:

 my $pem_key_string = <<'EOF';
 -----BEGIN PRIVATE KEY-----
 MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCoVm/Sl5r+Ofky
 jioRSZK26GW6WyjyfWKddsSi13/NOtCn0rRErSF/u3QrgGMpWFqKohqbi1VVC+SZ
 ...
 8c1vm2YFafgdkSk9Qd1oU2Fv1aOQy4VovOFzJ3CcR+2r7cbRfcpLGnintHtp9yek
 02p+d5g4OChfFNDhDtnIqjvY
 -----END PRIVATE KEY-----
 EOF

 my $jwk_key_json_string = '{"kty":"RSA","n":"0vx7agoebG...L6tSoc_BJECP","e":"AQAB"}';

 #a reference to SCALAR string with PEM or DER or JSON/JWK data,
 my $data = decode_jwt(token=>$t, key=>\$pem_key_string);
 my $data = decode_jwt(token=>$t, key=>\$der_key_string);
 my $data = decode_jwt(token=>$t, key=>\$jwk_key_json_string);

 #instance of Crypt::PK::RSA
 my $data = decode_jwt(token=>$t, key=>Crypt::PK::RSA->new('keyfile.pem'));
 my $data = decode_jwt(token=>$t, key=>Crypt::PK::RSA->new(\$pem_key_string));

 #instance of Crypt::OpenSSL::RSA
 my $data = decode_jwt(token=>$t, key=>Crypt::OpenSSL::RSA->new_private_key($pem_key_string));

 #instance of Crypt::X509 (public key only)
 my $data = decode_jwt(token=>$t, key=>Crypt::X509->new(cert=>$cert));

 #instance of Crypt::OpenSSL::X509 (public key only)
 my $data = decode_jwt(token=>$t, key=>Crypt::OpenSSL::X509->new_from_file('cert.pem'));
 my $data = decode_jwt(token=>$t, key=>Crypt::OpenSSL::X509->new_from_string($cert));

 #perl HASH ref with JWK structure (key type 'RSA')
 my $rsa_priv = {
   kty => "RSA",
   n   => "0vx7agoebGcQSuuPiLJXZpt...eZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
   e   => "AQAB",
   d   => "X4cTteJY_gn4FYPsXB8rdXi...FLN5EEaG6RoVH-HLKD9Mdx5ooGURknhnrRwUkC7h5fJLMWbFAKLWY2v7B6NqSzUvx0_YSf",
   p   => "83i-7IvMGXoMXCskv73TKr8...Z27zvoj6pbUQyLPBQxtPnwD20-60eTmD2ujMt5PoMrm8RmNhVWtjjMmMjOpSicFHjXOuVI",
   q   => "3dfOR9cuYq-0S-mkFLzgItg...q3hWeMuG0ouqnb3obLyuqjVZQ1dIrdgTnCdYzBcOW5r37AFXjift_NGiovonzhKpoVVS78",
   dp  => "G4sPXkc6Ya9y8oJW9_ILj4...zi_H7TkS8x5SdX3oE0oiYwxIiemTAu0UOa5pgFGyJ4c8t2VF40XRugKTP8akhFo5tA77Qe",
   dq  => "s9lAH9fggBsoFR8Oac2R_E...T2kGOhvIllTE1efA6huUvMfBcpn8lqW6vzzYY5SSF7pMd_agI3G8IbpBUb0JiraRNUfLhc",
   qi  => "GyM_p6JrXySiz1toFgKbWV...4ypu9bMWx3QJBfm0FoYzUIZEVEcOqwmRN81oDAaaBk0KWGDjJHDdDmFW3AN7I-pux_mHZG",
 };
 my $data = decode_jwt(token=>$t, key=>$rsa_priv});

Examples with ECC keys:

 my $pem_key_string = <<'EOF';
 -----BEGIN EC PRIVATE KEY-----
 MHcCAQEEIBG1c3z52T8XwMsahGVdOZWgKCQJfv+l7djuJjgetdbDoAoGCCqGSM49
 AwEHoUQDQgAEoBUyo8CQAFPeYPvv78ylh5MwFZjTCLQeb042TjiMJxG+9DLFmRSM
 lBQ9T/RsLLc+PmpB1+7yPAR+oR5gZn3kJQ==
 -----END EC PRIVATE KEY-----
 EOF

 my $jwk_key_json_string = '{"kty":"EC","crv":"P-256","x":"MKB..7D4","y":"4Et..FyM"}';

 #a reference to SCALAR string with PEM or DER or JSON/JWK data,
 my $data = decode_jwt(token=>$t, key=>\$pem_key_string);
 my $data = decode_jwt(token=>$t, key=>\$der_key_string);
 my $data = decode_jwt(token=>$t, key=>\$jwk_key_json_string);

 #instance of Crypt::PK::ECC
 my $data = decode_jwt(token=>$t, key=>Crypt::PK::ECC->new('keyfile.pem'));
 my $data = decode_jwt(token=>$t, key=>Crypt::PK::ECC->new(\$pem_key_string));

 #perl HASH ref with JWK structure (key type 'EC')
 my $ecc_priv = {
   kty => "EC",
   crv => "P-256",
   x   => "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
   y   => "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
   d   => "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE",
 };
 my $data = decode_jwt(token=>$t, key=>$ecc_priv});

=item keypass

When 'key' parameter is an encrypted private RSA or ECC key this optional parameter may contain a password for private key decryption.

=item kid_keys

This parametes can be either a JWK Set JSON string (see RFC7517) or a perl HASH ref with JWK Set structure like this:



( run in 0.654 second using v1.01-cache-2.11-cpan-787462296c9 )