OpenVPN 3 Core Library
Loading...
Searching...
No Matches
xkey_helper.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#include <assert.h>
29#define ASSERT assert
30
31static const char *const props = XKEY_PROV_PROPS;
32
33static XKEY_LOGGING_CALLBACK_fn *xkey_log_callback;
34
35static void
36print_openssl_errors(void)
37{
38 unsigned long e;
39 while ((e = ERR_get_error()))
40 {
41 msg(M_WARN, "OpenSSL error %lu: %s\n", e, ERR_error_string(e, NULL));
42 }
43}
44
50EVP_PKEY *
51xkey_load_generic_key(OSSL_LIB_CTX *libctx, void *handle, EVP_PKEY *pubkey,
52 XKEY_EXTERNAL_SIGN_fn *sign_op, XKEY_PRIVKEY_FREE_fn *free_op)
53{
54 EVP_PKEY *pkey = NULL;
55 const char *origin = "external";
56
57 /* UTF8 string pointers in here are only read from, so cast is safe */
58 OSSL_PARAM params[] = {
59 {"xkey-origin", OSSL_PARAM_UTF8_STRING, (char *) origin, 0, 0},
60 {"pubkey", OSSL_PARAM_OCTET_STRING, &pubkey, sizeof(pubkey), 0},
61 {"handle", OSSL_PARAM_OCTET_PTR, &handle, sizeof(handle), 0},
62 {"sign_op", OSSL_PARAM_OCTET_PTR, (void **) &sign_op, sizeof(sign_op), 0},
63 {"free_op", OSSL_PARAM_OCTET_PTR, (void **) &free_op, sizeof(free_op), 0},
64 {NULL, 0, NULL, 0, 0}
65 };
66
67 /* Do not use EVP_PKEY_new_from_pkey as that will take keymgmt from pubkey */
68 EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(libctx, EVP_PKEY_get0_type_name(pubkey), props);
69 if (!ctx
70 || EVP_PKEY_fromdata_init(ctx) != 1
71 || EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEYPAIR, params) != 1)
72 {
73 print_openssl_errors();
74 msg(M_WARN, "OpenSSL error: failed to load key into ovpn.xkey provider");
75 pkey = NULL;
76 }
77 if (ctx)
78 {
79 EVP_PKEY_CTX_free(ctx);
80 }
81
82 return pkey;
83}
84
100bool
101xkey_encode_pkcs1(unsigned char *enc, size_t *enc_len, const char *mdname,
102 const unsigned char *tbs, size_t tbslen)
103{
104 ASSERT(enc_len != NULL);
105 ASSERT(tbs != NULL);
106
107 /* Tabulate the digest info header for expected hash algorithms
108 * These were pre-computed using the DigestInfo definition:
109 * DigestInfo ::= SEQUENCE {
110 * digestAlgorithm DigestAlgorithmIdentifier,
111 * digest Digest }
112 * Also see the table in RFC 8017 section 9.2, Note 1.
113 */
114
115 const unsigned char sha1[] = {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b,
116 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14};
117 const unsigned char sha256[] = {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
118 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
119 const unsigned char sha384[] = {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
120 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30};
121 const unsigned char sha512[] = {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
122 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40};
123 const unsigned char sha224[] = {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
124 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c};
125 const unsigned char sha512_224[] = {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
126 0x01, 0x65, 0x03, 0x04, 0x02, 0x05, 0x05, 0x00, 0x04, 0x1c};
127 const unsigned char sha512_256[] = {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
128 0x01, 0x65, 0x03, 0x04, 0x02, 0x06, 0x05, 0x00, 0x04, 0x20};
129
130 typedef struct {
131 const int nid;
132 const unsigned char *header;
133 size_t sz;
134 } DIG_INFO;
135
136#define MAKE_DI(x) {NID_ ## x, x, sizeof(x)}
137
138 DIG_INFO dinfo[] = {MAKE_DI(sha1), MAKE_DI(sha256), MAKE_DI(sha384),
139 MAKE_DI(sha512), MAKE_DI(sha224), MAKE_DI(sha512_224),
140 MAKE_DI(sha512_256), {0,NULL,0}};
141
142 size_t out_len = 0;
143 int ret = 0;
144
145 int nid = OBJ_sn2nid(mdname);
146 if (nid == NID_undef)
147 {
148 /* try harder -- name variants like SHA2-256 doesn't work */
149 nid = EVP_MD_type(EVP_get_digestbyname(mdname));
150 if (nid == NID_undef)
151 {
152 msg(M_WARN, "Error: encode_pkcs11: invalid digest name <%s>", mdname);
153 goto done;
154 }
155 }
156
157 if (tbslen != EVP_MD_size(EVP_get_digestbyname(mdname)))
158 {
159 msg(M_WARN, "Error: encode_pkcs11: invalid input length <%zu>", tbslen);
160 goto done;
161 }
162
163 if (nid == NID_md5_sha1) /* no encoding needed -- just copy */
164 {
165 if (enc && (*enc_len >= tbslen))
166 {
167 memcpy(enc, tbs, tbslen);
168 ret = true;
169 }
170 out_len = tbslen;
171 goto done;
172 }
173
174 /* locate entry for nid in dinfo table */
175 DIG_INFO *di = dinfo;
176 while ((di->nid != nid) && (di->nid != 0))
177 {
178 di++;
179 }
180 if (di->nid != nid) /* not found in our table */
181 {
182 msg(M_WARN, "Error: encode_pkcs11: unsupported hash algorithm <%s>", mdname);
183 goto done;
184 }
185
186 out_len = tbslen + di->sz;
187
188 if (enc && (out_len <= *enc_len))
189 {
190 /* combine header and digest */
191 memcpy(enc, di->header, di->sz);
192 memcpy(enc + di->sz, tbs, tbslen);
193 dmsg(D_XKEY, "encode_pkcs1: digest length = %zu encoded length = %zu", tbslen, out_len);
194 ret = true;
195 }
196
197done:
198 *enc_len = out_len; /* assignment safe as out_len is > 0 at this point */
199
200 return ret;
201}
202
203void xkey_set_logging_cb_function(XKEY_LOGGING_CALLBACK_fn logfunc)
204{
205 xkey_log_callback = logfunc;
206}
207
208
209void openvpn_msg_xkey_compat(const unsigned int flags, const char *format, ...)
210{
211 va_list arglist;
212 va_start(arglist, format);
213
214 char msgbuf[4096] = {0};
215
216 vsnprintf(msgbuf, sizeof(msgbuf), format, arglist);
217
218 /* Do not print debug messages from the xkey provider */
219 bool debug = (flags & D_XKEY) == 0;
220 if (debug && xkey_log_callback != NULL)
221 {
222 xkey_log_callback(msgbuf, debug);
223 }
224 va_end(arglist);
225}
226
227#endif /* HAVE_XKEY_PROVIDER */
reroute_gw flags
std::string ret
#define D_XKEY
void openvpn_msg_xkey_compat(unsigned int flags, const char *format,...)
#define dmsg(flags,...)
#define msg(flags,...)
#define M_WARN