Skip to content

Commit e1d0264

Browse files
committed
EVP: Enforce the whole MAC life-cycle at the EVP layer
Extend the finalised flag into the full state machine of life_cycle-mac(7): EVP_MAC_update(), EVP_MAC_final() and EVP_MAC_finalXOF() now also fail, with EVP_R_OPERATION_NOT_INITIALIZED, on a context that has not been initialised with EVP_MAC_init() or EVP_MAC_init_SKEY(). The output length query (EVP_MAC_final() with a NULL output buffer) and the parameter functions remain usable in every state. The canonical transition table was out of step with reality and is corrected rather than enforced as written: EVP_MAC_final() and EVP_MAC_finalXOF() are legal straight after initialisation (a MAC over an empty message), the parameter functions are legal in the finaled state (needed by the length query and by the "final, set a new IV, re-init with the old key" reuse pattern), and rows for EVP_MAC_CTX_dup() and EVP_MAC_init_SKEY() are added. A key supplied through EVP_MAC_CTX_set_params() does not initialise the context. The only in-tree code relying on that, the CMAC used by AES-SIV in crypto/modes/siv128.c, now keys its template context with EVP_MAC_init() instead. Assisted-by: Claude:claude-fable-5-1
1 parent 0673930 commit e1d0264

7 files changed

Lines changed: 426 additions & 32 deletions

File tree

‎CHANGES.md‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ OpenSSL 4.2
3333

3434
### Changes between 4.1 and 4.2 [xx XXX xxxx]
3535

36+
* The EVP layer now enforces the MAC life-cycle described in
37+
life_cycle-mac(7). `EVP_MAC_update()`, `EVP_MAC_final()` and
38+
`EVP_MAC_finalXOF()` fail with an error when called on an `EVP_MAC_CTX`
39+
that has not been initialised with `EVP_MAC_init()` or
40+
`EVP_MAC_init_SKEY()`, including one whose key was only supplied through
41+
`EVP_MAC_CTX_set_params()`, or that has already been finalised and not
42+
been re-initialised since.
43+
<!-- https://github.com/openssl/openssl/pull/33084-->
44+
45+
*Daniel Kubec*
46+
3647
* `EVP_SKEY_get0_raw_key()` now accepts a NULL key pointer to retrieve only
3748
the key length. The length is obtained from the `OSSL_SKEY_PARAM_KEY_LENGTH`
3849
key parameter without exporting the key, so it is also available for keys

‎crypto/evp/evp_local.h‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,20 @@ struct evp_mac_ctx_st {
7575
* OSSL_FUNC_mac_newctx()
7676
*/
7777
void *algctx;
78+
/*
79+
* Life-cycle state, see life_cycle-mac(7). EVP_MAC_CTX_new() leaves it
80+
* at EVP_MAC_STATE_NEW (zero), a successful EVP_MAC_init() or
81+
* EVP_MAC_init_SKEY() moves to INITIALISED, EVP_MAC_update() to UPDATED
82+
* and EVP_MAC_final()/EVP_MAC_finalXOF() to FINALISED. EVP_MAC_update(),
83+
* EVP_MAC_final() and EVP_MAC_finalXOF() are rejected in the NEW and
84+
* FINALISED states.
85+
*/
86+
enum {
87+
EVP_MAC_STATE_NEW = 0,
88+
EVP_MAC_STATE_INITIALISED,
89+
EVP_MAC_STATE_UPDATED,
90+
EVP_MAC_STATE_FINALISED
91+
} state;
7892
} /* EVP_MAC_CTX */;
7993

8094
struct evp_kdf_ctx_st {

‎crypto/evp/mac_lib.c‎

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2018-2025 The OpenSSL Project Authors. All Rights Reserved.
2+
* Copyright 2018-2026 The OpenSSL Project Authors. All Rights Reserved.
33
*
44
* Licensed under the Apache License 2.0 (the "License"). You may not use
55
* this file except in compliance with the License. You can obtain a copy
@@ -119,7 +119,10 @@ int EVP_MAC_init(EVP_MAC_CTX *ctx, const unsigned char *key, size_t keylen,
119119
ERR_raise(ERR_R_EVP_LIB, ERR_R_UNSUPPORTED);
120120
return 0;
121121
}
122-
return ctx->meth->init(ctx->algctx, key, keylen, params);
122+
if (!ctx->meth->init(ctx->algctx, key, keylen, params))
123+
return 0;
124+
ctx->state = EVP_MAC_STATE_INITIALISED;
125+
return 1;
123126
}
124127

