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