OpenVPN
xkey_provider.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2021-2025 Selva Nair <selva.nair@gmail.com>
9 *
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.
14 *
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.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, see <https://www.gnu.org/licenses/>.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include "syshead.h"
29#include "error.h"
30#include "buffer.h"
31#include "xkey_common.h"
32
33#ifdef HAVE_XKEY_PROVIDER
34
35#include <openssl/provider.h>
36#include <openssl/params.h>
37#include <openssl/core_dispatch.h>
38#include <openssl/core_object.h>
39#include <openssl/core_names.h>
40#include <openssl/store.h>
41#include <openssl/evp.h>
42#include <openssl/err.h>
43
44/* A descriptive name */
45static const char *provname = "OpenVPN External Key Provider";
46
47typedef struct
48{
49 OSSL_LIB_CTX *libctx;
50} XKEY_PROVIDER_CTX;
51
52/* helper to print debug messages */
53#define xkey_dmsg(f, ...) \
54 do \
55 { \
56 dmsg(f | M_NOLF, "xkey_provider: In %s: ", __func__); \
57 dmsg(f | M_NOPREFIX, __VA_ARGS__); \
58 } while (0)
59
60typedef enum
61{
62 ORIGIN_UNDEFINED = 0,
63 OPENSSL_NATIVE, /* native key imported in */
64 EXTERNAL_KEY
65} XKEY_ORIGIN;
66
84typedef struct
85{
87 void *handle;
89 EVP_PKEY *pubkey;
91 XKEY_ORIGIN origin;
93 XKEY_EXTERNAL_SIGN_fn *sign;
95 XKEY_PRIVKEY_FREE_fn *free;
96 XKEY_PROVIDER_CTX *prov;
97 int refcount;
98} XKEY_KEYDATA;
99
100static inline const char *
101get_keytype(const XKEY_KEYDATA *key)
102{
103 int keytype = key->pubkey ? EVP_PKEY_get_id(key->pubkey) : 0;
104
105 switch (keytype)
106 {
107 case EVP_PKEY_RSA:
108 return "RSA";
109
110 case EVP_PKEY_ED448:
111 return "ED448";
112
113 case EVP_PKEY_ED25519:
114 return "ED25519";
115
116 default:
117 return "EC";
118 }
119}
120
121
122static int
123KEYSIZE(const XKEY_KEYDATA *key)
124{
125 return key->pubkey ? EVP_PKEY_get_size(key->pubkey) : 0;
126}
127
132int xkey_native_sign(XKEY_KEYDATA *key, unsigned char *sig, size_t *siglen,
133 const unsigned char *tbs, size_t tbslen, XKEY_SIGALG sigalg);
134
135
136/* keymgmt provider */
137
138/* keymgmt callbacks we implement */
139static OSSL_FUNC_keymgmt_new_fn keymgmt_new;
140static OSSL_FUNC_keymgmt_free_fn keymgmt_free;
141static OSSL_FUNC_keymgmt_load_fn keymgmt_load;
142static OSSL_FUNC_keymgmt_has_fn keymgmt_has;
143static OSSL_FUNC_keymgmt_match_fn keymgmt_match;
144static OSSL_FUNC_keymgmt_import_fn rsa_keymgmt_import;
145static OSSL_FUNC_keymgmt_import_fn ec_keymgmt_import;
146static OSSL_FUNC_keymgmt_import_types_fn keymgmt_import_types;
147static OSSL_FUNC_keymgmt_get_params_fn keymgmt_get_params;
148static OSSL_FUNC_keymgmt_gettable_params_fn keymgmt_gettable_params;
149static OSSL_FUNC_keymgmt_set_params_fn keymgmt_set_params;
150static OSSL_FUNC_keymgmt_query_operation_name_fn rsa_keymgmt_name;
151static OSSL_FUNC_keymgmt_query_operation_name_fn ec_keymgmt_name;
152
153static int keymgmt_import_helper(XKEY_KEYDATA *key, const OSSL_PARAM params[]);
154
155static XKEY_KEYDATA *
156keydata_new(void)
157{
158 xkey_dmsg(D_XKEY, "entry");
159
160 XKEY_KEYDATA *key = OPENSSL_zalloc(sizeof(*key));
161 if (!key)
162 {
163 msg(M_NONFATAL, "xkey_keydata_new: out of memory");
164 }
165
166 return key;
167}
168
169static void
170keydata_free(XKEY_KEYDATA *key)
171{
172 xkey_dmsg(D_XKEY, "entry");
173
174 if (!key || key->refcount-- > 0) /* free when refcount goes to zero */
175 {
176 return;
177 }
178 if (key->free && key->handle)
179 {
180 key->free(key->handle);
181 key->handle = NULL;
182 }
183 if (key->pubkey)
184 {
185 EVP_PKEY_free(key->pubkey);
186 }
187 OPENSSL_free(key);
188}
189
190static void *
191keymgmt_new(void *provctx)
192{
193 xkey_dmsg(D_XKEY, "entry");
194
195 XKEY_KEYDATA *key = keydata_new();
196 if (key)
197 {
198 key->prov = provctx;
199 }
200
201 return key;
202}
203
204static void *
205keymgmt_load(const void *reference, size_t reference_sz)
206{
207 xkey_dmsg(D_XKEY, "entry");
208
209 return NULL;
210}
211
244static int
245keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[], const char *name)
246{
247 xkey_dmsg(D_XKEY, "entry");
248
249 XKEY_KEYDATA *key = keydata;
250 ASSERT(key);
251
252 /* Our private key is immutable -- we import only if keydata is empty */
253 if (key->handle || key->pubkey)
254 {
255 msg(M_WARN, "Error: keymgmt_import: keydata not empty -- our keys are immutable");
256 return 0;
257 }
258
259 /* if params contain a custom origin, call our helper to import custom keys */
260 const OSSL_PARAM *p = OSSL_PARAM_locate_const(params, "xkey-origin");
261 if (p && p->data_type == OSSL_PARAM_UTF8_STRING)
262 {
263 key->origin = EXTERNAL_KEY;
264 xkey_dmsg(D_XKEY, "importing external key");
265 return keymgmt_import_helper(key, params);
266 }
267
268 xkey_dmsg(D_XKEY, "importing native key");
269
270 /* create a native public key and assign it to key->pubkey */
271 EVP_PKEY *pkey = NULL;
272 int selection_pub = selection & ~OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
273
274 EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(key->prov->libctx, name, NULL);
275 if (!ctx || (EVP_PKEY_fromdata_init(ctx) != 1)
276 || (EVP_PKEY_fromdata(ctx, &pkey, selection_pub, (OSSL_PARAM *)params) != 1))
277 {
278 msg(M_WARN, "Error: keymgmt_import failed for key type <%s>", name);
279 if (pkey)
280 {
281 EVP_PKEY_free(pkey);
282 }
283 if (ctx)
284 {
285 EVP_PKEY_CTX_free(ctx);
286 }
287 return 0;
288 }
289
290 key->pubkey = pkey;
291 key->origin = OPENSSL_NATIVE;
292 if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY)
293 {
294 /* create private key */
295 pkey = NULL;
296 if (EVP_PKEY_fromdata(ctx, &pkey, selection, (OSSL_PARAM *)params) == 1)
297 {
298 key->handle = pkey;
299 key->free = (XKEY_PRIVKEY_FREE_fn *)EVP_PKEY_free;
300 }
301 }
302 EVP_PKEY_CTX_free(ctx);
303
304 xkey_dmsg(D_XKEY, "imported native %s key", EVP_PKEY_get0_type_name(pkey));
305 return 1;
306}
307
308static int
309rsa_keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[])
310{
311 xkey_dmsg(D_XKEY, "entry");
312
313 return keymgmt_import(keydata, selection, params, "RSA");
314}
315
316static int
317ec_keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[])
318{
319 xkey_dmsg(D_XKEY, "entry");
320
321 return keymgmt_import(keydata, selection, params, "EC");
322}
323
324static int
325ed448_keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[])
326{
327 xkey_dmsg(D_XKEY, "entry");
328
329 return keymgmt_import(keydata, selection, params, "ED448");
330}
331
332static int
333ed25519_keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[])
334{
335 xkey_dmsg(D_XKEY, "entry");
336
337 return keymgmt_import(keydata, selection, params, "ED25519");
338}
339
340/* This function has to exist for key import to work
341 * though we do not support import of individual params
342 * like n or e. We simply return an empty list here for
343 * both rsa and ec, which works.
344 */
345static const OSSL_PARAM *
346keymgmt_import_types(int selection)
347{
348 xkey_dmsg(D_XKEY, "entry");
349
350 static const OSSL_PARAM key_types[] = { OSSL_PARAM_END };
351
352 if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
353 {
354 return key_types;
355 }
356 return NULL;
357}
358
359static void
360keymgmt_free(void *keydata)
361{
362 xkey_dmsg(D_XKEY, "entry");
363
364 keydata_free(keydata);
365}
366
367static int
368keymgmt_has(const void *keydata, int selection)
369{
370 xkey_dmsg(D_XKEY, "selection = %d", selection);
371
372 const XKEY_KEYDATA *key = keydata;
373 int ok = (key != NULL);
374
375 if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
376 {
377 ok = ok && key->pubkey;
378 }
379 if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY)
380 {
381 ok = ok && key->handle;
382 }
383
384 return ok;
385}
386
387static int
388keymgmt_match(const void *keydata1, const void *keydata2, int selection)
389{
390 const XKEY_KEYDATA *key1 = keydata1;
391 const XKEY_KEYDATA *key2 = keydata2;
392
393 xkey_dmsg(D_XKEY, "entry");
394
395 int ret = key1 && key2 && key1->pubkey && key2->pubkey;
396
397 /* our keys always have pubkey -- we only match them */
398
399 if (selection & OSSL_KEYMGMT_SELECT_KEYPAIR)
400 {
401 ret = ret && EVP_PKEY_eq(key1->pubkey, key2->pubkey);
402 xkey_dmsg(D_XKEY, "checking key pair match: res = %d", ret);
403 }
404
405 if (selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)
406 {
407 ret = ret && EVP_PKEY_parameters_eq(key1->pubkey, key2->pubkey);
408 xkey_dmsg(D_XKEY, "checking parameter match: res = %d", ret);
409 }
410
411 return ret;
412}
413
414/* A minimal set of key params that we can return */
415static const OSSL_PARAM *
416keymgmt_gettable_params(void *provctx)
417{
418 xkey_dmsg(D_XKEY, "entry");
419
420 static OSSL_PARAM gettable[] = { OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
421 OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
422 OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
423 OSSL_PARAM_END };
424 return gettable;
425}
426
427static int
428keymgmt_get_params(void *keydata, OSSL_PARAM *params)
429{
430 xkey_dmsg(D_XKEY, "entry");
431
432 XKEY_KEYDATA *key = keydata;
433 if (!key || !key->pubkey)
434 {
435 return 0;
436 }
437
438 return EVP_PKEY_get_params(key->pubkey, params);
439}
440
441/* Helper used by keymgmt_import and keymgmt_set_params
442 * for our keys. Not to be used for OpenSSL native keys.
443 */
444static int
445keymgmt_import_helper(XKEY_KEYDATA *key, const OSSL_PARAM *params)
446{
447 xkey_dmsg(D_XKEY, "entry");
448
449 const OSSL_PARAM *p;
450 EVP_PKEY *pkey = NULL;
451
452 ASSERT(key);
453 /* calling this with native keys is a coding error */
454 ASSERT(key->origin != OPENSSL_NATIVE);
455
456 if (params == NULL)
457 {
458 return 1; /* not an error */
459 }
460
461 /* our keys are immutable, we do not allow resetting parameters */
462 if (key->pubkey)
463 {
464 return 0;
465 }
466
467 /* only check params we understand and ignore the rest */
468
469 p = OSSL_PARAM_locate_const(params, "pubkey"); /*setting pubkey on our keydata */
470 if (p && p->data_type == OSSL_PARAM_OCTET_STRING && p->data_size == sizeof(pkey))
471 {
472 pkey = *(EVP_PKEY **)p->data;
473 ASSERT(pkey);
474
475 int id = EVP_PKEY_get_id(pkey);
476 if (id != EVP_PKEY_RSA && id != EVP_PKEY_EC && id != EVP_PKEY_ED25519
477 && id != EVP_PKEY_ED448)
478 {
479 msg(M_WARN, "Error: xkey keymgmt_import: unknown key type (%d)", id);
480 return 0;
481 }
482
483 key->pubkey = EVP_PKEY_dup(pkey);
484 if (key->pubkey == NULL)
485 {
486 msg(M_NONFATAL, "Error: xkey keymgmt_import: duplicating pubkey failed.");
487 return 0;
488 }
489 }
490
491 p = OSSL_PARAM_locate_const(params, "handle"); /*setting privkey */
492 if (p && p->data_type == OSSL_PARAM_OCTET_PTR && p->data_size == sizeof(key->handle))
493 {
494 key->handle = *(void **)p->data;
495 /* caller should keep the reference alive until we call free */
496 ASSERT(key->handle); /* fix your params array */
497 }
498
499 p = OSSL_PARAM_locate_const(params, "sign_op"); /*setting sign_op */
500 if (p && p->data_type == OSSL_PARAM_OCTET_PTR && p->data_size == sizeof(key->sign))
501 {
502 key->sign = *(void **)p->data;
503 ASSERT(key->sign); /* fix your params array */
504 }
505
506 /* optional parameters */
507 p = OSSL_PARAM_locate_const(params, "free_op"); /*setting free_op */
508 if (p && p->data_type == OSSL_PARAM_OCTET_PTR && p->data_size == sizeof(key->free))
509 {
510 key->free = *(void **)p->data;
511 }
512 xkey_dmsg(D_XKEY, "imported external %s key", EVP_PKEY_get0_type_name(key->pubkey));
513
514 return 1;
515}
516
528static int
529keymgmt_set_params(void *keydata, const OSSL_PARAM *params)
530{
531 XKEY_KEYDATA *key = keydata;
532 ASSERT(key);
533
534 xkey_dmsg(D_XKEY, "entry");
535
536 if (key->origin != OPENSSL_NATIVE)
537 {
538 return keymgmt_import_helper(key, params);
539 }
540 else if (key->handle == NULL) /* once handle is set our key is immutable */
541 {
542 /* pubkey is always native -- just delegate */
543 return EVP_PKEY_set_params(key->pubkey, (OSSL_PARAM *)params);
544 }
545 else
546 {
547 msg(M_WARN, "xkey keymgmt_set_params: key is immutable");
548 }
549 return 1;
550}
551
552static const char *
553rsa_keymgmt_name(int id)
554{
555 xkey_dmsg(D_XKEY, "entry");
556
557 return "RSA";
558}
559
560static const char *
561ec_keymgmt_name(int id)
562{
563 xkey_dmsg(D_XKEY, "entry");
564
565 if (id == OSSL_OP_SIGNATURE)
566 {
567 return "ECDSA";
568 }
569 /* though we do not implement keyexch we could be queried for
570 * keyexch mechanism supported by EC keys
571 */
572 else if (id == OSSL_OP_KEYEXCH)
573 {
574 return "ECDH";
575 }
576
577 msg(D_XKEY, "xkey ec_keymgmt_name called with op_id != SIGNATURE or KEYEXCH id=%d", id);
578 return "EC";
579}
580
581static const OSSL_DISPATCH rsa_keymgmt_functions[] = {
582 { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))keymgmt_new },
583 { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))keymgmt_free },
584 { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))keymgmt_load },
585 { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))keymgmt_has },
586 { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))keymgmt_match },
587 { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))rsa_keymgmt_import },
588 { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))keymgmt_import_types },
589 { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))keymgmt_gettable_params },
590 { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))keymgmt_get_params },
591 { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*)(void))keymgmt_set_params },
592 { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS,
593 (void (*)(void))keymgmt_gettable_params }, /* same as gettable */
594 { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, (void (*)(void))rsa_keymgmt_name },
595 { 0, NULL }
596};
597
598static const OSSL_DISPATCH ec_keymgmt_functions[] = {
599 { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))keymgmt_new },
600 { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))keymgmt_free },
601 { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))keymgmt_load },
602 { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))keymgmt_has },
603 { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))keymgmt_match },
604 { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ec_keymgmt_import },
605 { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))keymgmt_import_types },
606 { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))keymgmt_gettable_params },
607 { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))keymgmt_get_params },
608 { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*)(void))keymgmt_set_params },
609 { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS,
610 (void (*)(void))keymgmt_gettable_params }, /* same as gettable */
611 { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, (void (*)(void))ec_keymgmt_name },
612 { 0, NULL }
613};
614
615static const OSSL_DISPATCH ed448_keymgmt_functions[] = {
616 { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))keymgmt_new },
617 { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))keymgmt_free },
618 { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))keymgmt_load },
619 { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))keymgmt_has },
620 { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))keymgmt_match },
621 { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ed448_keymgmt_import },
622 { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))keymgmt_import_types },
623 { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))keymgmt_gettable_params },
624 { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))keymgmt_get_params },
625 { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*)(void))keymgmt_set_params },
626 { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS,
627 (void (*)(void))keymgmt_gettable_params }, /* same as gettable */
628 { 0, NULL }
629};
630
631static const OSSL_DISPATCH ed25519_keymgmt_functions[] = {
632 { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))keymgmt_new },
633 { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))keymgmt_free },
634 { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))keymgmt_load },
635 { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))keymgmt_has },
636 { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))keymgmt_match },
637 { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ed25519_keymgmt_import },
638 { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))keymgmt_import_types },
639 { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))keymgmt_gettable_params },
640 { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))keymgmt_get_params },
641 { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*)(void))keymgmt_set_params },
642 { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS,
643 (void (*)(void))keymgmt_gettable_params }, /* same as gettable */
644 { 0, NULL }
645};
646
647
648const OSSL_ALGORITHM keymgmts[] = {
649 { "RSA:rsaEncryption", XKEY_PROV_PROPS, rsa_keymgmt_functions, "OpenVPN xkey RSA Key Manager" },
650 { "RSA-PSS:RSASSA-PSS", XKEY_PROV_PROPS, rsa_keymgmt_functions,
651 "OpenVPN xkey RSA-PSS Key Manager" },
652 { "EC:id-ecPublicKey", XKEY_PROV_PROPS, ec_keymgmt_functions, "OpenVPN xkey EC Key Manager" },
653 { "ED448", XKEY_PROV_PROPS, ed448_keymgmt_functions, "OpenVPN xkey ED448 Key Manager" },
654 { "ED25519", XKEY_PROV_PROPS, ed25519_keymgmt_functions, "OpenVPN xkey ED25519 Key Manager" },
655 { NULL, NULL, NULL, NULL }
656};
657
658
659/* signature provider */
660
661/* signature provider callbacks we provide */
662static OSSL_FUNC_signature_newctx_fn signature_newctx;
663static OSSL_FUNC_signature_freectx_fn signature_freectx;
664static OSSL_FUNC_signature_sign_init_fn signature_sign_init;
665static OSSL_FUNC_signature_sign_fn signature_sign;
666static OSSL_FUNC_signature_digest_verify_init_fn signature_digest_verify_init;
667static OSSL_FUNC_signature_digest_verify_fn signature_digest_verify;
668static OSSL_FUNC_signature_digest_sign_init_fn signature_digest_sign_init;
669static OSSL_FUNC_signature_digest_sign_fn signature_digest_sign;
670static OSSL_FUNC_signature_set_ctx_params_fn signature_set_ctx_params;
671static OSSL_FUNC_signature_settable_ctx_params_fn signature_settable_ctx_params;
672static OSSL_FUNC_signature_get_ctx_params_fn signature_get_ctx_params;
673static OSSL_FUNC_signature_gettable_ctx_params_fn signature_gettable_ctx_params;
674
675typedef struct
676{
677 XKEY_PROVIDER_CTX *prov;
678 XKEY_KEYDATA *keydata;
679 XKEY_SIGALG sigalg;
680} XKEY_SIGNATURE_CTX;
681
682static const XKEY_SIGALG default_sigalg = {
683 .mdname = "MD5-SHA1", .saltlen = "digest", .padmode = "pkcs1", .keytype = "RSA"
684};
685
686const struct
687{
688 int nid;
689 const char *name;
690} digest_names[] = { { NID_md5_sha1, "MD5-SHA1" },
691 { NID_sha1, "SHA1" },
692 {
693 NID_sha224,
694 "SHA224",
695 },
696 { NID_sha256, "SHA256" },
697 { NID_sha384, "SHA384" },
698 { NID_sha512, "SHA512" },
699 { 0, NULL } };
700/* Use of NIDs as opposed to EVP_MD_fetch is okay here
701 * as these are only used for converting names passed in
702 * by OpenSSL to const strings.
703 */
704
705static struct
706{
707 int id;
708 const char *name;
709} padmode_names[] = { { RSA_PKCS1_PADDING, "pkcs1" },
710 { RSA_PKCS1_PSS_PADDING, "pss" },
711 { RSA_NO_PADDING, "none" },
712 { 0, NULL } };
713
714static const char *saltlen_names[] = { "digest", "max", "auto", NULL };
715
716/* Return a string literal for digest name - normalizes
717 * alternate names like SHA2-256 to SHA256 etc.
718 */
719static const char *
720xkey_mdname(const char *name)
721{
722 if (name == NULL)
723 {
724 return "none";
725 }
726
727 int i = 0;
728
729 int nid = EVP_MD_get_type(EVP_get_digestbyname(name));
730
731 while (digest_names[i].name && nid != digest_names[i].nid)
732 {
733 i++;
734 }
735 return digest_names[i].name ? digest_names[i].name : "MD5-SHA1";
736}
737
738static void *
739signature_newctx(void *provctx, const char *propq)
740{
741 xkey_dmsg(D_XKEY, "entry");
742
743 (void)propq; /* unused */
744
745 XKEY_SIGNATURE_CTX *sctx = OPENSSL_zalloc(sizeof(*sctx));
746 if (!sctx)
747 {
748 msg(M_NONFATAL, "xkey_signature_newctx: out of memory");
749 return NULL;
750 }
751
752 sctx->prov = provctx;
753 sctx->sigalg = default_sigalg;
754
755 return sctx;
756}
757
758static void
759signature_freectx(void *ctx)
760{
761 xkey_dmsg(D_XKEY, "entry");
762
763 XKEY_SIGNATURE_CTX *sctx = ctx;
764
765 keydata_free(sctx->keydata);
766
767 OPENSSL_free(sctx);
768}
769
770static const OSSL_PARAM *
771signature_settable_ctx_params(void *ctx, void *provctx)
772{
773 xkey_dmsg(D_XKEY, "entry");
774
775 static OSSL_PARAM settable[] = {
776 OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0),
777 OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
778 OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0), OSSL_PARAM_END
779 };
780
781 return settable;
782}
783
784static int
785signature_set_ctx_params(void *ctx, const OSSL_PARAM params[])
786{
787 xkey_dmsg(D_XKEY, "entry");
788
789 XKEY_SIGNATURE_CTX *sctx = ctx;
790 const OSSL_PARAM *p;
791
792 if (params == NULL)
793 {
794 return 1; /* not an error */
795 }
796 p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PAD_MODE);
797 if (p && p->data_type == OSSL_PARAM_UTF8_STRING)
798 {
799 sctx->sigalg.padmode = NULL;
800 for (int i = 0; padmode_names[i].id != 0; i++)
801 {
802 if (!strcmp(p->data, padmode_names[i].name))
803 {
804 sctx->sigalg.padmode = padmode_names[i].name;
805 break;
806 }
807 }
808 if (sctx->sigalg.padmode == NULL)
809 {
810 msg(M_WARN, "xkey signature_ctx: padmode <%s>, treating as <none>", (char *)p->data);
811 sctx->sigalg.padmode = "none";
812 }
813 xkey_dmsg(D_XKEY, "setting padmode as %s", sctx->sigalg.padmode);
814 }
815 else if (p && p->data_type == OSSL_PARAM_INTEGER)
816 {
817 sctx->sigalg.padmode = NULL;
818 int padmode = 0;
819 if (OSSL_PARAM_get_int(p, &padmode))
820 {
821 for (int i = 0; padmode_names[i].id != 0; i++)
822 {
823 if (padmode == padmode_names[i].id)
824 {
825 sctx->sigalg.padmode = padmode_names[i].name;
826 break;
827 }
828 }
829 }
830 if (padmode == 0 || sctx->sigalg.padmode == NULL)
831 {
832 msg(M_WARN, "xkey signature_ctx: padmode <%d>, treating as <none>", padmode);
833 sctx->sigalg.padmode = "none";
834 }
835 xkey_dmsg(D_XKEY, "setting padmode <%s>", sctx->sigalg.padmode);
836 }
837 else if (p)
838 {
839 msg(M_WARN, "xkey_signature_params: unknown padmode ignored");
840 }
841
842 p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST);
843 if (p && p->data_type == OSSL_PARAM_UTF8_STRING)
844 {
845 sctx->sigalg.mdname = xkey_mdname(p->data);
846 xkey_dmsg(D_XKEY, "setting hashalg as %s", sctx->sigalg.mdname);
847 }
848 else if (p)
849 {
850 msg(M_WARN, "xkey_signature_params: unknown digest type ignored");
851 }
852
853 p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PSS_SALTLEN);
854 if (p && p->data_type == OSSL_PARAM_UTF8_STRING)
855 {
856 sctx->sigalg.saltlen = NULL;
857 for (int i = 0; saltlen_names[i] != NULL; i++)
858 {
859 if (!strcmp(p->data, saltlen_names[i]))
860 {
861 sctx->sigalg.saltlen = saltlen_names[i];
862 break;
863 }
864 }
865 if (sctx->sigalg.saltlen == NULL)
866 {
867 msg(M_WARN, "xkey_signature_params: unknown saltlen <%s>", (char *)p->data);
868 sctx->sigalg.saltlen = "digest"; /* most common */
869 }
870 xkey_dmsg(D_XKEY, "setting saltlen to %s", sctx->sigalg.saltlen);
871 }
872 else if (p)
873 {
874 msg(M_WARN, "xkey_signature_params: unknown saltlen ignored");
875 }
876
877 return 1;
878}
879
880static const OSSL_PARAM *
881signature_gettable_ctx_params(void *ctx, void *provctx)
882{
883 xkey_dmsg(D_XKEY, "entry");
884
885 static OSSL_PARAM gettable[] = { OSSL_PARAM_END }; /* Empty list */
886
887 return gettable;
888}
889
890static int
891signature_get_ctx_params(void *ctx, OSSL_PARAM params[])
892{
893 xkey_dmsg(D_XKEY, "not implemented");
894 return 0;
895}
896
897static int
898signature_sign_init(void *ctx, void *provkey, const OSSL_PARAM params[])
899{
900 xkey_dmsg(D_XKEY, "entry");
901
902 XKEY_SIGNATURE_CTX *sctx = ctx;
903
904 if (sctx->keydata)
905 {
906 keydata_free(sctx->keydata);
907 }
908 sctx->keydata = provkey;
909 sctx->keydata->refcount++; /* we are keeping a copy */
910 sctx->sigalg.keytype = get_keytype(sctx->keydata);
911
912 signature_set_ctx_params(sctx, params);
913
914 return 1;
915}
916
917/* Sign digest or message using sign function */
918static int
919xkey_sign_dispatch(XKEY_SIGNATURE_CTX *sctx, unsigned char *sig, size_t *siglen,
920 const unsigned char *tbs, size_t tbslen)
921{
922 XKEY_EXTERNAL_SIGN_fn *sign = sctx->keydata->sign;
923 int ret = 0;
924
925 if (sctx->keydata->origin == OPENSSL_NATIVE)
926 {
927 ret = xkey_native_sign(sctx->keydata, sig, siglen, tbs, tbslen, sctx->sigalg);
928 }
929 else if (sign)
930 {
931 ret = sign(sctx->keydata->handle, sig, siglen, tbs, tbslen, sctx->sigalg);
932 xkey_dmsg(D_XKEY, "xkey_provider: external sign op returned ret = %d siglen = %d", ret,
933 (int)*siglen);
934 }
935 else
936 {
937 msg(M_NONFATAL, "xkey_provider: Internal error: No sign callback for external key.");
938 }
939
940 return ret;
941}
942
943static int
944signature_sign(void *ctx, unsigned char *sig, size_t *siglen, size_t sigsize,
945 const unsigned char *tbs, size_t tbslen)
946{
947 xkey_dmsg(D_XKEY, "entry with siglen = %zu", *siglen);
948
949 XKEY_SIGNATURE_CTX *sctx = ctx;
950 ASSERT(sctx);
951 ASSERT(sctx->keydata);
952
953 if (!sig)
954 {
955 *siglen = KEYSIZE(sctx->keydata);
956 return 1;
957 }
958
959 sctx->sigalg.op = "Sign";
960 return xkey_sign_dispatch(sctx, sig, siglen, tbs, tbslen);
961}
962
963static int
964signature_digest_verify_init(void *ctx, const char *mdname, void *provkey,
965 const OSSL_PARAM params[])
966{
967 xkey_dmsg(D_XKEY, "mdname <%s>", mdname);
968
969 msg(M_WARN, "xkey_provider: DigestVerifyInit is not implemented");
970 return 0;
971}
972
973/* We do not expect to be called for DigestVerify() but still
974 * return an empty function for it in the sign dispatch array
975 * for debugging purposes.
976 */
977static int
978signature_digest_verify(void *ctx, const unsigned char *sig, size_t siglen,
979 const unsigned char *tbs, size_t tbslen)
980{
981 xkey_dmsg(D_XKEY, "entry");
982
983 msg(M_WARN, "xkey_provider: DigestVerify is not implemented");
984 return 0;
985}
986
987static int
988signature_digest_sign_init(void *ctx, const char *mdname, void *provkey, const OSSL_PARAM params[])
989{
990 xkey_dmsg(D_XKEY, "mdname = <%s>", mdname);
991
992 XKEY_SIGNATURE_CTX *sctx = ctx;
993
994 ASSERT(sctx);
995 ASSERT(provkey);
996 ASSERT(sctx->prov);
997
998 if (sctx->keydata)
999 {
1000 keydata_free(sctx->keydata);
1001 }
1002 sctx->keydata = provkey; /* used by digest_sign */
1003 sctx->keydata->refcount++;
1004 sctx->sigalg.keytype = get_keytype(sctx->keydata);
1005
1006 signature_set_ctx_params(ctx, params);
1007 if (!strcmp(sctx->sigalg.keytype, "ED448") || !strcmp(sctx->sigalg.keytype, "ED25519"))
1008 {
1009 /* EdDSA requires NULL as digest for the DigestSign API instead
1010 * of using the normal Sign API. Ensure it is actually NULL too */
1011 if (mdname != NULL)
1012 {
1013 msg(M_WARN, "xkey digest_sign_init: mdname must be NULL for ED448/ED25519.");
1014 return 0;
1015 }
1016 sctx->sigalg.mdname = "none";
1017 }
1018 else if (mdname)
1019 {
1020 sctx->sigalg.mdname = xkey_mdname(mdname); /* get a string literal pointer */
1021 }
1022 else
1023 {
1024 msg(M_WARN, "xkey digest_sign_init: mdname is NULL.");
1025 }
1026 return 1;
1027}
1028
1029static int
1030signature_digest_sign(void *ctx, unsigned char *sig, size_t *siglen, size_t sigsize,
1031 const unsigned char *tbs, size_t tbslen)
1032{
1033 xkey_dmsg(D_XKEY, "entry");
1034
1035 XKEY_SIGNATURE_CTX *sctx = ctx;
1036
1037 ASSERT(sctx);
1038 ASSERT(sctx->keydata);
1039
1040 if (!sig) /* set siglen and return */
1041 {
1042 *siglen = KEYSIZE(sctx->keydata);
1043 return 1;
1044 }
1045
1046 if (sctx->keydata->origin != OPENSSL_NATIVE)
1047 {
1048 /* pass the message itself to the backend */
1049 sctx->sigalg.op = "DigestSign";
1050 return xkey_sign_dispatch(ctx, sig, siglen, tbs, tbslen);
1051 }
1052
1053 /* create digest and pass on to signature_sign() */
1054
1055 const char *mdname = sctx->sigalg.mdname;
1056 EVP_MD *md = EVP_MD_fetch(sctx->prov->libctx, mdname, NULL);
1057 if (!md)
1058 {
1059 msg(M_WARN, "WARN: xkey digest_sign_init: MD_fetch failed for <%s>", mdname);
1060 return 0;
1061 }
1062
1063 /* construct digest using OpenSSL */
1064 unsigned char buf[EVP_MAX_MD_SIZE];
1065 unsigned int sz;
1066 if (EVP_Digest(tbs, tbslen, buf, &sz, md, NULL) != 1)
1067 {
1068 msg(M_WARN, "WARN: xkey digest_sign: EVP_Digest failed");
1069 EVP_MD_free(md);
1070 return 0;
1071 }
1072 EVP_MD_free(md);
1073
1074 return signature_sign(ctx, sig, siglen, sigsize, buf, sz);
1075}
1076
1077/* Sign digest using native sign function -- will only work for native keys
1078 */
1079int
1080xkey_native_sign(XKEY_KEYDATA *key, unsigned char *sig, size_t *siglen, const unsigned char *tbs,
1081 size_t tbslen, XKEY_SIGALG sigalg)
1082{
1083 xkey_dmsg(D_XKEY, "entry");
1084
1085 ASSERT(key);
1086
1087 EVP_PKEY *pkey = key->handle;
1088 int ret = 0;
1089
1090 ASSERT(sig);
1091
1092 if (!pkey)
1093 {
1094 msg(M_NONFATAL, "Error: xkey provider: signature request with empty private key");
1095 return 0;
1096 }
1097
1098 const char *saltlen = sigalg.saltlen;
1099 const char *mdname = sigalg.mdname;
1100 const char *padmode = sigalg.padmode;
1101
1102 xkey_dmsg(D_XKEY, "digest=<%s>, padmode=<%s>, saltlen=<%s>", mdname, padmode, saltlen);
1103
1104 int i = 0;
1105 OSSL_PARAM params[6];
1106 if (EVP_PKEY_get_id(pkey) == EVP_PKEY_RSA)
1107 {
1108 params[i++] =
1109 OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, (char *)mdname, 0);
1110 params[i++] =
1111 OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, (char *)padmode, 0);
1112 if (!strcmp(sigalg.padmode, "pss"))
1113 {
1114 params[i++] = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN,
1115 (char *)saltlen, 0);
1116 /* same digest for mgf1 */
1117 params[i++] = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST,
1118 (char *)mdname, 0);
1119 }
1120 }
1121 params[i++] = OSSL_PARAM_construct_end();
1122
1123 EVP_PKEY_CTX *ectx = EVP_PKEY_CTX_new_from_pkey(key->prov->libctx, pkey, NULL);
1124
1125 if (!ectx)
1126 {
1127 msg(M_WARN, "WARN: xkey test_sign: call to EVP_PKEY_CTX_new...failed");
1128 return 0;
1129 }
1130
1131 if (EVP_PKEY_sign_init_ex(ectx, NULL) != 1)
1132 {
1133 msg(M_WARN, "WARN: xkey test_sign: call to EVP_PKEY_sign_init failed");
1134 return 0;
1135 }
1136 EVP_PKEY_CTX_set_params(ectx, params);
1137
1138 ret = EVP_PKEY_sign(ectx, sig, siglen, tbs, tbslen);
1139 EVP_PKEY_CTX_free(ectx);
1140
1141 return ret;
1142}
1143
1144static const OSSL_DISPATCH signature_functions[] = {
1145 { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))signature_newctx },
1146 { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))signature_freectx },
1147 { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))signature_sign_init },
1148 { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))signature_sign },
1149 { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, (void (*)(void))signature_digest_verify_init },
1150 { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY, (void (*)(void))signature_digest_verify },
1151 { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, (void (*)(void))signature_digest_sign_init },
1152 { OSSL_FUNC_SIGNATURE_DIGEST_SIGN, (void (*)(void))signature_digest_sign },
1153 { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))signature_set_ctx_params },
1154 { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, (void (*)(void))signature_settable_ctx_params },
1155 { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))signature_get_ctx_params },
1156 { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, (void (*)(void))signature_gettable_ctx_params },
1157 { 0, NULL }
1158};
1159
1160const OSSL_ALGORITHM signatures[] = {
1161 { "RSA:rsaEncryption", XKEY_PROV_PROPS, signature_functions, "OpenVPN xkey RSA Signature" },
1162 { "ECDSA", XKEY_PROV_PROPS, signature_functions, "OpenVPN xkey ECDSA Signature" },
1163 { "ED448", XKEY_PROV_PROPS, signature_functions, "OpenVPN xkey Ed448 Signature" },
1164 { "ED25519", XKEY_PROV_PROPS, signature_functions, "OpenVPN xkey Ed25519 Signature" },
1165 { NULL, NULL, NULL, NULL }
1166};
1167
1168/* main provider interface */
1169
1170/* provider callbacks we implement */
1171static OSSL_FUNC_provider_query_operation_fn query_operation;
1172static OSSL_FUNC_provider_gettable_params_fn gettable_params;
1173static OSSL_FUNC_provider_get_params_fn get_params;
1174static OSSL_FUNC_provider_teardown_fn teardown;
1175
1176static const OSSL_ALGORITHM *
1177query_operation(void *provctx, int op, int *no_store)
1178{
1179 xkey_dmsg(D_XKEY, "op = %d", op);
1180
1181 *no_store = 0;
1182
1183 switch (op)
1184 {
1185 case OSSL_OP_SIGNATURE:
1186 return signatures;
1187
1188 case OSSL_OP_KEYMGMT:
1189 return keymgmts;
1190
1191 default:
1192 xkey_dmsg(D_XKEY, "op not supported");
1193 break;
1194 }
1195 return NULL;
1196}
1197
1198static const OSSL_PARAM *
1199gettable_params(void *provctx)
1200{
1201 xkey_dmsg(D_XKEY, "entry");
1202
1203 static const OSSL_PARAM param_types[] = {
1204 OSSL_PARAM_DEFN(OSSL_PROV_PARAM_NAME, OSSL_PARAM_UTF8_PTR, NULL, 0), OSSL_PARAM_END
1205 };
1206
1207 return param_types;
1208}
1209static int
1210get_params(void *provctx, OSSL_PARAM params[])
1211{
1212 OSSL_PARAM *p;
1213
1214 xkey_dmsg(D_XKEY, "entry");
1215
1216 p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_NAME);
1217 if (p)
1218 {
1219 return (OSSL_PARAM_set_utf8_ptr(p, provname) != 0);
1220 }
1221
1222 return 0;
1223}
1224
1225static void
1226teardown(void *provctx)
1227{
1228 xkey_dmsg(D_XKEY, "entry");
1229
1230 XKEY_PROVIDER_CTX *prov = provctx;
1231 if (prov && prov->libctx)
1232 {
1233 OSSL_LIB_CTX_free(prov->libctx);
1234 }
1235 OPENSSL_free(prov);
1236}
1237
1238static const OSSL_DISPATCH dispatch_table[] = {
1239 { OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, (void (*)(void))gettable_params },
1240 { OSSL_FUNC_PROVIDER_GET_PARAMS, (void (*)(void))get_params },
1241 { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))query_operation },
1242 { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))teardown },
1243 { 0, NULL }
1244};
1245
1246int
1247xkey_provider_init(const OSSL_CORE_HANDLE *handle, const OSSL_DISPATCH *in,
1248 const OSSL_DISPATCH **out, void **provctx)
1249{
1250 XKEY_PROVIDER_CTX *prov;
1251
1252 xkey_dmsg(D_XKEY, "entry");
1253
1254 prov = OPENSSL_zalloc(sizeof(*prov));
1255 if (!prov)
1256 {
1257 msg(M_NONFATAL, "xkey_provider_init: out of memory");
1258 return 0;
1259 }
1260
1261 /* Make a child libctx for our use and set default prop query
1262 * on it to ensure calls we delegate won't loop back to us.
1263 */
1264 prov->libctx = OSSL_LIB_CTX_new_child(handle, in);
1265
1266 EVP_set_default_properties(prov->libctx, "provider!=ovpn.xkey");
1267
1268 *out = dispatch_table;
1269 *provctx = prov;
1270
1271 return 1;
1272}
1273
1274#endif /* HAVE_XKEY_PROVIDER */
static const char *const key1
Definition cert_data.h:55
#define D_XKEY
Definition errlevel.h:116
void OSSL_LIB_CTX
static void EVP_MD_free(const EVP_MD *md)
static const EVP_MD * EVP_MD_fetch(void *ctx, const char *algorithm, const char *properties)
#define M_NONFATAL
Definition error.h:89
#define msg(flags,...)
Definition error.h:150
#define ASSERT(x)
Definition error.h:217
#define M_WARN
Definition error.h:90
Container for bidirectional cipher and HMAC key material.
Definition crypto.h:240
Container for unidirectional cipher and HMAC key material.
Definition crypto.h:152
static int teardown(void **state)
Definition test.c:22