125128
int EVP_MAC_init_SKEY(EVP_MAC_CTX *ctx, EVP_SKEY *skey, const OSSL_PARAM params[])
@@ -130,12 +133,28 @@ int EVP_MAC_init_SKEY(EVP_MAC_CTX *ctx, EVP_SKEY *skey, const OSSL_PARAM params[
130133
ERR_raise(ERR_R_EVP_LIB, ERR_R_UNSUPPORTED);
131134
return 0;
132135
}
133-
return ctx->meth->init_skey(ctx->algctx, skey->keydata, params);
136+
if (!ctx->meth->init_skey(ctx->algctx, skey->keydata, params))
137+
return 0;
138+
ctx->state = EVP_MAC_STATE_INITIALISED;
139+
return 1;
134140
}
135141

136142
int EVP_MAC_update(EVP_MAC_CTX *ctx, const unsigned char *data, size_t datalen)
137143
{
138-
return ctx->meth->update(ctx->algctx, data, datalen);
144+
switch (ctx->state) {
145+
case EVP_MAC_STATE_NEW:
146+
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
147+
return 0;
148+
case EVP_MAC_STATE_FINALISED:
149+
ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR);
150+
return 0;
151+
default:
152+
break;
153+
}
154+
if (!ctx->meth->update(ctx->algctx, data, datalen))
155+
return 0;
156+
ctx->state = EVP_MAC_STATE_UPDATED;
157+
return 1;
139158
}
140159

141160
static int evp_mac_final(EVP_MAC_CTX *ctx, int xof,
@@ -164,6 +183,16 @@ static int evp_mac_final(EVP_MAC_CTX *ctx, int xof,
164183
*outl = macsize;
165184
return 1;
166185
}
186+
switch (ctx->state) {
187+
case EVP_MAC_STATE_NEW:
188+
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
189+
return 0;
190+
case EVP_MAC_STATE_FINALISED:
191+
ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR);
192+
return 0;
193+
default:
194+
break;
195+
}
167196
if (outsize < macsize) {
168197
ERR_raise(ERR_LIB_EVP, EVP_R_BUFFER_TOO_SMALL);
169198
return 0;
@@ -178,6 +207,7 @@ static int evp_mac_final(EVP_MAC_CTX *ctx, int xof,
178207
}
179208
}
180209
res = ctx->meth->final(ctx->algctx, out, &l, outsize);
210+
ctx->state = EVP_MAC_STATE_FINALISED;
181211
if (outl != NULL)
182212
*outl = l;
183213
return res;

