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