GithubHelp home page GithubHelp logo

potatosalad / erlang-jose Goto Github PK

View Code? Open in Web Editor NEW
310.0 17.0 101.0 1.63 MB

JSON Object Signing and Encryption (JOSE) for Erlang and Elixir

Home Page: http://hexdocs.pm/jose

License: MIT License

Makefile 0.14% Erlang 85.47% Elixir 14.33% Dockerfile 0.02% Shell 0.04%
jose cryptography jwt erlang elixir

erlang-jose's Introduction

JOSE

Build Status Hex.pm

JSON Object Signing and Encryption (JOSE) for Erlang and Elixir.

Installation

Add jose to your project's dependencies in mix.exs

defp deps() do
  [
    {:jose, "~> 1.11"}
  ]
end

If you are using deployment tools (exrm, etc.) and your app depends on jose directly, you will need to include jose in your applications list in mix.exs to ensure they get compiled into your release:

def application() do
  [
    mod: {YourApp, []},
    applications: [:jose]
  ]
end

Add jose to your project's dependencies in your Makefile for erlang.mk or the following to your rebar.config

{deps, [
  jose
]}.

JSON Encoder/Decoder

You will also need to specify either jiffy, jsone, jsx, ojson, Poison, or Jason as a dependency.

For example, with Elixir and mix.exs

defp deps() do
  [
    {:jose, "~> 1.11"},
    {:jason, "~> 1.4"}
  ]
end

Or with Erlang and rebar.config

{deps, [
  jose,
  ojson
]}.

jose will attempt to find a suitable JSON encoder/decoder and will try to use (in order) ojson, Jason, Poison, jiffy, jsone, or jsx.

You may also specify a different json_module as an application environment variable to jose or by using jose:json_module/1 or JOSE.json_module/1.

ChaCha20/Poly1305 Support

ChaCha20/Poly1305 encryption and one-time message authentication functions are experimentally supported based on RFC 7539.

Fallback support for ChaCha20/Poly1305 encryption and Poly1305 signing is also provided. See crypto_fallback below.

External support is also provided by the following libraries:

  • libsodium - ChaCha20/Poly1305 encryption and Poly1305 signing

Other modules which implement the jose_chacha20_poly1305 behavior may also be used as follows:

# ChaCha20/Poly1305
JOSE.chacha20_poly1305_module(:libsodium)                  # uses a fast Erlang port driver for libsodium
JOSE.chacha20_poly1305_module(:jose_jwa_chacha20_poly1305) # uses the pure Erlang implementation (slow)

Curve25519 and Curve448 Support

Curve25519 and Curve448 and their associated signing/key exchange functions are supported now that RFC 8037 has been published.

Fallback support for Ed25519, Ed25519ph, Ed448, Ed448ph, X25519, and X448 is provided. See crypto_fallback below.

External support is also provided by the following libraries:

  • libdecaf - Ed25519, Ed25519ph, Ed448, Ed448ph, X25519, X448
  • libsodium - Ed25519, Ed25519ph, X25519

If both libraries are present, libdecaf will be used by default. Other modules which implement the jose_curve25519 or jose_curve448 behaviors may also be used as follows:

# Curve25519
JOSE.curve25519_module(:libdecaf)            # uses a fast Erlang NIF for libdecaf
JOSE.curve25519_module(:jose_jwa_curve25519) # uses the pure Erlang implementation (slow)

# Curve448
JOSE.curve448_module(:libdecaf)          # uses a fast Erlang NIF for libdecaf
JOSE.curve448_module(:jose_jwa_curve448) # uses the pure Erlang implementation (slow)

SHA-3 Support

SHA-3 is experimentally supported for use with Ed448 and Ed448ph signing functions.

Fallback support for SHA-3 is provided. See crypto_fallback below.

External support for SHA-3 is provided by the keccakf1600 and libdecaf libraries. If present, keccakf1600 will be used by default. Other modules which implement the jose_sha3 behaviors may also be used as follows:

JOSE.sha3_module(:keccakf1600)   # uses a NIF written in C with timeslice reductions
JOSE.sha3_module(:jose_jwa_sha3) # uses the pure Erlang implementation (slow)

Cryptographic Algorithm Fallback

jose strives to support all of the cryptographic algorithms specified in the JOSE RFCs.

However, not all of the required algorithms are supported natively by Erlang/Elixir. For algorithms unsupported by the native crypto and public_key, jose has a pure Erlang implementation that may be used as a fallback.

See ALGORITHMS.md for more information about algorithm support for specific OTP versions.

By default, the algorithm fallback is disabled, but can be enabled by setting the crypto_fallback application environment variable for jose to true or by calling jose:crypto_fallback/1 or JOSE.crypto_fallback/1 with true.

You may also review which algorithms are currently supported with the jose_jwa:supports/0 or JOSE.JWA.supports/0 functions. For example, on Elixir 1.9.4 and OTP 22:

# crypto_fallback defaults to false
JOSE.JWA.supports()

[
  {:jwe,
   {:alg,
    ["A128GCMKW", "A128KW", "A192GCMKW", "A192KW", "A256GCMKW", "A256KW",
     "C20PKW", "ECDH-1PU", "ECDH-1PU+A128GCMKW", "ECDH-1PU+A128KW",
     "ECDH-1PU+A192GCMKW", "ECDH-1PU+A192KW", "ECDH-1PU+A256GCMKW",
     "ECDH-1PU+A256KW", "ECDH-1PU+C20PKW", "ECDH-1PU+XC20PKW", "ECDH-ES",
     "ECDH-ES+A128GCMKW", "ECDH-ES+A128KW", "ECDH-ES+A192GCMKW",
     "ECDH-ES+A192KW", "ECDH-ES+A256GCMKW", "ECDH-ES+A256KW", "ECDH-ES+C20PKW",
     "ECDH-ES+XC20PKW", "ECDH-SS", "ECDH-SS+A128GCMKW", "ECDH-SS+A128KW",
     "ECDH-SS+A192GCMKW", "ECDH-SS+A192KW", "ECDH-SS+A256GCMKW",
     "ECDH-SS+A256KW", "ECDH-SS+C20PKW", "ECDH-SS+XC20PKW",
     "PBES2-HS256+A128GCMKW", "PBES2-HS256+A128KW", "PBES2-HS384+A192GCMKW",
     "PBES2-HS384+A192KW", "PBES2-HS512+A256GCMKW", "PBES2-HS512+A256KW",
     "PBES2-HS512+C20PKW", "PBES2-HS512+XC20PKW", "RSA-OAEP", "RSA-OAEP-256",
     "RSA1_5", "XC20PKW", "dir"]},
   {:enc,
    ["A128CBC-HS256", "A128GCM", "A192CBC-HS384", "A192GCM", "A256CBC-HS512",
     "A256GCM", "C20P", "XC20P"]}, {:zip, ["DEF"]}},
  {:jwk, {:kty, ["EC", "OKP", "RSA", "oct"]},
   {:kty_OKP_crv,
    ["Ed25519", "Ed25519ph", "Ed448", "Ed448ph", "X25519", "X448"]}},
  {:jws,
   {:alg,
    ["ES256", "ES256K", "ES384", "ES512", "Ed25519", "Ed25519ph", "Ed448",
     "Ed448ph", "EdDSA", "HS256", "HS384", "HS512", "PS256", "PS384", "PS512",
     "Poly1305", "RS1", "RS256", "RS384", "RS512"]}}
]

# setting crypto_fallback to true
JOSE.crypto_fallback(true)

# additional algorithms are now available for use
JOSE.JWA.supports()

[
  {:jwe,
   {:alg,
    ["A128GCMKW", "A128KW", "A192GCMKW", "A192KW", "A256GCMKW", "A256KW",
     "C20PKW", "ECDH-1PU", "ECDH-1PU+A128GCMKW", "ECDH-1PU+A128KW",
     "ECDH-1PU+A192GCMKW", "ECDH-1PU+A192KW", "ECDH-1PU+A256GCMKW",
     "ECDH-1PU+A256KW", "ECDH-1PU+C20PKW", "ECDH-1PU+XC20PKW", "ECDH-ES",
     "ECDH-ES+A128GCMKW", "ECDH-ES+A128KW", "ECDH-ES+A192GCMKW",
     "ECDH-ES+A192KW", "ECDH-ES+A256GCMKW", "ECDH-ES+A256KW", "ECDH-ES+C20PKW",
     "ECDH-ES+XC20PKW", "ECDH-SS", "ECDH-SS+A128GCMKW", "ECDH-SS+A128KW",
     "ECDH-SS+A192GCMKW", "ECDH-SS+A192KW", "ECDH-SS+A256GCMKW",
     "ECDH-SS+A256KW", "ECDH-SS+C20PKW", "ECDH-SS+XC20PKW",
     "PBES2-HS256+A128GCMKW", "PBES2-HS256+A128KW", "PBES2-HS384+A192GCMKW",
     "PBES2-HS384+A192KW", "PBES2-HS512+A256GCMKW", "PBES2-HS512+A256KW",
     "PBES2-HS512+C20PKW", "PBES2-HS512+XC20PKW", "RSA-OAEP", "RSA-OAEP-256",
     "RSA1_5", "XC20PKW", "dir"]},
   {:enc,
    ["A128CBC-HS256", "A128GCM", "A192CBC-HS384", "A192GCM", "A256CBC-HS512",
     "A256GCM", "C20P", "XC20P"]}, {:zip, ["DEF"]}},
  {:jwk, {:kty, ["EC", "OKP", "RSA", "oct"]},
   {:kty_OKP_crv,
    ["Ed25519", "Ed25519ph", "Ed448", "Ed448ph", "X25519", "X448"]}},
  {:jws,
   {:alg,
    ["ES256", "ES256K", "ES384", "ES512", "Ed25519", "Ed25519ph", "Ed448",
     "Ed448ph", "EdDSA", "HS256", "HS384", "HS512", "PS256", "PS384", "PS512",
     "Poly1305", "RS1", "RS256", "RS384", "RS512"]}}
]

Unsecured Signing Vulnerability

The "none" signing algorithm is disabled by default to prevent accidental verification of empty signatures (read about the vulnerability here).

If you want to further restrict the signature algorithms allowed for a token, use JOSE.JWT.verify_strict/3:

# Signed Compact JSON Web Token (JWT) with HS256
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlLCJpc3MiOiJqb2UifQ.shLcxOl_HBBsOTvPnskfIlxHUibPN7Y9T4LhPB-iBwM"

# JSON Web Key (JWK)
jwk = %{
  "kty" => "oct",
  "k" => :jose_base64url.encode("symmetric key")
}

{verified, _, _} = JOSE.JWT.verify_strict(jwk, ["HS256"], token)
# {true, _, _}

{verified, _, _} = JOSE.JWT.verify_strict(jwk, ["RS256"], token)
# {false, _, _}

If you need to inspect the contents of a JSON Web token (JWT) prior to verifying it, use JOSE.JWT.peek_payload/1 or JOSE.JWT.peek_protected/1:

token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlLCJpc3MiOiJqb2UifQ.shLcxOl_HBBsOTvPnskfIlxHUibPN7Y9T4LhPB-iBwM"

payload = JOSE.JWT.peek_payload(token)
# %JOSE.JWT{fields: %{"exp" => 1300819380, "http://example.com/is_root" => true,
#    "iss" => "joe"}}

protected = JOSE.JWT.peek_protected(token)
# %JOSE.JWS{alg: {:jose_jws_alg_hmac, {:jose_jws_alg_hmac, :sha256}},
#  b64: :undefined, fields: %{"typ" => "JWT"}}