‎crypto/modes/siv128.c‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ int ossl_siv128_init(SIV128_CONTEXT *ctx, const unsigned char *key, int klen,
170170
static const unsigned char zero[SIV_LEN] = { 0 };
171171
size_t out_len = SIV_LEN;
172172
EVP_MAC_CTX *mac_ctx = NULL;
173-
OSSL_PARAM params[3];
173+
OSSL_PARAM params[2];
174174
const char *cbc_name;
175175

176176
if (ctx == NULL)
@@ -190,14 +190,12 @@ int ossl_siv128_init(SIV128_CONTEXT *ctx, const unsigned char *key, int klen,
190190
cbc_name = EVP_CIPHER_get0_name(cbc);
191191
params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER,
192192
(char *)cbc_name, 0);
193-
params[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
194-
(void *)key, klen);
195-
params[2] = OSSL_PARAM_construct_end();
193+
params[1] = OSSL_PARAM_construct_end();
196194

197195
if ((ctx->cipher_ctx = EVP_CIPHER_CTX_new()) == NULL
198196
|| (ctx->mac = EVP_MAC_fetch(libctx, OSSL_MAC_NAME_CMAC, propq)) == NULL
199197
|| (ctx->mac_ctx_init = EVP_MAC_CTX_new(ctx->mac)) == NULL
200-
|| !EVP_MAC_CTX_set_params(ctx->mac_ctx_init, params)
198+
|| !EVP_MAC_init(ctx->mac_ctx_init, key, klen, params)
201199
|| !EVP_EncryptInit_ex(ctx->cipher_ctx, ctr, NULL, key + klen, NULL)
202200
|| (mac_ctx = EVP_MAC_CTX_dup(ctx->mac_ctx_init)) == NULL
203201
|| !EVP_MAC_update(mac_ctx, zero, sizeof(zero))

‎doc/man3/EVP_MAC.pod‎

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,15 @@ call with I<out> pointing at the allocated space.
170170
EVP_MAC_finalXOF() does the final computation for an XOF based MAC and stores
171171
the result in the memory pointed at by I<out> of size I<outsize>.
172172

173+
EVP_MAC_update(), EVP_MAC_final() and EVP_MAC_finalXOF() require I<ctx> to
174+
have been initialised with EVP_MAC_init() or EVP_MAC_init_SKEY() and fail
175+
otherwise. Once EVP_MAC_final() or EVP_MAC_finalXOF() has been called,
176+
I<ctx> is finalised and these three functions fail again until it is
177+
re-initialised. Calling EVP_MAC_final() with I<out> set to NULL to query
178+
the output length is possible in any state, and a copy made with
179+
EVP_MAC_CTX_dup() is in the same state as the original.
180+
Supplying a key with EVP_MAC_CTX_set_params() does not initialise I<ctx>.
181+
173182
EVP_MAC_get_params() retrieves details about the implementation
174183
I<mac>.
175184
The set of parameters given with I<params> determine exactly what
@@ -344,9 +353,8 @@ Anything else may give undefined results.
344353

345354
=head1 NOTES
346355

347-
The MAC life-cycle is described in L<life_cycle-mac(7)>. In the future,
348-
the transitions described there will be enforced. When this is done, it will
349-
not be considered a breaking change to the API.
356+
The MAC life-cycle is described in L<life_cycle-mac(7)>. Since OpenSSL 4.2,
357+
the transitions described there are enforced as described above.
350358

351359
The usage of the parameter names "custom", "iv" and "salt" correspond to
352360
the names used in the standard where the algorithm was defined.
@@ -497,6 +505,10 @@ These functions were added in OpenSSL 3.0.
497505

498506
The EVP_MAC_init_SKEY() function was added in OpenSSL 3.5.
499507

508+
Since OpenSSL 4.2, EVP_MAC_update(), EVP_MAC_final() and EVP_MAC_finalXOF()
509+
fail on a context that has not been initialised, or that has been finalised
510+
and not re-initialised since.
511+
500512
=head1 COPYRIGHT
501513

502514
Copyright 2018-2026 The OpenSSL Project Authors. All Rights Reserved.

‎doc/man7/life_cycle-mac.pod‎

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ This state represents the MAC after it has been allocated.
2323
=item initialised
2424

2525
This state represents the MAC when it is set up and capable of processing
26-
input.
26+
input or generating output.
2727

2828
=item updated
2929

@@ -93,17 +93,19 @@ This is the canonical list.
9393
=begin man
9494

9595
Function Call --------------------- Current State ----------------------
96-
start newed initialised updated finaled freed
96+
start newed initialised updated finaled freed
9797
EVP_MAC_CTX_new newed
98-
EVP_MAC_init initialised initialised initialised initialised
99-
EVP_MAC_update updated updated
100-
EVP_MAC_final finaled
101-
EVP_MAC_finalXOF finaled
102-
EVP_MAC_CTX_free freed freed freed freed freed
103-
EVP_MAC_CTX_get_params newed initialised updated
104-
EVP_MAC_CTX_set_params newed initialised updated
105-
EVP_MAC_CTX_gettable_params newed initialised updated
106-
EVP_MAC_CTX_settable_params newed initialised updated
98+
EVP_MAC_CTX_dup newed initialised updated finaled
99+
EVP_MAC_init initialised initialised initialised initialised
100+
EVP_MAC_init_SKEY initialised initialised initialised initialised
101+
EVP_MAC_update updated updated
102+
EVP_MAC_final finaled finaled
103+
EVP_MAC_finalXOF finaled finaled
104+
EVP_MAC_CTX_free freed freed freed freed freed
105+
EVP_MAC_CTX_get_params newed initialised updated finaled
106+
EVP_MAC_CTX_set_params newed initialised updated finaled
107+
EVP_MAC_CTX_gettable_params newed initialised updated finaled
108+
EVP_MAC_CTX_settable_params newed initialised updated finaled
107109

108110
=end man
109111

@@ -126,13 +128,27 @@ This is the canonical list.
126128
<td style="border:1px solid" align="center"></td>
127129
<td style="border:1px solid" align="center"></td>
128130
<td style="border:1px solid" align="center"></td></tr>
131+
<tr><th style="border:1px solid" align="left">EVP_MAC_CTX_dup</th>
132+
<td style="border:1px solid" align="center"></td>
133+
<td style="border:1px solid" align="center">newed</td>
134+
<td style="border:1px solid" align="center">initialised</td>
135+
<td style="border:1px solid" align="center">updated</td>
136+
<td style="border:1px solid" align="center">finaled</td>
137+
<td style="border:1px solid" align="center"></td></tr>
129138
<tr><th style="border:1px solid" align="left">EVP_MAC_init</th>
130139
<td style="border:1px solid" align="center"></td>
131140
<td style="border:1px solid" align="center">initialised</td>
132141
<td style="border:1px solid" align="center">initialised</td>
133142
<td style="border:1px solid" align="center">initialised</td>
134143
<td style="border:1px solid" align="center">initialised</td>
135144
<td style="border:1px solid" align="center"></td></tr>
145+
<tr><th style="border:1px solid" align="left">EVP_MAC_init_SKEY</th>
146+
<td style="border:1px solid" align="center"></td>
147+
<td style="border:1px solid" align="center">initialised</td>
148+
<td style="border:1px solid" align="center">initialised</td>
149+
<td style="border:1px solid" align="center">initialised</td>
150+
<td style="border:1px solid" align="center">initialised</td>
151+
<td style="border:1px solid" align="center"></td></tr>
136152
<tr><th style="border:1px solid" align="left">EVP_MAC_update</th>
137153
<td style="border:1px solid" align="center"></td>
138154
<td style="border:1px solid" align="center"></td>
@@ -143,15 +159,15 @@ This is the canonical list.
143159
<tr><th style="border:1px solid" align="left">EVP_MAC_final</th>
144160
<td style="border:1px solid" align="center"></td>
145161
<td style="border:1px solid" align="center"></td>
146-
<td style="border:1px solid" align="center"></td>
162+
<td style="border:1px solid" align="center">finaled</td>
147163
<td style="border:1px solid" align="center">finaled</td>
148164
<td style="border:1px solid" align="center"></td>
149165
<td style="border:1px solid" align="center"></td></tr>
150166
<tr><th style="border:1px solid" align="left">EVP_MAC_finalXOF</th>
151-
<td style="border:1px solid" align="center"></td>
152167
<td style="border:1px solid" align="center"></td>
153168
<td style="border:1px solid" align="center"></td>
154169
<td style="border:1px solid" align="center">finaled</td>
170+
<td style="border:1px solid" align="center">finaled</td>
155171
<td style="border:1px solid" align="center"></td>
156172
<td style="border:1px solid" align="center"></td></tr>
157173
<tr><th style="border:1px solid" align="left">EVP_MAC_CTX_free</th>
@@ -166,37 +182,40 @@ This is the canonical list.
166182
<td style="border:1px solid" align="center">newed</td>
167183
<td style="border:1px solid" align="center">initialised</td>
168184
<td style="border:1px solid" align="center">updated</td>
169-
<td style="border:1px solid" align="center"></td>
185+
<td style="border:1px solid" align="center">finaled</td>
170186
<td style="border:1px solid" align="center"></td></tr>
171187
<tr><th style="border:1px solid" align="left">EVP_MAC_CTX_set_params</th>
172188
<td style="border:1px solid" align="center"></td>
173189
<td style="border:1px solid" align="center">newed</td>
174190
<td style="border:1px solid" align="center">initialised</td>
175191
<td style="border:1px solid" align="center">updated</td>
176-
<td style="border:1px solid" align="center"></td>
192+
<td style="border:1px solid" align="center">finaled</td>
177193
<td style="border:1px solid" align="center"></td></tr>
178194
<tr><th style="border:1px solid" align="left">EVP_MAC_CTX_gettable_params</th>
179195
<td style="border:1px solid" align="center"></td>
180196
<td style="border:1px solid" align="center">newed</td>
181197
<td style="border:1px solid" align="center">initialised</td>
182198
<td style="border:1px solid" align="center">updated</td>
183-
<td style="border:1px solid" align="center"></td>
199+
<td style="border:1px solid" align="center">finaled</td>
184200
<td style="border:1px solid" align="center"></td></tr>
185201
<tr><th style="border:1px solid" align="left">EVP_MAC_CTX_settable_params</th>
186202
<td style="border:1px solid" align="center"></td>
187203
<td style="border:1px solid" align="center">newed</td>
188204
<td style="border:1px solid" align="center">initialised</td>
189205
<td style="border:1px solid" align="center">updated</td>
190-
<td style="border:1px solid" align="center"></td>
206+
<td style="border:1px solid" align="center">finaled</td>
191207
<td style="border:1px solid" align="center"></td></tr>
192208
</table>
193209

194210
=end html
195211

196212
=head1 NOTES
197213

198-
At some point the EVP layer will begin enforcing the transitions described
199-
herein.
214+
Since OpenSSL 4.2, the EVP layer enforces the transitions described herein:
215+
EVP_MAC_update(), EVP_MAC_final() and EVP_MAC_finalXOF() fail in the
216+
B<newed> and B<finaled> states, see L<EVP_MAC(3)>. Querying the output
217+
length by calling EVP_MAC_final() with a NULL output buffer is permitted in
218+
every state and does not change it.
200219

201220
=head1 SEE ALSO
202221

@@ -208,7 +227,7 @@ The provider MAC interface was introduced in OpenSSL 3.0.
208227

209228
=head1 COPYRIGHT
210229

211-
Copyright 2021 The OpenSSL Project Authors. All Rights Reserved.
230+
Copyright 2021-2026 The OpenSSL Project Authors. All Rights Reserved.
212231

213232
Licensed under the Apache License 2.0 (the "License"). You may not use
214233
this file except in compliance with the License. You can obtain a copy

0 commit comments

Comments
 (0)