]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - gost_omac.c
tcl_tests: ca.try: Ignore openssl crl exit status for 'corrupted CRL' test
[openssl-gost/engine.git] / gost_omac.c
1 /*
2  * Copyright (c) 2019 Dmitry Belyavskiy <beldmit@gmail.com>
3  * Copyright (c) 2020 Vitaly Chikunov <vt@altlinux.org>
4  *
5  * Contents licensed under the terms of the OpenSSL license
6  * See https://www.openssl.org/source/license.html for details
7  */
8 #include <string.h>
9 #include <openssl/cmac.h>
10 #include <openssl/conf.h>
11 #include <openssl/err.h>
12 #include <openssl/evp.h>
13
14 #include "e_gost_err.h"
15 #include "gost_lcl.h"
16
17 #define min(a,b) (((a) < (b)) ? (a) : (b))
18
19 typedef struct omac_ctx {
20     CMAC_CTX *cmac_ctx;
21     size_t dgst_size;
22     const char *cipher_name;
23     int key_set;
24 /* 
25  * Here begins stuff related to TLSTREE processing
26  * We MUST store the original key to derive TLSTREE keys from it
27  * and TLS seq no.
28  * */
29     unsigned char key[32];
30 /*
31  * TODO
32  * TLSTREE intermediate values should be recalculated only when 
33  * C_i & (seq_no+1) != C_i & (seq_no)
34  * so somewhen we will store C_i & (seq_no) in this structure 
35  * to avoid redundant hash calculations.
36  * */
37 } OMAC_CTX;
38
39 #define MAX_GOST_OMAC_SIZE 16
40
41 static int omac_init(EVP_MD_CTX *ctx, const char *cipher_name)
42 {
43     OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
44     memset(c, 0, sizeof(OMAC_CTX));
45     c->cipher_name = cipher_name;
46     c->key_set = 0;
47
48     switch (OBJ_txt2nid(cipher_name)) {
49     case NID_magma_cbc:
50         c->dgst_size = 8;
51         break;
52
53     case NID_grasshopper_cbc:
54         c->dgst_size = 16;
55         break;
56     }
57
58     return 1;
59 }
60
61 static int magma_imit_init(EVP_MD_CTX *ctx)
62 {
63     return omac_init(ctx, SN_magma_cbc);
64 }
65
66 static int grasshopper_imit_init(EVP_MD_CTX *ctx)
67 {
68     return omac_init(ctx, SN_grasshopper_cbc);
69 }
70
71 static int omac_imit_update(EVP_MD_CTX *ctx, const void *data, size_t count)
72 {
73     OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
74     if (!c->key_set) {
75         GOSTerr(GOST_F_OMAC_IMIT_UPDATE, GOST_R_MAC_KEY_NOT_SET);
76         return 0;
77     }
78
79     return CMAC_Update(c->cmac_ctx, data, count);
80 }
81
82 static int omac_imit_final(EVP_MD_CTX *ctx, unsigned char *md)
83 {
84     OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
85     unsigned char mac[MAX_GOST_OMAC_SIZE];
86     size_t mac_size = sizeof(mac);
87
88     if (!c->key_set) {
89         GOSTerr(GOST_F_OMAC_IMIT_FINAL, GOST_R_MAC_KEY_NOT_SET);
90         return 0;
91     }
92
93     CMAC_Final(c->cmac_ctx, mac, &mac_size);
94
95     memcpy(md, mac, c->dgst_size);
96     return 1;
97 }
98
99 static int omac_imit_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
100 {
101     OMAC_CTX *c_to = EVP_MD_CTX_md_data(to);
102     const OMAC_CTX *c_from = EVP_MD_CTX_md_data(from);
103
104     if (c_from && c_to) {
105         c_to->dgst_size = c_from->dgst_size;
106         c_to->cipher_name = c_from->cipher_name;
107         c_to->key_set = c_from->key_set;
108         memcpy(c_to->key, c_from->key, 32);
109     } else {
110         return 0;
111     }
112     if (!c_from->cmac_ctx) {
113         if (c_to->cmac_ctx) {
114             CMAC_CTX_free(c_to->cmac_ctx);
115             c_to->cmac_ctx = NULL;
116         }
117         return 1;
118     }
119     if (c_to->cmac_ctx == c_from->cmac_ctx) {
120         c_to->cmac_ctx = CMAC_CTX_new();
121     }
122     return CMAC_CTX_copy(c_to->cmac_ctx, c_from->cmac_ctx);
123 }
124
125 /* Clean up imit ctx */
126 static int omac_imit_cleanup(EVP_MD_CTX *ctx)
127 {
128     OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
129
130     if (c) {
131         CMAC_CTX_free(c->cmac_ctx);
132         memset(EVP_MD_CTX_md_data(ctx), 0, sizeof(OMAC_CTX));
133     }
134     return 1;
135 }
136
137 static int omac_key(OMAC_CTX * c, const EVP_CIPHER *cipher,
138                     const unsigned char *key, size_t key_size)
139 {
140     int ret = 0;
141
142     CMAC_CTX_free(c->cmac_ctx);
143     c->cmac_ctx = CMAC_CTX_new();
144     if (c->cmac_ctx == NULL) {
145         GOSTerr(GOST_F_OMAC_KEY, ERR_R_MALLOC_FAILURE);
146         return 0;
147     }
148
149     ret = CMAC_Init(c->cmac_ctx, key, key_size, cipher, NULL);
150     if (ret > 0) {
151         c->key_set = 1;
152     }
153     return 1;
154 }
155
156 /* Called directly by gost_kexp15() */
157 int omac_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr)
158 {
159     switch (type) {
160     case EVP_MD_CTRL_KEY_LEN:
161         *((unsigned int *)(ptr)) = 32;
162         return 1;
163     case EVP_MD_CTRL_SET_KEY:
164         {
165             OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
166             const EVP_MD *md = EVP_MD_CTX_md(ctx);
167             EVP_CIPHER *cipher = NULL;
168             int ret = 0;
169
170             if (c->cipher_name == NULL) {
171                 if (EVP_MD_is_a(md, SN_magma_mac))
172                     c->cipher_name = SN_magma_cbc;
173                 else if (EVP_MD_is_a(md, SN_grasshopper_mac))
174                     c->cipher_name = SN_grasshopper_cbc;
175             }
176             if ((cipher =
177                  (EVP_CIPHER *)EVP_get_cipherbyname(c->cipher_name)) == NULL
178                 && (cipher =
179                     EVP_CIPHER_fetch(NULL, c->cipher_name, NULL)) == NULL) {
180                 GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_CIPHER_NOT_FOUND);
181                 goto set_key_end;
182             }
183
184             if (EVP_MD_meth_get_init(EVP_MD_CTX_md(ctx)) (ctx) <= 0) {
185                 GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_MAC_KEY_NOT_SET);
186                 goto set_key_end;
187             }
188             EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NO_INIT);
189
190             if (c->key_set) {
191                 GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_BAD_ORDER);
192                 goto set_key_end;
193             }
194
195             if (arg == 0) {
196                 struct gost_mac_key *key = (struct gost_mac_key *)ptr;
197                 ret = omac_key(c, cipher, key->key, 32);
198                 if (ret > 0)
199                     memcpy(c->key, key->key, 32);
200                 goto set_key_end;
201             } else if (arg == 32) {
202                 ret = omac_key(c, cipher, ptr, 32);
203                 if (ret > 0)
204                     memcpy(c->key, ptr, 32);
205                 goto set_key_end;
206             }
207             GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_KEY_SIZE);
208           set_key_end:
209             EVP_CIPHER_free(cipher);
210             if (ret > 0)
211                 return ret;
212             return 0;
213         }
214     case EVP_MD_CTRL_XOF_LEN:   /* Supported in OpenSSL */
215         {
216             OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
217             switch (OBJ_txt2nid(c->cipher_name)) {
218             case NID_magma_cbc:
219                 if (arg < 1 || arg > 8) {
220                     GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_SIZE);
221                     return 0;
222                 }
223                 c->dgst_size = arg;
224                 break;
225             case NID_grasshopper_cbc:
226                 if (arg < 1 || arg > 16) {
227                     GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_SIZE);
228                     return 0;
229                 }
230                 c->dgst_size = arg;
231                 break;
232             default:
233                 return 0;
234             }
235             return 1;
236         }
237 #ifdef EVP_MD_CTRL_TLSTREE
238     case EVP_MD_CTRL_TLSTREE:
239         {
240             OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
241             if (c->key_set) {
242                 unsigned char diversed_key[32];
243                 int ret = 0;
244                 if (gost_tlstree(OBJ_txt2nid(c->cipher_name),
245                                  c->key, diversed_key,
246                                  (const unsigned char *)ptr)) {
247                     EVP_CIPHER *cipher;
248                     if ((cipher = (EVP_CIPHER *)EVP_get_cipherbyname(c->cipher_name))
249                         || (cipher = EVP_CIPHER_fetch(NULL, c->cipher_name, NULL)))
250                         ret = omac_key(c, cipher, diversed_key, 32);
251                     EVP_CIPHER_free(cipher);
252                 }
253                 return ret;
254             }
255             GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_BAD_ORDER);
256             return 0;
257         }
258 #endif
259     default:
260         return 0;
261     }
262 }
263
264 static GOST_digest omac_template_digest = {
265     .input_blocksize = 8,
266     .app_datasize = sizeof(OMAC_CTX),
267     .flags = EVP_MD_FLAG_XOF,
268     .update = omac_imit_update,
269     .final = omac_imit_final,
270     .copy = omac_imit_copy,
271     .cleanup = omac_imit_cleanup,
272     .ctrl = omac_imit_ctrl,
273 };
274
275 GOST_digest magma_mac_digest = {
276     .nid = NID_magma_mac,
277     .template = &omac_template_digest,
278     .result_size = 8,
279     .init = magma_imit_init,
280 };
281
282 GOST_digest grasshopper_mac_digest = {
283     .nid = NID_grasshopper_mac,
284     .template = &omac_template_digest,
285     .result_size = 16,
286     .init = grasshopper_imit_init,
287 };