jose_utils v0.3.0 JOSEUtils.JWK View Source

Convenience functions to work with JWKs

Link to this section Summary

Functions

Returns the list of supported key derivation algorithm for a given JWK

Returns the key type for an algorithm or nil for the "none" and "dir" algorithms

Returns true if the key conforms to the key selector specification, false otherwise

Returns the digest used by a signature algorithm of the key

Returns the list of supported signature algorithms for a given JWK

Returns the public key from a private key

Verifies a JWK

Link to this section Types

Link to this type

certificate()

View Source
certificate() :: any()
Link to this type

key_selector()

View Source
key_selector() :: [key_selector_opt()]
Link to this type

key_selector_opt()

View Source
key_selector_opt() ::
  {:alg,
   JOSEUtils.JWA.sig_alg()
   | JOSEUtils.JWA.enc_alg()
   | [JOSEUtils.JWA.sig_alg()]
   | [JOSEUtils.JWA.enc_alg()]}
  | {:crv, JOSEUtils.JWA.crv() | [JOSEUtils.JWA.crv()]}
  | {:enc, JOSEUtils.JWA.enc_enc() | [JOSEUtils.JWA.enc_enc()]}
  | {:key_ops, key_op() | [key_op()]}
  | {:kid, kid()}
  | {:kty, kty() | [kty()]}
  | {:use, use()}
Link to this type

result()

View Source
result() :: :ok | {:error, atom()}
Link to this type

t()

View Source
t() :: %{required(String.t()) => any()}

A JSON Web Key in its map form

For instance:

%{
  "crv" => "P-256",
  "kty" => "EC",
  "x" => "6pwDpICQ8JBWdvuLuXeWILAxSEUNB_BBAswikgYKKmY",
  "y" => "fEHj1ehsIJ7PP-qon-oONl_J2yZLWpUncNRedZT7xqs"
}

Link to this section Functions

Link to this function

enc_algs_supported(arg1)

View Source
enc_algs_supported(t()) :: [JOSEUtils.JWA.enc_alg()]

Returns the list of supported key derivation algorithm for a given JWK

Examples

iex> JOSE.JWK.generate_key({:rsa, 2048}) |> JOSE.JWK.to_map() |> elem(1) |> JOSEUtils.JWK.enc_algs_supported()
["RSA1_5", "RSA-OAEP", "RSA-OAEP-256"]

iex> JOSE.JWK.generate_key({:ec, "P-256"}) |> JOSE.JWK.to_map() |> elem(1) |> JOSEUtils.JWK.enc_algs_supported()
["ECDH-ES", "ECDH-ES+A128KW", "ECDH-ES+A192KW", "ECDH-ES+A256KW"]

iex> JOSE.JWK.generate_key({:oct, 16}) |> JOSE.JWK.to_map() |> elem(1) |> JOSEUtils.JWK.enc_algs_supported()
["A128KW", "A128GCMKW", "dir", "PBES2-HS256+A128KW", "PBES2-HS384+A192KW", "PBES2-HS512+A256KW"]

iex> JOSE.JWK.generate_key({:oct, 32}) |> JOSE.JWK.to_map() |> elem(1) |> JOSEUtils.JWK.enc_algs_supported()
["A256KW", "A256GCMKW", "dir", "PBES2-HS256+A128KW", "PBES2-HS384+A192KW", "PBES2-HS512+A256KW"]

iex> JOSE.crypto_fallback(true)
iex> JOSE.JWK.generate_key({:okp, :Ed25519}) |> JOSE.JWK.to_map() |> elem(1) |> JOSEUtils.JWK.enc_algs_supported()
["ECDH-ES", "ECDH-ES+A128KW", "ECDH-ES+A192KW", "ECDH-ES+A256KW"]
Link to this function

key_type_for_alg(binary)

View Source
key_type_for_alg(JOSEUtils.JWA.sig_alg() | JOSEUtils.JWA.enc_alg()) :: kty()

Returns the key type for an algorithm or nil for the "none" and "dir" algorithms

Example

iex> JOSEUtils.JWK.key_type_for_alg("RS512")
"RSA"

iex> JOSEUtils.JWK.key_type_for_alg("ECDH-ES+A128KW")
"EC"

iex> JOSEUtils.JWK.key_type_for_alg("dir")
nil
Link to this function

match_key_selector?(jwk, key_selector)

View Source
match_key_selector?(t(), key_selector()) :: boolean()

Returns true if the key conforms to the key selector specification, false otherwise

Examples

iex> JOSE.JWK.generate_key({:ec, "P-256"}) |> Map.put(:fields, %{"kid" => "key_id"}) |> JOSE.JWK.to_map |> elem(1) |> JOSEUtils.JWK.match_key_selector?([])
true

iex> JOSE.JWK.generate_key({:ec, "P-256"}) |> Map.put(:fields, %{"kid" => "key_id"}) |> JOSE.JWK.to_map |> elem(1) |> JOSEUtils.JWK.match_key_selector?([kid: "abc"])
false

iex> JOSE.JWK.generate_key({:ec, "P-256"}) |> Map.put(:fields, %{"kid" => "key_id"}) |> JOSE.JWK.to_map |> elem(1) |> JOSEUtils.JWK.match_key_selector?([kty: "EC"])
true

