Implement the ECX Serializers
[openssl.git] / test / evp_pkey_provided_test.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 #include <openssl/evp.h>
11 #include <openssl/pem.h>
12 #include <openssl/serializer.h>
13 #include <openssl/provider.h>
14 #include <openssl/params.h>
15 #include <openssl/core_names.h>
16 #include "crypto/ecx.h"
17 #include "internal/nelem.h"
18 #include "crypto/evp.h"          /* For the internal API */
19 #include "testutil.h"
20
21 static char *datadir = NULL;
22
23 #define PRIV_TEXT    0
24 #define PRIV_PEM     1
25 #define PRIV_DER     2
26 #define PUB_TEXT     3
27 #define PUB_PEM      4
28 #define PUB_DER      5
29
30 static void stripcr(char *buf, size_t *len)
31 {
32     size_t i;
33     char *curr, *writ;
34
35     for (i = *len, curr = buf, writ = buf; i > 0; i--, curr++) {
36         if (*curr == '\r') {
37             (*len)--;
38             continue;
39         }
40         if (curr != writ)
41             *writ = *curr;
42         writ++;
43     }
44 }
45
46 static int compare_with_file(const char *alg, int type, BIO *membio)
47 {
48     char filename[80];
49     BIO *file = NULL;
50     char buf[1024];
51     char *memdata, *fullfile = NULL;
52     const char *suffix;
53     size_t readbytes;
54     int ret = 0;
55     int len;
56     size_t slen;
57
58     switch (type) {
59     case PRIV_TEXT:
60         suffix = "priv.txt";
61         break;
62
63     case PRIV_PEM:
64         suffix = "priv.pem";
65         break;
66
67     case PRIV_DER:
68         suffix = "priv.der";
69         break;
70
71     case PUB_TEXT:
72         suffix = "pub.txt";
73         break;
74
75     case PUB_PEM:
76         suffix = "pub.pem";
77         break;
78
79     case PUB_DER:
80         suffix = "pub.der";
81         break;
82
83     default:
84         TEST_error("Invalid file type");
85         goto err;
86     }
87
88     BIO_snprintf(filename, sizeof(filename), "%s.%s", alg, suffix);
89     fullfile = test_mk_file_path(datadir, filename);
90     if (!TEST_ptr(fullfile))
91         goto err;
92
93     file = BIO_new_file(fullfile, "rb");
94     if (!TEST_ptr(file))
95         goto err;
96
97     if (!TEST_true(BIO_read_ex(file, buf, sizeof(buf), &readbytes))
98             || !TEST_true(BIO_eof(file))
99             || !TEST_size_t_lt(readbytes, sizeof(buf)))
100         goto err;
101
102     len = BIO_get_mem_data(membio, &memdata);
103     if (!TEST_int_gt(len, 0))
104         goto err;
105
106     slen = len;
107     if (type != PRIV_DER && type != PUB_DER) {
108         stripcr(memdata, &slen);
109         stripcr(buf, &readbytes);
110     }
111
112     if (!TEST_mem_eq(memdata, slen, buf, readbytes))
113         goto err;
114
115     ret = 1;
116  err:
117     OPENSSL_free(fullfile);
118     (void)BIO_reset(membio);
119     BIO_free(file);
120     return ret;
121 }
122
123 static int test_print_key_using_pem(const char *alg, const EVP_PKEY *pk)
124 {
125     BIO *membio = BIO_new(BIO_s_mem());
126     int ret = 0;
127
128     if (!TEST_ptr(membio))
129         goto err;
130
131     if (!TEST_true(EVP_PKEY_print_private(membio, pk, 0, NULL))
132         || !TEST_true(compare_with_file(alg, PRIV_TEXT, membio))
133         /* Public key in PEM form */
134         || !TEST_true(PEM_write_bio_PUBKEY(membio, pk))
135         || !TEST_true(compare_with_file(alg, PUB_PEM, membio))
136         /* Unencrypted private key in PEM form */
137         || !TEST_true(PEM_write_bio_PrivateKey(membio, pk,
138                                                NULL, NULL, 0, NULL, NULL))
139         || !TEST_true(compare_with_file(alg, PRIV_PEM, membio))
140         /* Encrypted private key in PEM form */
141         || !TEST_true(PEM_write_bio_PrivateKey(bio_out, pk, EVP_aes_256_cbc(),
142                                                (unsigned char *)"pass", 4,
143                                                NULL, NULL)))
144         goto err;
145
146     ret = 1;
147  err:
148     BIO_free(membio);
149     return ret;
150 }
151
152 static int test_print_key_type_using_serializer(const char *alg, int type,
153                                                 const EVP_PKEY *pk)
154 {
155     const char *pq;
156     OSSL_SERIALIZER_CTX *ctx = NULL;
157     BIO *membio = BIO_new(BIO_s_mem());
158     int ret = 1;
159
160     switch (type) {
161     case PRIV_TEXT:
162         pq = OSSL_SERIALIZER_PrivateKey_TO_TEXT_PQ;
163         break;
164
165     case PRIV_PEM:
166         pq = OSSL_SERIALIZER_PrivateKey_TO_PEM_PQ;
167         break;
168
169     case PRIV_DER:
170         pq = OSSL_SERIALIZER_PrivateKey_TO_DER_PQ;
171         break;
172
173     case PUB_TEXT:
174         pq = OSSL_SERIALIZER_PUBKEY_TO_TEXT_PQ;
175         break;
176
177     case PUB_PEM:
178         pq = OSSL_SERIALIZER_PUBKEY_TO_PEM_PQ;
179         break;
180
181     case PUB_DER:
182         pq = OSSL_SERIALIZER_PUBKEY_TO_DER_PQ;
183         break;
184
185     default:
186         TEST_error("Invalid serialization type");
187         goto err;
188     }
189
190     if (!TEST_ptr(membio)) {
191         ret = 0;
192         goto err;
193     }
194
195     /* Make a context, it's valid for several prints */
196     TEST_note("Setting up a OSSL_SERIALIZER context with passphrase");
197     if (!TEST_ptr(ctx = OSSL_SERIALIZER_CTX_new_by_EVP_PKEY(pk, pq))
198         /* Check that this operation is supported */
199         || !TEST_ptr(OSSL_SERIALIZER_CTX_get_serializer(ctx)))
200         goto err;
201
202     /* Use no cipher.  This should give us an unencrypted PEM */
203     TEST_note("Testing with no encryption");
204     if (!TEST_true(OSSL_SERIALIZER_to_bio(ctx, membio))
205         || !TEST_true(compare_with_file(alg, type, membio)))
206         ret = 0;
207
208     if (type == PRIV_PEM) {
209         /* Set a passphrase to be used later */
210         if (!TEST_true(OSSL_SERIALIZER_CTX_set_passphrase(ctx,
211                                                           (unsigned char *)"pass",
212                                                           4)))
213             goto err;
214
215         /* Use a valid cipher name */
216         TEST_note("Displaying PEM encrypted with AES-256-CBC");
217         if (!TEST_true(OSSL_SERIALIZER_CTX_set_cipher(ctx, "AES-256-CBC", NULL))
218             || !TEST_true(OSSL_SERIALIZER_to_bio(ctx, bio_out)))
219             ret = 0;
220
221         /* Use an invalid cipher name, which should generate no output */
222         TEST_note("NOT Displaying PEM encrypted with (invalid) FOO");
223         if (!TEST_false(OSSL_SERIALIZER_CTX_set_cipher(ctx, "FOO", NULL))
224             || !TEST_false(OSSL_SERIALIZER_to_bio(ctx, bio_out)))
225             ret = 0;
226
227         /* Clear the cipher.  This should give us an unencrypted PEM again */
228         TEST_note("Testing with encryption cleared (no encryption)");
229         if (!TEST_true(OSSL_SERIALIZER_CTX_set_cipher(ctx, NULL, NULL))
230             || !TEST_true(OSSL_SERIALIZER_to_bio(ctx, membio))
231             || !TEST_true(compare_with_file(alg, type, membio)))
232             ret = 0;
233     }
234
235 err:
236     BIO_free(membio);
237     OSSL_SERIALIZER_CTX_free(ctx);
238     return ret;
239 }
240
241 static int test_print_key_using_serializer(const char *alg, const EVP_PKEY *pk)
242 {
243     int i;
244     int ret = 1;
245
246     for (i = 0; i < 6; i++)
247         ret = ret && test_print_key_type_using_serializer(alg, i, pk);
248
249     return ret;
250 }
251
252 /* Array indexes used in test_fromdata_rsa */
253 #define N       0
254 #define E       1
255 #define D       2
256 #define P       3
257 #define Q       4
258 #define DP      5
259 #define DQ      6
260 #define QINV    7
261
262 static int test_fromdata_rsa(void)
263 {
264     int ret = 0;
265     EVP_PKEY_CTX *ctx = NULL, *key_ctx = NULL;
266     EVP_PKEY *pk = NULL;
267     /*
268      * 32-bit RSA key, extracted from this command,
269      * executed with OpenSSL 1.0.2:
270      *
271      * openssl genrsa 32 | openssl rsa -text
272      */
273     static unsigned long key_numbers[] = {
274         0xbc747fc5,              /* N */
275         0x10001,                 /* E */
276         0x7b133399,              /* D */
277         0xe963,                  /* P */
278         0xceb7,                  /* Q */
279         0x8599,                  /* DP */
280         0xbd87,                  /* DQ */
281         0xcc3b,                  /* QINV */
282     };
283     OSSL_PARAM fromdata_params[] = {
284         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_N, &key_numbers[N]),
285         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_E, &key_numbers[E]),
286         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_D, &key_numbers[D]),
287         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_FACTOR, &key_numbers[P]),
288         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_FACTOR, &key_numbers[Q]),
289         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_EXPONENT, &key_numbers[DP]),
290         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_EXPONENT, &key_numbers[DQ]),
291         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_COEFFICIENT, &key_numbers[QINV]),
292         OSSL_PARAM_END
293     };
294
295     if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)))
296         goto err;
297
298     if (!TEST_true(EVP_PKEY_key_fromdata_init(ctx))
299         || !TEST_true(EVP_PKEY_fromdata(ctx, &pk, fromdata_params))
300         || !TEST_int_eq(EVP_PKEY_bits(pk), 32)
301         || !TEST_int_eq(EVP_PKEY_security_bits(pk), 8)
302         || !TEST_int_eq(EVP_PKEY_size(pk), 4))
303         goto err;
304
305     if (!TEST_ptr(key_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pk, "")))
306         goto err;
307
308     if (!TEST_true(EVP_PKEY_check(key_ctx))
309         || !TEST_true(EVP_PKEY_public_check(key_ctx))
310         || !TEST_true(EVP_PKEY_private_check(key_ctx))
311         || !TEST_true(EVP_PKEY_pairwise_check(key_ctx)))
312         goto err;
313
314     ret = test_print_key_using_pem("RSA", pk)
315           && test_print_key_using_serializer("RSA", pk);
316
317  err:
318     EVP_PKEY_free(pk);
319     EVP_PKEY_CTX_free(key_ctx);
320     EVP_PKEY_CTX_free(ctx);
321
322     return ret;
323 }
324
325 #ifndef OPENSSL_NO_DH
326 /* Array indexes used in test_fromdata_dh */
327 #define PRIV_KEY        0
328 #define PUB_KEY         1
329 #define FFC_P           2
330 #define FFC_G           3
331
332 static int test_fromdata_dh(void)
333 {
334     int ret = 0;
335     EVP_PKEY_CTX *ctx = NULL;
336     EVP_PKEY *pk = NULL;
337     /*
338      * 32-bit DH key, extracted from this command,
339      * executed with OpenSSL 1.0.2:
340      *
341      * openssl dhparam -out dhp.pem 32
342      * openssl genpkey -paramfile dhp.pem | openssl pkey -text
343      */
344     static unsigned long key_numbers[] = {
345         0x666c2b06,              /* priv-key */
346         0x6fa6de50,              /* pub-key */
347         0x8bb45f53,              /* P */
348         0x2,                     /* G */
349     };
350     OSSL_PARAM fromdata_params[] = {
351         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_PRIV_KEY, &key_numbers[PRIV_KEY]),
352         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_PUB_KEY, &key_numbers[PUB_KEY]),
353         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_FFC_P, &key_numbers[FFC_P]),
354         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_FFC_G, &key_numbers[FFC_G]),
355         OSSL_PARAM_END
356     };
357
358     if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)))
359         goto err;
360
361     if (!TEST_true(EVP_PKEY_key_fromdata_init(ctx))
362         || !TEST_true(EVP_PKEY_fromdata(ctx, &pk, fromdata_params))
363         || !TEST_int_eq(EVP_PKEY_bits(pk), 32)
364         || !TEST_int_eq(EVP_PKEY_security_bits(pk), 0) /* Missing Q */
365         || !TEST_int_eq(EVP_PKEY_size(pk), 4))
366         goto err;
367
368     ret = test_print_key_using_pem("DH", pk)
369           && test_print_key_using_serializer("DH", pk);
370
371  err:
372     EVP_PKEY_free(pk);
373     EVP_PKEY_CTX_free(ctx);
374
375     return ret;
376 }
377 #endif
378
379 #ifndef OPENSSL_NO_EC
380 /* Array indexes used in test_fromdata_ecx */
381 # define PRIV_KEY        0
382 # define PUB_KEY         1
383
384 # define X25519_IDX      0
385 # define X448_IDX        1
386
387 static int test_fromdata_ecx(int tst)
388 {
389     int ret = 0;
390     EVP_PKEY_CTX *ctx = NULL;
391     EVP_PKEY *pk = NULL;
392     const char *alg = (tst == X25519_IDX) ? "X25519" : "X448";
393
394     /* X448_KEYLEN > X25519_KEYLEN */
395     static unsigned char key_numbers[2][2][X448_KEYLEN] = {
396         /* X25519: Keys from RFC 7748 6.1 */
397         {
398             /* Private Key */
399             {
400                 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16,
401                 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87,
402                 0xeb, 0xc0, 0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9,
403                 0x2c, 0x2a
404             },
405             /* Public Key */
406             {
407                 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b,
408                 0x7d, 0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d,
409                 0x26, 0x38, 0x1a, 0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b,
410                 0x4e, 0x6a
411             }
412         },
413         /* X448: Keys from RFC 7748 6.2 */
414         {
415             /* Private Key */
416             {
417                 0x9a, 0x8f, 0x49, 0x25, 0xd1, 0x51, 0x9f, 0x57, 0x75, 0xcf,
418                 0x46, 0xb0, 0x4b, 0x58, 0x00, 0xd4, 0xee, 0x9e, 0xe8, 0xba,
419                 0xe8, 0xbc, 0x55, 0x65, 0xd4, 0x98, 0xc2, 0x8d, 0xd9, 0xc9,
420                 0xba, 0xf5, 0x74, 0xa9, 0x41, 0x97, 0x44, 0x89, 0x73, 0x91,
421                 0x00, 0x63, 0x82, 0xa6, 0xf1, 0x27, 0xab, 0x1d, 0x9a, 0xc2,
422                 0xd8, 0xc0, 0xa5, 0x98, 0x72, 0x6b
423             },
424             /* Public Key */
425             {
426                 0x9b, 0x08, 0xf7, 0xcc, 0x31, 0xb7, 0xe3, 0xe6, 0x7d, 0x22,
427                 0xd5, 0xae, 0xa1, 0x21, 0x07, 0x4a, 0x27, 0x3b, 0xd2, 0xb8,
428                 0x3d, 0xe0, 0x9c, 0x63, 0xfa, 0xa7, 0x3d, 0x2c, 0x22, 0xc5,
429                 0xd9, 0xbb, 0xc8, 0x36, 0x64, 0x72, 0x41, 0xd9, 0x53, 0xd4,
430                 0x0c, 0x5b, 0x12, 0xda, 0x88, 0x12, 0x0d, 0x53, 0x17, 0x7f,
431                 0x80, 0xe5, 0x32, 0xc4, 0x1f, 0xa0
432             }
433         }
434     };
435     OSSL_PARAM x25519_fromdata_params[] = {
436         OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY,
437                                 key_numbers[X25519_IDX][PRIV_KEY],
438                                 X25519_KEYLEN),
439         OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
440                                 key_numbers[X25519_IDX][PUB_KEY],
441                                 X25519_KEYLEN),
442         OSSL_PARAM_END
443     };
444     OSSL_PARAM x448_fromdata_params[] = {
445         OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY,
446                                 key_numbers[X448_IDX][PRIV_KEY],
447                                 X448_KEYLEN),
448         OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
449                                 key_numbers[X448_IDX][PUB_KEY],
450                                 X448_KEYLEN),
451         OSSL_PARAM_END
452     };
453     OSSL_PARAM *fromdata_params;
454     int bits, security_bits, size;
455
456     if (tst == X25519_IDX) {
457         fromdata_params = x25519_fromdata_params;
458         bits = X25519_BITS;
459         security_bits = X25519_SECURITY_BITS;
460         size = X25519_KEYLEN;
461     } else {
462         fromdata_params = x448_fromdata_params;
463         bits = X448_BITS;
464         security_bits = X448_SECURITY_BITS;
465         size = X448_KEYLEN;
466     }
467
468     ctx = EVP_PKEY_CTX_new_from_name(NULL, alg, NULL);
469     if (!TEST_ptr(ctx))
470         goto err;
471
472     if (!TEST_true(EVP_PKEY_key_fromdata_init(ctx))
473         || !TEST_true(EVP_PKEY_fromdata(ctx, &pk, fromdata_params))
474         || !TEST_int_eq(EVP_PKEY_bits(pk), bits)
475         || !TEST_int_eq(EVP_PKEY_security_bits(pk), security_bits)
476         || !TEST_int_eq(EVP_PKEY_size(pk), size))
477         goto err;
478
479     ret = test_print_key_using_pem(alg, pk)
480           && test_print_key_using_serializer(alg, pk);
481
482  err:
483     EVP_PKEY_free(pk);
484     EVP_PKEY_CTX_free(ctx);
485
486     return ret;
487 }
488 #endif
489
490
491 int setup_tests(void)
492 {
493     if (!test_skip_common_options()) {
494         TEST_error("Error parsing test options\n");
495         return 0;
496     }
497
498     if (!TEST_ptr(datadir = test_get_argument(0)))
499         return 0;
500
501     ADD_TEST(test_fromdata_rsa);
502 #ifndef OPENSSL_NO_DH
503     ADD_TEST(test_fromdata_dh);
504 #endif
505 #ifndef OPENSSL_NO_EC
506     ADD_ALL_TESTS(test_fromdata_ecx, 2);
507 #endif
508     return 1;
509 }