]> git.ipfire.org Git - thirdparty/openssl.git/blob - providers/common/ciphers/cipher_ccm.c
Add basic aria and camellia ciphers modes to default provider
[thirdparty/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 return 1;
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 rv = 1;
392 err:
393 *padlen = olen;
394 return rv;
395 }
396
397 void ccm_initctx(PROV_CCM_CTX *ctx, size_t keybits, const PROV_CCM_HW *hw)
398 {
399 ctx->keylen = keybits / 8;
400 ctx->key_set = 0;
401 ctx->iv_set = 0;
402 ctx->tag_set = 0;
403 ctx->len_set = 0;
404 ctx->l = 8;
405 ctx->m = 12;
406 ctx->tls_aad_len = -1;
407 ctx->hw = hw;
408 }
409
410 void ccm_finalctx(PROV_CCM_CTX *ctx)
411 {
412 OPENSSL_cleanse(ctx->iv, sizeof(ctx->iv));
413 }