# If you want to inspect the JSON, you can convert it back to a regular map:
{_, protected_map} = JOSE.JWS.to_map(protected)
# {_, %{"alg" => "HS256", "typ" => "JWT"}}

You may also enable the "none" algorithm as an application environment variable for jose or by using jose:unsecured_signing/1 or JOSE.unsecured_signing/1.

# unsecured_signing defaults to false
JOSE.JWA.supports[:jws]

{:alg,
 ["ES256", "ES256K", "ES384", "ES512", "Ed25519", "Ed25519ph", "Ed448",
  "Ed448ph", "EdDSA", "HS256", "HS384", "HS512", "PS256", "PS384", "PS512",
  "Poly1305", "RS1", "RS256", "RS384", "RS512"]}

# setting unsecured_signing to true
JOSE.unsecured_signing(true)

# the "none" algorithm is now available for use
JOSE.JWA.supports[:jws]

{:alg,
 ["ES256", "ES256K", "ES384", "ES512", "Ed25519", "Ed25519ph", "Ed448",
  "Ed448ph", "EdDSA", "HS256", "HS384", "HS512", "PS256", "PS384", "PS512",
  "Poly1305", "RS1", "RS256", "RS384", "RS512", "none"]}

Usage

JSON Web Signature (JWS) of JSON Web Token (JWT) using HMAC using SHA-256 (HS256) with JSON Web Key (JWK)

Elixir

# JSON Web Key (JWK)
jwk = %{
  "kty" => "oct",
  "k" => :jose_base64url.encode("symmetric key")
}

# JSON Web Signature (JWS)
jws = %{
  "alg" => "HS256"
}

# JSON Web Token (JWT)
jwt = %{
  "iss" => "joe",
  "exp" => 1300819380,
  "http://example.com/is_root" => true
}

signed = JOSE.JWT.sign(jwk, jws, jwt)
# {%{alg: :jose_jws_alg_hmac},
#  %{"payload" => "eyJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlLCJpc3MiOiJqb2UifQ",
#    "protected" => "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9",
#    "signature" => "shLcxOl_HBBsOTvPnskfIlxHUibPN7Y9T4LhPB-iBwM"}}

compact_signed = JOSE.JWS.compact(signed)
# {%{alg: :jose_jws_alg_hmac},
#  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlLCJpc3MiOiJqb2UifQ.shLcxOl_HBBsOTvPnskfIlxHUibPN7Y9T4LhPB-iBwM"}

verified = JOSE.JWT.verify(jwk, compact_signed)
# {true,
#  %JOSE.JWT{fields: %{"exp" => 1300819380, "http://example.com/is_root" => true,
#     "iss" => "joe"}},
#  %JOSE.JWS{alg: {:jose_jws_alg_hmac, :HS256}, b64: :undefined,
#   fields: %{"typ" => "JWT"}}}

verified == JOSE.JWT.verify(jwk, signed)
# true

Erlang

% JSON Web Key (JWK)
JWK = #{
  <<"kty">> => <<"oct">>,
  <<"k">> => jose_base64url:encode(<<"symmetric key">>)
}.

% JSON Web Signature (JWS)
JWS = #{
  <<"alg">> => <<"HS256">>
}.

% JSON Web Token (JWT)
JWT = #{
  <<"iss">> => <<"joe">>,
  <<"exp">> => 1300819380,
  <<"http://example.com/is_root">> => true
}.

Signed = jose_jwt:sign(JWK, JWS, JWT).
% {#{alg => jose_jws_alg_hmac},
%  #{<<"payload">> => <<"eyJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlLCJpc3MiOiJqb2UifQ">>,
%    <<"protected">> => <<"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9">>,
%    <<"signature">> => <<"shLcxOl_HBBsOTvPnskfIlxHUibPN7Y9T4LhPB-iBwM">>}}

CompactSigned = jose_jws:compact(Signed).
% {#{alg => jose_jws_alg_hmac},
%  <<"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlLCJpc3MiOiJqb2UifQ.shLcxOl_HBBsOTvPnskfIlxHUibPN7Y9T4LhPB-iBwM">>}

Verified = jose_jwt:verify(JWK, CompactSigned).
% {true,
%     #jose_jwt{
%         fields =
%             #{<<"exp">> => 1300819380,
%               <<"http://example.com/is_root">> => true,
%               <<"iss">> => <<"joe">>}},
%     #jose_jws{
%         alg = {jose_jws_alg_hmac,'HS256'},
%         b64 = undefined,
%         fields = #{<<"typ">> => <<"JWT">>}}}

Verified =:= jose_jwt:verify(JWK, Signed).
% true
Reading JSON Web Keys (JWK) from PEM files

The examples below use three keys created with openssl:

# RSA Private Key
openssl genrsa -out rsa-2048.pem 2048

# EC Private Key (Alice)
openssl ecparam -name secp256r1 -genkey -noout -out ec-secp256r1-alice.pem

# EC Private Key (Bob)
openssl ecparam -name secp256r1 -genkey -noout -out ec-secp256r1-bob.pem

Elixir

# RSA examples
rsa_private_jwk = JOSE.JWK.from_pem_file("rsa-2048.pem")
rsa_public_jwk  = JOSE.JWK.to_public(rsa_private_jwk)

## Sign and Verify (defaults to PS256)
message = "my message"
signed = JOSE.JWK.sign(message, rsa_private_jwk)
{true, ^message, _} = JOSE.JWK.verify(signed, rsa_public_jwk)

## Sign and Verify (specify RS256)
signed = JOSE.JWK.sign(message, %{ "alg" => "RS256" }, rsa_private_jwk)
{true, ^message, _} = JOSE.JWK.verify(signed, rsa_public_jwk)

## Encrypt and Decrypt (defaults to RSA-OAEP with A128CBC-HS256)
plain_text = "my plain text"
encrypted = JOSE.JWK.block_encrypt(plain_text, rsa_public_jwk)
{^plain_text, _} = JOSE.JWK.block_decrypt(encrypted, rsa_private_jwk)

## Encrypt and Decrypt (specify RSA-OAEP-256 with A128GCM)
encrypted = JOSE.JWK.block_encrypt(plain_text, %{ "alg" => "RSA-OAEP-256", "enc" => "A128GCM" }, rsa_public_jwk)
{^plain_text, _} = JOSE.JWK.block_decrypt(encrypted, rsa_private_jwk)

# EC examples
alice_private_jwk = JOSE.JWK.from_pem_file("ec-secp256r1-alice.pem")
alice_public_jwk  = JOSE.JWK.to_public(alice_private_jwk)
bob_private_jwk   = JOSE.JWK.from_pem_file("ec-secp256r1-bob.pem")
bob_public_jwk    = JOSE.JWK.to_public(bob_private_jwk)

## Sign and Verify (defaults to ES256)
message = "my message"
signed = JOSE.JWK.sign(message, alice_private_jwk)
{true, ^message, _} = JOSE.JWK.verify(signed, alice_public_jwk)

## Encrypt and Decrypt (defaults to ECDH-ES with A128GCM)
### Alice sends Bob a secret message using Bob's public key and Alice's private key
alice_to_bob = "For Bob's eyes only."
encrypted = JOSE.JWK.box_encrypt(alice_to_bob, bob_public_jwk, alice_private_jwk)
### Only Bob can decrypt the message using his private key (Alice's public key is embedded in the JWE header)
{^alice_to_bob, _} = JOSE.JWK.box_decrypt(encrypted, bob_private_jwk)

Erlang

% RSA examples
RSAPrivateJWK = jose_jwk:from_pem_file("rsa-2048.pem"),
RSAPublicJWK  = jose_jwk:to_public(RSAPrivateJWK).

%% Sign and Verify (defaults to PS256)
Message = <<"my message">>,
SignedPS256 = jose_jwk:sign(Message, RSAPrivateJWK),
{true, Message, _} = jose_jwk:verify(SignedPS256, RSAPublicJWK).

%% Sign and Verify (specify RS256)
SignedRS256 = jose_jwk:sign(Message, #{ <<"alg">> => <<"RS256">> }, RSAPrivateJWK),
{true, Message, _} = jose_jwk:verify(SignedRS256, RSAPublicJWK).

%% Encrypt and Decrypt (defaults to RSA-OAEP with A128CBC-HS256)
PlainText = <<"my plain text">>,
EncryptedRSAOAEP = jose_jwk:block_encrypt(PlainText, RSAPublicJWK),
{PlainText, _} = jose_jwk:block_decrypt(EncryptedRSAOAEP, RSAPrivateJWK).

%% Encrypt and Decrypt (specify RSA-OAEP-256 with A128GCM)
EncryptedRSAOAEP256 = jose_jwk:block_encrypt(PlainText, #{ <<"alg">> => <<"RSA-OAEP-256">>, <<"enc">> => <<"A128GCM">> }, RSAPublicJWK),
{PlainText, _} = jose_jwk:block_decrypt(EncryptedRSAOAEP256, RSAPrivateJWK).

% EC examples
AlicePrivateJWK = jose_jwk:from_pem_file("ec-secp256r1-alice.pem"),
AlicePublicJWK  = jose_jwk:to_public(AlicePrivateJWK),
BobPrivateJWK   = jose_jwk:from_pem_file("ec-secp256r1-bob.pem"),
BobPublicJWK    = jose_jwk:to_public(BobPrivateJWK).

%% Sign and Verify (defaults to ES256)
Message = <<"my message">>,
SignedES256 = jose_jwk:sign(Message, AlicePrivateJWK),
{true, Message, _} = jose_jwk:verify(SignedES256, AlicePublicJWK).

%% Encrypt and Decrypt (defaults to ECDH-ES with A128GCM)
%%% Alice sends Bob a secret message using Bob's public key and Alice's private key
AliceToBob = <<"For Bob's eyes only.">>,
EncryptedECDHES = jose_jwk:box_encrypt(AliceToBob, BobPublicJWK, AlicePrivateJWK),
%%% Only Bob can decrypt the message using his private key (Alice's public key is embedded in the JWE header)
{AliceToBob, _} = jose_jwk:box_decrypt(EncryptedECDHES, BobPrivateJWK).

Algorithm Support

JSON Web Encryption (JWE) RFC 7516

  • DEF

JSON Web Key (JWK) RFC 7517

JSON Web Signature (JWS) RFC 7515

Additional Specifications

unsecured This algorithm is disabled by default due to the unsecured signing vulnerability. Use the unsecured_signing setting to enable this algorithm.

erlang-jose's People

Contributors

alexandrejbr avatar aymanosman avatar badlop avatar behe avatar brettbeatty avatar cs-victor-nascimento avatar dmorn avatar ericmj avatar ishikawa avatar jareddellitt avatar kpanic avatar kpy3 avatar lnikkila avatar maennchen avatar michaelklishin avatar moogle19 avatar ntrepid8 avatar pavledjo avatar pjk25 avatar potatosalad avatar requestben avatar richiban avatar spencerdcarlson avatar ssepml avatar talklittle avatar thalesmg avatar thiamsantos avatar tokafish avatar victorolinasc avatar whatyouhide avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

erlang-jose's Issues

Wanted sample code

Calling, (this line from the readme)
Signed = jose_jwt:sign(JWK, JWS, JWT).
gets
** exception error: unsupported_json_module
in function jose_json_unsupported:encode/1 (src/jose_json_unsupported.erl, line 26)
in call from jose_jwt:to_binary/1 (src/jose_jwt.erl, line 89)
in call from jose_jwt:sign/3 (src/jose_jwt.erl, line 170)
in call from a:main/0 (a.erl, line 25)

I tried jose:start().first but that didn't help. I am new to Erlang, sorry.

Poison encoding/decoding

Hey @potatosalad!

I've been testing your encoding/decoding with Poison and am running into some issues. I have this simple token (which is valid according to jwt.io and was generate with erlang-jose. It is an HS256 with "secret" as its key):

token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSm9obiBEb2UifQ.xuEv8qrfXu424LZk8bVgr9MQJUIrp1rHcPyZw_KSsds"

But when I try this on iex:

JOSE.json_module Poison
JOSE.JWK.verify token, "secret"

I get a nasty Poison error:

** (Poison.SyntaxError) Unexpected token: s
    (poison) lib/poison/parser.ex:56: Poison.Parser.parse!/2
    (poison) lib/poison.ex:83: Poison.decode!/2
      (jose) src/jose_jwk.erl:120: :jose_jwk.from_binary/1
      (jose) src/jose_jwk.erl:429: :jose_jwk.verify/2
      (jose) lib/jose/jwk.ex:141: JOSE.JWK.verify/2

I verified that I can decode both base64url decoded parts of the token using :jose.decode(binary).

Consider changing license?

Hi @potatosalad

Would you be open to considering changing the license of erlang-jose to say something like the MIT or the Apache 2.0 license?

Our lawyers are giving a bit of a hard time with your current license.

If you are open to the idea, I would be more than happy to create a pull-request to minimize the effort on your part.

Thank you!

Sebastian

JOSE.JWK.thumbprint/1 error

Hi,

I've encountered a crash when trying to compute a key thumbprint.

Library version 1.8.4, Erlang 20, Elixir 1.6, the example is copied from docs:

iex> jwk1 = JOSE.JWK.from_oct("secret")
%JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, "secret"}}

iex> JOSE.JWK.thumbprint(jwk1)
** (ArgumentError) argument error
    :erlang.iolist_to_binary({:ok, "{\"k\":\"c2VjcmV0\",\"kty\":\"oct\"}"})
    (crypto) crypto.erl:131: :crypto.hash/2
    (jose) src/jose_jwk.erl:778: :jose_jwk.thumbprint/2

Am I doing something wrong, or is this a bug?

Jason support

The new hotness in Elixir is Jason for json encoding. It would be great to get default support.

handling invalid token without raising Exception

What do you think of returning false when the token is invalid instead of raising ArgumentError?

jwk = %{
  "kty" => "oct",
  "k" => :base64url.encode("symmetric key")
}

{false, _, _} = JOSE.JWT.verify(jwk, "invalid")

I'm suggesting that because feels more natural and also make it much easier to use with pipes in Elixir.

Add behaviour for base64url

Hi @potatosalad ! I've found that the Base.url_encode64 and Base.url_decode64! implementations from core Elixir library are almost twice the speed of the version in base64url dep. It would be nice if this could be replaceable! I've noticed from running a simple mix profile.fprof -e test that these functions are called many times (encode and decode).

I am refactoring Joken which is a wrapper for JOSE and did some benchmarking. With the dep base64url I get:

Operating System: Linux
CPU Information: Intel(R) Core(TM) i7-4510U CPU @ 2.00GHz
Number of Available Cores: 4
Available memory: 15.55 GB
Elixir 1.6.0-rc.1
Erlang 20.2
Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
parallel: 1
inputs: none specified
Estimated total run time: 21 s


Benchmarking HS256...
Benchmarking HS384...
Benchmarking HS512...

Name            ips        average  deviation         median         99th %
HS256       14.29 K       70.00 μs    ±21.04%          67 μs         146 μs
HS384       13.88 K       72.05 μs    ±18.60%          69 μs         147 μs
HS512       13.07 K       76.53 μs    ±29.45%          73 μs      130.99 μs

Comparison: 
HS256       14.29 K
HS384       13.88 K - 1.03x slower
HS512       13.07 K - 1.09x slower

After I've overriden the dep with this implementation (I know I haven't implemented the mime function):

