Skip to content

Commit 718d213

Browse files
committed
Version 1.11.7 (2024-04-07)
* Security Patches * [CVE-2023-50966](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-50966): Add `jose:pbes2_count_maximum/0`. By default, the maximum iterations are set to 10,000 and it will raise an error if `p2c` is larger than this value. * Changes * Declare Poison as an optional dependency, thanks to [@lnikkila][https://github.com/lnikkila]; see [#144](#144). * Ensure `jiffy:encode/1` returns a binary, thanks to [@ssepml](https://github.com/ssepml); see [#145](#145). * Various type spec additions and dialyzer/dialyxir integrations, thanks to [@whatyouhide](https://github.com/whatyouhide) and [@maennchen](https://github.com/maennchen). * Doc updates and fixes, thanks to [@aymanosman](https://github.com/aymanosman) and [@adamu](https://github.com/adamu); see [#158](#158) and [#159](#159).
1 parent c11b525 commit 718d213

File tree

10 files changed

+158
-18
lines changed

10 files changed

+158
-18
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Changelog
22

3+
## 1.11.7 (2024-04-07)
4+
5+
* Security Patches
6+
* [CVE-2023-50966](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-50966): Add `jose:pbes2_count_maximum/0`. By default, the maximum iterations are set to 10,000 and it will raise an error if `p2c` is larger than this value.
7+
* Changes
8+
* Declare Poison as an optional dependency, thanks to [@lnikkila][https://github.com/lnikkila]; see [#144](https://github.com/potatosalad/erlang-jose/pull/144).
9+
* Ensure `jiffy:encode/1` returns a binary, thanks to [@ssepml](https://github.com/ssepml); see [#145](https://github.com/potatosalad/erlang-jose/pull/145).
10+
* Various type spec additions and dialyzer/dialyxir integrations, thanks to [@whatyouhide](https://github.com/whatyouhide) and [@maennchen](https://github.com/maennchen).
11+
* Doc updates and fixes, thanks to [@aymanosman](https://github.com/aymanosman) and [@adamu](https://github.com/adamu); see [#158](https://github.com/potatosalad/erlang-jose/pull/158) and [#159](https://github.com/potatosalad/erlang-jose/pull/159).
12+
313
## 1.11.6 (2023-07-18)
414

515
* Fixes

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
PROJECT = jose
22
PROJECT_DESCRIPTION = JSON Object Signing and Encryption (JOSE) for Erlang and Elixir.
3-
PROJECT_VERSION = 1.11.6
3+
PROJECT_VERSION = 1.11.7
44

55
TEST_DEPS = jiffy jsone jsx libdecaf libsodium ojson proper thoas
66

src/jose.app.src

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
%% vim: ts=4 sw=4 ft=erlang noet
33
{application, jose, [
44
{description, "JSON Object Signing and Encryption (JOSE) for Erlang and Elixir."},
5-
{vsn, "1.11.6"},
5+
{vsn, "1.11.7"},
66
{id, "git"},
77
{mod, {'jose_app', []}},
88
{registered, []},
@@ -17,6 +17,9 @@
1717
{maintainers, ["Andrew Bennett"]},
1818
{licenses, ["MIT"]},
1919
{links, [{"Github", "https://github.com/potatosalad/erlang-jose"}]},
20-
{env, [{crypto_fallback, true}]}
20+
{env, [
21+
{crypto_fallback, true},
22+
{pbes2_count_maximum, 10000}
23+
]}
2124
]}.
2225

src/jose.erl

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
-export([encode/1]).
2424
-export([json_module/0]).
2525
-export([json_module/1]).
26+
-export([pbes2_count_maximum/0]).
27+
-export([pbes2_count_maximum/1]).
2628
-export([sha3_module/0]).
2729
-export([sha3_module/1]).
2830
-export([unsecured_signing/0]).
@@ -84,17 +86,27 @@ json_module() ->
8486
json_module(JSONModule) when is_atom(JSONModule) ->
8587
?MAYBE_START_JOSE(jose_server:json_module(JSONModule)).
8688

89+
-spec pbes2_count_maximum() -> non_neg_integer().
90+
pbes2_count_maximum() ->
91+
?MAYBE_START_JOSE(ets:lookup_element(?TAB, pbes2_count_maximum, 2)).
92+
93+
-spec pbes2_count_maximum(PBES2CountMaximum) -> ok when PBES2CountMaximum :: non_neg_integer().
94+
pbes2_count_maximum(PBES2CountMaximum) when is_integer(PBES2CountMaximum) andalso PBES2CountMaximum >= 0 ->
95+
?MAYBE_START_JOSE(jose_server:pbes2_count_maximum(PBES2CountMaximum)).
96+
8797
sha3_module() ->
8898
?MAYBE_START_JOSE(ets:lookup_element(?TAB, sha3_module, 2)).
8999

90100
sha3_module(SHA3Module) when is_atom(SHA3Module) ->
91101
?MAYBE_START_JOSE(jose_server:sha3_module(SHA3Module)).
92102

103+
-spec unsecured_signing() -> boolean().
93104
unsecured_signing() ->
94-
jose_jwa:unsecured_signing().
105+
?MAYBE_START_JOSE(ets:lookup_element(?TAB, unsecured_signing, 2)).
95106

96-
unsecured_signing(Boolean) when is_boolean(Boolean) ->
97-
jose_jwa:unsecured_signing(Boolean).
107+
-spec unsecured_signing(UnsecuredSigning) -> ok when UnsecuredSigning :: boolean().
108+
unsecured_signing(UnsecuredSigning) when is_boolean(UnsecuredSigning) ->
109+
?MAYBE_START_JOSE(jose_server:unsecured_signing(UnsecuredSigning)).
98110

99111
xchacha20_poly1305_module() ->
100112
?MAYBE_START_JOSE(ets:lookup_element(?TAB, xchacha20_poly1305_module, 2)).

src/jose_server.erl

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
-export([curve25519_module/1]).
2323
-export([curve448_module/1]).
2424
-export([json_module/1]).
25+
-export([pbes2_count_maximum/1]).
2526
-export([sha3_module/1]).
27+
-export([unsecured_signing/1]).
2628
-export([xchacha20_poly1305_module/1]).
2729

2830
%% gen_server callbacks
@@ -72,9 +74,17 @@ curve448_module(Curve448Module) when is_atom(Curve448Module) ->
7274
json_module(JSONModule) when is_atom(JSONModule) ->
7375
gen_server:call(?SERVER, {json_module, JSONModule}).
7476

77+
-spec pbes2_count_maximum(PBES2CountMaximum) -> ok when PBES2CountMaximum :: non_neg_integer().
78+
pbes2_count_maximum(PBES2CountMaximum) when is_integer(PBES2CountMaximum) andalso PBES2CountMaximum >= 0 ->
79+
gen_server:call(?SERVER, {pbes2_count_maximum, PBES2CountMaximum}).
80+
7581
sha3_module(SHA3Module) when is_atom(SHA3Module) ->
7682
gen_server:call(?SERVER, {sha3_module, SHA3Module}).
7783

84+
-spec unsecured_signing(UnsecuredSigning) -> ok when UnsecuredSigning :: boolean().
85+
unsecured_signing(UnsecuredSigning) when is_boolean(UnsecuredSigning) ->
86+
gen_server:call(?SERVER, {unsecured_signing, UnsecuredSigning}).
87+
7888
xchacha20_poly1305_module(XChaCha20Poly1305Module) when is_atom(XChaCha20Poly1305Module) ->
7989
gen_server:call(?SERVER, {xchacha20_poly1305_module, XChaCha20Poly1305Module}).
8090

@@ -114,10 +124,20 @@ handle_call({json_module, M}, _From, State) ->
114124
JSONModule = check_json_module(M),
115125
true = ets:insert(?TAB, {json_module, JSONModule}),
116126
{reply, ok, State};
127+
handle_call({pbes2_count_maximum, PBES2CountMaximum}, _From, State) when is_integer(PBES2CountMaximum) andalso PBES2CountMaximum >= 0 ->
128+
true = ets:insert(?TAB, {pbes2_count_maximum, PBES2CountMaximum}),
129+
{reply, ok, State};
117130
handle_call({sha3_module, M}, _From, State) ->
118131
SHA3Module = check_sha3_module(M),
119132
true = ets:insert(?TAB, {sha3_module, SHA3Module}),
120133
{reply, ok, State};
134+
handle_call({unsecured_signing, UnsecuredSigning}, _From, State) when is_boolean(UnsecuredSigning) ->
135+
true = ets:insert(?TAB, {unsecured_signing, UnsecuredSigning}),
136+
_ = spawn(fun() ->
137+
_ = catch jose_jwa:unsecured_signing(UnsecuredSigning),
138+
exit(normal)
139+
end),
140+
{reply, ok, State};
121141
handle_call({xchacha20_poly1305_module, M}, _From, State) ->
122142
XChaCha20Poly1305Module = check_xchacha20_poly1305_module(M),
123143
Entries = lists:flatten(check_crypto(?CRYPTO_FALLBACK, [{xchacha20_poly1305_module, XChaCha20Poly1305Module}])),
@@ -149,8 +169,18 @@ code_change(_OldVsn, State, _Extra) ->
149169

150170
%% @private
151171
support_check() ->
172+
PBES2CountMaximum =
173+
case application:get_env(jose, pbes2_count_maximum, 10000) of
174+
V1 when is_integer(V1) andalso V1 >= 0 ->
175+
V1
176+
end,
177+
UnsecuredSigning =
178+
case application:get_env(jose, unsecured_signing, false) of
179+
V2 when is_boolean(V2) ->
180+
V2
181+
end,
152182
Fallback = ?CRYPTO_FALLBACK,
153-
Entries = lists:flatten(lists:foldl(fun(Check, Acc) ->
183+
Entries1 = lists:flatten(lists:foldl(fun(Check, Acc) ->
154184
Check(Fallback, Acc)
155185
end, [], [
156186
fun check_sha3/2,
@@ -163,8 +193,13 @@ support_check() ->
163193
fun check_crypto/2,
164194
fun check_public_key/2
165195
])),
196+
Entries2 = [
197+
{pbes2_count_maximum, PBES2CountMaximum},
198+
{unsecured_signing, UnsecuredSigning}
199+
| Entries1
200+
],
166201
true = ets:delete_all_objects(?TAB),
167-
true = ets:insert(?TAB, Entries),
202+
true = ets:insert(?TAB, Entries2),
168203
ok.
169204

170205
%%%-------------------------------------------------------------------

src/jwa/jose_jwa.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ supports() ->
380380
].
381381

382382
unsecured_signing() ->
383-
application:get_env(jose, unsecured_signing, false).
383+
jose:unsecured_signing().
384384

385385
unsecured_signing(Boolean) when is_boolean(Boolean) ->
386386
application:set_env(jose, unsecured_signing, Boolean),

src/jwe/jose_jwe_alg_pbes2.erl

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
-export([key_encrypt/3]).
2424
-export([next_cek/3]).
2525
%% API
26+
-export([format_error/2]).
2627
-export([hmac_supported/0]).
2728
-export([wrap_supported/0]).
2829

@@ -99,22 +100,22 @@ key_decrypt(Password, {_ENCModule, _ENC, EncryptedKey}, #jose_jwe_alg_pbes2{hmac
99100
when is_binary(Password)
100101
andalso is_binary(IV)
101102
andalso is_binary(TAG) ->
102-
{ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
103+
{ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
103104
jose_jwa:block_decrypt({aes_gcm, Bits}, DerivedKey, IV, {<<>>, EncryptedKey, TAG});
104105
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) ->
105-
{ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
106+
{ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
106107
jose_jwa_aes_kw:unwrap(EncryptedKey, DerivedKey);
107108
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})
108109
when is_binary(Password)
109110
andalso is_binary(IV)
110111
andalso is_binary(TAG) ->
111-
{ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
112+
{ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
112113
jose_jwa:block_decrypt({chacha20_poly1305, Bits}, DerivedKey, IV, {<<>>, EncryptedKey, TAG});
113114
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})
114115
when is_binary(Password)
115116
andalso is_binary(IV)
116117
andalso is_binary(TAG) ->
117-
{ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
118+
{ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
118119
jose_jwa:block_decrypt({xchacha20_poly1305, Bits}, DerivedKey, IV, {<<>>, EncryptedKey, TAG});
119120
key_decrypt(#jose_jwk{kty={KTYModule, KTY}}, EncryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{}) ->
120121
key_decrypt(KTYModule:derive_key(KTY), EncryptedKey, JWEPBES2).
@@ -131,23 +132,23 @@ key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt
131132
andalso is_binary(Salt)
132133
andalso is_integer(Iterations)
133134
andalso is_binary(IV) ->
134-
{ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
135+
{ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
135136
{CipherText, CipherTag} = jose_jwa:block_encrypt({aes_gcm, Bits}, DerivedKey, IV, {<<>>, DecryptedKey}),
136137
{CipherText, JWEPBES2#jose_jwe_alg_pbes2{ tag = CipherTag }};
137138
key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=aes_kw, bits=Bits})
138139
when is_binary(Password)
139140
andalso is_binary(DecryptedKey)
140141
andalso is_binary(Salt)
141142
andalso is_integer(Iterations) ->
142-
{ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
143+
{ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
143144
{jose_jwa_aes_kw:wrap(DecryptedKey, DerivedKey), JWEPBES2};
144145
key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=c20p_kw, bits=Bits, iv=IV})
145146
when is_binary(Password)
146147
andalso is_binary(DecryptedKey)
147148
andalso is_binary(Salt)
148149
andalso is_integer(Iterations)
149150
andalso is_binary(IV) ->
150-
{ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
151+
{ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
151152
{CipherText, CipherTag} = jose_jwa:block_encrypt({chacha20_poly1305, Bits}, DerivedKey, IV, {<<>>, DecryptedKey}),
152153
{CipherText, JWEPBES2#jose_jwe_alg_pbes2{ tag = CipherTag }};
153154
key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=xc20p_kw, bits=Bits, iv=IV})
@@ -156,7 +157,7 @@ key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt
156157
andalso is_binary(Salt)
157158
andalso is_integer(Iterations)
158159
andalso is_binary(IV) ->
159-
{ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
160+
{ok, DerivedKey} = pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)),
160161
{CipherText, CipherTag} = jose_jwa:block_encrypt({xchacha20_poly1305, Bits}, DerivedKey, IV, {<<>>, DecryptedKey}),
161162
{CipherText, JWEPBES2#jose_jwe_alg_pbes2{ tag = CipherTag }};
162163
key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{wrap=aes_gcm_kw, iv=undefined}) when is_binary(Password) ->
@@ -175,6 +176,12 @@ next_cek(_Key, {ENCModule, ENC}, ALG=#jose_jwe_alg_pbes2{}) ->
175176
%% API functions
176177
%%====================================================================
177178

179+
-spec format_error(dynamic(), dynamic()) -> dynamic().
180+
format_error(_Reason, [{_M, _F, _As, Info} | _]) ->
181+
ErrorInfo = proplists:get_value(error_info, Info, #{}),
182+
ErrorDescription1 = maps:get(cause, ErrorInfo),
183+
ErrorDescription1.
184+
178185
hmac_supported() ->
179186
[sha256, sha384, sha512].
180187

@@ -197,6 +204,21 @@ from_map_pbes2(F=#{ <<"tag">> := TAG }, H) ->
197204
from_map_pbes2(F, H) ->
198205
{H, F}.
199206

207+
%% @private
208+
pbkdf2(Mac, Password, Salt, Iterations, DerivedKeyLen) ->
209+
PBES2CountMaximum = jose:pbes2_count_maximum(),
210+
case PBES2CountMaximum < Iterations of
211+
false ->
212+
jose_jwa_pkcs5:pbkdf2(Mac, Password, Salt, Iterations, DerivedKeyLen);
213+
true ->
214+
erlang:error(badarg, [Mac, <<"REDACTED">>, Salt, Iterations, DerivedKeyLen], [
215+
{error_info, #{
216+
module => ?MODULE,
217+
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]))}
218+
}}
219+
])
220+
end.
221+
200222
%% @private
201223
to_map_pbes2(F, H=#jose_jwe_alg_pbes2{ iter = P2C }) when is_integer(P2C) ->
202224
to_map_pbes2(F#{ <<"p2c">> => P2C }, H#jose_jwe_alg_pbes2{ iter = undefined });

test/jose_jwe_SUITE.erl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
-export([alg_ecdh_1pu_key_encrypt_and_key_decrypt/1]).
2828
-export([alg_ecdh_es_from_map_and_to_map/1]).
2929
-export([alg_ecdh_es_key_encrypt_and_key_decrypt/1]).
30+
-export([alg_pbes2_cve_2023_50966/1]).
3031
-export([alg_pbes2_from_map_and_to_map/1]).
3132
-export([alg_pbes2_key_encrypt_and_key_decrypt/1]).
3233
-export([alg_rsa_from_map_and_to_map/1]).
@@ -53,6 +54,7 @@ all() ->
5354
{group, jose_jwe_alg_pbes2},
5455
{group, jose_jwe_alg_rsa},
5556
{group, jose_jwe_alg_xc20p_kw},
57+
{group, jose_jwe_cve},
5658
{group, jose_jwe_enc_aes},
5759
{group, jose_jwe_enc_c20p},
5860
{group, jose_jwe_enc_xc20p},
@@ -69,6 +71,9 @@ groups() ->
6971
alg_c20p_kw_from_map_and_to_map,
7072
alg_c20p_kw_key_encrypt_and_key_decrypt
7173
]},
74+
{jose_jwe_cve, [shuffle], [
75+
alg_pbes2_cve_2023_50966
76+
]},
7277
{jose_jwe_alg_dir, [parallel], [
7378
alg_dir_from_map_and_to_map,
7479
alg_dir_key_decrypt,
@@ -195,6 +200,11 @@ alg_ecdh_es_key_encrypt_and_key_decrypt(Config) ->
195200
jose_jwe_alg_ecdh_es_props:prop_key_encrypt_and_key_decrypt(),
196201
Config).
197202

203+
alg_pbes2_cve_2023_50966(Config) ->
204+
ct_property_test:quickcheck(
205+
jose_jwe_alg_pbes2_props:prop_cve_2023_50966(),
206+
Config).
207+
198208
alg_pbes2_from_map_and_to_map(Config) ->
199209
ct_property_test:quickcheck(
200210
jose_jwe_alg_pbes2_props:prop_from_map_and_to_map(),

test/jose_jws_SUITE.erl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ groups() ->
7676
init_per_suite(Config) ->
7777
application:set_env(jose, crypto_fallback, true),
7878
application:set_env(jose, unsecured_signing, true),
79-
_ = application:ensure_all_started(jose),
79+
{ok, _} = application:ensure_all_started(jose),
80+
ok = jose:crypto_fallback(true),
81+
ok = jose:unsecured_signing(true),
8082
ct_property_test:init_per_suite(Config).
8183

8284
end_per_suite(_Config) ->

test/property_test/jose_jwe_alg_pbes2_props.erl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,52 @@ jwk_jwe_gen() ->
6161
jwk_jwe_maps(),
6262
{Key, jose_jwk:from_map(JWKMap), jose_jwe:from_map(JWEMap)}).
6363

64+
prop_cve_2023_50966() ->
65+
?FORALL({_Key, JWK, BaseJWE, PBES2CountMaximum},
66+
?LET({{Key, JWK, BaseJWE}, PBES2CountMaximum},
67+
{jwk_jwe_gen(), range(2, 100)},
68+
{Key, oneof([Key, JWK]), BaseJWE, PBES2CountMaximum}),
69+
begin
70+
OriginalPBES2CountMaximum = jose:pbes2_count_maximum(),
71+
try jose:pbes2_count_maximum(PBES2CountMaximum) of
72+
ok ->
73+
LesserJWE = jose_jwe:merge(BaseJWE, #{<<"p2c">> => PBES2CountMaximum - 1}),
74+
MaximumJWE = jose_jwe:merge(BaseJWE, #{<<"p2c">> => PBES2CountMaximum}),
75+
GreaterJWE = jose_jwe:merge(BaseJWE, #{<<"p2c">> => PBES2CountMaximum + 1}),
76+
{LesserDecKey1, LesserDecJWE} = jose_jwe:next_cek(JWK, LesserJWE),
77+
{LesserEncKey, LesserEncJWE} = jose_jwe:key_encrypt(JWK, LesserDecKey1, LesserDecJWE),
78+
LesserDecKey2 = jose_jwe:key_decrypt(JWK, LesserEncKey, LesserEncJWE),
79+
{MaximumDecKey1, MaximumDecJWE} = jose_jwe:next_cek(JWK, MaximumJWE),
80+
{MaximumEncKey, MaximumEncJWE} = jose_jwe:key_encrypt(JWK, MaximumDecKey1, MaximumDecJWE),
81+
MaximumDecKey2 = jose_jwe:key_decrypt(JWK, MaximumEncKey, MaximumEncJWE),
82+
{GreaterDecKey, GreaterDecJWE} = jose_jwe:next_cek(JWK, GreaterJWE),
83+
GreaterEncResult =
84+
try
85+
jose_jwe:key_encrypt(JWK, GreaterDecKey, GreaterDecJWE)
86+
catch
87+
GreaterEncClass:GreaterEncReason ->
88+
{GreaterEncClass, GreaterEncReason}
89+
end,
90+
{GreaterEncKey, GreaterEncJWE1} = jose_jwe:key_encrypt(JWK, GreaterDecKey, MaximumDecJWE),
91+
GreaterEncJWE2 = jose_jwe:merge(GreaterEncJWE1, #{<<"p2c">> => 1000000000}),
92+
GreaterDecResult =
93+
try
94+
jose_jwe:key_decrypt(JWK, GreaterEncKey, GreaterEncJWE2)
95+
catch
96+
GreaterDecClass:GreaterDecReason ->
97+
{GreaterDecClass, GreaterDecReason}
98+
end,
99+
conjunction([
100+
{lesser, LesserDecKey1 =:= LesserDecKey2},
101+
{maximum, MaximumDecKey1 =:= MaximumDecKey2},
102+
{greater_key_encrypt, {error, badarg} =:= GreaterEncResult},
103+
{greater_key_decrypt, {error, badarg} =:= GreaterDecResult}
104+
])
105+
after
106+
ok = jose:pbes2_count_maximum(OriginalPBES2CountMaximum)
107+
end
108+
end).
109+
64110
prop_from_map_and_to_map() ->
65111
?FORALL(JWEMap,
66112
?LET({{_Key, _JWKMap, JWEMap}, Extras},

0 commit comments

Comments
 (0)