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