defmodule :base64url do
  def encode(term) when is_binary(term),
    do: Base.url_encode64(term, ignore: :whitespace, padding: false)

  def encode(term) when is_list(term), do: :erlang.iolist_to_binary(term) |> encode()

  def decode(term) when is_binary(term),
    do: Base.url_decode64!(term, ignore: :whitespace, padding: false)

  def decode(term) when is_list(term), do: :erlang.iolist_to_binary(term) |> decode()
end

I get the following stats:

Operating System: Linux
CPU Information: Intel(R) Core(TM) i7-4510U CPU @ 2.00GHz
Number of Available Cores: 4
Available memory: 15.55 GB
Elixir 1.6.0-rc.1
Erlang 20.2
Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
parallel: 1
inputs: none specified
Estimated total run time: 21 s


Benchmarking HS256...
Benchmarking HS384...
Benchmarking HS512...

Name            ips        average  deviation         median         99th %
HS256       20.98 K       47.66 μs    ±47.37%          45 μs         113 μs
HS384       20.96 K       47.72 μs    ±25.63%          45 μs          91 μs
HS512       20.10 K       49.76 μs    ±33.52%          47 μs          95 μs

Comparison: 
HS256       20.98 K
HS384       20.96 K - 1.00x slower
HS512       20.10 K - 1.04x slower

That's ~5k more ips and on average 22 micro seconds faster for each operation. This would bump JOSEs speed a lot!

It would be really nice if we could have some kind of encode/decode @callback. I am not 100% sure how to implement this (and these functions are used throughout the code base) so that's why I am not sending a PR.

Thanks once again for your work!

publishing cutkey to hex?

your cutkey repo doesn't have any issues open so I've taken to using this repo. Would it be possible for you to publish cutkey to hex and do a formalized release?

Compiling dependency failed

I tried adding jose as dependency to an existing application. I added the following line

{jose, {git, "git://github.com/potatosalad/erlang-jose.git", {tag, "1.7.3"}}},

to rebar.config. I am using *_rebar3 *_for building.
When i try to compile , the following errors occur

_undefined callback function decrypt_private/3 (behaviour 'jose_jwk_use_enc')

undefined callback function derive_key/1 (behaviour 'jose_jwk_use_enc')

undefined callback function derive_key/1 (behaviour 'jose_jwk_use_enc')
_
the file in which the error appears is " jose/src/jose_jwk_kty_ec.erl "
What is the problem here?How can I fix this?

RS256 data structure example for JOSE.JWK.from_map/1

I have a RS256 public key in JSON format

{
  "keys": [
    {
      "alg": "RS256",
      "kty": "RSA",
      "use": "sig",
      "x5c": [       
  "MIIDGTCCAgGgAwIBAgIJSgNeCzv/721VMA0GCSqGSIb3DQEBCwUAMCoxKDAmBgNVBAMTH2tyaXNobmEtYWNhZGVteS11YS5ldS5hdXRoMC5jb20wHhcNMTgwNzExMTgwNTE2WhcNMzIwMzE5MTgwNTE2WjAqMSgwJgYDVQQDEx9rcmlzaG5hLWFjYWRlbXktdWEuZXUuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6XmZxnobQD1yKLTCT1LMCVCEQ3uVA5sP7szF6UPQTDauZLD4JPy5MQzZ0Qm7GL/4VU/RGp1eIP3SHvvGZtfZqEud7QbKevUmeB63FKzchdzVfZtTNiGqcdJ8k7ozlYAzmPU+KmpRKfeFv4YldyHE6cEOk6P61vKTrZRXQN+6WL7Wlkv0V2NV94mlWvWVI/KsU16amieYXlsg145iIc7nBcoOdsoU7AEthz/jQbuVnGdWWSL4hq8K0ykAH7MdXp2smDPGhXUO+TUIQBTYw1Hd1jjywCebUZuJYPns7UtbP8ikHfsWJWXe3pi23iS0qv/NT7wsMRXYvJWdz30PokuO1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSk2w1Eo+1JoZGgS36S8iHq6fjQ4zAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBALEUbhgWGyz7+/v1FsTaBwZUXkW4JVkpttgBS768nMP6Jerd1jRFbR+ffET+pPHm7+r9kNfdQmbJnlJH07s3Wex4MPUxAPmjPoE4d76xhJLLU+yc+T4d6p+PbatK34+HsXARi07xVCHd8xo7geHsvaud0X0tCzTT+TnxyVO6J7PQGMV8U/EO2OZmwhPbRWrYwTq0iKyFgBv76Ksd9UfAL9wO3LCMls2alIx20a/0iRj34S95hgJXMlVm8JsojJPtYJju3wzz3i/ZP0n3easoNKUZIZabxAs6V5MSSxPeY0Z6G5OdNPxJfinfWZ4qv4ApDDZNNTLhY/+xqaSeNArpj3M="
      ],
      "n": "6XmZxnobQD1yKLTCT1LMCVCEQ3uVA5sP7szF6UPQTDauZLD4JPy5MQzZ0Qm7GL_4VU_RGp1eIP3SHvvGZtfZqEud7QbKevUmeB63FKzchdzVfZtTNiGqcdJ8k7ozlYAzmPU-KmpRKfeFv4YldyHE6cEOk6P61vKTrZRXQN-6WL7Wlkv0V2NV94mlWvWVI_KsU16amieYXlsg145iIc7nBcoOdsoU7AEthz_jQbuVnGdWWSL4hq8K0ykAH7MdXp2smDPGhXUO-TUIQBTYw1Hd1jjywCebUZuJYPns7UtbP8ikHfsWJWXe3pi23iS0qv_NT7wsMRXYvJWdz30PokuO1w",
      "e": "AQAB",
      "kid": "MzI5QzgzOTNBREY4NkFFNDY1NTY3ODVBQjlBOTk1MkZCQzVFMTBGNA",
      "x5t": "MzI5QzgzOTNBREY4NkFFNDY1NTY3ODVBQjlBOTk1MkZCQzVFMTBGNA"
    }
  ]
}

How should it be represented in Elixir data structure for JOSE.JWK.from_map/1?

ueberauth/guardian#520

crypto:rand_bytes/1 is deprecated and will be removed in a future release

When I use Erlang/OTP 19.0 and elixir 1.3,Unable to compile correctly.Compile errors are as follows:
compile: warnings being treated as errors
src/jose_jwe_alg_aes_kw.erl:103:crypto:rand_bytes/1 is deprecated and will be removed in a future release;use crypto:strong_rand_bytes/1
.........
And 他here are other many documents.

I modify the file in accordance with the requirements of the compiler and Compile pass.

Add support for firebase kid:key maps.

Google serves firebase keys in a somewhat nonstandard form. #{kid := key}
https://www.googleapis.com/robot/v1/metadata/x509/[email protected]

It seems that many jose implementations, have made allowances for this structure and when passed a map of keys correctly extract and verify a firebase token using this data structure.

e.g. http://stackoverflow.com/questions/40839874/how-to-decode-firebase-jwt-token-in-python
along with some php and node and I suspect others.

Although it's a little nonstandardized putting up some docs or possible code changes for handling firebase certs will probably save some people a bunch of time down the road.

Additionally I was unable to use from_pem calls to prepare keys from the the google RSA certificates. Although possibly this was due to user error. This forced me to manually extract the certificates using :public_keys and logic derived from from https://codegists.com/snippet/erlang/jwterl_ahmadster_erlang
before passing on to JWK (below code snippet).

