2 * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
10 /* Dispatch functions for ccm mode */
12 #include "prov/ciphercommon.h"
13 #include "prov/ciphercommon_ccm.h"
14 #include "prov/providercommonerr.h"
16 static int ccm_cipher_internal(PROV_CCM_CTX
*ctx
, unsigned char *out
,
17 size_t *padlen
, const unsigned char *in
,
20 static int ccm_tls_init(PROV_CCM_CTX
*ctx
, unsigned char *aad
, size_t alen
)
24 if (alen
!= EVP_AEAD_TLS1_AAD_LEN
)
27 /* Save the aad for later use. */
28 memcpy(ctx
->buf
, aad
, alen
);
29 ctx
->tls_aad_len
= alen
;
31 len
= ctx
->buf
[alen
- 2] << 8 | ctx
->buf
[alen
- 1];
32 if (len
< EVP_CCM_TLS_EXPLICIT_IV_LEN
)
35 /* Correct length for explicit iv. */
36 len
-= EVP_CCM_TLS_EXPLICIT_IV_LEN
;
41 /* Correct length for tag. */
44 ctx
->buf
[alen
- 2] = (unsigned char)(len
>> 8);
45 ctx
->buf
[alen
- 1] = (unsigned char)(len
& 0xff);
47 /* Extra padding: tag appended to record. */
51 static int ccm_tls_iv_set_fixed(PROV_CCM_CTX
*ctx
, unsigned char *fixed
,
54 if (flen
!= EVP_CCM_TLS_FIXED_IV_LEN
)
57 /* Copy to first part of the iv. */
58 memcpy(ctx
->iv
, fixed
, flen
);
62 static size_t ccm_get_ivlen(PROV_CCM_CTX
*ctx
)
67 int ccm_set_ctx_params(void *vctx
, const OSSL_PARAM params
[])
69 PROV_CCM_CTX
*ctx
= (PROV_CCM_CTX
*)vctx
;
73 p
= OSSL_PARAM_locate_const(params
, OSSL_CIPHER_PARAM_AEAD_TAG
);
75 if (p
->data_type
!= OSSL_PARAM_OCTET_STRING
) {
76 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_GET_PARAMETER
);
79 if ((p
->data_size
& 1) || (p
->data_size
< 4) || p
->data_size
> 16) {
80 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_TAGLEN
);
84 if (p
->data
!= NULL
) {
86 ERR_raise(ERR_LIB_PROV
, PROV_R_TAG_NOT_NEEDED
);
89 memcpy(ctx
->buf
, p
->data
, p
->data_size
);
92 ctx
->m
= p
->data_size
;
95 p
= OSSL_PARAM_locate_const(params
, OSSL_CIPHER_PARAM_AEAD_IVLEN
);
99 if (!OSSL_PARAM_get_size_t(p
, &sz
)) {
100 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_GET_PARAMETER
);
104 if (ivlen
< 2 || ivlen
> 8) {
105 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_IVLEN
);
111 p
= OSSL_PARAM_locate_const(params
, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD
);
113 if (p
->data_type
!= OSSL_PARAM_OCTET_STRING
) {
114 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_GET_PARAMETER
);
117 sz
= ccm_tls_init(ctx
, p
->data
, p
->data_size
);
119 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_DATA
);
122 ctx
->tls_aad_pad_sz
= sz
;
125 p
= OSSL_PARAM_locate_const(params
, OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED
);
127 if (p
->data_type
!= OSSL_PARAM_OCTET_STRING
) {
128 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_GET_PARAMETER
);
131 if (ccm_tls_iv_set_fixed(ctx
, p
->data
, p
->data_size
) == 0) {
132 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_IVLEN
);
140 int ccm_get_ctx_params(void *vctx
, OSSL_PARAM params
[])
142 PROV_CCM_CTX
*ctx
= (PROV_CCM_CTX
*)vctx
;
145 p
= OSSL_PARAM_locate(params
, OSSL_CIPHER_PARAM_IVLEN
);
146 if (p
!= NULL
&& !OSSL_PARAM_set_size_t(p
, ccm_get_ivlen(ctx
))) {
147 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_SET_PARAMETER
);
151 p
= OSSL_PARAM_locate(params
, OSSL_CIPHER_PARAM_AEAD_TAGLEN
);
155 if (!OSSL_PARAM_set_size_t(p
, m
)) {
156 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_SET_PARAMETER
);
161 p
= OSSL_PARAM_locate(params
, OSSL_CIPHER_PARAM_IV
);
163 if (ccm_get_ivlen(ctx
) != p
->data_size
) {
164 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_IVLEN
);
167 if (!OSSL_PARAM_set_octet_string(p
, ctx
->iv
, p
->data_size
)) {
168 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_SET_PARAMETER
);
173 p
= OSSL_PARAM_locate(params
, OSSL_CIPHER_PARAM_KEYLEN
);
174 if (p
!= NULL
&& !OSSL_PARAM_set_size_t(p
, ctx
->keylen
)) {
175 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_SET_PARAMETER
);
179 p
= OSSL_PARAM_locate(params
, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD
);
180 if (p
!= NULL
&& !OSSL_PARAM_set_size_t(p
, ctx
->tls_aad_pad_sz
)) {
181 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_SET_PARAMETER
);
185 p
= OSSL_PARAM_locate(params
, OSSL_CIPHER_PARAM_AEAD_TAG
);
187 if (!ctx
->enc
|| !ctx
->tag_set
) {
188 ERR_raise(ERR_LIB_PROV
, PROV_R_TAG_NOTSET
);
191 if (p
->data_type
!= OSSL_PARAM_OCTET_STRING
) {
192 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_SET_PARAMETER
);
195 if (!ctx
->hw
->gettag(ctx
, p
->data
, p
->data_size
))
204 static int ccm_init(void *vctx
, const unsigned char *key
, size_t keylen
,
205 const unsigned char *iv
, size_t ivlen
, int enc
)
207 PROV_CCM_CTX
*ctx
= (PROV_CCM_CTX
*)vctx
;
212 if (ivlen
!= ccm_get_ivlen(ctx
)) {
213 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_IVLEN
);
216 memcpy(ctx
->iv
, iv
, ivlen
);
220 if (keylen
!= ctx
->keylen
) {
221 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_KEYLEN
);
224 return ctx
->hw
->setkey(ctx
, key
, keylen
);
229 int ccm_einit(void *vctx
, const unsigned char *key
, size_t keylen
,
230 const unsigned char *iv
, size_t ivlen
)
232 return ccm_init(vctx
, key
, keylen
, iv
, ivlen
, 1);
235 int ccm_dinit(void *vctx
, const unsigned char *key
, size_t keylen
,
236 const unsigned char *iv
, size_t ivlen
)
238 return ccm_init(vctx
, key
, keylen
, iv
, ivlen
, 0);
241 int ccm_stream_update(void *vctx
, unsigned char *out
, size_t *outl
,
242 size_t outsize
, const unsigned char *in
,
245 PROV_CCM_CTX
*ctx
= (PROV_CCM_CTX
*)vctx
;
248 ERR_raise(ERR_LIB_PROV
, PROV_R_OUTPUT_BUFFER_TOO_SMALL
);
252 if (!ccm_cipher_internal(ctx
, out
, outl
, in
, inl
)) {
253 ERR_raise(ERR_LIB_PROV
, PROV_R_CIPHER_OPERATION_FAILED
);
259 int ccm_stream_final(void *vctx
, unsigned char *out
, size_t *outl
,
262 PROV_CCM_CTX
*ctx
= (PROV_CCM_CTX
*)vctx
;
265 i
= ccm_cipher_internal(ctx
, out
, outl
, NULL
, 0);
273 int ccm_cipher(void *vctx
,
274 unsigned char *out
, size_t *outl
, size_t outsize
,
275 const unsigned char *in
, size_t inl
)
277 PROV_CCM_CTX
*ctx
= (PROV_CCM_CTX
*)vctx
;
280 ERR_raise(ERR_LIB_PROV
, PROV_R_OUTPUT_BUFFER_TOO_SMALL
);
284 if (ccm_cipher_internal(ctx
, out
, outl
, in
, inl
) <= 0)
291 /* Copy the buffered iv */
292 static int ccm_set_iv(PROV_CCM_CTX
*ctx
, size_t mlen
)
294 const PROV_CCM_HW
*hw
= ctx
->hw
;
296 if (!hw
->setiv(ctx
, ctx
->iv
, ccm_get_ivlen(ctx
), mlen
))
302 static int ccm_tls_cipher(PROV_CCM_CTX
*ctx
,
303 unsigned char *out
, size_t *padlen
,
304 const unsigned char *in
, size_t len
)
309 /* Encrypt/decrypt must be performed in place */
310 if (out
!= in
|| len
< (EVP_CCM_TLS_EXPLICIT_IV_LEN
+ (size_t)ctx
->m
))
313 /* If encrypting set explicit IV from sequence number (start of AAD) */
315 memcpy(out
, ctx
->buf
, EVP_CCM_TLS_EXPLICIT_IV_LEN
);
316 /* Get rest of IV from explicit IV */
317 memcpy(ctx
->iv
+ EVP_CCM_TLS_FIXED_IV_LEN
, in
, EVP_CCM_TLS_EXPLICIT_IV_LEN
);
318 /* Correct length value */
319 len
-= EVP_CCM_TLS_EXPLICIT_IV_LEN
+ ctx
->m
;
320 if (!ccm_set_iv(ctx
, len
))
324 if (!ctx
->hw
->setaad(ctx
, ctx
->buf
, ctx
->tls_aad_len
))
327 /* Fix buffer to point to payload */
328 in
+= EVP_CCM_TLS_EXPLICIT_IV_LEN
;
329 out
+= EVP_CCM_TLS_EXPLICIT_IV_LEN
;
331 if (!ctx
->hw
->auth_encrypt(ctx
, in
, out
, len
, out
+ len
, ctx
->m
))
333 olen
= len
+ EVP_CCM_TLS_EXPLICIT_IV_LEN
+ ctx
->m
;
335 if (!ctx
->hw
->auth_decrypt(ctx
, in
, out
, len
,
336 (unsigned char *)in
+ len
, ctx
->m
))
346 static int ccm_cipher_internal(PROV_CCM_CTX
*ctx
, unsigned char *out
,
347 size_t *padlen
, const unsigned char *in
,
352 const PROV_CCM_HW
*hw
= ctx
->hw
;
354 /* If no key set, return error */
358 if (ctx
->tls_aad_len
!= UNINITIALISED_SIZET
)
359 return ccm_tls_cipher(ctx
, out
, padlen
, in
, len
);
361 /* EVP_*Final() doesn't return any data */
362 if (in
== NULL
&& out
!= NULL
)
370 if (!ccm_set_iv(ctx
, len
))
373 /* If we have AAD, we need a message length */
374 if (!ctx
->len_set
&& len
)
376 if (!hw
->setaad(ctx
, in
, len
))
380 /* If not set length yet do it */
381 if (!ctx
->len_set
&& !ccm_set_iv(ctx
, len
))
385 if (!hw
->auth_encrypt(ctx
, in
, out
, len
, NULL
, 0))
389 /* The tag must be set before actually decrypting data */
393 if (!hw
->auth_decrypt(ctx
, in
, out
, len
, ctx
->buf
, ctx
->m
))
395 /* Finished - reset flags so calling this method again will fail */
409 void ccm_initctx(PROV_CCM_CTX
*ctx
, size_t keybits
, const PROV_CCM_HW
*hw
)
411 ctx
->keylen
= keybits
/ 8;
418 ctx
->tls_aad_len
= UNINITIALISED_SIZET
;