potatosalad / erlang-jose

JSON Object Signing and Encryption (JOSE) for Erlang and Elixir
http://hexdocs.pm/jose
MIT License
309 stars 102 forks source link

Opt-in for fallback algorithms #2

Closed potatosalad closed 9 years ago

potatosalad commented 9 years ago

Continuing the discussion from pull request bryanjos/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:

cs-victor-nascimento commented 9 years ago

My point in the discussion was that using custom implemented crypto algorithms has an implicit risk associated with them. They are less reviewed than those present in Erlang crypto module for example. That is not to say that they should not be used as there are some that are not even available in the Erlang distribution.

So the opt-in mechanism would be to make available by default only those algorithms (hashes, ciphers and whatever is needed) that are in the Erlang distribution. All else would raise (throw). As an example, aes_cbc128 and aes_cbc256 should be available by default but no aes_cbc192.

If the user needs algorithms that are not available in crypto he could pass an application flag like use_erlang_jose_crypto_algorithms to enable its use.

What do you think?

potatosalad commented 9 years ago

I agree that by default it should raise an error when a non-supported algorithm is used.

My current plan is to have the auto-detection from jose_sup.erl assign the fallback module as something like jose_jwa_unsupported for the AES algorithms so it can raise an appropriate error if someone attempts to use it. Any algorithms assigned to the unsupported module won't be present in jose_jwa:supports/0 or jose_jwa:ciphers/0. I think having an application flag would also be the appropriate way to opt-in.

As far as the PS256, PS384, and PS512 algorithms go, I'm not sure what's best to do there. There is no native implementation in any version of Erlang, so I'm not sure if an opt-in method should apply there or not. The algorithms are based on RFC 3447 and the Haskell implementation from Crypto.PubKey.RSA.PSS. Compared to the AES algorithms, the RSA PSS sign/verify implementation is much less complex.

cs-victor-nascimento commented 9 years ago

:+1:

IMHO PS*\ should also be opt-in. The reasons we considered this as a good practice for AES also apply here. If the use case needs it, then I the user will be ok with enabling this.

It would also be nice to have some comment on code that points the person to Crypto.PubKey.RSA.PSS.

I was trying to set up some Elixir documentation but am still swimming against all those acronyms Oo. If I survive I will send you a PR.

potatosalad commented 9 years ago

Commit potatosalad/erlang-jose@8848b172575fb7d7e1e2977e8ae0a21678d2157a on the cavp branch has some of the fallback functionality added. There is some more information about the algorithm verification changes at issue #1.

The three application configuration options I added were:

  1. crypto_fallback (defaults to false)
  2. crypto_aes_fallback (defaults to value of crypto_fallback)
  3. crypto_rsa_fallback (defaults to value of crypto_fallback)

I also renamed some of the functions in jose_jwa from supports/0 to crypto_supports/0 and ciphers/0 to crypto_ciphers/0. jose_jwa/supports/0 now returns the list of supported algorithms as specified in the JOSE RFC documents:

# OTP 18
JOSE.JWA.supports
# [{:jwe,
#   {:alg,
#    ["A128GCMKW", "A128KW", "A192GCMKW", "A256GCMKW", "A256KW", "ECDH-ES",
#     "ECDH-ES+A128KW", "ECDH-ES+A192KW", "ECDH-ES+A256KW", "PBES2-HS256+A128KW",
#     "PBES2-HS512+A256KW", "RSA-OAEP", "RSA1_5", "dir"]},
#   {:enc, ["A128CBC-HS256", "A128GCM", "A192GCM", "A256CBC-HS512", "A256GCM"]}},
#  {:jws,
#   {:alg,
#    ["ES256", "ES384", "ES512", "HS256", "HS384", "HS512", "RS256", "RS384",
#     "RS512"]}}]

# OTP 17
JOSE.JWA.supports
# [{:jwe,
#   {:alg,
#    ["ECDH-ES", "ECDH-ES+A128KW", "ECDH-ES+A192KW", "ECDH-ES+A256KW", "RSA-OAEP",
#     "RSA1_5", "dir"]},
#   {:enc, ["A128CBC-HS256", "A256CBC-HS512"]}},
#  {:jws,
#   {:alg,
#    ["ES256", "ES384", "ES512", "HS256", "HS384", "HS512", "RS256", "RS384",
#     "RS512"]}}]

The list of natively supported encryption algorithms is pretty sad on OTP 17 :grimacing:

All algorithms will show up as supported if the crypto_fallback flag is set to true.

There is also a jose_jwa:is_native_cipher/1 function that can check whether crypto is being used directly or not for a specific AES cipher. I use it here to determine which algorithm is used by default for encryption/decryption.

I still have a couple of algorithms to informally verify:

I also want to pull the crypto detection code out of jose_sup and move it into a gen_server that will allow it to react to configuration changes.

Adding a note about the haskell implementation might be fine. My original implementation that was actually based on it is here: potatosalad/erlang-crypto_rsassa_pss. There were some issues discovered with the algorithm when I started running it against the triq property tests and so it was completely rewritten following RFC 3447 exactly. None of the original haskell implementation remains in this project, while the implementation in erlang-crypto_rsassa_pss is still heavily based on it.

potatosalad commented 9 years ago

I've actually changed the implementation slightly from my last comment:

There is only a single crypto_fallback flag which enables or disables the use of the non-native algorithms. It can be turned on and off with jose_jwa:crypto_fallback/1 or JOSE.JWA.crypto_fallback/1. By default, this flag is false.

cs-victor-nascimento commented 9 years ago

Nice work on this one @potatosalad! Your work is much appreciated. THanks.