From_pem failed due to a inability to match the decoded record to a from_key call in jose_jwk_kty.erl

    ["Bearer " <> token] = get_req_header(conn, "authorization");
    [header, _,_] = String.split(token, ".")
    encoding_key = :base64url.decode(header) |> Poison.decode!() |> Map.get("kid")
    # TODO track expiration time, and cache entry rather than continuously querying.
    # TODO fail to fetch handling.
    api_tokens_url = "https://www.googleapis.com/robot/v1/metadata/x509/[email protected]"
    request = HTTPotion.get(api_tokens_url)
    keys = Poison.decode!(request.body)
    [cert] = :public_key.pem_decode(keys[encoding_key])
    {:Certificate, {:TBSCertificate, _, _, _, _, _, _, {:SubjectPublicKeyInfo,
          {:AlgorithmIdentifier, _, _}, rsa_pub_key_der}, _, _, _}, _, _} = :public_key.pem_entry_decode(cert)
    rsa_pub_key =  :public_key.der_decode(:RSAPublicKey, rsa_pub_key_der)
    jwk = JOSE.JWK.from_key(rsa_pub_key)
    verified = JOSE.JWT.verify_strict(jwk, ["RS256"], token)

JWK.block_decrypt error when using RSA-OAEP-256 - A128GCM

Hi,

When we tried to bump from jose 1.8.4 to 1.9.0, some of our tests started to fail with the following message:

     ** (ErlangError) Erlang error: {:crypt_unsupported, [[rsa_padding: :rsa_pkcs1_oaep_padding, rsa_oaep_md: :sha256]]}
     code: |> JOSE.JWK.block_encrypt(%{"alg" => "RSA-OAEP-256", "enc" => "A128GCM"}, jwk)
     stacktrace:
       (jose) src/jose_jwa_unsupported.erl:49: :jose_jwa_unsupported.encrypt_public/3
       (jose) src/jose_jwe_alg_rsa.erl:73: :jose_jwe_alg_rsa.key_encrypt/3
       (jose) src/jose_jwe.erl:296: :jose_jwe.key_encrypt/3
       (jose) src/jose_jwe.erl:204: :jose_jwe.block_encrypt/5

when reading the CHANGELOG, I can see something about fixing some RSA padding:

Extra sanity check for RSA padding modes when falling back.

I guess it might be related but I have no idea how to dig further.

If it can help, I reproduced the error on a separate repository : https://github.com/kdisneur/jose_error

Thanks for your help

Fallback algorithm verification

Continuing the discussion from pull request joken-elixir/joken#57.

The following encryption and signature algorithms have fallback implementations which need to be verified as being correct:

Algorithm Purpose OTP 17 OTP 18 Fallback Definition
AES CBC 128-bit Encryption X X jose_jwa_aes NIST.800-38A
AES CBC 192-bit Encryption jose_jwa_aes NIST.800-38A
AES CBC 256-bit Encryption X X jose_jwa_aes NIST.800-38A
AES CTR 128-bit Encryption X X NIST.800-38A
AES CTR 192-bit Encryption X X NIST.800-38A
AES CTR 256-bit Encryption X X NIST.800-38A
AES ECB 128-bit Encryption X jose_jwa_aes NIST.800-38A
AES ECB 192-bit Encryption jose_jwa_aes NIST.800-38A
AES ECB 256-bit Encryption X jose_jwa_aes NIST.800-38A
AES GCM 128-bit Encryption X jose_jwa_aes NIST.800-38D
AES GCM 192-bit Encryption X jose_jwa_aes NIST.800-38D
AES GCM 256-bit Encryption X jose_jwa_aes NIST.800-38D
RSAES-OAEP Encryption X X jose_jwa_pkcs1 RFC 3447
RSAES-OAEP-256 Encryption jose_jwa_pkcs1 RFC 3447
RSAES-PKCS1-v1_5 Encryption X X RFC 3447
RSASSA-PKCS1-v1_5 Signature X X RFC 3447
RSASSA-PSS Signature jose_jwa_pkcs1 RFC 3447

There are also several "helper" algorithms used with the above that have no native implementations currently in OTP:

Algorithm Purpose Fallback Definition
AES Key Wrap Key Wrap jose_jwa_aes_kw RFC 3394
Concat KDF Key Derivation jose_jwa_concat_kdf NIST.800-56A
MGF1 Mask Generation jose_jwa_pkcs1 RFC 3447
PBKDF1 Key Derivation jose_jwa_pkcs5 RFC 2898
PBKDF2 Key Derivation jose_jwa_pkcs5 RFC 2898
PKCS #7 Padding Padding jose_jwa_pkcs7 RFC 2315

Informal Verification Status

  • AES CBC 128-bit
  • AES CBC 192-bit
  • AES CBC 256-bit
  • AES ECB 128-bit
  • AES ECB 192-bit
  • AES ECB 256-bit
  • AES GCM 128-bit
  • AES GCM 192-bit
  • AES GCM 256-bit
  • RSAES-OAEP
  • RSAES-OAEP-256
  • RSASSA-PSS
  • AES Key Wrap
  • Concat KDF
  • MGF1
  • PBKDF1 (optional)
  • PBKDF2
  • PKCS #7 Padding (optional)

generating a JWT for Apples MapKit JS

I am trying to generate JWT to allow access to Apple MapKit JS.
My code generates a key but I get an authorisation error from Apple.. so I think I am missing something.

This is the information about the token requirements from the Apple docs:

# Key
# alg: ES256
# kid: MYID1234
# typ JWT

# claims
# iss: MYISSID1234
# iat: issued at time
# exp: expiration time

this is my code:

jwk = JOSE.JWK.from_pem(Application.get_env(:myapp, :apple_maps_key)) |> JOSE.JWK.merge(%{"kid" => "MYID1234"})

time_now = :os.system_time(:seconds)
expires_at = time_now + 3600
claims = %{
  "iss" => "MYISSID1234",
  "iat" => time_now,
  "exp" => expires_at
}

JOSE.JWS.sign(jwk, JOSE.encode(claims), %{"alg" => "ES256"}) |> JOSE.JWS.compact |> elem(1)

The value of :apple_maps_key is the content from the downloaded .p8 file that i got from Apple. Something like this:

config :myapp, :apple_maps_key,
"""
-----BEGIN PRIVATE KEY-----
KeyContentHere
-----END PRIVATE KEY-----
"""

Would appreciate any help/clue to solve this 😄

erlang error: {:not_supported, ["P-521", :HS512]} on 1.8.0

Upgrading from 1.7.9 to 1.8.0 brings me erlang error: {:not_supported, ["P-521", :HS512]}. Does that mean that my tokens were failing silently before or is this a bug with 1.8.0?

Here's the specific trace:

(jose) src/jose_jwk_kty_ec.erl:355: :jose_jwk_kty_ec.jws_alg_to_digest_type/2
(jose) src/jose_jwk_kty_ec.erl:186: :jose_jwk_kty_ec.sign/3
(jose) src/jose_jws.erl:311: :jose_jws.sign/4
(jose) src/jose_jwt.erl:171: :jose_jwt.sign/3
lib/guardian.ex:303: Guardian.encode_claims/1

Thanks for your help with this issue.

Not able to verify using RSA public key

Hi @potatosalad

We have an authentication server where a public key will be hosted. So we will get the public key from a url like :- http://localhost/jwks.json
The public key will be a json of the form;

{
 "keys": [
   {
     "kty": "RSA",
     "e": "AQAB",
     "use": "sig",
     "kid": "mak1",
     "n": "ie4OsY4wbR9RSlxqYfY26ZA7dj_eK9kCmUEKCRZnCsPvOb0d3ZLySFbe7x5kQJAHgswR-AcxZXSHNsLhwA1bb5oul7TTa4ea4Z65ivFentzQJ87BBi8AGiGRO6laOLsRbv_9rd9WCtpNkyCMNflqzMO707g7GpbnyCzm0bPQxQmVvY6STCm2apmIgRs59KRsygLnhdDAWc4Gzajoc4Zbvpcd3IpEjSeqDn806lDLAtCKTAzU2IDc26jK38eJFhz2BA66QEOADn9CFEIP2afpVbWVbf-6Nb-OeBL0A_CsIR7RA6pOCMJTDi-0dG1jFnttVkR_gnceXcruOQmQSq0R_Q"
   }
 ]
}

We tried the following code sample to verify a jwt ;

PrivateKeys = <<"{\"keys\":[{\"kty\":\"RSA\",\"d\":\"BEwStO4KhE_NM9wOhW1vcZ-s_nSxAvyt3k1ZjyqP_D5EJjlKRlELVw9o3DwijFydC-iAHz7wLUJyZtRxb8PwsnqG3IvcXUqjmUt28sc0s7KVKNMiaZFzA3zCiO4_Am_tWNCvDBr4trlv-D7NokPrYjPlX6Io7WKj6bkFlcMsjwmRr60VnUplrt0YWQmSZa18Nn2Xg4f3U0qMVM9HsSztegayZlAQJhVQT3Z_FP9MXcnxNP8RCADcfSD7CvbwHDp3ttxLN89qEiUVezyjmGSmrnCOVEcDdy2RDbTbxToAEBbFgIXIEIXTpAT60mi04e3HwCe8ZH1Lk5Z-GxNSpVnqgQ\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"mak1\",\"alg\":\"RS256\",\"n\":\"v5SM4zitKoxHsM6bmZepdTk6iYYAo_7Beh3t-nLKgJD1_BIyyIB2cKGY12wb81Cz0DRACvtfHsJKwiZb_MG8J5IruWvIeQjcz2xdCcd8JuKLN25HLOgRk_zegmZju4xTuJqe9kA6z0Ow4Xv5OFjBU9COuIRzjmENpZrfZXy_QNANVdnvx9Yc_OzjfW0eV91ay2nXVQ9YTprdcgezPnrZSZsol6hw5Zgg6N7ptCN-N_-S8AgLyRnesLFYsodkNQeDs3jv73MfLkB7pU_HVlK2Cob3nwKANVC1mgVD5-MV98D_t_AtuID6cfRy25UBAPHd-d7hOYne0iM_rhWF8z8DLw\"}]}">>.

PrivateKeysMap = jsx:decode(PrivateKeys, [return_maps]).

AllKeys = maps:get(<<"keys">>, PrivateKeysMap).

[PrivateKey] = lists:filter(fun(KeyMap) -> maps:get(<<"kid">>, KeyMap) =:=  <<"mak1">>  end, AllKeys).

PrivateJwk = jose_jwk:from_map(PrivateKey).

JWS = #{
  <<"alg">> => <<"RS256">>,
  <<"kid">> => <<"mak1">>
}.

JWT = #{
  <<"iss">> => <<"joe">>,
  <<"exp">> => 1300819380,
  <<"http://example.com/is_root">> => true
}.

Signed = jose_jwt:sign(PrivateJwk, JWS, JWT).

CompactSigned = jose_jws:compact(Signed).

And if we verify the JWK by ;

jose_jwt:verify(PrivateJwk, CompactSigned).
{true,
    {jose_jwt,
        #{<<"exp">> => 1300819380,
          <<"http://example.com/is_root">> => true,
          <<"iss">> => <<"joe">>}},
    #jose_jws{
        alg = 
            {jose_jws_alg_rsa_pkcs1_v1_5,
                {jose_jws_alg_rsa_pkcs1_v1_5,sha256}},
        b64 = undefined,
        fields = #{<<"kid">> => <<"mak1">>,<<"typ">> => <<"JWT">>}}}

It gets verified properly and gives {true, _, _}.

But if we use the public key:

PublicKeys = <<"{\"keys\":[{\"kty\":\"RSA\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"mak1\",\"n\":\"ie4OsY4wbR9RSlxqYfY26ZA7dj_eK9kCmUEKCRZnCsPvOb0d3ZLySFbe7x5kQJAHgswR-AcxZXSHNsLhwA1bb5oul7TTa4ea4Z65ivFentzQJ87BBi8AGiGRO6laOLsRbv_9rd9WCtpNkyCMNflqzMO707g7GpbnyCzm0bPQxQmVvY6STCm2apmIgRs59KRsygLnhdDAWc4Gzajoc4Zbvpcd3IpEjSeqDn806lDLAtCKTAzU2IDc26jK38eJFhz2BA66QEOADn9CFEIP2afpVbWVbf-6Nb-OeBL0A_CsIR7RA6pOCMJTDi-0dG1jFnttVkR_gnceXcruOQmQSq0R_Q\"}]}">>.

