0009e9876c56d69aa30b0e6945aecf49223b4c8e
[openssl.git] / providers / implementations / ciphers / ciphercommon_ccm.c
1 /*
2  * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
3  *
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
8  */
9
10 /* Dispatch functions for ccm mode */
11
12 #include "prov/ciphercommon.h"
13 #include "prov/ciphercommon_ccm.h"
14 #include "prov/providercommon.h"
15 #include "prov/providercommonerr.h"
16
17 static int ccm_cipher_internal(PROV_CCM_CTX *ctx, unsigned char *out,
18                                size_t *padlen, const unsigned char *in,
19                                size_t len);
20
21 static int ccm_tls_init(PROV_CCM_CTX *ctx, unsigned char *aad, size_t alen)
22 {
23     size_t len;
24
25     if (!ossl_prov_is_running() || alen != EVP_AEAD_TLS1_AAD_LEN)
26         return 0;
27
28     /* Save the aad for later use. */
29     memcpy(ctx->buf, aad, alen);
30     ctx->tls_aad_len = alen;
31
32     len = ctx->buf[alen - 2] << 8 | ctx->buf[alen - 1];
33     if (len < EVP_CCM_TLS_EXPLICIT_IV_LEN)
34         return 0;
35
36     /* Correct length for explicit iv. */
37     len -= EVP_CCM_TLS_EXPLICIT_IV_LEN;
38
39     if (!ctx->enc) {
40         if (len < ctx->m)
41             return 0;
42         /* Correct length for tag. */
43         len -= ctx->m;
44     }
45     ctx->buf[alen - 2] = (unsigned char)(len >> 8);
46     ctx->buf[alen - 1] = (unsigned char)(len & 0xff);
47
48     /* Extra padding: tag appended to record. */
49     return ctx->m;
50 }
51
52 static int ccm_tls_iv_set_fixed(PROV_CCM_CTX *ctx, unsigned char *fixed,
53                                 size_t flen)
54 {
55     if (flen != EVP_CCM_TLS_FIXED_IV_LEN)
56         return 0;
57
58     /* Copy to first part of the iv. */
59     memcpy(ctx->iv, fixed, flen);
60     return 1;
61 }
62
63 static size_t ccm_get_ivlen(PROV_CCM_CTX *ctx)
64 {
65     return 15 - ctx->l;
66 }
67
68 int ccm_set_ctx_params(void *vctx, const OSSL_PARAM params[])
69 {
70     PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx;
71     const OSSL_PARAM *p;
72     size_t sz;
73
74     p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG);
75     if (p != NULL) {
76         if (p->data_type != OSSL_PARAM_OCTET_STRING) {
77             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
78             return 0;
79         }
80         if ((p->data_size & 1) || (p->data_size < 4) || p->data_size > 16) {
81             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAGLEN);
82             return 0;
83         }
84
85         if (p->data != NULL) {
86             if (ctx->enc) {
87                 ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOT_NEEDED);
88                 return 0;
89             }
90             memcpy(ctx->buf, p->data, p->data_size);
91             ctx->tag_set = 1;
92         }
93         ctx->m = p->data_size;
94     }
95
96     p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_IVLEN);
97     if (p != NULL) {
98         size_t ivlen;
99
100         if (!OSSL_PARAM_get_size_t(p, &sz)) {
101             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
102             return 0;
103         }
104         ivlen = 15 - sz;
105         if (ivlen < 2 || ivlen > 8) {
106             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IVLEN);
107             return 0;
108         }
109         ctx->l = ivlen;
110     }
111
112     p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD);
113     if (p != NULL) {
114         if (p->data_type != OSSL_PARAM_OCTET_STRING) {
115             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
116             return 0;
117         }
118         sz = ccm_tls_init(ctx, p->data, p->data_size);
119         if (sz == 0) {
120             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DATA);
121             return 0;
122         }
123         ctx->tls_aad_pad_sz = sz;
124     }
125
126     p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED);
127     if (p != NULL) {
128         if (p->data_type != OSSL_PARAM_OCTET_STRING) {
129             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
130             return 0;
131         }
132         if (ccm_tls_iv_set_fixed(ctx, p->data, p->data_size) == 0) {
133             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IVLEN);
134             return 0;
135         }
136     }
137
138     return 1;
139 }
140
141 int ccm_get_ctx_params(void *vctx, OSSL_PARAM params[])
142 {
143     PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx;
144     OSSL_PARAM *p;
145
146     p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN);
147     if (p != NULL && !OSSL_PARAM_set_size_t(p, ccm_get_ivlen(ctx))) {
148         ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
149         return 0;
150     }
151
152     p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN);
153     if (p != NULL) {
154         size_t m = ctx->m;
155
156         if (!OSSL_PARAM_set_size_t(p, m)) {
157             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
158             return 0;
159         }
160     }
161
162     p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV);
163     if (p != NULL) {
164         if (ccm_get_ivlen(ctx) > p->data_size) {
165             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IVLEN);
166             return 0;
167         }
168         if (!OSSL_PARAM_set_octet_string(p, ctx->iv, p->data_size)
169             && !OSSL_PARAM_set_octet_ptr(p, &ctx->iv, p->data_size)) {
170             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
171             return 0;
172         }
173     }
174
175     p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_UPDATED_IV);
176     if (p != NULL) {
177         if (ccm_get_ivlen(ctx) > p->data_size) {
178             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IVLEN);
179             return 0;
180         }
181         if (!OSSL_PARAM_set_octet_string(p, ctx->iv, p->data_size)
182             && !OSSL_PARAM_set_octet_ptr(p, &ctx->iv, p->data_size)) {
183             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
184             return 0;
185         }
186     }
187
188     p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN);
189     if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->keylen)) {
190         ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
191         return 0;
192     }
193
194     p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD);
195     if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tls_aad_pad_sz)) {
196         ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
197         return 0;
198     }
199
200     p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG);
201     if (p != NULL) {
202         if (!ctx->enc || !ctx->tag_set) {
203             ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOTSET);
204             return 0;
205         }
206         if (p->data_type != OSSL_PARAM_OCTET_STRING) {
207             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
208             return 0;
209         }
210         if (!ctx->hw->gettag(ctx, p->data, p->data_size))
211             return 0;
212         ctx->tag_set = 0;
213         ctx->iv_set = 0;
214         ctx->len_set = 0;
215     }
216     return 1;
217 }
218
219 static int ccm_init(void *vctx, const unsigned char *key, size_t keylen,
220                     const unsigned char *iv, size_t ivlen, int enc)
221 {
222     PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx;
223
224     if (!ossl_prov_is_running())
225         return 0;
226
227     ctx->enc = enc;
228
229     if (iv != NULL) {
230         if (ivlen != ccm_get_ivlen(ctx)) {
231             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IVLEN);
232             return 0;
233         }
234         memcpy(ctx->iv, iv, ivlen);
235         ctx->iv_set = 1;
236     }
237     if (key != NULL) {
238         if (keylen != ctx->keylen) {
239             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEYLEN);
240             return 0;
241         }
242         return ctx->hw->setkey(ctx, key, keylen);
243     }
244     return 1;
245 }
246
247 int ccm_einit(void *vctx, const unsigned char *key, size_t keylen,
248                      const unsigned char *iv, size_t ivlen)
249 {
250     return ccm_init(vctx, key, keylen, iv, ivlen, 1);
251 }
252
253 int ccm_dinit(void *vctx, const unsigned char *key, size_t keylen,
254                      const unsigned char *iv, size_t ivlen)
255 {
256     return ccm_init(vctx, key, keylen, iv, ivlen, 0);
257 }
258
259 int ccm_stream_update(void *vctx, unsigned char *out, size_t *outl,
260                              size_t outsize, const unsigned char *in,
261                              size_t inl)
262 {
263     PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx;
264
265     if (outsize < inl) {
266         ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
267         return 0;
268     }
269
270     if (!ccm_cipher_internal(ctx, out, outl, in, inl)) {
271         ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
272         return 0;
273     }
274     return 1;
275 }
276
277 int ccm_stream_final(void *vctx, unsigned char *out, size_t *outl,
278                             size_t outsize)
279 {
280     PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx;
281     int i;
282
283     if (!ossl_prov_is_running())
284         return 0;
285
286     i = ccm_cipher_internal(ctx, out, outl, NULL, 0);
287     if (i <= 0)
288         return 0;
289
290     *outl = 0;
291     return 1;
292 }
293
294 int ccm_cipher(void *vctx, unsigned char *out, size_t *outl, size_t outsize,
295                const unsigned char *in, size_t inl)
296 {
297     PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx;
298
299     if (!ossl_prov_is_running())
300         return 0;
301
302     if (outsize < inl) {
303         ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
304         return 0;
305     }
306
307     if (ccm_cipher_internal(ctx, out, outl, in, inl) <= 0)
308         return 0;
309
310     *outl = inl;
311     return 1;
312 }
313
314 /* Copy the buffered iv */
315 static int ccm_set_iv(PROV_CCM_CTX *ctx, size_t mlen)
316 {
317     const PROV_CCM_HW *hw = ctx->hw;
318
319     if (!hw->setiv(ctx, ctx->iv, ccm_get_ivlen(ctx), mlen))
320         return 0;
321     ctx->len_set = 1;
322     return 1;
323 }
324
325 static int ccm_tls_cipher(PROV_CCM_CTX *ctx,
326                           unsigned char *out, size_t *padlen,
327                           const unsigned char *in, size_t len)
328 {
329     int rv = 0;
330     size_t olen = 0;
331
332     if (!ossl_prov_is_running())
333         goto err;
334
335     /* Encrypt/decrypt must be performed in place */
336     if (in == NULL || out != in || len < EVP_CCM_TLS_EXPLICIT_IV_LEN + ctx->m)
337         goto err;
338
339     /* If encrypting set explicit IV from sequence number (start of AAD) */
340     if (ctx->enc)
341         memcpy(out, ctx->buf, EVP_CCM_TLS_EXPLICIT_IV_LEN);
342     /* Get rest of IV from explicit IV */
343     memcpy(ctx->iv + EVP_CCM_TLS_FIXED_IV_LEN, in, EVP_CCM_TLS_EXPLICIT_IV_LEN);
344     /* Correct length value */
345     len -= EVP_CCM_TLS_EXPLICIT_IV_LEN + ctx->m;
346     if (!ccm_set_iv(ctx, len))
347         goto err;
348
349     /* Use saved AAD */
350     if (!ctx->hw->setaad(ctx, ctx->buf, ctx->tls_aad_len))
351         goto err;
352
353     /* Fix buffer to point to payload */
354     in += EVP_CCM_TLS_EXPLICIT_IV_LEN;
355     out += EVP_CCM_TLS_EXPLICIT_IV_LEN;
356     if (ctx->enc) {
357         if (!ctx->hw->auth_encrypt(ctx, in, out, len,  out + len, ctx->m))
358             goto err;
359         olen = len + EVP_CCM_TLS_EXPLICIT_IV_LEN + ctx->m;
360     } else {
361         if (!ctx->hw->auth_decrypt(ctx, in, out, len,
362                                    (unsigned char *)in + len, ctx->m))
363             goto err;
364         olen = len;
365     }
366     rv = 1;
367 err:
368     *padlen = olen;
369     return rv;
370 }
371
372 static int ccm_cipher_internal(PROV_CCM_CTX *ctx, unsigned char *out,
373                                size_t *padlen, const unsigned char *in,
374                                size_t len)
375 {
376     int rv = 0;
377     size_t olen = 0;
378     const PROV_CCM_HW *hw = ctx->hw;
379
380     /* If no key set, return error */
381     if (!ctx->key_set)
382         return 0;
383
384     if (ctx->tls_aad_len != UNINITIALISED_SIZET)
385         return ccm_tls_cipher(ctx, out, padlen, in, len);
386
387     /* EVP_*Final() doesn't return any data */
388     if (in == NULL && out != NULL)
389         goto finish;
390
391     if (!ctx->iv_set)
392         goto err;
393
394     if (out == NULL) {
395         if (in == NULL) {
396             if (!ccm_set_iv(ctx, len))
397                 goto err;
398         } else {
399             /* If we have AAD, we need a message length */
400             if (!ctx->len_set && len)
401                 goto err;
402             if (!hw->setaad(ctx, in, len))
403                 goto err;
404         }
405     } else {
406         /* If not set length yet do it */
407         if (!ctx->len_set && !ccm_set_iv(ctx, len))
408             goto err;
409
410         if (ctx->enc) {
411             if (!hw->auth_encrypt(ctx, in, out, len, NULL, 0))
412                 goto err;
413             ctx->tag_set = 1;
414         } else {
415             /* The tag must be set before actually decrypting data */
416             if (!ctx->tag_set)
417                 goto err;
418
419             if (!hw->auth_decrypt(ctx, in, out, len, ctx->buf, ctx->m))
420                 goto err;
421             /* Finished - reset flags so calling this method again will fail */
422             ctx->iv_set = 0;
423             ctx->tag_set = 0;
424             ctx->len_set = 0;
425         }
426     }
427     olen = len;
428 finish:
429     rv = 1;
430 err:
431     *padlen = olen;
432     return rv;
433 }
434
435 void ccm_initctx(PROV_CCM_CTX *ctx, size_t keybits, const PROV_CCM_HW *hw)
436 {
437     ctx->keylen = keybits / 8;
438     ctx->key_set = 0;
439     ctx->iv_set = 0;
440     ctx->tag_set = 0;
441     ctx->len_set = 0;
442     ctx->l = 8;
443     ctx->m = 12;
444     ctx->tls_aad_len = UNINITIALISED_SIZET;
445     ctx->hw = hw;
446 }
447