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