PublicKeysMap = jsx:decode(PublicKeys, [return_maps]).

AllPublicKeys = maps:get(<<"keys">>, PublicKeysMap).

[PublicKey] = lists:filter(fun(KeyMap) -> maps:get(<<"kid">>, KeyMap) =:=  <<"mak1">>  end, AllPublicKeys).

PublicJwk = jose_jwk:from_map(PublicKey). `

And tried;

jose_jws:verify(PublicJwk, CompactSigned).
{false,
    <<"{\"exp\":1300819380,\"http://example.com/is_root\":true,\"iss\":\"joe\"}">>,
    #jose_jws{
        alg = 
            {jose_jws_alg_rsa_pkcs1_v1_5,
                {jose_jws_alg_rsa_pkcs1_v1_5,sha256}},
        b64 = undefined,
        fields = #{<<"kid">> => <<"mak1">>,<<"typ">> => <<"JWT">>}}}

This is verified false.

How can we verify with public key?

Also, can you please explain the details of how the verify function works?
What all does it check?
Can we verify whether the token claim contains attributes like, a valid expiration time, a subject etc.?
An equivalent java example would be ;

HttpsJwks httpsJkws = new HttpsJwks("http://localhost/jwks.json");
HttpsJwksVerificationKeyResolver httpsJwksKeyResolver = new HttpsJwksVerificationKeyResolver(httpsJkws);
JwtConsumer jwtConsumer = new JwtConsumerBuilder()
                .setRequireExpirationTime() // the JWT must have an expiration time
                .setMaxFutureValidityInMinutes(300) // but the  expiration time can't be too crazy
                .setAllowedClockSkewInSeconds(30) // allow some leeway in validating time based claims to  account for clock skew
                .setRequireSubject() // the JWT must have a subject claim
                .setExpectedIssuer("Issuer") // whom the JWT needs to have been issued by
                .setExpectedAudience("Audience") // to whom the JWT is intended for
                .setVerificationKeyResolver(httpsJwksKeyResolver) // verify the signature with the public key
                .build(); // create the JwtConsumer instance

Support JWK Set

I want to verify the ID Token in JWT from Google, with their public certificates. However, their public keys fetched from https://www.googleapis.com/oauth2/v3/certs are JWK Set containing multiple JWKs. Calling JOSE.JWK.verify/2 with the JWK Set ends up to function clause error,

iex(6)> JOSE.JWK.verify(signed, jwks)                                                                                                                                        {:error, :function_clause}

, whereas calling JOSE.JWK.verify/2 with each key of the set ends up to only one is verified. This is confusing. How can I use the JWK Set properly?

Signing using JWK (pem file) does not work

Hey,

I got some problems signing my JWT.

Here is what I did:

$ openssl genrsa -out key.pem 2048
$ mv key.pem apps/open_banking/priv/
iex> private_key = Path.join(:code.priv_dir(:open_banking), "key.pem")
iex> rsa_private_jwk = JOSE.JWK.from_pem_file private_key
%JOSE.JWK{fields: %{}, keys: :undefined,
 kty: {:jose_jwk_kty_rsa,
  {:RSAPrivateKey, :"two-prime",
   22332046457435375700241003783212182157205040613088050719590460598788118069205188827134018462832392367420766922675394541217931575350309172026899043009661168397423302584811127842859679661836353606078889592361604906869138279289527532047246660686961391605200017082581947908542302592280837181705509488144630324336776733764948348943636700234620953579588331252380307886562130640702222294659019555815317154077272471492817527117870405984207980260266219135412084712972560648491942923930106640788079505822690722812708890791400059595754605411902505602892984101896880989203912385120404069539802499161112324404101236303359646521127,
   65537,
   5451395077987261248645125326515227888840902692039346253444744017263718401378528325319896049077507562048879705036253747812754159367292462793327904696103870668812701142130528147917499355021712696492822004342599681097585702611865991084301266119444105511390357710715260122386739656549870046430638277481999419087461624894059458878952978396535102971239299099318937593948732260285460999588619876956332528349571659566659574974593931448789108228935216664260481475883213290473542682238114271084408603871967592252370681167305912634957815186927661169325493241219170057029631164522504445029609195486179757953089159104620695570177,
   150887572182841440636877430850908581755558371140126630838246938591497064624568162594488086971879222753955672313964965227039323255542843809749142999120593590046863974369594156037537394851849981259256929111503923815819237701779532116940472653266570337129764457982654879705888137749160267628309997231862574866919,
   148004544936106543508552321602208804176694304414002164923904570823798268536802882401528847675097095905997211404107810718458081557809555190293572137345019351371409317991610435490704214236427684081041827184226202265919219822532141503574411026716274645851436486375693069449772728421718102720809102539460159191233,
   142603801416497795010567331270494936377275889193101658414180953193138787032990942871049904923191894321639080022806597512818539803852300269039659554488768884354070337496044866728855893613206829565239710884499466518577715855326341452785082253851688360948479191342106910510139392466015194724047376574215115502419,
   19837220542880508387309818773422679339733017531662954006005428233154462224808528297221865480233347428754436501116667063657716837874775055183159706035348734034918587198655813744149805725815657978971747409650166481588025495843910019796414643005870828526771413038803850070140586942587726235555291769635748330497,
   50403300109040396758556275682841361005603617537181539020347988394450752313081994368221099880412626826381519161645518774185327850635905880855265366670844196584423855117267341372161428320313466558605873133909267516902767431014853648114897372120368656497856772558151087460387068286871345423932505740591096089993,
   :asn1_NOVALUE}}}

iex> rsa_public_jwk  = JOSE.JWK.to_public(rsa_private_jwk)
%JOSE.JWK{fields: %{}, keys: :undefined,
 kty: {:jose_jwk_kty_rsa,
  {:RSAPublicKey,
   22332046457435375700241003783212182157205040613088050719590460598788118069205188827134018462832392367420766922675394541217931575350309172026899043009661168397423302584811127842859679661836353606078889592361604906869138279289527532047246660686961391605200017082581947908542302592280837181705509488144630324336776733764948348943636700234620953579588331252380307886562130640702222294659019555815317154077272471492817527117870405984207980260266219135412084712972560648491942923930106640788079505822690722812708890791400059595754605411902505602892984101896880989203912385120404069539802499161112324404101236303359646521127,
   65537}}}

iex> data = %{"claims" => %{"id_token" => %{"openbanking_intent_id" => %{"value" => "id here", "essential" => true}}}}
iex> data_string = Poison.encode data
iex> signed = JOSE.JWK.sign(data_string, rsa_private_jwk)
** (FunctionClauseError) no function clause matching in :jose_jws.sign/4

    The following arguments were given to :jose_jws.sign/4:

        # 1
        {:jose_jwk, :undefined,
     {:jose_jwk_kty_rsa,
      {:RSAPrivateKey, :"two-prime",
       22332046457435375700241003783212182157205040613088050719590460598788118069205188827134018462832392367420766922675394541217931575350309172026899043009661168397423302584811127842859679661836353606078889592361604906869138279289527532047246660686961391605200017082581947908542302592280837181705509488144630324336776733764948348943636700234620953579588331252380307886562130640702222294659019555815317154077272471492817527117870405984207980260266219135412084712972560648491942923930106640788079505822690722812708890791400059595754605411902505602892984101896880989203912385120404069539802499161112324404101236303359646521127,
       65537,
       5451395077987261248645125326515227888840902692039346253444744017263718401378528325319896049077507562048879705036253747812754159367292462793327904696103870668812701142130528147917499355021712696492822004342599681097585702611865991084301266119444105511390357710715260122386739656549870046430638277481999419087461624894059458878952978396535102971239299099318937593948732260285460999588619876956332528349571659566659574974593931448789108228935216664260481475883213290473542682238114271084408603871967592252370681167305912634957815186927661169325493241219170057029631164522504445029609195486179757953089159104620695570177,
       150887572182841440636877430850908581755558371140126630838246938591497064624568162594488086971879222753955672313964965227039323255542843809749142999120593590046863974369594156037537394851849981259256929111503923815819237701779532116940472653266570337129764457982654879705888137749160267628309997231862574866919,
       148004544936106543508552321602208804176694304414002164923904570823798268536802882401528847675097095905997211404107810718458081557809555190293572137345019351371409317991610435490704214236427684081041827184226202265919219822532141503574411026716274645851436486375693069449772728421718102720809102539460159191233,
       142603801416497795010567331270494936377275889193101658414180953193138787032990942871049904923191894321639080022806597512818539803852300269039659554488768884354070337496044866728855893613206829565239710884499466518577715855326341452785082253851688360948479191342106910510139392466015194724047376574215115502419,
       19837220542880508387309818773422679339733017531662954006005428233154462224808528297221865480233347428754436501116667063657716837874775055183159706035348734034918587198655813744149805725815657978971747409650166481588025495843910019796414643005870828526771413038803850070140586942587726235555291769635748330497,
       50403300109040396758556275682841361005603617537181539020347988394450752313081994368221099880412626826381519161645518774185327850635905880855265366670844196584423855117267341372161428320313466558605873133909267516902767431014853648114897372120368656497856772558151087460387068286871345423932505740591096089993,
       :asn1_NOVALUE}}, %{}}

        # 2
        {:ok,
     "{\"claims\":{\"id_token\":{\"openbanking_intent_id\":{\"value\":\"id here\",\"essential\":true}}}}"}

        # 3
        %{}

        # 4
        {:jose_jws, {:jose_jws_alg_rsa_pss, :PS256}, :undefined, %{}}

    (jose) src/jose_jws.erl:259: :jose_jws.sign/4

I basically followed the example in the README.

I want to implement https://openbanking.atlassian.net/wiki/spaces/DZ/pages/7046134/Open+Banking+Security+Profile+-+Implementer+s+Draft+v1.1.0#OpenBankingSecurityProfile-Implementer'sDraftv1.1.0-JSONSecuritySuiteInformationv1.0 and have quite a lot of problems doing so. Maybe someone who is a bit deeper into this topic could help me out with this.

Thanks.

Tests do not build if jose is not installed

I'm working on packaging jose for Fedora, and I noticed that I cannot build the tests unless jose is already installed. I think it is due to some of the test files including jose/include/ instead of just include/. For example:

$ rebar eunit                               
==> erlang-jose-1.8.4 (eunit)                              
test/property_test/jose_jwk_kty_okp_x448_props.erl:5: can't find include lib "jose/include/jose_public_key.hrl"       
test/property_test/jose_jwk_kty_okp_x448_props.erl:26: record jose_X448PublicKey undefined                            
test/property_test/jose_jwk_kty_okp_x448_props.erl:27: record jose_X448PrivateKey undefined                           
test/property_test/jose_jwk_kty_okp_x448_props.erl:25: variable 'PK' is unused                                        
test/property_test/jose_jwk_kty_okp_x448_props.erl:25: variable 'S' is unused                                         
Compiling test/property_test/jose_jwk_kty_okp_x448_props.erl failed:                                                  
ERROR: eunit failed while processing /home/rbarlow/rpmbuild/BUILD/erlang-jose-1.8.4: rebar_abort

If I edit test/property_test/jose_jwk_kty_okp_x448_props.erl and remove jose/ from that include_lib() call, it builds (but a similar problem happens with another file later).

Fix project versions for dependencies

I'm in the process of adding your project to Buildroot (see buildroot.org) but I notice it depends on a project without specifying which version:
'''
{deps, [
{base64url, ".*", {git, "git://github.com/dvv/base64url.git", {branch, "master"}}}
]}.
'''
I suggest you fix the version at least when you make a release of your project. Thanks.
Best,

Opt-in for fallback algorithms

Continuing the discussion from pull request joken-elixir/joken#57.

See #1 for the full algorithm fallback table.

From @cs-victor-nascimento:

But I guess that having at least a big warning or a mandatory config change for making the fallback algorithms opt-in and not opt-out would definitely benefit users.

Currently, only the AES ciphers support any sort of fallback detection. The following algorithms have no fallback detection due to the fact that there is no working algorithm present in any version of OTP:

  • RSAES-OAEP-256 (JWE: {"enc":"RSA-OAEP-256"})
  • RSASSA-PSS (JWS: {"alg":"PS256"}, {"alg":"PS384"}, and {"alg":"PS512"})

Can't verify RSA PSS algorithms

We have recently updated our dependecy on erlang-jose to 1.3 and we've detected that our PSS tests are failing.

This commit is breaking the test.

I have already mentioned this in Joken's repository. I am just opening the issue so we can track this one.

Thanks for your help!

Compile warnings on elixir 1.7.3

I get the following when compiling jose on elixir

==> jose
Compiling 89 files (.erl)
src/jose_public_key.erl:44: Warning: erlang:get_stacktrace/0: deprecated; use the new try/catch syntax for retrieving the stack backtrace
src/jose_public_key.erl:60: Warning: erlang:get_stacktrace/0: deprecated; use the new try/catch syntax for retrieving the stack backtrace
src/jose_public_key.erl:84: Warning: erlang:get_stacktrace/0: deprecated; use the new try/catch syntax for retrieving the stack backtrace
src/jose_public_key.erl:107: Warning: erlang:get_stacktrace/0: deprecated; use the new try/catch syntax for retrieving the stack backtrace
src/jose_public_key.erl:122: Warning: erlang:get_stacktrace/0: deprecated; use the new try/catch syntax for retrieving the stack backtrace
src/jose_public_key.erl:234: Warning: erlang:get_stacktrace/0: deprecated; use the new try/catch syntax for retrieving the stack backtrace

There is anything we could do to remove these warnings? This is expected behaviour?

Attempting to `block_decrypt` with a different key returns a FunctionClauseError

Given the following example, where a non-matching key is used for decryption:

encryption_key = JOSE.JWK.from_oct(<<0::128>>)
different_key = JOSE.JWK.from_oct(<<1::128>>)

encrypted_a128gcmkw = JOSE.JWE.block_encrypt(encryption_key, "{}", %{ "alg" => "A128GCMKW", "enc" => "A128GCM" }) |> JOSE.JWE.compact |> elem(1)
JOSE.JWE.block_decrypt(different_key, encrypted_a128gcmkw) |> elem(0)

Expected Result

Some descriptive error message, stating that a non-matching key was used.

Actual Result

** (FunctionClauseError) no function clause matching in :jose_jwe_enc_aes.block_decrypt/4

Improving this would be great, because in a system where multiple remote parties connect to each-other using JOSE, implementers need good feedback to know where implementation mistakes are happening (malformed key? malformed cyphertext? malformed plain text after decoding?).

It would be even nicer if you can alter the signature of the decryption functions to return ok/error-tuples, and provide versions with bangs that throw.

jose does not build with erlang 20

When I build Jose on Fedora 28 or Rawhide, I get an error:

…
Compiled src/jose_chacha20_poly1305_crypto.erl
Compiled src/jose_app.erl
Compiled src/jose.erl
test/property_test/jose_jwt_props.erl:9: export_all flag enabled - all functions will be exported
Compiling test/property_test/jose_jwt_props.erl failed:
DEBUG: Worker compilation failed: {{error,
                                    {error,[],
                                     [["test/property_test/jose_jwt_props.erl:9: export_all flag enabled - all functions will be exported\n"]]}},
                                   {source,
                                    "test/property_test/jose_jwt_props.erl"}}
ERROR: eunit failed while processing /home/rbarlow/rpmbuild/BUILD/erlang-jose-1.8.4: rebar_abort

Removing the warnings_as_errors from rebar.config get things building again for me as a workaround.

Encoding issue

Hi.
I use guardian in my elixir project. Also I want to decode JWT on frontend but have some problem with decoding base64 value. Also I found that I have problem with decoding same base64 value using Base.decode64.

To extract problem from the rest code I wrote this test. Firstly, I found that JOSE and Base.encode64 returns different values (as different paddings that isn't problem for javascript's atob decoder, and fully different values that you can see in first assertion in my test).
Also I found that for this particular payload you can't decode base64 value even if you fix paddings (just uncomment corresponding line) because JOSE encoder adds _ character, that unsupported by Base.decode64 and by javascript's atob

Can you help me with it?

Block decrypt strict and JWE peek functions

Hi @potatosalad ! I am focusing more on the JWE part of things now and would like to ask you if there is interest in adding some functionalities to it:

  • block_decrypt_strict similar to verify_strict where we only accept a known set of algorithms. This avoids "downgrading" to weaker crypto for example;
  • jose_jwe:peek/1 and related would be needed to implement decrypt strict.

I could work on those if you think they are worthy additions to this mighty library.

Thanks once again for your work!

JOSE.JWS.sign/3 - wrong signature when b64 is set to false

I'm trying to sign a payload using the JWS Unencoded Payload Option (b64 set to false) with both Elixir and Node.js. I'm inclined to believe that the Elixir/Erlang might get the wrong result since i tried to validate with two external systems and the node.js output works well.
Note: when b64 is set to true the results are identical with both languages.

defmodule Gist do
  def signature do
    # this is a RSA private key
    certificate_path = Path.join(:code.priv_dir(:my_app), "secrets/newRS256.key")

    jwk = JOSE.JWK.from_pem_file(certificate_path)

    payload = %{
      "foo" => "test"
    }

    jose_header = %{
      "alg" => "RS256",
      "b64" => false,
      "kid" => "kid",
      "typ" => "JOSE"
    }

    jws = JOSE.JWS.from_map(jose_header)

    signed_rs256 =
      JOSE.JWS.sign(
        jwk,
        payload |> JOSE.encode(),
        jws
      )

    {true, _jwt, _jws} = JOSE.JWS.verify_strict(jwk, ["RS256"], signed_rs256)

    # JOSE.JWS.compact(signed_rs256 |> elem(1))
    signed_rs256
  end
end

Result:

{%{alg: :jose_jws_alg_rsa_pkcs1_v1_5},
 %{
   "payload" => "eyJmb28iOiJ0ZXN0In0",
   "protected" => "eyJhbGciOiJSUzI1NiIsImI2NCI6ZmFsc2UsImtpZCI6ImtpZCIsInR5cCI6IkpPU0UifQ",
   "signature" => "WcqakCfgzxDxpZ9Mv2tHmzfyphPxdZKle1h0bc3tV6ulDymnZK-bhpkaDD9U1nzkOhZNAXUONL5D6pYn8kMyX-BjwBWtZlKi4RTY4OjBKmPsNPaFAQpjwSOYvZgynq-0NCtNeQFW2enDKnv6drcAax0BeP-yrclNUNGqdqAxy5z8yQSfphy_yAqDsyKP_cMbUIk8bhNLjRcdQ6Nn9lzngZg6GGo7D7ZiDGFn2f8B1c2bh-w9c8lioHoAhlle5cKTuJvbkVZCYpUlYk85a9vCmD4SH_DhN49A-drY_h1xpO_SCH_xl_oSnjMe89BYcDL1YgGmwfITITKjgOzFhdeW8w"
 }}

Node.js output:

{ payload: 'eyJmb28iOiJ0ZXN0In0',
  signatures:
   [ { protected:
        'eyJhbGciOiJSUzI1NiIsImI2NCI6ZmFsc2UsImtpZCI6ImtpZCIsInR5cCI6IkpPU0UifQ',
       signature:
        'vC4VZAwO9pFAvfLJhQBQDwxhb2iMNnCimnUOUMA58AgbQtJvj1QS54UVEcesiZlzCxsI2UcfDrzMPVIiJlsweQ4C8OBt5SIt9Jy_qeNNGKY2hyiD4DIU79QHclwW9_00cSDmY6h2MW8N3bVSK5N3a36MMTa45l22er8DUn1VYZtn759QZ4CohkPaW_CloL3A306PPYdoaktCoi0CmAOut4EKBDts8sHMFdnd0UVUyTAUH0kbjrS3DbB95OJ_-b2ywY_MNEvIe2Y3NHbrDCMvqOiFJoEXRvxK0xjnnyKZSeuEm_Xhd2UrW_MiNq3QaONetoGdzQxCM3k5Kq6WRQRnow' } ] }

The equivalent gist in node.js & test pub/priv keys

JWS.peek should be more robust

When calling JOSE.JWS.peek with any opaque value or slightly modified JWT-binary it throws an ArgumentError:

iex(3)> JOSE.JWS.peek("a")
** (ArgumentError) argument error: ["a"]
    src/jose_jws.erl:463: :jose_jws.do_expand/1
    src/jose_jws.erl:176: :jose_jws.expand/1
    src/jose_jws.erl:225: :jose_jws.peek_payload/1`

