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