1 /*
2 * OpenConnect (SSL + DTLS) VPN client
3 *
4 * Copyright © 2008-2015 Intel Corporation.
5 *
6 * Author: David Woodhouse <dwmw2@infradead.org>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * version 2.1, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 */
17
18 #include <config.h>
19
20 #include <errno.h>
21 #include <string.h>
22 #include <sys/types.h>
23 #include <ctype.h>
24
25 #include "openconnect-internal.h"
26 #include <openssl/rand.h>
27
28 #ifdef HAVE_LIBP11 /* And p11-kit */
29
30 #include <libp11.h>
31 #include <p11-kit/pkcs11.h>
32
pkcs11_ctx(struct openconnect_info * vpninfo)33 static PKCS11_CTX *pkcs11_ctx(struct openconnect_info *vpninfo)
34 {
35 PKCS11_CTX *ctx;
36
37 if (!vpninfo->pkcs11_ctx) {
38 ERR_load_PKCS11_strings();
39
40 ctx = PKCS11_CTX_new();
41 if (!ctx) {
42 vpn_progress(vpninfo, PRG_ERR,
43 _("Failed to establish libp11 PKCS#11 context:\n"));
44 openconnect_report_ssl_errors(vpninfo);
45 return NULL;
46 }
47 if (PKCS11_CTX_load(ctx, DEFAULT_PKCS11_MODULE) < 0) {
48 vpn_progress(vpninfo, PRG_ERR,
49 _("Failed to load PKCS#11 provider module (%s):\n"),
50 DEFAULT_PKCS11_MODULE);
51 openconnect_report_ssl_errors(vpninfo);
52 PKCS11_CTX_free(ctx);
53 return NULL;
54 }
55 vpninfo->pkcs11_ctx = ctx;
56 }
57
58 return vpninfo->pkcs11_ctx;
59 }
60
parse_uri_attr(const char * attr,int attrlen,unsigned char ** field,size_t * field_len)61 static int parse_uri_attr(const char *attr, int attrlen, unsigned char **field,
62 size_t *field_len)
63 {
64 size_t outlen = 0;
65 unsigned char *out;
66 int ret = 0;
67
68 out = malloc(attrlen + 1);
69 if (!out)
70 return -ENOMEM;
71
72 while (!ret && attrlen) {
73 if (*attr == '%') {
74 if (attrlen < 3) {
75 ret = -EINVAL;
76 } else {
77 out[outlen++] = unhex(attr+1);
78
79 attrlen -= 3;
80 attr += 3;
81 }
82
83 } else {
84 out[outlen++] = *(attr++);
85 attrlen--;
86 }
87 }
88
89 if (ret)
90 free(out);
91 else {
92 if (field_len)
93 *field_len = outlen;
94 out[outlen] = 0;
95 *field = out;
96 }
97
98 return ret;
99 }
100
101
102
parse_pkcs11_uri(const char * uri,PKCS11_TOKEN ** p_tok,unsigned char ** id,size_t * id_len,char ** label,char ** pin)103 static int parse_pkcs11_uri(const char *uri, PKCS11_TOKEN **p_tok,
104 unsigned char **id, size_t *id_len,
105 char **label, char **pin)
106 {
107 PKCS11_TOKEN *tok;
108 char *newlabel = NULL;
109 const char *end, *p;
110 int ret = 0;
111
112 tok = calloc(1, sizeof(*tok));
113 if (!tok) {
114 fprintf(stderr, "Could not allocate memory for token info\n");
115 return -ENOMEM;
116 }
117
118 *id = NULL;
119
120 /* We are only ever invoked if the string starts with 'pkcs11:' */
121 end = uri + 6;
122 while (!ret && end[0] && end[1]) {
123 p = end + 1;
124 end = strchr(p, ';');
125 if (!end)
126 end = p + strlen(p);
127
128 if (!strncmp(p, "model=", 6)) {
129 p += 6;
130 ret = parse_uri_attr(p, end - p, (void *)&tok->model, NULL);
131 } else if (!strncmp(p, "manufacturer=", 13)) {
132 p += 13;
133 ret = parse_uri_attr(p, end - p, (void *)&tok->manufacturer, NULL);
134 } else if (!strncmp(p, "token=", 6)) {
135 p += 6;
136 ret = parse_uri_attr(p, end - p, (void *)&tok->label, NULL);
137 } else if (!strncmp(p, "serial=", 7)) {
138 p += 7;
139 ret = parse_uri_attr(p, end - p, (void *)&tok->serialnr, NULL);
140 } else if (!strncmp(p, "object=", 7)) {
141 p += 7;
142 ret = parse_uri_attr(p, end - p, (void *)&newlabel, NULL);
143 } else if (!strncmp(p, "id=", 3)) {
144 p += 3;
145 ret = parse_uri_attr(p, end - p, (void *)id, id_len);
146 } else if (!strncmp(p, "type=", 5) || !strncmp(p, "object-type=", 12)) {
147 p = strchr(p, '=') + 1;
148
149 if ((end - p == 4 && !strncmp(p, "cert", 4)) ||
150 (end - p == 7 && !strncmp(p, "private", 7))) {
151 /* Actually, just ignore it */
152 } else
153 ret = -EINVAL;
154 /* Ignore object type for now. */
155 } else if (!strncmp(p, "pin-value=", 10)) {
156 /* XXX We could do better than this but it'll cover all sane
157 use cases. */
158 char *pinvalue = NULL;
159 p += 10;
160 ret = parse_uri_attr(p, end - p, (void *)&pinvalue, NULL);
161 if (pinvalue) {
162 free(*pin);
163 *pin = pinvalue;
164 }
165 } else {
166 ret = -EINVAL;
167 }
168 }
169
170 if (!ret) {
171 *label = newlabel;
172 *p_tok = tok;
173 } else {
174 free(tok);
175 tok = NULL;
176 free(newlabel);
177 free(*id);
178 *id = NULL;
179 }
180
181 return ret;
182 }
183
request_pin(struct openconnect_info * vpninfo,struct pin_cache * cache,int retrying)184 static int request_pin(struct openconnect_info *vpninfo, struct pin_cache *cache, int retrying)
185 {
186 struct oc_auth_form f;
187 struct oc_form_opt o;
188 char message[1024];
189 int ret;
190
191 if (!vpninfo || !vpninfo->process_auth_form)
192 return -EINVAL;
193
194 if (vpninfo->cert_password) {
195 cache->pin = vpninfo->cert_password;
196 vpninfo->cert_password = NULL;
197 return 0;
198 }
199 memset(&f, 0, sizeof(f));
200 f.auth_id = (char *)"pkcs11_pin";
201 f.opts = &o;
202 message[sizeof(message)-1] = 0;
203 snprintf(message, sizeof(message) - 1, _("PIN required for %s"), cache->token);
204 f.message = message;
205 if (retrying)
206 f.error = (char *)_("Wrong PIN");
207 o.next = NULL;
208 o.type = OC_FORM_OPT_PASSWORD;
209 o.name = (char *)"pkcs11_pin";
210 o.label = (char *)_("Enter PIN:");
211 o._value = NULL;
212
213 ret = process_auth_form(vpninfo, &f);
214 if (ret || !o._value)
215 return -EIO;
216
217 cache->pin = o._value;
218 return 0;
219 }
220
slot_login(struct openconnect_info * vpninfo,PKCS11_CTX * ctx,PKCS11_SLOT * slot)221 static int slot_login(struct openconnect_info *vpninfo, PKCS11_CTX *ctx, PKCS11_SLOT *slot)
222 {
223 PKCS11_TOKEN *token = slot->token;
224 struct pin_cache *cache = vpninfo->pin_cache;
225 int ret, retrying = 0;
226
227 retry:
228 ERR_clear_error();
229 if (!token->secureLogin) {
230 if (!cache) {
231 for (cache = vpninfo->pin_cache; cache; cache = cache->next)
232 if (!strcmp(slot->description, cache->token))
233 break;
234 }
235 if (!cache) {
236 cache = malloc(sizeof(*cache));
237 if (!cache)
238 return -ENOMEM;
239 cache->pin = NULL;
240 cache->next = vpninfo->pin_cache;
241 cache->token = strdup(slot->description);
242 if (!cache->token) {
243 free(cache);
244 return -ENOMEM;
245 }
246 vpninfo->pin_cache = cache;
247 }
248 if (!cache->pin) {
249 ret = request_pin(vpninfo, cache, retrying);
250 if (ret)
251 return ret;
252 }
253 }
254 ret = PKCS11_login(slot, 0, cache ? cache->pin : NULL);
255 if (ret) {
256 unsigned long err = ERR_peek_error();
257 if (ERR_GET_LIB(err) == ERR_LIB_PKCS11 &&
258 ERR_GET_FUNC(err) == PKCS11_F_PKCS11_LOGIN)
259 err = ERR_GET_REASON(err);
260 else
261 err = CKR_OK; /* Anything we don't explicitly match */
262
263 switch (ERR_GET_REASON(err)) {
264 case CKR_PIN_INCORRECT:
265 /* They'll be told about it in the next UI prompt */
266 if (cache) {
267 free(cache->pin);
268 cache->pin = NULL;
269 }
270 retrying = 1;
271 goto retry;
272 case CKR_PIN_LOCKED:
273 vpn_progress(vpninfo, PRG_ERR, _("PIN locked\n"));
274 break;
275 case CKR_PIN_EXPIRED:
276 vpn_progress(vpninfo, PRG_ERR, _("PIN expired\n"));
277 break;
278 case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
279 vpn_progress(vpninfo, PRG_ERR, _("Another user already logged in\n"));
280 break;
281 default:
282 vpn_progress(vpninfo, PRG_ERR,
283 _("Unknown error logging in to PKCS#11 token\n"));
284 openconnect_report_ssl_errors(vpninfo);
285 }
286 ERR_clear_error();
287 return -EPERM;
288 }
289 vpn_progress(vpninfo, PRG_TRACE,
290 _("Logged in to PKCS#11 slot '%s'\n"),
291 slot->description);
292 return 0;
293 }
294
slot_find_cert(struct openconnect_info * vpninfo,PKCS11_CTX * ctx,PKCS11_SLOT * slot,const char * cert_label,unsigned char * cert_id,size_t cert_id_len)295 static PKCS11_CERT *slot_find_cert(struct openconnect_info *vpninfo, PKCS11_CTX *ctx,
296 PKCS11_SLOT *slot, const char *cert_label,
297 unsigned char *cert_id, size_t cert_id_len)
298 {
299 PKCS11_CERT *cert_list = NULL, *cert = NULL;
300 unsigned int cert_count;
301
302 if (PKCS11_enumerate_certs(slot->token, &cert_list, &cert_count) < 0) {
303 vpn_progress(vpninfo, PRG_ERR,
304 _("Failed to enumerate certs in PKCS#11 slot '%s'\n"),
305 slot->description);
306 return NULL;
307 }
308
309 vpn_progress(vpninfo, PRG_TRACE,
310 _("Found %d certs in slot '%s'\n"),
311 cert_count, slot->description);
312
313 for (cert = cert_list; cert < &cert_list[cert_count]; cert++) {
314
315 if (cert_label && strcmp(cert_label, cert->label))
316 continue;
317
318 if (cert_id && (cert_id_len != cert->id_len ||
319 memcmp(cert_id, cert->id, cert_id_len)))
320 continue;
321
322 return cert;
323 }
324 return NULL;
325 }
326
load_pkcs11_certificate(struct openconnect_info * vpninfo)327 int load_pkcs11_certificate(struct openconnect_info *vpninfo)
328 {
329 PKCS11_CTX *ctx;
330 PKCS11_TOKEN *match_tok = NULL;
331 PKCS11_CERT *cert = NULL;
332 char *cert_label = NULL;
333 unsigned char *cert_id = NULL;
334 size_t cert_id_len = 0;
335 PKCS11_SLOT *slot_list = NULL, *slot, *login_slot = NULL;
336 unsigned int slot_count, matching_slots = 0;
337 int ret = 0;
338
339 ctx = pkcs11_ctx(vpninfo);
340 if (!ctx)
341 return -EIO;
342
343 if (parse_pkcs11_uri(vpninfo->cert, &match_tok, &cert_id,
344 &cert_id_len, &cert_label, &vpninfo->cert_password) < 0) {
345 vpn_progress(vpninfo, PRG_ERR,
346 _("Failed to parse PKCS#11 URI '%s'\n"),
347 vpninfo->cert);
348 return -EINVAL;
349 }
350
351 if (PKCS11_enumerate_slots(ctx, &slot_list, &slot_count) < 0) {
352 vpn_progress(vpninfo, PRG_ERR,
353 _("Failed to enumerate PKCS#11 slots\n"));
354 openconnect_report_ssl_errors(vpninfo);
355 ret = -EIO;
356 goto out;
357 }
358 for (slot = slot_list; slot < &slot_list[slot_count] && slot != login_slot; slot++) {
359 if (!slot->token)
360 continue;
361 if (match_tok->label &&
362 strcmp(match_tok->label, slot->token->label))
363 continue;
364 if (match_tok->manufacturer &&
365 strcmp(match_tok->manufacturer, slot->token->manufacturer))
366 continue;
367 if (match_tok->model &&
368 strcmp(match_tok->model, slot->token->model))
369 continue;
370 if (match_tok->serialnr &&
371 strcmp(match_tok->serialnr, slot->token->serialnr))
372 continue;
373
374
375 cert = slot_find_cert(vpninfo, ctx, slot, cert_label, cert_id, cert_id_len);
376 if (cert)
377 goto got_cert;
378
379 login_slot = slot;
380 matching_slots++;
381 }
382 /* If there was precisely one matching slot, and we still didn't find the cert,
383 try logging in to it. */
384 if (matching_slots == 1 && (login_slot->token->loginRequired || login_slot->token->userPinSet)) {
385 slot = login_slot;
386 vpn_progress(vpninfo, PRG_INFO,
387 _("Logging in to PKCS#11 slot '%s'\n"),
388 slot->description);
389 if (!slot_login(vpninfo, ctx, slot)) {
390 cert = slot_find_cert(vpninfo, ctx, slot, cert_label, cert_id, cert_id_len);
391 if (cert)
392 goto got_cert;
393 }
394 }
395 ret = -EINVAL;
396 vpn_progress(vpninfo, PRG_ERR,
397 _("Failed to find PKCS#11 cert '%s'\n"),
398 vpninfo->cert);
399 got_cert:
400 if (cert) {
401 /* This happens if the cert is too large for the fixed buffer
402 in libp11 :( */
403 if (!cert->x509) {
404 vpn_progress(vpninfo, PRG_ERR,
405 _("Certificate X.509 content not fetched by libp11\n"));
406 ret = -EIO;
407 goto out;
408 }
409
410 vpn_progress(vpninfo, PRG_DEBUG,
411 _("Using PKCS#11 certificate %s\n"), vpninfo->cert);
412
413 vpninfo->cert_x509 = X509_dup(cert->x509);
414 if (!SSL_CTX_use_certificate(vpninfo->https_ctx, vpninfo->cert_x509)) {
415 vpn_progress(vpninfo, PRG_ERR,
416 _("Failed to install certificate in OpenSSL context\n"));
417 openconnect_report_ssl_errors(vpninfo);
418 ret = -EIO;
419 goto out;
420 }
421 /* If the key is in PKCS#11 too (which is likely), then keep the slot around.
422 We might want to know which slot the certificate was found in, so we can
423 log into it to find the key. */
424 if (!strncmp(vpninfo->sslkey, "pkcs11:", 7)) {
425 vpninfo->pkcs11_slot_list = slot_list;
426 vpninfo->pkcs11_slot_count = slot_count;
427 vpninfo->pkcs11_cert_slot = slot;
428 slot_list = NULL;
429 }
430 /* Also remember the ID of the cert, in case it helps us find the matching key */
431 vpninfo->pkcs11_cert_id = malloc(cert->id_len);
432 if (vpninfo->pkcs11_cert_id) {
433 vpninfo->pkcs11_cert_id_len = cert->id_len;
434 memcpy(vpninfo->pkcs11_cert_id, cert->id, cert->id_len);
435 }
436 }
437 out:
438 if (match_tok) {
439 free(match_tok->model);
440 free(match_tok->manufacturer);
441 free(match_tok->serialnr);
442 free(match_tok->label);
443 free(match_tok);
444 }
445 free(cert_id);
446 free(cert_label);
447 if (slot_list)
448 PKCS11_release_all_slots(ctx, slot_list, slot_count);
449
450 return ret;
451 }
452
slot_find_key(struct openconnect_info * vpninfo,PKCS11_CTX * ctx,PKCS11_SLOT * slot,const char * key_label,unsigned char * key_id,size_t key_id_len)453 static PKCS11_KEY *slot_find_key(struct openconnect_info *vpninfo, PKCS11_CTX *ctx,
454 PKCS11_SLOT *slot, const char *key_label,
455 unsigned char *key_id, size_t key_id_len)
456 {
457 PKCS11_KEY *key_list = NULL, *key = NULL;
458 unsigned int key_count;
459
460 if (PKCS11_enumerate_keys(slot->token, &key_list, &key_count) < 0) {
461 vpn_progress(vpninfo, PRG_ERR,
462 _("Failed to enumerate keys in PKCS#11 slot '%s'\n"),
463 slot->description);
464 return NULL;
465 }
466
467 vpn_progress(vpninfo, PRG_TRACE,
468 _("Found %d keys in slot '%s'\n"),
469 key_count, slot->description);
470
471 for (key = key_list; key < &key_list[key_count]; key++) {
472
473 if (key_label && strcmp(key_label, key->label))
474 continue;
475
476 if (key_id && (key_id_len != key->id_len ||
477 memcmp(key_id, key->id, key_id_len)))
478 continue;
479
480 return key;
481 }
482 return NULL;
483 }
484
485 #ifndef OPENSSL_NO_EC
486 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
487 #define EVP_PKEY_id(k) ((k)->type)
488 #endif
validate_ecdsa_key(struct openconnect_info * vpninfo,EC_KEY * priv_ec)489 static int validate_ecdsa_key(struct openconnect_info *vpninfo, EC_KEY *priv_ec)
490 {
491 EVP_PKEY *pub_pkey;
492 EC_KEY *pub_ec;
493 unsigned char rdata[SHA1_SIZE];
494 unsigned int siglen = ECDSA_size(priv_ec);
495 unsigned char *sig;
496 int ret = -EINVAL;
497
498 pub_pkey = X509_get_pubkey(vpninfo->cert_x509);
499 if (!pub_pkey) {
500 vpn_progress(vpninfo, PRG_ERR,
501 _("Certificate has no public key\n"));
502 goto out;
503 }
504 pub_ec = EVP_PKEY_get1_EC_KEY(pub_pkey);
505 if (!pub_ec) {
506 vpn_progress(vpninfo, PRG_ERR,
507 _("Certificate does not match private key\n"));
508 goto out_pkey;
509 }
510 vpn_progress(vpninfo, PRG_TRACE, _("Checking EC key matches cert\n"));
511 sig = malloc(siglen);
512 if (!sig) {
513 vpn_progress(vpninfo, PRG_ERR,
514 _("Failed to allocate signature buffer\n"));
515 ret = -ENOMEM;
516 goto out_pubec;
517 }
518 if (!RAND_bytes(rdata, sizeof(rdata))) {
519 /* Actually, who cares? */
520 }
521 if (!ECDSA_sign(NID_sha1, rdata, sizeof(rdata),
522 sig, &siglen, priv_ec)) {
523 vpn_progress(vpninfo, PRG_ERR,
524 _("Failed to sign dummy data to validate EC key\n"));
525 openconnect_report_ssl_errors(vpninfo);
526 goto out_sig;
527 }
528 if (!ECDSA_verify(NID_sha1, rdata, sizeof(rdata), sig, siglen, pub_ec)) {
529 vpn_progress(vpninfo, PRG_ERR,
530 _("Certificate does not match private key\n"));
531 goto out_sig;
532 }
533
534 /* Finally, copy the public EC_POINT data now that we know it really did match */
535 EC_KEY_set_public_key(priv_ec, EC_KEY_get0_public_key(pub_ec));
536 ret = 0;
537
538 out_sig:
539 free(sig);
540 out_pubec:
541 EC_KEY_free(pub_ec);
542 out_pkey:
543 EVP_PKEY_free(pub_pkey);
544 out:
545 return ret;
546 }
547 #endif
548
load_pkcs11_key(struct openconnect_info * vpninfo)549 int load_pkcs11_key(struct openconnect_info *vpninfo)
550 {
551 PKCS11_CTX *ctx;
552 PKCS11_TOKEN *match_tok = NULL;
553 PKCS11_KEY *key = NULL;
554 EVP_PKEY *pkey = NULL;
555 char *key_label = NULL;
556 unsigned char *key_id = NULL;
557 size_t key_id_len = 0;
558 PKCS11_SLOT *slot_list = NULL, *slot, *login_slot = NULL;
559 unsigned int slot_count, matching_slots = 0;
560 int ret = 0;
561
562 ctx = pkcs11_ctx(vpninfo);
563 if (!ctx)
564 return -EIO;
565
566 if (parse_pkcs11_uri(vpninfo->sslkey, &match_tok, &key_id,
567 &key_id_len, &key_label, &vpninfo->cert_password) < 0) {
568 vpn_progress(vpninfo, PRG_ERR,
569 _("Failed to parse PKCS#11 URI '%s'\n"),
570 vpninfo->sslkey);
571 return -EINVAL;
572 }
573
574 if (vpninfo->pkcs11_slot_list) {
575 slot_list = vpninfo->pkcs11_slot_list;
576 slot_count = vpninfo->pkcs11_slot_count;
577 } else if (PKCS11_enumerate_slots(ctx, &slot_list, &slot_count) < 0) {
578 vpn_progress(vpninfo, PRG_ERR,
579 _("Failed to enumerate PKCS#11 slots\n"));
580 openconnect_report_ssl_errors(vpninfo);
581 ret = -EIO;
582 goto out;
583 }
584
585 for (slot = slot_list; slot < &slot_list[slot_count] && slot != login_slot; slot++) {
586 if (!slot->token)
587 continue;
588 if (match_tok->label &&
589 strcmp(match_tok->label, slot->token->label))
590 continue;
591 if (match_tok->manufacturer &&
592 strcmp(match_tok->manufacturer, slot->token->manufacturer))
593 continue;
594 if (match_tok->model &&
595 strcmp(match_tok->model, slot->token->model))
596 continue;
597 if (match_tok->serialnr &&
598 strcmp(match_tok->serialnr, slot->token->serialnr))
599 continue;
600
601 key = slot_find_key(vpninfo, ctx, slot, key_label, key_id, key_id_len);
602 if (key)
603 goto got_key;
604
605 login_slot = slot;
606 matching_slots++;
607 }
608 /* If there was precisely one matching slot, or if we know which slot
609 the cert was found in and the key wasn't separately specified, then
610 try that slot. */
611 if (matching_slots != 1 && vpninfo->pkcs11_cert_slot &&
612 vpninfo->sslkey == vpninfo->cert) {
613 /* Use the slot the cert was found in, if one specifier was given for both */
614 matching_slots = 1;
615 login_slot = vpninfo->pkcs11_cert_slot;
616 vpninfo->pkcs11_cert_slot = NULL;
617 }
618 if (matching_slots == 1 && (login_slot->token->loginRequired || login_slot->token->userPinSet)) {
619 slot = login_slot;
620 vpn_progress(vpninfo, PRG_INFO,
621 _("Logging in to PKCS#11 slot '%s'\n"),
622 slot->description);
623 if (!slot_login(vpninfo, ctx, slot)) {
624 key = slot_find_key(vpninfo, ctx, slot, key_label, key_id, key_id_len);
625 if (key)
626 goto got_key;
627
628 /* We still haven't found it. If we weren't explicitly given a URI for
629 the key and we're inferring the location of the key from the cert,
630 then drop the label and try matching the CKA_ID of the cert. */
631 if (vpninfo->cert == vpninfo->sslkey && vpninfo->pkcs11_cert_id &&
632 (key_label || !key_id)) {
633 key = slot_find_key(vpninfo, ctx, slot, NULL, vpninfo->pkcs11_cert_id,
634 vpninfo->pkcs11_cert_id_len);
635 if (key)
636 goto got_key;
637 }
638 }
639 }
640 ret = -EINVAL;
641 vpn_progress(vpninfo, PRG_ERR,
642 _("Failed to find PKCS#11 key '%s'\n"),
643 vpninfo->sslkey);
644
645 got_key:
646 if (key) {
647 vpn_progress(vpninfo, PRG_DEBUG,
648 _("Using PKCS#11 key %s\n"), vpninfo->sslkey);
649
650 pkey = PKCS11_get_private_key(key);
651 if (!pkey) {
652 vpn_progress(vpninfo, PRG_ERR,
653 _("Failed to instantiated private key from PKCS#11\n"));
654 openconnect_report_ssl_errors(vpninfo);
655 ret = -EIO;
656 goto out;
657 }
658
659 #ifndef OPENSSL_NO_EC
660 /*
661 * If an EC EVP_PKEY has no public key, OpenSSL will crash
662 * when trying to check it matches the certificate:
663 * https://github.com/openssl/openssl/issues/1532
664 *
665 * Work around this by detecting this condition, manually
666 * checking that the certificate *does* match by performing
667 * a signature and validating it against the cert, then
668 * copying the EC_POINT public key information from the cert.
669 */
670 if (EVP_PKEY_id(pkey) == EVP_PKEY_EC) {
671 EC_KEY *priv_ec = EVP_PKEY_get1_EC_KEY(pkey);
672
673 ret = 0;
674 if (!EC_KEY_get0_public_key(priv_ec))
675 ret = validate_ecdsa_key(vpninfo, priv_ec);
676 EC_KEY_free(priv_ec);
677 if (ret)
678 goto out;
679 }
680 #endif
681 if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, pkey)) {
682 vpn_progress(vpninfo, PRG_ERR, _("Add key from PKCS#11 failed\n"));
683 openconnect_report_ssl_errors(vpninfo);
684 ret = -EINVAL;
685 goto out;
686 }
687
688 /* We have to keep the entire slot list around, because the EVP_PKEY
689 depends on the one we're using, and we have no way to free the
690 others. */
691 vpninfo->pkcs11_slot_list = slot_list;
692 vpninfo->pkcs11_slot_count = slot_count;
693 slot_list = NULL;
694 }
695 out:
696 if (match_tok) {
697 free(match_tok->model);
698 free(match_tok->manufacturer);
699 free(match_tok->serialnr);
700 free(match_tok->label);
701 free(match_tok);
702 }
703 free(key_id);
704 free(key_label);
705 if (slot_list)
706 PKCS11_release_all_slots(ctx, slot_list, slot_count);
707
708 return ret;
709 }
710 #else
load_pkcs11_key(struct openconnect_info * vpninfo)711 int load_pkcs11_key(struct openconnect_info *vpninfo)
712 {
713 vpn_progress(vpninfo, PRG_ERR,
714 _("This version of OpenConnect was built without PKCS#11 support\n"));
715 return -EINVAL;
716 }
load_pkcs11_certificate(struct openconnect_info * vpninfo)717 int load_pkcs11_certificate(struct openconnect_info *vpninfo)
718 {
719 vpn_progress(vpninfo, PRG_ERR,
720 _("This version of OpenConnect was built without PKCS#11 support\n"));
721 return -EINVAL;
722 }
723 #endif
724