Would it be possible to make this more robust and return an error-tuple instead? Otherwise it is not possible to trust this method with any user provided input.

JOSE.JWT.sign never returns if the first argument is an empty list

Hi @potatosalad,
I think I've found a strange behaviour when calling JOSE.JWT.sign.

Steps to reproduce:

jws = %{"alg" => "RS256"}
jwt = %{"iss" => "some_iss"}
JOSE.JWT.sign([], jws, jwt)

The last call never returns.

This could be triggered (as I did) if the JWK is taken from an invalid PEM with JOSE.JWK.from_pem("some_invalid_pem"), that returns an empty list.

Jose compilation fails on Elixir 1.8.1

I'm new to this, so perhaps I've made a mistake. I'm trying to compile with Elixir 1.8.1, and I'm getting this error. I'm not really sure where to begin fixing this. Any tips?

Thanks!

elixir --version
Erlang/OTP 21 [erts-10.2.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1]

Elixir 1.8.1 (compiled with Erlang/OTP 20)
mix deps.compile jose
==> jose
Compiling 90 files (.erl)
src/jose_jwa.erl:13: can't find include lib "public_key/include/public_key.hrl"
src/jose_jwa.erl:98: record 'RSAPrivateKey' undefined
src/jose_jwa.erl:105: record 'RSAPublicKey' undefined
src/jose_jwa.erl:112: record 'RSAPrivateKey' undefined
src/jose_jwa.erl:123: record 'RSAPublicKey' undefined
src/jose_jwe_alg_ecdh_es.erl:15: can't find include lib "public_key/include/public_key.hrl"
src/jose_jwe_alg_ecdh_es.erl:31: record 'ECParameters' undefined
src/jose_jwe_alg_ecdh_es.erl:31: record 'ECPoint' undefined
include/jose_public_key.hrl:14: can't find include lib "public_key/include/public_key.hrl"
src/jose_jwk_kty.erl:76: undefined macro 'rsaEncryption'
src/jose_jwk_kty.erl:32: function from_key/1 undefined
src/jose_jwk_kty.erl:88: record 'ECParameters' undefined
src/jose_jwk_kty.erl:90: record 'ECPrivateKey' undefined
src/jose_jwk_kty.erl:92: record 'ECPoint' undefined
src/jose_jwk_kty.erl:98: record 'RSAPrivateKey' undefined
src/jose_jwk_kty.erl:100: record 'RSAPublicKey' undefined
src/jose_jwk_kty.erl:104: record 'ECParameters' undefined
src/jose_jwk_kty.erl:106: record 'ECPrivateKey' undefined
src/jose_jwk_kty.erl:108: record 'ECPoint' undefined
include/jose_public_key.hrl:14: can't find include lib "public_key/include/public_key.hrl"
src/jose_jwk_kty_okp_ed25519.erl:13: Warning: behaviour jose_jwk_kty undefined
src/jose_jwk_kty_okp_ed25519ph.erl:13: Warning: behaviour jose_jwk_kty undefined
include/jose_public_key.hrl:14: can't find include lib "public_key/include/public_key.hrl"
src/jose_jwk_kty_okp_ed448.erl:13: Warning: behaviour jose_jwk_kty undefined
src/jose_jwk_pem.erl:13: can't find include lib "public_key/include/public_key.hrl"
src/jose_jwk_pem.erl:54: record 'Certificate' undefined
src/jose_jwk_pem.erl:59: record 'Certificate' undefined
src/jose_jwk_pem.erl:60: variable 'SubjectPublicKeyInfo' is unbound
src/jose_jwk_pem.erl:62: record 'SubjectPublicKeyInfo' undefined
src/jose_jwa_pkcs1.erl:13: can't find include lib "public_key/include/public_key.hrl"
src/jose_jwa_pkcs1.erl:50: record 'RSAPublicKey' undefined
src/jose_jwa_pkcs1.erl:51: record 'RSAPrivateKey' undefined
src/jose_jwa_pkcs1.erl:59: record 'RSAPrivateKey' undefined
src/jose_jwa_pkcs1.erl:74: record 'RSAPublicKey' undefined
src/jose_jwa_pkcs1.erl:95: record 'RSAPrivateKey' undefined
src/jose_jwa_pkcs1.erl:115: record 'RSAPublicKey' undefined
src/jose_jwa_pkcs1.erl:531: record 'RSAPrivateKey' undefined
src/jose_jwa_pkcs1.erl:549: record 'RSAPrivateKey' undefined
src/jose_jwa_pkcs1.erl:554: variable 'N' is unbound
src/jose_jwa_pkcs1.erl:575: record 'RSAPublicKey' undefined
src/jose_jwa_pkcs1.erl:593: record 'RSAPublicKey' undefined
src/jose_jwa_pkcs1.erl:615: record 'RSAPublicKey' undefined
src/jose_jwa_pkcs1.erl:622: variable 'N' is unbound
src/jose_jwa_pkcs1.erl:647: record 'RSAPrivateKey' undefined
src/jose_jwa_pkcs1.erl:649: variable 'N' is unbound
src/jose_jwa_pkcs1.erl:664: record 'RSAPublicKey' undefined
src/jose_jwa_pkcs1.erl:667: variable 'N' is unbound
src/jose_jwa_pkcs1.erl:702: record 'RSAPrivateKey' undefined
src/jose_jwa_pkcs1.erl:706: variable 'Modulus' is unbound
src/jose_jwa_pkcs1.erl:715: record 'RSAPrivateKey' undefined
src/jose_jwa_pkcs1.erl:739: record 'RSAPublicKey' undefined
src/jose_jwa_pkcs1.erl:743: variable 'Modulus' is unbound
src/jose_jwa_pkcs1.erl:757: record 'RSAPublicKey' undefined
src/jose_jwa_pkcs1.erl:770: record 'RSAPrivateKey' undefined
src/jose_jwa_pkcs1.erl:773: variable 'Modulus' is unbound
src/jose_jwa_pkcs1.erl:782: record 'RSAPrivateKey' undefined
src/jose_jwa_pkcs1.erl:797: record 'RSAPrivateKey' undefined
src/jose_jwa_pkcs1.erl:801: variable 'Modulus' is unbound
src/jose_jwa_pkcs1.erl:810: record 'RSAPrivateKey' undefined
src/jose_jwa_pkcs1.erl:823: record 'RSAPublicKey' undefined
src/jose_jwa_pkcs1.erl:827: variable 'Modulus' is unbound
src/jose_jwa_pkcs1.erl:836: record 'RSAPublicKey' undefined
src/jose_jwa_pkcs1.erl:850: record 'RSAPublicKey' undefined
src/jose_jwa_pkcs1.erl:855: variable 'Modulus' is unbound
src/jose_jwa_pkcs1.erl:864: record 'RSAPublicKey' undefined
src/jose_jwa_pkcs1.erl:895: record 'RSAPrivateKey' undefined
src/jose_jwa_pkcs1.erl:896: variable 'E' is unbound
src/jose_jwa_pkcs1.erl:896: variable 'N' is unbound
src/jose_jwa_pkcs1.erl:899: record 'RSAPublicKey' undefined
src/jose_jwa_pkcs1.erl:900: variable 'E' is unbound
src/jose_jwa_pkcs1.erl:900: variable 'N' is unbound
src/jose_jwk_kty_okp_ed448ph.erl:13: Warning: behaviour jose_jwk_kty undefined
src/jose_server.erl:14: can't find include lib "public_key/include/public_key.hrl"
src/jose_server.erl:179: variable 'PrivateKey' is unbound
src/jose_server.erl:179: variable 'PublicKey' is unbound
src/jose_server.erl:179: record 'ECPrivateKey' undefined
src/jose_server.erl:181: variable 'PrivateKey' is unbound
src/jose_server.erl:181: variable 'PublicKey' is unbound
src/jose_server.erl:181: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:17: can't find include lib "public_key/include/public_key.hrl"
src/jose_jwk_kty_ec.erl:45: record 'ECParameters' undefined
src/jose_jwk_kty_ec.erl:45: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:45: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:54: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:56: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:58: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:60: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:63: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:67: variable 'D' is unbound
src/jose_jwk_kty_ec.erl:67: variable 'PublicKey' is unbound
src/jose_jwk_kty_ec.erl:71: variable 'Parameters' is unbound
src/jose_jwk_kty_ec.erl:76: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:79: variable 'PublicKey' is unbound
src/jose_jwk_kty_ec.erl:86: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:90: variable 'D' is unbound
src/jose_jwk_kty_ec.erl:90: variable 'PublicKey' is unbound
src/jose_jwk_kty_ec.erl:91: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:96: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:98: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:108: record 'ECParameters' undefined
src/jose_jwk_kty_ec.erl:114: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:115: variable 'P' is unbound
src/jose_jwk_kty_ec.erl:116: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:126: record 'ECParameters' undefined
src/jose_jwk_kty_ec.erl:128: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:130: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:174: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:174: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:176: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:176: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:177: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:178: variable 'ECParameters' is unbound
src/jose_jwk_kty_ec.erl:185: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:188: record 'ECDSA-Sig-Value' undefined
src/jose_jwk_kty_ec.erl:189: variable 'R' is unbound
src/jose_jwk_kty_ec.erl:190: variable 'S' is unbound
src/jose_jwk_kty_ec.erl:196: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:199: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:203: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:205: variable 'Parameters' is unbound
src/jose_jwk_kty_ec.erl:214: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:215: variable 'Octets0' is unbound
src/jose_jwk_kty_ec.erl:221: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:222: variable 'ECParameters' is unbound
src/jose_jwk_kty_ec.erl:224: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:233: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:240: record 'ECDSA-Sig-Value' undefined
src/jose_jwk_kty_ec.erl:246: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:247: variable 'Octets0' is unbound
src/jose_jwk_kty_ec.erl:253: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:254: variable 'ECParameters' is unbound
src/jose_jwk_kty_ec.erl:261: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:263: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:282: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:285: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:288: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:290: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:299: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:301: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:303: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:305: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:307: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:309: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:311: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:323: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:350: record 'ECPrivateKey' undefined
src/jose_jwk_kty_ec.erl:351: variable 'Parameters' is unbound
src/jose_jwk_kty_ec.erl:352: record 'ECPoint' undefined
src/jose_jwk_kty_ec.erl:13: Warning: behaviour jose_jwk_kty undefined
src/jose_jwk_kty_ec.erl:215: Warning: variable 'Octets' is unused
src/jose_jwk_kty_ec.erl:238: Warning: variable 'R' is unused
src/jose_jwk_kty_ec.erl:239: Warning: variable 'S' is unused
src/jose_jwk_kty_ec.erl:247: Warning: variable 'Octets' is unused
src/jose_jwk_kty_ec.erl:298: Warning: variable 'D' is unused
src/jose_jwk_kty_ec.erl:300: Warning: variable 'D' is unused
src/jose_jwk_kty_ec.erl:308: Warning: variable 'X' is unused
src/jose_jwk_kty_ec.erl:308: Warning: variable 'Y' is unused
src/jose_jwk_kty_ec.erl:310: Warning: variable 'X' is unused
src/jose_jwk_kty_ec.erl:310: Warning: variable 'Y' is unused
src/jose_jwk_kty_ec.erl:322: Warning: variable 'X' is unused
src/jose_jwk_kty_ec.erl:322: Warning: variable 'Y' is unused
include/jose_public_key.hrl:14: can't find include lib "public_key/include/public_key.hrl"
src/jose_jwk_kty_okp_x25519.erl:13: Warning: behaviour jose_jwk_kty undefined
include/jose_public_key.hrl:14: can't find include lib "public_key/include/public_key.hrl"
src/jose_jwk_kty_okp_x448.erl:13: Warning: behaviour jose_jwk_kty undefined
src/jose_jwk_kty_rsa.erl:17: can't find include lib "public_key/include/public_key.hrl"
src/jose_jwk_kty_rsa.erl:46: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:46: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:55: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:57: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:59: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:61: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:64: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:76: variable 'D' is unbound
src/jose_jwk_kty_rsa.erl:77: variable 'DP' is unbound
src/jose_jwk_kty_rsa.erl:78: variable 'DQ' is unbound
src/jose_jwk_kty_rsa.erl:79: variable 'E' is unbound
src/jose_jwk_kty_rsa.erl:81: variable 'N' is unbound
src/jose_jwk_kty_rsa.erl:82: variable 'P' is unbound
src/jose_jwk_kty_rsa.erl:83: variable 'Q' is unbound
src/jose_jwk_kty_rsa.erl:84: variable 'QI' is unbound
src/jose_jwk_kty_rsa.erl:86: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:98: variable 'D' is unbound
src/jose_jwk_kty_rsa.erl:99: variable 'DP' is unbound
src/jose_jwk_kty_rsa.erl:100: variable 'DQ' is unbound
src/jose_jwk_kty_rsa.erl:101: variable 'E' is unbound
src/jose_jwk_kty_rsa.erl:103: variable 'N' is unbound
src/jose_jwk_kty_rsa.erl:106: variable 'OD' is unbound
src/jose_jwk_kty_rsa.erl:107: variable 'OR' is unbound
src/jose_jwk_kty_rsa.erl:108: variable 'OT' is unbound
src/jose_jwk_kty_rsa.erl:110: record 'OtherPrimeInfo' undefined
src/jose_jwk_kty_rsa.erl:113: variable 'OTH' is unbound
src/jose_jwk_kty_rsa.erl:114: variable 'P' is unbound
src/jose_jwk_kty_rsa.erl:115: variable 'Q' is unbound
src/jose_jwk_kty_rsa.erl:116: variable 'QI' is unbound
src/jose_jwk_kty_rsa.erl:118: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:122: variable 'E' is unbound
src/jose_jwk_kty_rsa.erl:124: variable 'N' is unbound
src/jose_jwk_kty_rsa.erl:127: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:129: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:139: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:140: variable 'E' is unbound
src/jose_jwk_kty_rsa.erl:140: variable 'N' is unbound
src/jose_jwk_kty_rsa.erl:141: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:142: variable 'E' is unbound
src/jose_jwk_kty_rsa.erl:142: variable 'N' is unbound
src/jose_jwk_kty_rsa.erl:181: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:184: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:186: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:187: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:194: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:198: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:202: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:212: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:213: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:215: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:223: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:231: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:232: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:239: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:241: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:260: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:263: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:267: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:269: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:277: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:288: variable 'D' is unbound
src/jose_jwk_kty_rsa.erl:289: variable 'E' is unbound
src/jose_jwk_kty_rsa.erl:290: variable 'N' is unbound
src/jose_jwk_kty_rsa.erl:306: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:367: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:369: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:371: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:373: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:375: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:377: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:379: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:381: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:384: record 'OtherPrimeInfo' undefined
src/jose_jwk_kty_rsa.erl:389: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:390: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:401: variable 'D' is unbound
src/jose_jwk_kty_rsa.erl:402: variable 'E' is unbound
src/jose_jwk_kty_rsa.erl:403: variable 'N' is unbound
src/jose_jwk_kty_rsa.erl:432: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:434: record 'RSAPublicKey' undefined
src/jose_jwk_kty_rsa.erl:488: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:505: record 'RSAPrivateKey' undefined
src/jose_jwk_kty_rsa.erl:13: Warning: behaviour jose_jwk_kty undefined
src/jose_jwk_kty_rsa.erl:303: Warning: variable 'DP' is unused
src/jose_jwk_kty_rsa.erl:304: Warning: variable 'DQ' is unused
src/jose_jwk_kty_rsa.erl:305: Warning: variable 'QI' is unused
src/jose_jwk_kty_rsa.erl:366: Warning: variable 'D' is unused
src/jose_jwk_kty_rsa.erl:368: Warning: variable 'DP' is unused
src/jose_jwk_kty_rsa.erl:370: Warning: variable 'DQ' is unused
src/jose_jwk_kty_rsa.erl:372: Warning: variable 'E' is unused
src/jose_jwk_kty_rsa.erl:374: Warning: variable 'N' is unused
src/jose_jwk_kty_rsa.erl:376: Warning: variable 'P' is unused
src/jose_jwk_kty_rsa.erl:378: Warning: variable 'Q' is unused
src/jose_jwk_kty_rsa.erl:380: Warning: variable 'QI' is unused
src/jose_jwk_kty_rsa.erl:383: Warning: variable 'OtherPrimeInfos' is unused
src/jose_jwk_kty_rsa.erl:388: Warning: variable 'OD' is unused
src/jose_jwk_kty_rsa.erl:388: Warning: variable 'OR' is unused
src/jose_jwk_kty_rsa.erl:388: Warning: variable 'OT' is unused
src/jose_jwk_kty_rsa.erl:431: Warning: variable 'E' is unused
src/jose_jwk_kty_rsa.erl:433: Warning: variable 'N' is unused
src/jose_jwk_kty_oct.erl:13: Warning: behaviour jose_jwk_kty undefined
include/jose_public_key.hrl:14: can't find include lib "public_key/include/public_key.hrl"
src/jose_public_key.erl:68: record 'PrivateKeyInfo' undefined
src/jose_public_key.erl:70: record 'SubjectPublicKeyInfo' undefined
src/jose_public_key.erl:91: record 'PrivateKeyInfo' undefined
src/jose_public_key.erl:93: record 'SubjectPublicKeyInfo' undefined
src/jose_public_key.erl:285: record 'PrivateKeyInfo' undefined
src/jose_public_key.erl:293: variable 'PrivateKey' is unbound
src/jose_public_key.erl:298: record 'SubjectPublicKeyInfo' undefined
src/jose_public_key.erl:305: variable 'PublicKey' is unbound
src/jose_public_key.erl:306: record 'PrivateKeyInfo' undefined
src/jose_public_key.erl:314: variable 'PrivateKey' is unbound
src/jose_public_key.erl:319: record 'SubjectPublicKeyInfo' undefined
src/jose_public_key.erl:326: variable 'PublicKey' is unbound
src/jose_public_key.erl:327: record 'PrivateKeyInfo' undefined
src/jose_public_key.erl:335: variable 'PrivateKey' is unbound
src/jose_public_key.erl:340: record 'SubjectPublicKeyInfo' undefined
src/jose_public_key.erl:347: variable 'PublicKey' is unbound
src/jose_public_key.erl:348: record 'PrivateKeyInfo' undefined
src/jose_public_key.erl:356: variable 'PrivateKey' is unbound
src/jose_public_key.erl:361: record 'SubjectPublicKeyInfo' undefined
src/jose_public_key.erl:368: variable 'PublicKey' is unbound
src/jose_public_key.erl:374: record 'PrivateKeyInfo' undefined
src/jose_public_key.erl:386: record 'SubjectPublicKeyInfo' undefined
src/jose_public_key.erl:395: record 'PrivateKeyInfo' undefined
src/jose_public_key.erl:407: record 'SubjectPublicKeyInfo' undefined
src/jose_public_key.erl:416: record 'PrivateKeyInfo' undefined
src/jose_public_key.erl:428: record 'SubjectPublicKeyInfo' undefined
src/jose_public_key.erl:437: record 'PrivateKeyInfo' undefined
src/jose_public_key.erl:449: record 'SubjectPublicKeyInfo' undefined
src/jose_public_key.erl:373: Warning: variable 'PrivateKey' is unused
src/jose_public_key.erl:385: Warning: variable 'PublicKey' is unused
src/jose_public_key.erl:394: Warning: variable 'PrivateKey' is unused
src/jose_public_key.erl:406: Warning: variable 'PublicKey' is unused
src/jose_public_key.erl:415: Warning: variable 'PrivateKey' is unused
src/jose_public_key.erl:427: Warning: variable 'PublicKey' is unused
src/jose_public_key.erl:436: Warning: variable 'PrivateKey' is unused
src/jose_public_key.erl:448: Warning: variable 'PublicKey' is unused
could not compile dependency :jose, "mix compile" failed. You can recompile this dependency with "mix deps.compile jose", update it with "mix deps.update jose" or clean it with "mix deps.clean jose"

