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 "cipher_locl.h"
14 static int ccm_cipher_internal(PROV_CCM_CTX
*ctx
, unsigned char *out
,
15 size_t *padlen
, const unsigned char *in
,
18 static int ccm_tls_init(PROV_CCM_CTX
*ctx
, unsigned char *aad
, size_t alen
)
22 if (alen
!= EVP_AEAD_TLS1_AAD_LEN
)
25 /* Save the aad for later use. */
26 memcpy(ctx
->buf
, aad
, alen
);
27 ctx
->tls_aad_len
= alen
;
29 len
= ctx
->buf
[alen
- 2] << 8 | ctx
->buf
[alen
- 1];
30 if (len
< EVP_CCM_TLS_EXPLICIT_IV_LEN
)
33 /* Correct length for explicit iv. */
34 len
-= EVP_CCM_TLS_EXPLICIT_IV_LEN
;
39 /* Correct length for tag. */
42 ctx
->buf
[alen
- 2] = (unsigned char)(len
>> 8);
43 ctx
->buf
[alen
- 1] = (unsigned char)(len
& 0xff);
45 /* Extra padding: tag appended to record. */
49 static int ccm_tls_iv_set_fixed(PROV_CCM_CTX
*ctx
, unsigned char *fixed
,
52 if (flen
!= EVP_CCM_TLS_FIXED_IV_LEN
)
55 /* Copy to first part of the iv. */
56 memcpy(ctx
->iv
, fixed
, flen
);
60 static size_t ccm_get_ivlen(PROV_CCM_CTX
*ctx
)
65 int ccm_set_ctx_params(void *vctx
, const OSSL_PARAM params
[])
67 PROV_CCM_CTX
*ctx
= (PROV_CCM_CTX
*)vctx
;
71 p
= OSSL_PARAM_locate_const(params
, OSSL_CIPHER_PARAM_AEAD_TAG
);
73 if (p
->data_type
!= OSSL_PARAM_OCTET_STRING
) {
74 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_GET_PARAMETER
);
77 if ((p
->data_size
& 1) || (p
->data_size
< 4) || p
->data_size
> 16) {
78 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_TAGLEN
);
82 if (p
->data
!= NULL
) {
84 ERR_raise(ERR_LIB_PROV
, PROV_R_TAG_NOT_NEEDED
);
87 memcpy(ctx
->buf
, p
->data
, p
->data_size
);
90 ctx
->m
= p
->data_size
;
93 p
= OSSL_PARAM_locate_const(params
, OSSL_CIPHER_PARAM_AEAD_IVLEN
);
97 if (!OSSL_PARAM_get_size_t(p
, &sz
)) {
98 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_GET_PARAMETER
);
102 if (ivlen
< 2 || ivlen
> 8) {
103 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_IVLEN
);
109 p
= OSSL_PARAM_locate_const(params
, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD
);
111 if (p
->data_type
!= OSSL_PARAM_OCTET_STRING
) {
112 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_GET_PARAMETER
);
115 sz
= ccm_tls_init(ctx
, p
->data
, p
->data_size
);
117 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_DATA
);
120 ctx
->tls_aad_pad_sz
= sz
;
123 p
= OSSL_PARAM_locate_const(params
, OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED
);
125 if (p
->data_type
!= OSSL_PARAM_OCTET_STRING
) {
126 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_GET_PARAMETER
);
129 if (ccm_tls_iv_set_fixed(ctx
, p
->data
, p
->data_size
) == 0) {
130 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_IVLEN
);
138 int ccm_get_ctx_params(void *vctx
, OSSL_PARAM params
[])
140 PROV_CCM_CTX
*ctx
= (PROV_CCM_CTX
*)vctx
;
143 p
= OSSL_PARAM_locate(params
, OSSL_CIPHER_PARAM_IVLEN
);
144 if (p
!= NULL
&& !OSSL_PARAM_set_int(p
, ccm_get_ivlen(ctx
))) {
145 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_SET_PARAMETER
);
149 p
= OSSL_PARAM_locate(params
, OSSL_CIPHER_PARAM_IV
);
151 if (ccm_get_ivlen(ctx
) != p
->data_size
) {
152 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_IVLEN
);
155 if (!OSSL_PARAM_set_octet_string(p
, ctx
->iv
, p
->data_size
)) {
156 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_SET_PARAMETER
);
161 p
= OSSL_PARAM_locate(params
, OSSL_CIPHER_PARAM_KEYLEN
);
162 if (p
!= NULL
&& !OSSL_PARAM_set_int(p
, ctx
->keylen
)) {
163 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_SET_PARAMETER
);
167 p
= OSSL_PARAM_locate(params
, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD
);
168 if (p
!= NULL
&& !OSSL_PARAM_set_size_t(p
, ctx
->tls_aad_pad_sz
)) {
169 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_SET_PARAMETER
);
173 p
= OSSL_PARAM_locate(params
, OSSL_CIPHER_PARAM_AEAD_TAG
);
175 if (!ctx
->enc
|| !ctx
->tag_set
) {
176 ERR_raise(ERR_LIB_PROV
, PROV_R_TAG_NOTSET
);
179 if (p
->data_type
!= OSSL_PARAM_OCTET_STRING
) {
180 ERR_raise(ERR_LIB_PROV
, PROV_R_FAILED_TO_SET_PARAMETER
);
183 if (!ctx
->hw
->gettag(ctx
, p
->data
, p
->data_size
))
192 static int ccm_init(void *vctx
, const unsigned char *key
, size_t keylen
,
193 const unsigned char *iv
, size_t ivlen
, int enc
)
195 PROV_CCM_CTX
*ctx
= (PROV_CCM_CTX
*)vctx
;
200 if (ivlen
!= ccm_get_ivlen(ctx
)) {
201 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_IVLEN
);
205 memcpy(ctx
->iv
, iv
, ivlen
);
209 if (keylen
!= ctx
->keylen
) {
210 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_KEYLEN
);
213 return ctx
->hw
->setkey(ctx
, key
, keylen
);
218 int ccm_einit(void *vctx
, const unsigned char *key
, size_t keylen
,
219 const unsigned char *iv
, size_t ivlen
)
221 return ccm_init(vctx
, key
, keylen
, iv
, ivlen
, 1);
224 int ccm_dinit(void *vctx
, const unsigned char *key
, size_t keylen
,
225 const unsigned char *iv
, size_t ivlen
)
227 return ccm_init(vctx
, key
, keylen
, iv
, ivlen
, 0);
230 int ccm_stream_update(void *vctx
, unsigned char *out
, size_t *outl
,
231 size_t outsize
, const unsigned char *in
,
234 PROV_CCM_CTX
*ctx
= (PROV_CCM_CTX
*)vctx
;
237 ERR_raise(ERR_LIB_PROV
, PROV_R_OUTPUT_BUFFER_TOO_SMALL
);
241 if (!ccm_cipher_internal(ctx
, out
, outl
, in
, inl
)) {
242 ERR_raise(ERR_LIB_PROV
, PROV_R_CIPHER_OPERATION_FAILED
);
248 int ccm_stream_final(void *vctx
, unsigned char *out
, size_t *outl
,
251 PROV_CCM_CTX
*ctx
= (PROV_CCM_CTX
*)vctx
;
254 i
= ccm_cipher_internal(ctx
, out
, outl
, NULL
, 0);
262 int ccm_cipher(void *vctx
,
263 unsigned char *out
, size_t *outl
, size_t outsize
,
264 const unsigned char *in
, size_t inl
)
266 PROV_CCM_CTX
*ctx
= (PROV_CCM_CTX
*)vctx
;
269 ERR_raise(ERR_LIB_PROV
, PROV_R_OUTPUT_BUFFER_TOO_SMALL
);
273 if (ccm_cipher_internal(ctx
, out
, outl
, in
, inl
) <= 0)
280 /* Copy the buffered iv */
281 static int ccm_set_iv(PROV_CCM_CTX
*ctx
, size_t mlen
)
283 const PROV_CCM_HW
*hw
= ctx
->hw
;
285 if (!hw
->setiv(ctx
, ctx
->iv
, ccm_get_ivlen(ctx
), mlen
))
291 static int ccm_tls_cipher(PROV_CCM_CTX
*ctx
,
292 unsigned char *out
, size_t *padlen
,
293 const unsigned char *in
, size_t len
)
298 /* Encrypt/decrypt must be performed in place */
299 if (out
!= in
|| len
< (EVP_CCM_TLS_EXPLICIT_IV_LEN
+ (size_t)ctx
->m
))
302 /* If encrypting set explicit IV from sequence number (start of AAD) */
304 memcpy(out
, ctx
->buf
, EVP_CCM_TLS_EXPLICIT_IV_LEN
);
305 /* Get rest of IV from explicit IV */
306 memcpy(ctx
->iv
+ EVP_CCM_TLS_FIXED_IV_LEN
, in
, EVP_CCM_TLS_EXPLICIT_IV_LEN
);
307 /* Correct length value */
308 len
-= EVP_CCM_TLS_EXPLICIT_IV_LEN
+ ctx
->m
;
309 if (!ccm_set_iv(ctx
, len
))
313 if (!ctx
->hw
->setaad(ctx
, ctx
->buf
, ctx
->tls_aad_len
))
316 /* Fix buffer to point to payload */
317 in
+= EVP_CCM_TLS_EXPLICIT_IV_LEN
;
318 out
+= EVP_CCM_TLS_EXPLICIT_IV_LEN
;
320 if (!ctx
->hw
->auth_encrypt(ctx
, in
, out
, len
, out
+ len
, ctx
->m
))
322 olen
= len
+ EVP_CCM_TLS_EXPLICIT_IV_LEN
+ ctx
->m
;
324 if (!ctx
->hw
->auth_decrypt(ctx
, in
, out
, len
,
325 (unsigned char *)in
+ len
, ctx
->m
))
335 static int ccm_cipher_internal(PROV_CCM_CTX
*ctx
, unsigned char *out
,
336 size_t *padlen
, const unsigned char *in
,
341 const PROV_CCM_HW
*hw
= ctx
->hw
;
343 /* If no key set, return error */
347 if (ctx
->tls_aad_len
>= 0)
348 return ccm_tls_cipher(ctx
, out
, padlen
, in
, len
);
350 /* EVP_*Final() doesn't return any data */
351 if (in
== NULL
&& out
!= NULL
)
359 if (!ccm_set_iv(ctx
, len
))
362 /* If we have AAD, we need a message length */
363 if (!ctx
->len_set
&& len
)
365 if (!hw
->setaad(ctx
, in
, len
))
369 /* If not set length yet do it */
370 if (!ctx
->len_set
&& !ccm_set_iv(ctx
, len
))
374 if (!hw
->auth_encrypt(ctx
, in
, out
, len
, NULL
, 0))
378 /* The tag must be set before actually decrypting data */
382 if (!hw
->auth_decrypt(ctx
, in
, out
, len
, ctx
->buf
, ctx
->m
))
384 /* Finished - reset flags so calling this method again will fail */
397 void ccm_initctx(PROV_CCM_CTX
*ctx
, size_t keybits
, const PROV_CCM_HW
*hw
)
399 ctx
->keylen
= keybits
/ 8;
406 ctx
->tls_aad_len
= -1;
410 void ccm_finalctx(PROV_CCM_CTX
*ctx
)
412 OPENSSL_cleanse(ctx
->iv
, sizeof(ctx
->iv
));