JOSEUtils.JWK (jose_utils v0.4.0) 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

Specs

certificate() :: any()

Specs

key_op() :: String.t()

Specs

key_selector() :: [key_selector_opt()]

Specs

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()}

Specs

kid() :: String.t()

Specs

kty() :: String.t()

Specs

result() :: :ok | {:error, atom()}

Specs

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"
}

Specs

use() :: String.t()

Link to this section Functions

Link to this function

enc_algs_supported(arg1)

View Source

Specs

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

Specs

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

Specs

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

Specs

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

Specs

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"]

Specs

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"}

Specs

verify(t()) :: result()

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