Compiler error building with rebar.

I am trying to compile https://github.com/dmunch/couch_jwt_auth on Windows using rebar. The rebar get-deps co eunit command fails while compiling erlang-jose.

c:/Users/Peter/source/couch_jwt_auth/deps/jose/src/jose_chacha20_poly1305.erl:13: undefined callback function block_decrypt/3 (behaviour 'jose_block_encryptor')

I don't know erlang so I am not sure why this is failing. I see there is a jose_block_encryptor.erl that defines a block_decrypt that takes 3 arguments. I assume that is what this error is about. I see it is wrapped in a ifdef block, do I need to define this value some place?

RSA Padding

We have a JWE created from another library that I am trying to decode using a shared RSA key. The header of the JWT looks like this...

{
  "alg": "RSA-OAEP",
  "enc": "A128GCM"
}

I have the correct RSA PEM file which seems to load and work correctly the issue is that when trying to decode I get a Erlang error: :decrypt_failed. The logged out error also includes [rsa_padding: :rsa_pkcs1_padding] I think this is root cause of the issue as I believe the upstream JWE is using rsa_pkcs1_oaep_padding. Is it possible to change the RSA padding type used by JOSE. I looked through the code and it seems like the lower level JWA.decrypt_private/3 takes a rsa_padding option