iex> JOSE.JWK.generate_key({:ec, "P-256"}) |> Map.put(:fields, %{"kid" => "key_id"}) |> JOSE.JWK.to_map |> elem(1) |> JOSEUtils.JWK.match_key_selector?([kty: "RSA"])
false

iex> JOSE.JWK.generate_key({:ec, "P-256"}) |> Map.put(:fields, %{"kid" => "key_id"}) |> JOSE.JWK.to_map |> elem(1) |> JOSEUtils.JWK.match_key_selector?([use: "sig"])
true

iex> JOSE.JWK.generate_key({:ec, "P-256"}) |> Map.put(:fields, %{"kid" => "key_id"}) |> JOSE.JWK.to_map |> elem(1) |> JOSEUtils.JWK.match_key_selector?([use: "enc"])
true

iex> JOSE.JWK.generate_key({:ec, "P-256"}) |> Map.put(:fields, %{"kid" => "key_id"}) |> JOSE.JWK.to_map |> elem(1) |> JOSEUtils.JWK.match_key_selector?([key_ops: "a"])
true

iex> JOSE.JWK.generate_key({:ec, "P-256"}) |> Map.put(:fields, %{"kid" => "key_id"}) |> JOSE.JWK.to_map |> elem(1) |> JOSEUtils.JWK.match_key_selector?([key_ops: "sign"])
true

iex> JOSE.JWK.generate_key({:ec, "P-256"}) |> Map.put(:fields, %{"kid" => "key_id"}) |> JOSE.JWK.to_map |> elem(1) |> JOSEUtils.JWK.match_key_selector?([alg: ["ES256", "ES512"]])
true

iex> JOSE.JWK.generate_key({:ec, "P-256"}) |> Map.put(:fields, %{"alg" => "ES384"}) |> JOSE.JWK.to_map |> elem(1) |> JOSEUtils.JWK.match_key_selector?([alg: ["ES256", "ES512"]])
false
Link to this function

sig_alg_digest(map)

View Source
sig_alg_digest(t()) :: atom()

Returns the digest used by a signature algorithm of the key

Link to this function

sig_algs_supported(arg1)

View Source
sig_algs_supported(t()) :: [JOSEUtils.JWA.sig_alg()]

Returns the list of supported signature algorithms for a given JWK

Example

iex> JOSE.JWK.generate_key({:ec, "P-256"}) |> JOSE.JWK.to_map() |> elem(1) |> JOSEUtils.JWK.sig_algs_supported()
["ES256"]

iex> JOSE.JWK.generate_key({:ec, "P-521"}) |> JOSE.JWK.to_map() |> elem(1) |> JOSEUtils.JWK.sig_algs_supported()
["ES512"]

iex> JOSE.JWK.generate_key({:oct, 32}) |> JOSE.JWK.to_map() |> elem(1) |> JOSEUtils.JWK.sig_algs_supported()
["HS256"]

iex> JOSE.JWK.generate_key({:oct, 48}) |> JOSE.JWK.to_map() |> elem(1) |> JOSEUtils.JWK.sig_algs_supported()
["HS256", "HS384"]

iex> JOSE.JWK.generate_key({:oct, 47}) |> JOSE.JWK.to_map() |> elem(1) |> JOSEUtils.JWK.sig_algs_supported()
["HS256"]

iex> JOSE.JWK.generate_key({:oct, 64}) |> JOSE.JWK.to_map() |> elem(1) |> JOSEUtils.JWK.sig_algs_supported()
["HS256", "HS384", "HS512"]

iex> JOSE.JWK.generate_key({:rsa,2048}) |> JOSE.JWK.to_map() |> elem(1) |> JOSEUtils.JWK.sig_algs_supported()
["RS256", "RS384", "RS512", "PS256", "PS384", "PS512"]

iex> JOSE.crypto_fallback(true)
iex> JOSE.JWK.generate_key({:okp, :Ed25519}) |> JOSE.JWK.to_map() |> elem(1) |> JOSEUtils.JWK.sig_algs_supported()
["EdDSA"]
Link to this function

to_public(jwk_oct)

View Source
to_public(t()) :: t()

Returns the public key from a private key

For "oct" symmetrical keys, it returns all fields except the "k" private secret. It is recommended to have the "kid" attribute set in this case, otherwise the key is indistinguishable from other similar symmetrical keys.

Examples

iex> match?(%{"kty" => "EC", "crv" => "P-521"}, JOSE.JWK.generate_key({:ec, "P-521"}) |> JOSE.JWK.to_map() |> elem(1) |> JOSEUtils.JWK.to_public())
true

iex> JOSE.JWK.generate_key({:oct, 32}) |> JOSE.JWK.to_map() |> elem(1) |> JOSEUtils.JWK.to_public()                                                
%{"kty" => "oct"}

Verifies a JWK

It performs the following checks:

  • verifies that the "x5c" member (if present) against:

    • the JWK key
    • the "alg" member
    • the "use" member
    • the "key_ops" member
    • the "x5t" member, if present
    • the "x5t#S256" member, if present
    • validates the certificate chain
  • verifies that the "use" and "key_ops" members are consistent
  • verifies that the "key_ops" operations are related to each other