]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - test_context.c
MSVC: No support for GCC's compound statement expressions
[openssl-gost/engine.git] / test_context.c
1 /*
2  * Copyright (C) 2018,2020 Vitaly Chikunov <vt@altlinux.org> All Rights Reserved.
3  *
4  * Contents licensed under the terms of the OpenSSL license
5  * See https://www.openssl.org/source/license.html for details
6  */
7
8 #include <openssl/engine.h>
9 #include <openssl/evp.h>
10 #include <openssl/rand.h>
11 #include <openssl/err.h>
12 #include <openssl/asn1.h>
13 #include <string.h>
14 #ifndef EVP_MD_CTRL_SET_KEY
15 # include "gost_lcl.h"
16 #endif
17
18 #define T(e) \
19     if (!(e)) { \
20         ERR_print_errors_fp(stderr); \
21         OpenSSLDie(__FILE__, __LINE__, #e); \
22     }
23
24 #define cRED    "\033[1;31m"
25 #define cDRED   "\033[0;31m"
26 #define cGREEN  "\033[1;32m"
27 #define cDGREEN "\033[0;32m"
28 #define cBLUE   "\033[1;34m"
29 #define cDBLUE  "\033[0;34m"
30 #define cNORM   "\033[m"
31 #define TEST_ASSERT(e) {if ((test = (e))) \
32                  printf(cRED "  Test FAILED" cNORM "\n"); \
33              else \
34                  printf(cGREEN "  Test passed" cNORM "\n");}
35
36 static void hexdump(const void *ptr, size_t len)
37 {
38     const unsigned char *p = ptr;
39     size_t i, j;
40
41     for (i = 0; i < len; i += j) {
42         for (j = 0; j < 16 && i + j < len; j++)
43             printf("%s%02x", j? "" : " ", p[i + j]);
44     }
45     printf("\n");
46 }
47
48 #define TEST_SIZE 256
49 #define STEP_SIZE 16
50
51 static int test_contexts_cipher(const char *name, const int enc, int acpkm)
52 {
53     EVP_CIPHER_CTX *ctx, *save;
54     unsigned char pt[TEST_SIZE] = {1};
55     unsigned char b[TEST_SIZE]; /* base output */
56     unsigned char c[TEST_SIZE]; /* cloned output */
57     unsigned char K[32] = {1};
58     unsigned char iv[16] = {1};
59     int outlen, tmplen;
60     int ret = 0, test = 0;
61
62     EVP_CIPHER *type;
63     ERR_set_mark();
64     T((type = (EVP_CIPHER *)EVP_get_cipherbyname(name))
65       || (type = EVP_CIPHER_fetch(NULL, name, NULL)));
66     ERR_pop_to_mark();
67
68     printf(cBLUE "%s test for %s" cNORM "\n",
69            enc ? "Encryption" : "Decryption", name);
70
71     /* produce base encryption */
72     ctx = EVP_CIPHER_CTX_new();
73     T(ctx);
74     T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, enc));
75     if (acpkm) {
76         if (EVP_CIPHER_get0_provider(type) != NULL) {
77             OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END };
78             size_t v = (size_t)acpkm;
79
80             params[0] = OSSL_PARAM_construct_size_t("key-mesh", &v);
81             T(EVP_CIPHER_CTX_set_params(ctx, params));
82         } else {
83             T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL));
84         }
85     }
86     T(EVP_CIPHER_CTX_set_padding(ctx, 0));
87     T(EVP_CipherUpdate(ctx, b, &outlen, pt, sizeof(b)));
88     T(EVP_CipherFinal_ex(ctx, b + outlen, &tmplen));
89
90     /* and now tests */
91     EVP_CIPHER_CTX_reset(ctx);
92     EVP_CIPHER_CTX_reset(ctx); /* double call is intentional */
93     T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, enc));
94     T(EVP_CIPHER_CTX_set_padding(ctx, 0));
95     if (acpkm) {
96         if (EVP_CIPHER_get0_provider(type) != NULL) {
97             OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END };
98             size_t v = (size_t)acpkm;
99
100             params[0] = OSSL_PARAM_construct_size_t("key-mesh", &v);
101             T(EVP_CIPHER_CTX_set_params(ctx, params));
102         } else {
103             T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL));
104         }
105     }
106     save = ctx;
107
108     printf(" cloned contexts: ");
109     int i;
110     memset(c, 0, sizeof(c));
111     for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
112         EVP_CIPHER_CTX *copy = EVP_CIPHER_CTX_new();
113         T(copy);
114         T(EVP_CIPHER_CTX_copy(copy, ctx));
115         if (save != ctx) /* else original context */
116             EVP_CIPHER_CTX_free(ctx);
117         ctx = copy;
118
119         T(EVP_CipherUpdate(ctx, c + STEP_SIZE * i, &outlen,
120                            pt + STEP_SIZE * i, STEP_SIZE));
121     }
122
123     outlen = i * STEP_SIZE;
124     T(EVP_CipherFinal_ex(ctx, c + outlen, &tmplen));
125     TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, TEST_SIZE));
126     EVP_CIPHER_CTX_free(ctx);
127     if (test) {
128         printf("  b[%d] = ", outlen);
129         hexdump(b, outlen);
130         printf("  c[%d] = ", outlen);
131         hexdump(c, outlen);
132     }
133     ret |= test;
134
135     /* resume original context */
136     printf("    base context: ");
137     memset(c, 0, sizeof(c));
138     T(EVP_CipherUpdate(save, c, &outlen, pt, sizeof(c)));
139     T(EVP_CipherFinal_ex(save, c + outlen, &tmplen));
140     TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, TEST_SIZE));
141     EVP_CIPHER_CTX_cleanup(save); /* multiple calls are intentional */
142     EVP_CIPHER_CTX_cleanup(save);
143     EVP_CIPHER_CTX_free(save);
144     EVP_CIPHER_free(type);
145     if (test) {
146         printf("  b[%d] = ", outlen);
147         hexdump(b, outlen);
148         printf("  c[%d] = ", outlen);
149         hexdump(c, outlen);
150     }
151     ret |= test;
152
153     return ret;
154 }
155
156 static int test_contexts_digest_or_legacy_mac(const EVP_MD *type, int mac)
157 {
158     int ret = 0, test = 0;
159     unsigned char K[32] = {1};
160
161     /* produce base digest */
162     EVP_MD_CTX *ctx, *save;
163     unsigned char pt[TEST_SIZE] = {1};
164     unsigned char b[EVP_MAX_MD_SIZE] = {0};
165     unsigned char c[EVP_MAX_MD_SIZE];
166     unsigned int outlen, tmplen;
167
168     /* Simply digest whole input. */
169     T(ctx = EVP_MD_CTX_new());
170     T(EVP_DigestInit_ex(ctx, type, NULL));
171     if (mac)
172         T(EVP_MD_CTX_ctrl(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K));
173     T(EVP_DigestUpdate(ctx, pt, sizeof(pt)));
174     T(EVP_DigestFinal_ex(ctx, b, &tmplen));
175     save = ctx; /* will be not freed while cloning */
176
177     /* cloned digest */
178     EVP_MD_CTX_reset(ctx); /* test double reset */
179     EVP_MD_CTX_reset(ctx);
180     T(EVP_DigestInit_ex(ctx, type, NULL));
181     if (mac)
182         T(EVP_MD_CTX_ctrl(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K));
183     printf(" cloned contexts: ");
184     memset(c, 0, sizeof(c));
185     int i;
186     for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
187         /* Clone and continue digesting next part of input. */
188         EVP_MD_CTX *copy;
189         T(copy = EVP_MD_CTX_new());
190         T(EVP_MD_CTX_copy_ex(copy, ctx));
191
192         /* rolling */
193         if (save != ctx)
194             EVP_MD_CTX_free(ctx);
195         ctx = copy;
196
197         T(EVP_DigestUpdate(ctx, pt + STEP_SIZE * i, STEP_SIZE));
198     }
199     outlen = i * STEP_SIZE;
200     T(EVP_DigestFinal_ex(ctx, c, &tmplen));
201     /* Should be same as the simple digest. */
202     TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
203     EVP_MD_CTX_free(ctx);
204     if (test) {
205         printf("  b[%d] = ", outlen);
206         hexdump(b, outlen);
207         printf("  c[%d] = ", outlen);
208         hexdump(c, outlen);
209     }
210     ret |= test;
211
212     /* Resume original context, what if it's damaged? */
213     printf("    base context: ");
214     memset(c, 0, sizeof(c));
215     T(EVP_DigestUpdate(save, pt, sizeof(pt)));
216     T(EVP_DigestFinal_ex(save, c, &tmplen));
217     TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
218     EVP_MD_CTX_free(save);
219     if (test) {
220         printf("  b[%d] = ", outlen);
221         hexdump(b, outlen);
222         printf("  c[%d] = ", outlen);
223         hexdump(c, outlen);
224     }
225     ret |= test;
226
227     return ret;
228 }
229
230 static int test_contexts_digest(const char *name)
231 {
232     EVP_MD *type;
233     ERR_set_mark();
234     T((type = (EVP_MD *)EVP_get_digestbyname(name))
235       || (type = EVP_MD_fetch(NULL, name, NULL)));
236     ERR_pop_to_mark();
237
238     printf(cBLUE "Digest test for %s" cNORM "\n", name);
239     int ret = test_contexts_digest_or_legacy_mac(type, 0);
240     EVP_MD_free(type);
241     return ret;
242 }
243
244 static int test_contexts_mac(const char *name)
245 {
246     int ret = 0, test = 0;
247     unsigned char K[32] = {1};
248     const EVP_MD *type = EVP_get_digestbyname(name);
249     EVP_MAC *mac;
250
251     if (type) {
252         printf(cBLUE "Mac via EVP_MD test for %s" cNORM "\n", name);
253         return test_contexts_digest_or_legacy_mac(type, 1);
254     }
255
256     T(mac = EVP_MAC_fetch(NULL, name, NULL));
257     printf(cBLUE "Mac test for %s" cNORM "\n", name);
258
259     /* produce base mac */
260     EVP_MAC_CTX *ctx;
261     unsigned char pt[TEST_SIZE] = {1};
262     unsigned char b[EVP_MAX_MD_SIZE] = {0};
263     unsigned char c[EVP_MAX_MD_SIZE] = {0};
264     size_t outlen, tmplen;
265
266     /* Simply mac whole input. */
267     T(ctx = EVP_MAC_CTX_new(mac));
268     T(EVP_MAC_init(ctx, K, sizeof(K), NULL));
269     T(EVP_MAC_update(ctx, pt, sizeof(pt)));
270     T(EVP_MAC_final(ctx, b, &tmplen, sizeof(b)));
271     EVP_MAC_CTX_free(ctx);
272
273     /* Mac with rolling input. */
274     printf(" cloned contexts: ");
275     T(ctx = EVP_MAC_CTX_new(mac));
276     T(EVP_MAC_init(ctx, K, sizeof(K), NULL));
277     int i;
278     for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
279         T(EVP_MAC_update(ctx, pt + STEP_SIZE * i, STEP_SIZE));
280     }
281     outlen = i * STEP_SIZE;
282     T(EVP_MAC_final(ctx, c, &tmplen, sizeof(c)));
283     EVP_MAC_CTX_free(ctx);
284     EVP_MAC_free(mac);
285
286     /* Rolling mac should give the same result as the simple mac. */
287     TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
288
289     if (test) {
290         printf("  b[%d] = ", (int)outlen);
291         hexdump(b, outlen);
292         printf("  c[%d] = ", (int)outlen);
293         hexdump(c, outlen);
294     }
295     ret |= test;
296
297     return ret;
298 }
299
300 static struct testcase_cipher {
301     const char *name;
302     int acpkm;
303 } testcases_ciphers[] = {
304     { SN_id_Gost28147_89, },
305     { SN_gost89_cnt, },
306     { SN_gost89_cnt_12, },
307     { SN_gost89_cbc, },
308     { SN_grasshopper_ecb, },
309     { SN_grasshopper_cbc, },
310     { SN_grasshopper_cfb, },
311     { SN_grasshopper_ofb, },
312     { SN_grasshopper_ctr, },
313     { SN_magma_cbc, },
314     { SN_magma_ctr, },
315     { SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm, 256 / 8 },
316     { 0 },
317 };
318
319 static struct testcase_digest {
320     const char *name;
321     int mac;
322 } testcases_digests[] = {
323     { SN_id_GostR3411_94, },
324     { SN_id_Gost28147_89_MAC, 1 },
325     { SN_id_GostR3411_2012_256, },
326     { SN_id_GostR3411_2012_512, },
327     { SN_gost_mac_12, 1 },
328     { SN_magma_mac, 1 },
329     { SN_grasshopper_mac, 1 },
330     { SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac, 1 },
331     { 0 },
332 };
333 int main(int argc, char **argv)
334 {
335     int ret = 0;
336
337     OPENSSL_add_all_algorithms_conf();
338
339     const struct testcase_cipher *tc;
340     for (tc = testcases_ciphers; tc->name; tc++) {
341         ret |= test_contexts_cipher(tc->name, 1, tc->acpkm);
342         ret |= test_contexts_cipher(tc->name, 0, tc->acpkm);
343     }
344     const struct testcase_digest *td;
345     for (td = testcases_digests; td->name; td++) {
346         if (td->mac)
347             ret |= test_contexts_mac(td->name);
348         else
349             ret |= test_contexts_digest(td->name);
350     }
351
352     if (ret)
353         printf(cDRED "= Some tests FAILED!" cNORM "\n");
354     else
355         printf(cDGREEN "= All tests passed!" cNORM "\n");
356     return ret;
357 }