defdelegate decrypt_private(cipher_text, private_key, options), to: :jose_jwa
but I was unable to unpick how I might be able to set this using the higher level JWE.block_decrypt/2

public_key:decrypt_private OTP bug

Hi @potatosalad !

I've found an odd bug on OTP public_key module that makes RSA-OAEP broken here on JOSE.

The bug report is here. What happens is that public_key:decrypt_private/3 is not respecting the options passed to it. So, RSA-OAEP breaks here. Options is ignored.

The fix would be to switch it to use crypto:private_decrypt directly. To do that we need to unwrap the private key because crypto accepts a list of integers instead of the record. For a two-prime RSA private key what I am currently doing is:

{:RSAPrivateKey, _, n, e, d, p1, p2, e1, e2, c, _} = priv_key
:crypto.private_decrypt(:rsa, encrypted_key, [e, n, d, p1, p2, e1, e2, c], [rsa_padding: :rsa_pkcs1_oaep_padding, rsa_oaep_md: :sha256, rsa_mgf1_md: :sha256])

I hope this helps. Since I am not that familiar with Erlang tools (common test and so on) I haven't tried opening a PR for this fix.

Extracting RSA private key from Google service account json key

Using Elixir 1.1 and Erlang 18.1 on OSX, when I execute the following code I get a no function clause matching error. This is the example code from the JWS.sign method with the algorithm changed to RS256. The HS256 does work.

jwk = JOSE.JWK.from(%{"k" => "qUg4Yw", "kty" => "oct"})
JOSE.JWS.sign(jwk, "{}", %{ "alg" => "RS256" })
** (FunctionClauseError) no function clause matching in :crypto.do_hmac/3
    (crypto) crypto.erl:983: :crypto.do_hmac({:rsa_pkcs1_padding, :sha256}, <<169, 72, 56, 99>>, "eyJhbGciOiJSUzI1NiJ9.e30")
      (jose) src/jose_jws.erl:234: :jose_jws.sign/4

Since I'm already pretty much in completely new territory with jwt, I was wondering if the algorithms supported on osx are different than other platforms? Any suggestions? I'm trying to sign for Google's Oauth2 for service accounts which wants a SHA256withRSA (also known as RSASSA-PKCS1-V1_5-SIGN with the SHA-256 hash function).

Doing a :crypte.supports I get:

[hashs: [:md4, :md5, :sha, :ripemd160, :sha224, :sha256, :sha384, :sha512],
 ciphers: [:des_cbc, :des_cfb, :des3_cbc, :des_ede3, :blowfish_cbc,
  :blowfish_cfb64, :blowfish_ofb64, :blowfish_ecb, :aes_cbc128, :aes_cfb8,
  :aes_cfb128, :aes_cbc256, :rc2_cbc, :aes_ctr, :rc4, :aes_ecb, :des3_cbf,
  :aes_ige256, :aes_gcm],
 public_keys: [:rsa, :dss, :dh, :srp, :ec_gf2m, :ecdsa, :ecdh]]

Cutkey dependency issue

Hey @potatosalad! I was going to try and update your .travis.yml to also test on elixir 1.1 and 1.2 but could not build project because of cutkey. Here is what I get:

c_src/cutkey.c:24:28: fatal error: openssl/engine.h: Arquivo ou diretório não encontrado
compilation terminated.
ERROR: compile failed while processing /home/victornascimento/dev/elixir/erlang-jose/deps/cutkey: rebar_abort
** (Mix) Could not compile dependency :cutkey, "/home/victornascimento/.mix/rebar compile skip_deps=true deps_dir="/home/victornascimento/dev/elixir/erlang-jose/_build/test/lib"" command failed. You can recompile this dependency with "mix deps.compile cutkey", update it with "mix deps.update cutkey" or clean it with "mix deps.clean cutkey"

First a little translation: "Arquivo ou diretório não encontrado" -> "File or directory not found" :D

Tried to clean and re-install the dependency but no success.

I am running Ubuntu 15.10 64bit (kernel 4.2) and here is the output of "openssl version":

➜  erlang-jose git:(master) openssl version  
OpenSSL 1.0.2d 9 Jul 2015

If you need more info just say and I'll provide.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.