2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
8 * Copyright (C) 2021-2022 Selva Nair <selva.nair@gmail.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by the
12 * Free Software Foundation, either version 2 of the License,
13 * or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #elif defined(_MSC_VER)
28 #include "config-msvc.h"
34 #include "xkey_common.h"
36 #ifdef HAVE_XKEY_PROVIDER
40 #include <openssl/bio.h>
41 #include <openssl/pem.h>
42 #include <openssl/core_names.h>
43 #include <openssl/evp.h>
45 struct management
*management
; /* global */
46 static int mgmt_callback_called
;
49 #define _countof(x) sizeof((x))/sizeof(*(x))
52 static OSSL_PROVIDER
*prov
[2];
54 /* public keys for testing -- RSA and EC */
55 static const char *const pubkey1
= "-----BEGIN PUBLIC KEY-----\n"
56 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7GWP6RLCGlvmVioIqYI6\n"
57 "LUR4owA7sJ/nJxBAk+/xzD6gqgSigBsTqeb+gdZwkKjY1N4w2DUA0r5i8Eja/BWN\n"
58 "xMZtC5nxK4MACtMqIwvlzfk130NhFXKtlZj2cyFBXqDdRyeg1ZrUQagcHVcgcReP\n"
59 "9yiePgfO7NUOQk8edEeOR53SFCgnLBQQ9dGWtZN0hO/5BN6NSm/fd6vq0VjTRP5a\n"
60 "BAH/BnqX9/3jV0jh8N9AE59mI1rjVVQ9VDnuAPkS8dLfdC661/CNxt0YWByTIgt1\n"
61 "+qjW4LUvLbnU/rlPhuJ1SBZg+z/JtDBCKfs7syu5WYFqRvNFg7/91Rr/NwxvW/1h\n"
63 "-----END PUBLIC KEY-----\n";
65 static const char *const pubkey2
= "-----BEGIN PUBLIC KEY-----\n"
66 "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEO85iXW+HgnUkwlj1DohNVw0GsnGIh1gZ\n"
67 "u95ff1JiUaJIkYNIkZA+hwIPFVH5aJcSCv3SPIeDS2VUAESNKHZJBQ==\n"
68 "-----END PUBLIC KEY-----\n";
70 static const char *const pubkey3
= "-----BEGIN PUBLIC KEY-----\n"
71 "MCowBQYDK2VwAyEA+q5xjF5hGyyqYZidJdz/0saEQabL3N4wIZJBxNGbgJE=\n"
72 "-----END PUBLIC KEY-----";
74 static const char *pubkeys
[] = {pubkey1
, pubkey2
, pubkey3
};
76 static const char *prov_name
= "ovpn.xkey";
78 static const char *test_msg
= "Lorem ipsum dolor sit amet, consectetur "
79 "adipisici elit, sed eiusmod tempor incidunt "
80 "ut labore et dolore magna aliqua.";
82 static const char *test_msg_b64
=
83 "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2ljaS"
84 "BlbGl0LCBzZWQgZWl1c21vZCB0ZW1wb3IgaW5jaWR1bnQgdXQgbGFib3JlIGV0IGRv"
85 "bG9yZSBtYWduYSBhbGlxdWEu";
87 /* Sha256 digest of test_msg excluding NUL terminator */
88 static const uint8_t test_digest
[] = {
89 0x77, 0x38, 0x65, 0x00, 0x1e, 0x96, 0x48, 0xc6, 0x57, 0x0b, 0xae,
90 0xc0, 0xb7, 0x96, 0xf9, 0x66, 0x4d, 0x5f, 0xd0, 0xb7, 0xdb, 0xf3,
91 0x3a, 0xbf, 0x02, 0xcc, 0x78, 0x61, 0x83, 0x20, 0x20, 0xee
94 static const char *test_digest_b64
= "dzhlAB6WSMZXC67At5b5Zk1f0Lfb8zq/Asx4YYMgIO4=";
96 /* Dummy signature used only to check that the expected callback
97 * was successfully exercised. Keep this shorter than 64 bytes
98 * --- the smallest size of the actual signature with the above
101 static const uint8_t good_sig
[] = {
102 0xd8, 0xa7, 0xd9, 0x81, 0xd8, 0xaa, 0xd8, 0xad, 0x20, 0xd9, 0x8a, 0xd8,
103 0xa7, 0x20, 0xd8, 0xb3, 0xd9, 0x85, 0xd8, 0xb3, 0xd9, 0x85, 0x0
106 static const char *good_sig_b64
= "2KfZgdiq2K0g2YrYpyDYs9mF2LPZhQA=";
109 load_pubkey(const char *pem
)
111 BIO
*in
= BIO_new_mem_buf(pem
, -1);
114 EVP_PKEY
*pkey
= PEM_read_bio_PUBKEY(in
, NULL
, NULL
, NULL
);
115 assert_non_null(pkey
);
124 prov
[0] = OSSL_PROVIDER_load(NULL
, "default");
125 OSSL_PROVIDER_add_builtin(NULL
, prov_name
, xkey_provider_init
);
126 prov
[1] = OSSL_PROVIDER_load(NULL
, prov_name
);
128 /* set default propq matching what we use in ssl_openssl.c */
129 EVP_set_default_properties(NULL
, "?provider!=ovpn.xkey");
131 #ifdef ENABLE_MANAGEMENT
132 management
= test_calloc(sizeof(*management
), 1);
139 for (size_t i
= 0; i
< _countof(prov
); i
++)
143 OSSL_PROVIDER_unload(prov
[i
]);
146 test_free(management
);
149 /* Mock management callback for signature.
150 * We check that the received data to sign matches test_msg or
151 * test_digest and return a predefined string as signature so that
152 * the caller can validate all steps up to sending the data to
153 * the management client.
156 management_query_pk_sig(struct management
*man
, const char *b64_data
,
157 const char *algorithm
)
161 /* indicate entry to the callback */
162 mgmt_callback_called
= 1;
164 const char *expected_tbs
= test_digest_b64
;
165 if (strstr(algorithm
, "data=message"))
167 expected_tbs
= test_msg_b64
;
168 /* ED25519 does not have a hash algorithm even though it goes via
169 * the DigestSign path (data=message) */
170 if (!strstr(algorithm
, "ED25519"))
172 assert_non_null(strstr(algorithm
, "hashalg=SHA256"));
175 assert_string_equal(b64_data
, expected_tbs
);
177 /* We test using ED25519, ECDSA or PSS with saltlen = digest */
178 if (!strstr(algorithm
, "ECDSA") && !strstr(algorithm
, "ED25519"))
180 assert_non_null(strstr(algorithm
, "RSA_PKCS1_PSS_PADDING,hashalg=SHA256,saltlen=digest"));
183 /* Return a predefined string as sig so that the caller
184 * can confirm that this callback was exercised.
186 out
= strdup(good_sig_b64
);
187 assert_non_null(out
);
192 /* Check signature and keymgmt methods can be fetched from the provider */
194 xkey_provider_test_fetch(void **state
)
196 assert_true(OSSL_PROVIDER_available(NULL
, prov_name
));
198 const char *algs
[] = {"RSA", "ECDSA"};
200 for (size_t i
= 0; i
< _countof(algs
); i
++)
202 EVP_SIGNATURE
*sig
= EVP_SIGNATURE_fetch(NULL
, algs
[i
], "provider=ovpn.xkey");
203 assert_non_null(sig
);
204 assert_string_equal(OSSL_PROVIDER_get0_name(EVP_SIGNATURE_get0_provider(sig
)), prov_name
);
206 EVP_SIGNATURE_free(sig
);
209 const char *names
[] = {"RSA", "EC"};
211 for (size_t i
= 0; i
< _countof(names
); i
++)
213 EVP_KEYMGMT
*km
= EVP_KEYMGMT_fetch(NULL
, names
[i
], "provider=ovpn.xkey");
215 assert_string_equal(OSSL_PROVIDER_get0_name(EVP_KEYMGMT_get0_provider(km
)), prov_name
);
217 EVP_KEYMGMT_free(km
);
221 /* sign a test message using pkey -- caller must free the returned sig */
223 digest_sign(EVP_PKEY
*pkey
)
228 OSSL_PARAM params
[6] = {OSSL_PARAM_END
};
230 const char *mdname
= "SHA256";
231 const char *padmode
= "pss";
232 const char *saltlen
= "digest";
234 if (EVP_PKEY_get_id(pkey
) == EVP_PKEY_RSA
)
236 params
[0] = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST
, (char *)mdname
, 0);
237 params
[1] = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE
, (char *)padmode
, 0);
238 params
[2] = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN
, (char *)saltlen
, 0);
239 /* same digest for mgf1 */
240 params
[3] = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST
, (char *)saltlen
, 0);
241 params
[4] = OSSL_PARAM_construct_end();
243 else if (EVP_PKEY_get_id(pkey
) == EVP_PKEY_ED25519
)
246 params
[0] = OSSL_PARAM_construct_end();
250 EVP_PKEY_CTX
*pctx
= NULL
;
251 EVP_MD_CTX
*mctx
= EVP_MD_CTX_new();
254 || EVP_DigestSignInit_ex(mctx
, &pctx
, mdname
, NULL
, NULL
, pkey
, params
) <= 0)
256 fail_msg("Failed to initialize EVP_DigestSignInit_ex()");
260 /* sign with sig = NULL to get required siglen */
261 assert_int_equal(EVP_DigestSign(mctx
, sig
, &siglen
, (uint8_t *)test_msg
, strlen(test_msg
)), 1);
262 assert_true(siglen
> 0);
264 if ((sig
= test_calloc(1, siglen
)) == NULL
)
266 fail_msg("Out of memory");
268 assert_int_equal(EVP_DigestSign(mctx
, sig
, &siglen
, (uint8_t *)test_msg
, strlen(test_msg
)), 1);
273 EVP_MD_CTX_free(mctx
); /* pctx is internally allocated and freed by mctx */
278 #ifdef ENABLE_MANAGEMENT
279 /* Check loading of management external key and have sign callback exercised
280 * for RSA and EC keys with and without digest support in management client.
281 * Sha256 digest used for both cases with pss padding for RSA.
284 xkey_provider_test_mgmt_sign_cb(void **state
)
287 for (size_t i
= 0; i
< _countof(pubkeys
); i
++)
289 pubkey
= load_pubkey(pubkeys
[i
]);
290 assert_true(pubkey
!= NULL
);
291 EVP_PKEY
*privkey
= xkey_load_management_key(NULL
, pubkey
);
292 assert_true(privkey
!= NULL
);
294 management
->settings
.flags
= MF_EXTERNAL_KEY
|MF_EXTERNAL_KEY_PSSPAD
;
296 /* first without digest support in management client */
298 mgmt_callback_called
= 0;
299 uint8_t *sig
= digest_sign(privkey
);
300 assert_non_null(sig
);
302 /* check callback for signature got exercised */
303 assert_int_equal(mgmt_callback_called
, 1);
304 assert_memory_equal(sig
, good_sig
, sizeof(good_sig
));
307 if (!(management
->settings
.flags
& MF_EXTERNAL_KEY_DIGEST
))
309 management
->settings
.flags
|= MF_EXTERNAL_KEY_DIGEST
;
310 goto again
; /* this time with digest support announced */
313 EVP_PKEY_free(pubkey
);
314 EVP_PKEY_free(privkey
);
317 #endif /* ifdef ENABLE_MANAGEMENT */
319 /* helpers for testing generic key load and sign */
320 static int xkey_free_called
;
321 static int xkey_sign_called
;
323 xkey_free(void *handle
)
325 xkey_free_called
= 1;
326 /* We use a dummy string as handle -- check its value */
327 assert_string_equal(handle
, "xkey_handle");
331 xkey_sign(void *handle
, unsigned char *sig
, size_t *siglen
,
332 const unsigned char *tbs
, size_t tbslen
, XKEY_SIGALG s
)
336 *siglen
= 256; /* some arbitrary size */
340 xkey_sign_called
= 1; /* called with non-null sig */
342 if (!strcmp(s
.op
, "DigestSign"))
344 assert_memory_equal(tbs
, test_msg
, strlen(test_msg
));
348 assert_memory_equal(tbs
, test_digest
, sizeof(test_digest
));
351 /* For the test use sha256 and PSS padding for RSA and none for EDDSA */
352 if (!strcmp(s
.keytype
, "ED25519"))
354 assert_string_equal(s
.mdname
, "none");
358 assert_int_equal(OBJ_sn2nid(s
.mdname
), NID_sha256
);
360 if (!strcmp(s
.keytype
, "RSA"))
362 assert_string_equal(s
.padmode
, "pss"); /* we use PSS for the test */
364 else if (strcmp(s
.keytype
, "EC") && strcmp(s
.keytype
, "ED25519"))
366 fail_msg("Unknown keytype: %s", s
.keytype
);
369 /* return a predefined string as sig */
370 memcpy(sig
, good_sig
, min_int(sizeof(good_sig
), *siglen
));
375 /* Load a key as a generic key and check its sign op gets
376 * called for signature.
379 xkey_provider_test_generic_sign_cb(void **state
)
382 const char *dummy
= "xkey_handle"; /* a dummy handle for the external key */
384 for (size_t i
= 0; i
< _countof(pubkeys
); i
++)
386 pubkey
= load_pubkey(pubkeys
[i
]);
387 assert_true(pubkey
!= NULL
);
389 EVP_PKEY
*privkey
= xkey_load_generic_key(NULL
, (void *)dummy
, pubkey
, xkey_sign
, xkey_free
);
390 assert_true(privkey
!= NULL
);
392 xkey_sign_called
= 0;
393 xkey_free_called
= 0;
394 uint8_t *sig
= digest_sign(privkey
);
395 assert_non_null(sig
);
397 /* check callback for signature got exercised */
398 assert_int_equal(xkey_sign_called
, 1);
399 assert_memory_equal(sig
, good_sig
, sizeof(good_sig
));
402 EVP_PKEY_free(pubkey
);
403 EVP_PKEY_free(privkey
);
405 /* check key's free-op got called */
406 assert_int_equal(xkey_free_called
, 1);
415 const struct CMUnitTest tests
[] = {
416 cmocka_unit_test(xkey_provider_test_fetch
),
417 #ifdef ENABLE_MANAGEMENT
418 cmocka_unit_test(xkey_provider_test_mgmt_sign_cb
),
420 cmocka_unit_test(xkey_provider_test_generic_sign_cb
),
423 int ret
= cmocka_run_group_tests_name("xkey provider tests", tests
, NULL
, NULL
);
428 #else /* ifdef HAVE_XKEY_PROVIDER */
434 #endif /* HAVE_XKEY_PROVIDER */