Make the naming scheme for dispatched functions more consistent
[oweals/openssl.git] / providers / implementations / ciphers / cipher_chacha20_poly1305.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 chacha20_poly1305 cipher */
11
12 #include "cipher_chacha20_poly1305.h"
13 #include "prov/implementations.h"
14 #include "prov/providercommonerr.h"
15
16
17 #define CHACHA20_POLY1305_KEYLEN CHACHA_KEY_SIZE
18 #define CHACHA20_POLY1305_BLKLEN 1
19 #define CHACHA20_POLY1305_MAX_IVLEN 12
20 #define CHACHA20_POLY1305_MODE 0
21 /* TODO(3.0) Figure out what flags are required */
22 #define CHACHA20_POLY1305_FLAGS (EVP_CIPH_FLAG_AEAD_CIPHER                     \
23                                 | EVP_CIPH_ALWAYS_CALL_INIT                    \
24                                 | EVP_CIPH_CTRL_INIT                           \
25                                 | EVP_CIPH_CUSTOM_COPY                         \
26                                 | EVP_CIPH_FLAG_CUSTOM_CIPHER                  \
27                                 | EVP_CIPH_CUSTOM_IV                           \
28                                 | EVP_CIPH_CUSTOM_IV_LENGTH)
29
30 static OSSL_FUNC_cipher_newctx_fn chacha20_poly1305_newctx;
31 static OSSL_FUNC_cipher_freectx_fn chacha20_poly1305_freectx;
32 static OSSL_FUNC_cipher_encrypt_init_fn chacha20_poly1305_einit;
33 static OSSL_FUNC_cipher_decrypt_init_fn chacha20_poly1305_dinit;
34 static OSSL_FUNC_cipher_get_params_fn chacha20_poly1305_get_params;
35 static OSSL_FUNC_cipher_get_ctx_params_fn chacha20_poly1305_get_ctx_params;
36 static OSSL_FUNC_cipher_set_ctx_params_fn chacha20_poly1305_set_ctx_params;
37 static OSSL_FUNC_cipher_cipher_fn chacha20_poly1305_cipher;
38 static OSSL_FUNC_cipher_final_fn chacha20_poly1305_final;
39 static OSSL_FUNC_cipher_gettable_ctx_params_fn chacha20_poly1305_gettable_ctx_params;
40 #define chacha20_poly1305_settable_ctx_params cipher_aead_settable_ctx_params
41 #define chacha20_poly1305_gettable_params cipher_generic_gettable_params
42 #define chacha20_poly1305_update chacha20_poly1305_cipher
43
44 static void *chacha20_poly1305_newctx(void *provctx)
45 {
46     PROV_CHACHA20_POLY1305_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
47
48     if (ctx != NULL) {
49         cipher_generic_initkey(&ctx->base, CHACHA20_POLY1305_KEYLEN * 8,
50                                CHACHA20_POLY1305_BLKLEN * 8,
51                                CHACHA20_POLY1305_IVLEN * 8,
52                                CHACHA20_POLY1305_MODE,
53                                CHACHA20_POLY1305_FLAGS,
54                                PROV_CIPHER_HW_chacha20_poly1305(
55                                    CHACHA20_POLY1305_KEYLEN * 8),
56                                NULL);
57         ctx->nonce_len = CHACHA20_POLY1305_IVLEN;
58         ctx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
59         chacha20_initctx(&ctx->chacha);
60     }
61     return ctx;
62 }
63
64 static void chacha20_poly1305_freectx(void *vctx)
65 {
66     PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)vctx;
67
68     if (ctx != NULL)
69         OPENSSL_clear_free(ctx, sizeof(*ctx));
70 }
71
72 static int chacha20_poly1305_get_params(OSSL_PARAM params[])
73 {
74     return cipher_generic_get_params(params, 0, CHACHA20_POLY1305_FLAGS,
75                                      CHACHA20_POLY1305_KEYLEN * 8,
76                                      CHACHA20_POLY1305_BLKLEN * 8,
77                                      CHACHA20_POLY1305_IVLEN * 8);
78 }
79
80 static int chacha20_poly1305_get_ctx_params(void *vctx, OSSL_PARAM params[])
81 {
82     PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)vctx;
83     OSSL_PARAM *p;
84
85     p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN);
86     if (p != NULL) {
87         if (!OSSL_PARAM_set_size_t(p, ctx->nonce_len)) {
88             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
89             return 0;
90         }
91     }
92     p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN);
93     if (p != NULL && !OSSL_PARAM_set_size_t(p, CHACHA20_POLY1305_KEYLEN)) {
94         ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
95         return 0;
96     }
97     p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN);
98     if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tag_len)) {
99         ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
100         return 0;
101     }
102     p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD);
103     if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tls_aad_pad_sz)) {
104         ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
105         return 0;
106     }
107
108     p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG);
109     if (p != NULL) {
110         if (p->data_type != OSSL_PARAM_OCTET_STRING) {
111             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
112             return 0;
113         }
114         if (!ctx->base.enc) {
115             ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOTSET);
116             return 0;
117         }
118         if (p->data_size == 0 || p->data_size > POLY1305_BLOCK_SIZE) {
119             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAGLEN);
120             return 0;
121         }
122         memcpy(p->data, ctx->tag, p->data_size);
123     }
124
125     return 1;
126 }
127
128 static const OSSL_PARAM chacha20_poly1305_known_gettable_ctx_params[] = {
129     OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
130     OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL),
131     OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TAGLEN, NULL),
132     OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0),
133     OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD, NULL),
134     OSSL_PARAM_END
135 };
136 static const OSSL_PARAM *chacha20_poly1305_gettable_ctx_params(void)
137 {
138     return chacha20_poly1305_known_gettable_ctx_params;
139 }
140
141 static int chacha20_poly1305_set_ctx_params(void *vctx,
142                                             const OSSL_PARAM params[])
143 {
144     const OSSL_PARAM *p;
145     size_t len;
146     PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)vctx;
147     PROV_CIPHER_HW_CHACHA20_POLY1305 *hw =
148         (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->base.hw;
149
150     p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN);
151     if (p != NULL) {
152         if (!OSSL_PARAM_get_size_t(p, &len)) {
153             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
154             return 0;
155         }
156         if (len != CHACHA20_POLY1305_KEYLEN) {
157             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
158             return 0;
159         }
160     }
161     p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN);
162     if (p != NULL) {
163         if (!OSSL_PARAM_get_size_t(p, &len)) {
164             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
165             return 0;
166         }
167         if (len == 0 || len > CHACHA20_POLY1305_MAX_IVLEN) {
168             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
169             return 0;
170         }
171         ctx->nonce_len = len;
172     }
173
174     p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG);
175     if (p != NULL) {
176         if (p->data_type != OSSL_PARAM_OCTET_STRING) {
177             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
178             return 0;
179         }
180         if (p->data_size == 0 || p->data_size > POLY1305_BLOCK_SIZE) {
181             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAGLEN);
182             return 0;
183         }
184         if (p->data != NULL) {
185             if (ctx->base.enc) {
186                 ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOT_NEEDED);
187                 return 0;
188             }
189             memcpy(ctx->tag, p->data, p->data_size);
190         }
191         ctx->tag_len = p->data_size;
192     }
193
194     p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD);
195     if (p != NULL) {
196         if (p->data_type != OSSL_PARAM_OCTET_STRING) {
197             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
198             return 0;
199         }
200         len = hw->tls_init(&ctx->base, p->data, p->data_size);
201         if (len == 0) {
202             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DATA);
203             return 0;
204         }
205         ctx->tls_aad_pad_sz = len;
206     }
207
208     p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED);
209     if (p != NULL) {
210         if (p->data_type != OSSL_PARAM_OCTET_STRING) {
211             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
212             return 0;
213         }
214         if (hw->tls_iv_set_fixed(&ctx->base, p->data, p->data_size) == 0) {
215             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IVLEN);
216             return 0;
217         }
218     }
219     /* ignore OSSL_CIPHER_PARAM_AEAD_MAC_KEY */
220     return 1;
221 }
222
223 static int chacha20_poly1305_einit(void *vctx, const unsigned char *key,
224                                   size_t keylen, const unsigned char *iv,
225                                   size_t ivlen)
226 {
227     int ret;
228
229     ret = cipher_generic_einit(vctx, key, keylen, iv, ivlen);
230     if (ret && iv != NULL) {
231         PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
232         PROV_CIPHER_HW_CHACHA20_POLY1305 *hw =
233             (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw;
234
235         hw->initiv(ctx);
236     }
237     return ret;
238 }
239
240 static int chacha20_poly1305_dinit(void *vctx, const unsigned char *key,
241                                   size_t keylen, const unsigned char *iv,
242                                   size_t ivlen)
243 {
244     int ret;
245
246     ret = cipher_generic_dinit(vctx, key, keylen, iv, ivlen);
247     if (ret && iv != NULL) {
248         PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
249         PROV_CIPHER_HW_CHACHA20_POLY1305 *hw =
250             (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw;
251
252         hw->initiv(ctx);
253     }
254     return ret;
255 }
256
257 static int chacha20_poly1305_cipher(void *vctx, unsigned char *out,
258                                     size_t *outl, size_t outsize,
259                                     const unsigned char *in, size_t inl)
260 {
261     PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
262     PROV_CIPHER_HW_CHACHA20_POLY1305 *hw =
263         (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw;
264
265     if (inl == 0) {
266         *outl = 0;
267         return 1;
268     }
269
270     if (outsize < inl) {
271         ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
272         return 0;
273     }
274
275     if (!hw->aead_cipher(ctx, out, outl, in, inl))
276         return 0;
277
278     *outl = inl;
279     return 1;
280 }
281
282 static int chacha20_poly1305_final(void *vctx, unsigned char *out, size_t *outl,
283                                    size_t outsize)
284 {
285     PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
286     PROV_CIPHER_HW_CHACHA20_POLY1305 *hw =
287         (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw;
288
289     if (hw->aead_cipher(ctx, out, outl, NULL, 0) <= 0)
290         return 0;
291
292     *outl = 0;
293     return 1;
294 }
295
296 /* chacha20_poly1305_functions */
297 const OSSL_DISPATCH chacha20_poly1305_functions[] = {
298     { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))chacha20_poly1305_newctx },
299     { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))chacha20_poly1305_freectx },
300     { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))chacha20_poly1305_einit },
301     { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))chacha20_poly1305_dinit },
302     { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))chacha20_poly1305_update },
303     { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))chacha20_poly1305_final },
304     { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))chacha20_poly1305_cipher },
305     { OSSL_FUNC_CIPHER_GET_PARAMS,
306         (void (*)(void))chacha20_poly1305_get_params },
307     { OSSL_FUNC_CIPHER_GETTABLE_PARAMS,
308         (void (*)(void))chacha20_poly1305_gettable_params },
309     { OSSL_FUNC_CIPHER_GET_CTX_PARAMS,
310          (void (*)(void))chacha20_poly1305_get_ctx_params },
311     { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS,
312         (void (*)(void))chacha20_poly1305_gettable_ctx_params },
313     { OSSL_FUNC_CIPHER_SET_CTX_PARAMS,
314         (void (*)(void))chacha20_poly1305_set_ctx_params },
315     { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS,
316         (void (*)(void))chacha20_poly1305_settable_ctx_params },
317     { 0, NULL }
318 };
319