|
| 1 | +From 353268ce161dc90fefe599afa83561b9a3cbd14c Mon Sep 17 00:00:00 2001 |
| 2 | +From: Kanishk-Bansal <kbkanishk975@gmail.com> |
| 3 | +Date: Thu, 13 Feb 2025 13:18:41 +0000 |
| 4 | +Subject: [PATCH] Fix CVE |
| 5 | +# Upstream Source: https://github.com/potatosalad/erlang-jose/commit/718d213f07b08056737923f8063d5df56dcb66ae |
| 6 | +# Upstream Source2: https://github.com/potatosalad/erlang-jose/commit/a352bb579a98e5bdea4c72ac92b8923afea6dcec |
| 7 | + |
| 8 | +--- |
| 9 | + deps/jose/src/jose.app.src | 5 ++- |
| 10 | + deps/jose/src/jose.erl | 18 +++++++++-- |
| 11 | + deps/jose/src/jose_server.erl | 39 ++++++++++++++++++++++-- |
| 12 | + deps/jose/src/jwa/jose_jwa.erl | 2 +- |
| 13 | + deps/jose/src/jwe/jose_jwe_alg_pbes2.erl | 38 ++++++++++++++++++----- |
| 14 | + 5 files changed, 87 insertions(+), 15 deletions(-) |
| 15 | + |
| 16 | +diff --git a/deps/jose/src/jose.app.src b/deps/jose/src/jose.app.src |
| 17 | +index 3909e59..3378ea4 100644 |
| 18 | +--- a/deps/jose/src/jose.app.src |
| 19 | ++++ b/deps/jose/src/jose.app.src |
| 20 | +@@ -10,4 +10,7 @@ |
| 21 | + {licenses,["MIT"]}, |
| 22 | + {links,[{"Github", |
| 23 | + "https://github.com/potatosalad/erlang-jose"}]}, |
| 24 | +- {env,[{crypto_fallback,true}]}]}. |
| 25 | ++ {env, [ |
| 26 | ++ {crypto_fallback, true}, |
| 27 | ++ {pbes2_count_maximum, 10000} |
| 28 | ++ ]}]}. |
| 29 | +diff --git a/deps/jose/src/jose.erl b/deps/jose/src/jose.erl |
| 30 | +index 58e005d..fe47755 100644 |
| 31 | +--- a/deps/jose/src/jose.erl |
| 32 | ++++ b/deps/jose/src/jose.erl |
| 33 | +@@ -23,6 +23,8 @@ |
| 34 | + -export([encode/1]). |
| 35 | + -export([json_module/0]). |
| 36 | + -export([json_module/1]). |
| 37 | ++-export([pbes2_count_maximum/0]). |
| 38 | ++-export([pbes2_count_maximum/1]). |
| 39 | + -export([sha3_module/0]). |
| 40 | + -export([sha3_module/1]). |
| 41 | + -export([unsecured_signing/0]). |
| 42 | +@@ -84,17 +86,27 @@ json_module() -> |
| 43 | + json_module(JSONModule) when is_atom(JSONModule) -> |
| 44 | + ?MAYBE_START_JOSE(jose_server:json_module(JSONModule)). |
| 45 | + |
| 46 | ++-spec pbes2_count_maximum() -> non_neg_integer(). |
| 47 | ++pbes2_count_maximum() -> |
| 48 | ++ ?MAYBE_START_JOSE(ets:lookup_element(?TAB, pbes2_count_maximum, 2)). |
| 49 | ++ |
| 50 | ++-spec pbes2_count_maximum(PBES2CountMaximum) -> ok when PBES2CountMaximum :: non_neg_integer(). |
| 51 | ++pbes2_count_maximum(PBES2CountMaximum) when is_integer(PBES2CountMaximum) andalso PBES2CountMaximum >= 0 -> |
| 52 | ++ ?MAYBE_START_JOSE(jose_server:pbes2_count_maximum(PBES2CountMaximum)). |
| 53 | ++ |
| 54 | + sha3_module() -> |
| 55 | + ?MAYBE_START_JOSE(ets:lookup_element(?TAB, sha3_module, 2)). |
| 56 | + |
| 57 | + sha3_module(SHA3Module) when is_atom(SHA3Module) -> |
| 58 | + ?MAYBE_START_JOSE(jose_server:sha3_module(SHA3Module)). |
| 59 | + |
| 60 | ++-spec unsecured_signing() -> boolean(). |
| 61 | + unsecured_signing() -> |
| 62 | +- jose_jwa:unsecured_signing(). |
| 63 | ++ ?MAYBE_START_JOSE(ets:lookup_element(?TAB, unsecured_signing, 2)). |
| 64 | + |
| 65 | +-unsecured_signing(Boolean) when is_boolean(Boolean) -> |
| 66 | +- jose_jwa:unsecured_signing(Boolean). |
| 67 | ++-spec unsecured_signing(UnsecuredSigning) -> ok when UnsecuredSigning :: boolean(). |
| 68 | ++unsecured_signing(UnsecuredSigning) when is_boolean(UnsecuredSigning) -> |
| 69 | ++ ?MAYBE_START_JOSE(jose_server:unsecured_signing(UnsecuredSigning)). |
| 70 | + |
| 71 | + xchacha20_poly1305_module() -> |
| 72 | + ?MAYBE_START_JOSE(ets:lookup_element(?TAB, xchacha20_poly1305_module, 2)). |
| 73 | +diff --git a/deps/jose/src/jose_server.erl b/deps/jose/src/jose_server.erl |
| 74 | +index 94cbe37..9f3c02e 100644 |
| 75 | +--- a/deps/jose/src/jose_server.erl |
| 76 | ++++ b/deps/jose/src/jose_server.erl |
| 77 | +@@ -22,7 +22,9 @@ |
| 78 | + -export([curve25519_module/1]). |
| 79 | + -export([curve448_module/1]). |
| 80 | + -export([json_module/1]). |
| 81 | ++-export([pbes2_count_maximum/1]). |
| 82 | + -export([sha3_module/1]). |
| 83 | ++-export([unsecured_signing/1]). |
| 84 | + -export([xchacha20_poly1305_module/1]). |
| 85 | + |
| 86 | + %% gen_server callbacks |
| 87 | +@@ -72,9 +74,17 @@ curve448_module(Curve448Module) when is_atom(Curve448Module) -> |
| 88 | + json_module(JSONModule) when is_atom(JSONModule) -> |
| 89 | + gen_server:call(?SERVER, {json_module, JSONModule}). |
| 90 | + |
| 91 | ++-spec pbes2_count_maximum(PBES2CountMaximum) -> ok when PBES2CountMaximum :: non_neg_integer(). |
| 92 | ++pbes2_count_maximum(PBES2CountMaximum) when is_integer(PBES2CountMaximum) andalso PBES2CountMaximum >= 0 -> |
| 93 | ++ gen_server:call(?SERVER, {pbes2_count_maximum, PBES2CountMaximum}). |
| 94 | ++ |
| 95 | + sha3_module(SHA3Module) when is_atom(SHA3Module) -> |
| 96 | + gen_server:call(?SERVER, {sha3_module, SHA3Module}). |
| 97 | + |
| 98 | ++-spec unsecured_signing(UnsecuredSigning) -> ok when UnsecuredSigning :: boolean(). |
| 99 | ++unsecured_signing(UnsecuredSigning) when is_boolean(UnsecuredSigning) -> |
| 100 | ++ gen_server:call(?SERVER, {unsecured_signing, UnsecuredSigning}). |
| 101 | ++ |
| 102 | + xchacha20_poly1305_module(XChaCha20Poly1305Module) when is_atom(XChaCha20Poly1305Module) -> |
| 103 | + gen_server:call(?SERVER, {xchacha20_poly1305_module, XChaCha20Poly1305Module}). |
| 104 | + |
| 105 | +@@ -114,10 +124,20 @@ handle_call({json_module, M}, _From, State) -> |
| 106 | + JSONModule = check_json_module(M), |
| 107 | + true = ets:insert(?TAB, {json_module, JSONModule}), |
| 108 | + {reply, ok, State}; |
| 109 | ++handle_call({pbes2_count_maximum, PBES2CountMaximum}, _From, State) when is_integer(PBES2CountMaximum) andalso PBES2CountMaximum >= 0 -> |
| 110 | ++ true = ets:insert(?TAB, {pbes2_count_maximum, PBES2CountMaximum}), |
| 111 | ++ {reply, ok, State}; |
| 112 | + handle_call({sha3_module, M}, _From, State) -> |
| 113 | + SHA3Module = check_sha3_module(M), |
| 114 | + true = ets:insert(?TAB, {sha3_module, SHA3Module}), |
| 115 | + {reply, ok, State}; |
| 116 | ++handle_call({unsecured_signing, UnsecuredSigning}, _From, State) when is_boolean(UnsecuredSigning) -> |
| 117 | ++ true = ets:insert(?TAB, {unsecured_signing, UnsecuredSigning}), |
| 118 | ++ _ = spawn(fun() -> |
| 119 | ++ _ = catch jose_jwa:unsecured_signing(UnsecuredSigning), |
| 120 | ++ exit(normal) |
| 121 | ++ end), |
| 122 | ++ {reply, ok, State}; |
| 123 | + handle_call({xchacha20_poly1305_module, M}, _From, State) -> |
| 124 | + XChaCha20Poly1305Module = check_xchacha20_poly1305_module(M), |
| 125 | + Entries = lists:flatten(check_crypto(?CRYPTO_FALLBACK, [{xchacha20_poly1305_module, XChaCha20Poly1305Module}])), |
| 126 | +@@ -149,8 +169,18 @@ code_change(_OldVsn, State, _Extra) -> |
| 127 | + |
| 128 | + %% @private |
| 129 | + support_check() -> |
| 130 | ++ PBES2CountMaximum = |
| 131 | ++ case application:get_env(jose, pbes2_count_maximum, 10000) of |
| 132 | ++ V1 when is_integer(V1) andalso V1 >= 0 -> |
| 133 | ++ V1 |
| 134 | ++ end, |
| 135 | ++ UnsecuredSigning = |
| 136 | ++ case application:get_env(jose, unsecured_signing, false) of |
| 137 | ++ V2 when is_boolean(V2) -> |
| 138 | ++ V2 |
| 139 | ++ end, |
| 140 | + Fallback = ?CRYPTO_FALLBACK, |
| 141 | +- Entries = lists:flatten(lists:foldl(fun(Check, Acc) -> |
| 142 | ++ Entries1 = lists:flatten(lists:foldl(fun(Check, Acc) -> |
| 143 | + Check(Fallback, Acc) |
| 144 | + end, [], [ |
| 145 | + fun check_ec_key_mode/2, |
| 146 | +@@ -163,8 +193,13 @@ support_check() -> |
| 147 | + fun check_crypto/2, |
| 148 | + fun check_public_key/2 |
| 149 | + ])), |
| 150 | ++ Entries2 = [ |
| 151 | ++ {pbes2_count_maximum, PBES2CountMaximum}, |
| 152 | ++ {unsecured_signing, UnsecuredSigning} |
| 153 | ++ | Entries1 |
| 154 | ++ ], |
| 155 | + true = ets:delete_all_objects(?TAB), |
| 156 | +- true = ets:insert(?TAB, Entries), |
| 157 | ++ true = ets:insert(?TAB, Entries2), |
| 158 | + ok. |
| 159 | + |
| 160 | + %%%------------------------------------------------------------------- |
| 161 | +diff --git a/deps/jose/src/jwa/jose_jwa.erl b/deps/jose/src/jwa/jose_jwa.erl |
| 162 | +index 39fb565..394c796 100644 |
| 163 | +--- a/deps/jose/src/jwa/jose_jwa.erl |
| 164 | ++++ b/deps/jose/src/jwa/jose_jwa.erl |
| 165 | +@@ -368,7 +368,7 @@ supports() -> |
| 166 | + ]. |
| 167 | + |
| 168 | + unsecured_signing() -> |
| 169 | +- application:get_env(jose, unsecured_signing, false). |
| 170 | ++ jose:unsecured_signing(). |
| 171 | + |
| 172 | + unsecured_signing(Boolean) when is_boolean(Boolean) -> |
| 173 | + application:set_env(jose, unsecured_signing, Boolean), |
| 174 | +diff --git a/deps/jose/src/jwe/jose_jwe_alg_pbes2.erl b/deps/jose/src/jwe/jose_jwe_alg_pbes2.erl |
| 175 | +index 8c11f67..bc48502 100644 |
| 176 | +--- a/deps/jose/src/jwe/jose_jwe_alg_pbes2.erl |
| 177 | ++++ b/deps/jose/src/jwe/jose_jwe_alg_pbes2.erl |
| 178 | +@@ -23,6 +23,7 @@ |
| 179 | + -export([key_encrypt/3]). |
| 180 | + -export([next_cek/3]). |
| 181 | + %% API |
| 182 | ++-export([format_error/2]). |
| 183 | + -export([hmac_supported/0]). |
| 184 | + -export([wrap_supported/0]). |
| 185 | + |
| 186 | +@@ -99,22 +100,22 @@ key_decrypt(Password, {_ENCModule, _ENC, EncryptedKey}, #jose_jwe_alg_pbes2{hmac |
| 187 | + when is_binary(Password) |
| 188 | + andalso is_binary(IV) |
| 189 | + andalso is_binary(TAG) -> |
| 190 | +- {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 191 | ++ {ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 192 | + jose_jwa:block_decrypt({aes_gcm, Bits}, DerivedKey, IV, {<<>>, EncryptedKey, TAG}); |
| 193 | + key_decrypt(Password, {_ENCModule, _ENC, EncryptedKey}, #jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=aes_kw, bits=Bits}) when is_binary(Password) -> |
| 194 | +- {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 195 | ++ {ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 196 | + jose_jwa_aes_kw:unwrap(EncryptedKey, DerivedKey); |
| 197 | + key_decrypt(Password, {_ENCModule, _ENC, EncryptedKey}, #jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=c20p_kw, bits=Bits, iv=IV, tag=TAG}) |
| 198 | + when is_binary(Password) |
| 199 | + andalso is_binary(IV) |
| 200 | + andalso is_binary(TAG) -> |
| 201 | +- {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 202 | ++ {ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 203 | + jose_jwa:block_decrypt({chacha20_poly1305, Bits}, DerivedKey, IV, {<<>>, EncryptedKey, TAG}); |
| 204 | + key_decrypt(Password, {_ENCModule, _ENC, EncryptedKey}, #jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=xc20p_kw, bits=Bits, iv=IV, tag=TAG}) |
| 205 | + when is_binary(Password) |
| 206 | + andalso is_binary(IV) |
| 207 | + andalso is_binary(TAG) -> |
| 208 | +- {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 209 | ++ {ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 210 | + jose_jwa:block_decrypt({xchacha20_poly1305, Bits}, DerivedKey, IV, {<<>>, EncryptedKey, TAG}); |
| 211 | + key_decrypt(#jose_jwk{kty={KTYModule, KTY}}, EncryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{}) -> |
| 212 | + key_decrypt(KTYModule:derive_key(KTY), EncryptedKey, JWEPBES2). |
| 213 | +@@ -131,7 +132,7 @@ key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt |
| 214 | + andalso is_binary(Salt) |
| 215 | + andalso is_integer(Iterations) |
| 216 | + andalso is_binary(IV) -> |
| 217 | +- {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 218 | ++ {ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 219 | + {CipherText, CipherTag} = jose_jwa:block_encrypt({aes_gcm, Bits}, DerivedKey, IV, {<<>>, DecryptedKey}), |
| 220 | + {CipherText, JWEPBES2#jose_jwe_alg_pbes2{ tag = CipherTag }}; |
| 221 | + key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=aes_kw, bits=Bits}) |
| 222 | +@@ -139,7 +140,7 @@ key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt |
| 223 | + andalso is_binary(DecryptedKey) |
| 224 | + andalso is_binary(Salt) |
| 225 | + andalso is_integer(Iterations) -> |
| 226 | +- {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 227 | ++ {ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 228 | + {jose_jwa_aes_kw:wrap(DecryptedKey, DerivedKey), JWEPBES2}; |
| 229 | + key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=c20p_kw, bits=Bits, iv=IV}) |
| 230 | + when is_binary(Password) |
| 231 | +@@ -147,7 +148,7 @@ key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt |
| 232 | + andalso is_binary(Salt) |
| 233 | + andalso is_integer(Iterations) |
| 234 | + andalso is_binary(IV) -> |
| 235 | +- {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 236 | ++ {ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 237 | + {CipherText, CipherTag} = jose_jwa:block_encrypt({chacha20_poly1305, Bits}, DerivedKey, IV, {<<>>, DecryptedKey}), |
| 238 | + {CipherText, JWEPBES2#jose_jwe_alg_pbes2{ tag = CipherTag }}; |
| 239 | + key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=xc20p_kw, bits=Bits, iv=IV}) |
| 240 | +@@ -156,7 +157,7 @@ key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt |
| 241 | + andalso is_binary(Salt) |
| 242 | + andalso is_integer(Iterations) |
| 243 | + andalso is_binary(IV) -> |
| 244 | +- {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 245 | ++ {ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), |
| 246 | + {CipherText, CipherTag} = jose_jwa:block_encrypt({xchacha20_poly1305, Bits}, DerivedKey, IV, {<<>>, DecryptedKey}), |
| 247 | + {CipherText, JWEPBES2#jose_jwe_alg_pbes2{ tag = CipherTag }}; |
| 248 | + key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{wrap=aes_gcm_kw, iv=undefined}) when is_binary(Password) -> |
| 249 | +@@ -175,6 +176,12 @@ next_cek(_Key, {ENCModule, ENC}, ALG=#jose_jwe_alg_pbes2{}) -> |
| 250 | + %% API functions |
| 251 | + %%==================================================================== |
| 252 | + |
| 253 | ++-spec format_error(term(), term()) -> term(). |
| 254 | ++format_error(_Reason, [{_M, _F, _As, Info} | _]) -> |
| 255 | ++ ErrorInfo = proplists:get_value(error_info, Info, #{}), |
| 256 | ++ ErrorDescription1 = maps:get(cause, ErrorInfo), |
| 257 | ++ ErrorDescription1. |
| 258 | ++ |
| 259 | + hmac_supported() -> |
| 260 | + [sha256, sha384, sha512]. |
| 261 | + |
| 262 | +@@ -197,6 +204,21 @@ from_map_pbes2(F=#{ <<"tag">> := TAG }, H) -> |
| 263 | + from_map_pbes2(F, H) -> |
| 264 | + {H, F}. |
| 265 | + |
| 266 | ++%% @private |
| 267 | ++pbkdf2(Mac, Password, Salt, Iterations, DerivedKeyLen) -> |
| 268 | ++ PBES2CountMaximum = jose:pbes2_count_maximum(), |
| 269 | ++ case PBES2CountMaximum < Iterations of |
| 270 | ++ false -> |
| 271 | ++ jose_jwa_pkcs5:pbkdf2(Mac, Password, Salt, Iterations, DerivedKeyLen); |
| 272 | ++ true -> |
| 273 | ++ erlang:error(badarg, [Mac, <<"REDACTED">>, Salt, Iterations, DerivedKeyLen], [ |
| 274 | ++ {error_info, #{ |
| 275 | ++ module => ?MODULE, |
| 276 | ++ cause => #{4 => lists:flatten(io_lib:format("maximum PBES2 iterations is set to ~w, but ~w was attempted (see jose:pbes2_count_maximum/0)", [PBES2CountMaximum, Iterations]))} |
| 277 | ++ }} |
| 278 | ++ ]) |
| 279 | ++ end. |
| 280 | ++ |
| 281 | + %% @private |
| 282 | + to_map_pbes2(F, H=#jose_jwe_alg_pbes2{ iter = P2C }) when is_integer(P2C) -> |
| 283 | + to_map_pbes2(F#{ <<"p2c">> => P2C }, H#jose_jwe_alg_pbes2{ iter = undefined }); |
| 284 | +-- |
| 285 | +2.45.2 |
| 286 | + |
0 commit comments