Use request_passphrase() for OpenSSL PEM files
[platform/upstream/openconnect.git] / openssl.c
1 /*
2  * OpenConnect (SSL + DTLS) VPN client
3  *
4  * Copyright © 2008-2012 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  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to:
19  *
20  *   Free Software Foundation, Inc.
21  *   51 Franklin Street, Fifth Floor,
22  *   Boston, MA 02110-1301 USA
23  */
24
25 #include <errno.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <ctype.h>
29
30 #include <openssl/ssl.h>
31 #include <openssl/err.h>
32 #include <openssl/engine.h>
33 #include <openssl/evp.h>
34 #include <openssl/rand.h>
35 #include <openssl/pkcs12.h>
36 #include <openssl/x509v3.h>
37 #include <openssl/x509.h>
38 #include <openssl/bio.h>
39
40 #include "openconnect-internal.h"
41
42 int openconnect_sha1(unsigned char *result, void *data, int len)
43 {
44         EVP_MD_CTX c;
45
46         EVP_MD_CTX_init(&c);
47         EVP_Digest(data, len, result, NULL, EVP_sha1(), NULL);
48         EVP_MD_CTX_cleanup(&c);
49
50         return 0;
51 }
52
53 int openconnect_get_cert_DER(struct openconnect_info *vpninfo,
54                              struct x509_st *cert, unsigned char **buf)
55 {
56         BIO *bp = BIO_new(BIO_s_mem());
57         BUF_MEM *certinfo;
58         size_t l;
59
60         if (!i2d_X509_bio(bp, cert)) {
61                 BIO_free(bp);
62                 return -EIO;
63         }
64
65         BIO_get_mem_ptr(bp, &certinfo);
66         l = certinfo->length;
67         *buf = malloc(l);
68         if (!*buf) {
69                 BIO_free(bp);
70                 return -ENOMEM;
71         }
72         memcpy(*buf, certinfo->data, l);
73         BIO_free(bp);
74         return l;
75 }
76
77 int openconnect_random(void *bytes, int len)
78 {
79         if (RAND_bytes(bytes, len) != 1)
80                 return -EIO;
81         return 0;
82 }
83
84 /* Helper functions for reading/writing lines over SSL.
85    We could use cURL for the HTTP stuff, but it's overkill */
86
87 int openconnect_SSL_write(struct openconnect_info *vpninfo, char *buf, size_t len)
88 {
89         size_t orig_len = len;
90
91         while (len) {
92                 int done = SSL_write(vpninfo->https_ssl, buf, len);
93
94                 if (done > 0)
95                         len -= done;
96                 else {
97                         int err = SSL_get_error(vpninfo->https_ssl, done);
98                         fd_set wr_set, rd_set;
99                         int maxfd = vpninfo->ssl_fd;
100
101                         FD_ZERO(&wr_set);
102                         FD_ZERO(&rd_set);
103                         
104                         if (err == SSL_ERROR_WANT_READ)
105                                 FD_SET(vpninfo->ssl_fd, &rd_set);
106                         else if (err == SSL_ERROR_WANT_WRITE)
107                                 FD_SET(vpninfo->ssl_fd, &wr_set);
108                         else {
109                                 vpn_progress(vpninfo, PRG_ERR, _("Failed to write to SSL socket"));
110                                 openconnect_report_ssl_errors(vpninfo);
111                                 return -EIO;
112                         }
113                         if (vpninfo->cancel_fd != -1) {
114                                 FD_SET(vpninfo->cancel_fd, &rd_set);
115                                 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
116                                         maxfd = vpninfo->cancel_fd;
117                         }
118                         select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
119                         if (vpninfo->cancel_fd != -1 &&
120                             FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
121                                 vpn_progress(vpninfo, PRG_ERR, _("SSL write cancelled\n"));
122                                 return -EINTR;
123                         }
124                 }
125         }
126         return orig_len;
127 }
128
129 int openconnect_SSL_read(struct openconnect_info *vpninfo, char *buf, size_t len)
130 {
131         int done;
132
133         while ((done = SSL_read(vpninfo->https_ssl, buf, len)) == -1) {
134                 int err = SSL_get_error(vpninfo->https_ssl, done);
135                 fd_set wr_set, rd_set;
136                 int maxfd = vpninfo->ssl_fd;
137
138                 FD_ZERO(&wr_set);
139                 FD_ZERO(&rd_set);
140                         
141                 if (err == SSL_ERROR_WANT_READ)
142                         FD_SET(vpninfo->ssl_fd, &rd_set);
143                 else if (err == SSL_ERROR_WANT_WRITE)
144                         FD_SET(vpninfo->ssl_fd, &wr_set);
145                 else {
146                         vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket"));
147                         openconnect_report_ssl_errors(vpninfo);
148                         return -EIO;
149                 }
150                 if (vpninfo->cancel_fd != -1) {
151                         FD_SET(vpninfo->cancel_fd, &rd_set);
152                         if (vpninfo->cancel_fd > vpninfo->ssl_fd)
153                                 maxfd = vpninfo->cancel_fd;
154                 }
155                 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
156                 if (vpninfo->cancel_fd != -1 &&
157                     FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
158                         vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
159                         return -EINTR;
160                 }
161         }
162         return done;
163 }
164
165 static int print_err(const char *str, size_t len, void *ptr)
166 {
167         struct openconnect_info *vpninfo = ptr;
168
169         vpn_progress(vpninfo, PRG_ERR, "%s", str);
170         return 0;
171 }
172
173 void openconnect_report_ssl_errors(struct openconnect_info *vpninfo)
174 {
175         ERR_print_errors_cb(print_err, vpninfo);
176 }
177
178 int openconnect_SSL_gets(struct openconnect_info *vpninfo, char *buf, size_t len)
179 {
180         int i = 0;
181         int ret;
182
183         if (len < 2)
184                 return -EINVAL;
185
186         while (1) {
187                 ret = SSL_read(vpninfo->https_ssl, buf + i, 1);
188                 if (ret == 1) {
189                         if (buf[i] == '\n') {
190                                 buf[i] = 0;
191                                 if (i && buf[i-1] == '\r') {
192                                         buf[i-1] = 0;
193                                         i--;
194                                 }
195                                 return i;
196                         }
197                         i++;
198
199                         if (i >= len - 1) {
200                                 buf[i] = 0;
201                                 return i;
202                         }
203                 } else {
204                         fd_set rd_set, wr_set;
205                         int maxfd = vpninfo->ssl_fd;
206                         
207                         FD_ZERO(&rd_set);
208                         FD_ZERO(&wr_set);
209                         
210                         ret = SSL_get_error(vpninfo->https_ssl, ret);
211                         if (ret == SSL_ERROR_WANT_READ)
212                                 FD_SET(vpninfo->ssl_fd, &rd_set);
213                         else if (ret == SSL_ERROR_WANT_WRITE)
214                                 FD_SET(vpninfo->ssl_fd, &wr_set);
215                         else {
216                                 vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket\n"));
217                                 openconnect_report_ssl_errors(vpninfo);
218                                 ret = -EIO;
219                                 break;
220                         }
221                         if (vpninfo->cancel_fd != -1) {
222                                 FD_SET(vpninfo->cancel_fd, &rd_set);
223                                 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
224                                         maxfd = vpninfo->cancel_fd;
225                         }
226                         select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
227                         if (vpninfo->cancel_fd != -1 &&
228                             FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
229                                 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
230                                 ret = -EINTR;
231                                 break;
232                         }
233                 }
234         }
235         buf[i] = 0;
236         return i ?: ret;
237 }
238
239 static int pem_pw_cb(char *buf, int len, int w, void *v)
240 {
241         struct openconnect_info *vpninfo = v;
242         char *pass = NULL;
243         int plen;
244
245         if (vpninfo->cert_password) {
246                 pass = vpninfo->cert_password;
247                 vpninfo->cert_password = NULL;
248         } else if (request_passphrase(vpninfo, &pass,
249                                       _("Enter PEM pass phrase:")))
250                 return -1;
251
252         plen = strlen(pass);
253
254         if (len <= plen) {
255                 vpn_progress(vpninfo, PRG_ERR,
256                              _("PEM password too long (%d >= %d)\n"),
257                              plen, len);
258                 free(pass);
259                 return -1;
260         }
261
262         memcpy(buf, pass, plen+1);
263         free(pass);
264         return plen;
265 }
266
267 static int load_pkcs12_certificate(struct openconnect_info *vpninfo, PKCS12 *p12)
268 {
269         EVP_PKEY *pkey = NULL;
270         X509 *cert = NULL;
271         STACK_OF(X509) *ca;
272         int ret = 0;
273         char *pass;
274
275         pass = vpninfo->cert_password;
276         vpninfo->cert_password = NULL;
277  retrypass:
278         /* We do this every time round the loop, to work around a bug in
279            OpenSSL < 1.0.0-beta2 -- where the stack at *ca will be freed
280            when PKCS12_parse() returns an error, but *ca is left pointing
281            to the freed memory. */
282         ca = NULL;
283         if (!pass && request_passphrase(vpninfo, &pass,
284                                         _("Enter PKCS#12 pass phrase:")) < 0) {
285                 PKCS12_free(p12);
286                 return -EINVAL;
287         }
288         if (!PKCS12_parse(p12, pass, &pkey, &cert, &ca)) {
289                 unsigned long err = ERR_peek_error();
290
291                 openconnect_report_ssl_errors(vpninfo);
292
293                 if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
294                     ERR_GET_FUNC(err) == PKCS12_F_PKCS12_PARSE &&
295                     ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
296                         vpn_progress(vpninfo, PRG_ERR,
297                                      _("Parse PKCS#12 failed (wrong passphrase?)\n"));
298                         free(pass);
299                         pass = NULL;
300                         goto retrypass;
301                 }
302
303                 vpn_progress(vpninfo, PRG_ERR,
304                              _("Parse PKCS#12 failed (see above errors)\n"));
305                 PKCS12_free(p12);
306                 return -EINVAL;
307         }
308         if (cert) {
309                 vpninfo->cert_x509 = cert;
310                 SSL_CTX_use_certificate(vpninfo->https_ctx, cert);
311         } else {
312                 vpn_progress(vpninfo, PRG_ERR,
313                              _("PKCS#12 contained no certificate!"));
314                 ret = -EINVAL;
315         }
316
317         if (pkey) {
318                 SSL_CTX_use_PrivateKey(vpninfo->https_ctx, pkey);
319                 EVP_PKEY_free(pkey);
320         } else {
321                 vpn_progress(vpninfo, PRG_ERR,
322                              _("PKCS#12 contained no private key!"));
323                 ret = -EINVAL;
324         }
325
326         /* Only include supporting certificates which are actually necessary */
327         if (ca) {
328                 int i;
329         next:
330                 for (i = 0; i < sk_X509_num(ca); i++) {
331                         X509 *cert2 = sk_X509_value(ca, i);
332                         if (X509_check_issued(cert2, cert) == X509_V_OK) {
333                                 char buf[200];
334
335                                 if (cert2 == cert)
336                                         break;
337                                 if (X509_check_issued(cert2, cert2) == X509_V_OK)
338                                         break;
339
340                                 X509_NAME_oneline(X509_get_subject_name(cert2),
341                                                   buf, sizeof(buf));
342                                 vpn_progress(vpninfo, PRG_DEBUG,
343                                              _("Extra cert from PKCS#12: '%s'\n"), buf);
344                                 CRYPTO_add(&cert2->references, 1, CRYPTO_LOCK_X509);
345                                 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert2);
346                                 cert = cert2;
347                                 goto next;
348                         }
349                 }
350                 sk_X509_pop_free(ca, X509_free);
351         }
352
353         PKCS12_free(p12);
354         return ret;
355 }
356
357 #ifdef HAVE_ENGINE
358 static int load_tpm_certificate(struct openconnect_info *vpninfo)
359 {
360         ENGINE *e;
361         EVP_PKEY *key;
362         ENGINE_load_builtin_engines();
363
364         e = ENGINE_by_id("tpm");
365         if (!e) {
366                 vpn_progress(vpninfo, PRG_ERR, _("Can't load TPM engine.\n"));
367                 openconnect_report_ssl_errors(vpninfo);
368                 return -EINVAL;
369         }
370         if (!ENGINE_init(e) || !ENGINE_set_default_RSA(e) ||
371             !ENGINE_set_default_RAND(e)) {
372                 vpn_progress(vpninfo, PRG_ERR, _("Failed to init TPM engine\n"));
373                 openconnect_report_ssl_errors(vpninfo);
374                 ENGINE_free(e);
375                 return -EINVAL;
376         }
377
378         if (vpninfo->cert_password) {
379                 if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->cert_password),
380                                      vpninfo->cert_password, NULL, 0)) {
381                         vpn_progress(vpninfo, PRG_ERR,
382                                      _("Failed to set TPM SRK password\n"));
383                         openconnect_report_ssl_errors(vpninfo);
384                 }
385         }
386         key = ENGINE_load_private_key(e, vpninfo->sslkey, NULL, NULL);
387         if (!key) {
388                 vpn_progress(vpninfo, PRG_ERR,
389                              _("Failed to load TPM private key\n"));
390                 openconnect_report_ssl_errors(vpninfo);
391                 ENGINE_free(e);
392                 ENGINE_finish(e);
393                 return -EINVAL;
394         }
395         if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
396                 vpn_progress(vpninfo, PRG_ERR, _("Add key from TPM failed\n"));
397                 openconnect_report_ssl_errors(vpninfo);
398                 ENGINE_free(e);
399                 ENGINE_finish(e);
400                 return -EINVAL;
401         }
402         return 0;
403 }
404 #else
405 static int load_tpm_certificate(struct openconnect_info *vpninfo)
406 {
407         vpn_progress(vpninfo, PRG_ERR,
408                      _("This version of OpenConnect was built without TPM support\n"));
409         return -EINVAL;
410 }
411 #endif
412
413 static int reload_pem_cert(struct openconnect_info *vpninfo)
414 {
415         BIO *b = BIO_new(BIO_s_file_internal());
416
417         if (!b)
418                 return -ENOMEM;
419
420         if (BIO_read_filename(b, vpninfo->cert) <= 0) {
421         err:
422                 BIO_free(b);
423                 vpn_progress(vpninfo, PRG_ERR,
424                              _("Failed to reload X509 cert for expiry check\n"));
425                 openconnect_report_ssl_errors(vpninfo);
426                 return -EIO;
427         }
428         vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, NULL, NULL);
429         if (!vpninfo->cert_x509)
430                 goto err;
431
432         return 0;
433 }
434
435 static int load_certificate(struct openconnect_info *vpninfo)
436 {
437         vpn_progress(vpninfo, PRG_TRACE,
438                      _("Using certificate file %s\n"), vpninfo->cert);
439
440         if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
441             vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
442                 FILE *f;
443                 PKCS12 *p12;
444
445                 f = fopen(vpninfo->cert, "r");
446                 if (!f) {
447                         vpn_progress(vpninfo, PRG_ERR,
448                                      _("Failed to open certificate file %s: %s\n"),
449                                      vpninfo->cert, strerror(errno));
450                         return -ENOENT;
451                 }
452                 p12 = d2i_PKCS12_fp(f, NULL);
453                 fclose(f);
454                 if (p12)
455                         return load_pkcs12_certificate(vpninfo, p12);
456
457                 /* Not PKCS#12 */
458                 if (vpninfo->cert_type == CERT_TYPE_PKCS12) {
459                         vpn_progress(vpninfo, PRG_ERR, _("Read PKCS#12 failed\n"));
460                         openconnect_report_ssl_errors(vpninfo);
461                         return -EINVAL;
462                 }
463                 /* Clear error and fall through to see if it's a PEM file... */
464                 ERR_clear_error();
465         }
466
467         /* It's PEM or TPM now, and either way we need to load the plain cert: */
468         if (!SSL_CTX_use_certificate_chain_file(vpninfo->https_ctx,
469                                                 vpninfo->cert)) {
470                 vpn_progress(vpninfo, PRG_ERR,
471                              _("Loading certificate failed\n"));
472                 openconnect_report_ssl_errors(vpninfo);
473                 return -EINVAL;
474         }
475
476         /* Ew, we can't get it back from the OpenSSL CTX in any sane fashion */
477         reload_pem_cert(vpninfo);
478
479         if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
480                 FILE *f = fopen(vpninfo->sslkey, "r");
481                 char buf[256];
482
483                 if (!f) {
484                         vpn_progress(vpninfo, PRG_ERR,
485                                      _("Failed to open private key file %s: %s\n"),
486                                      vpninfo->cert, strerror(errno));
487                         return -ENOENT;
488                 }
489
490                 buf[255] = 0;
491                 while (fgets(buf, 255, f)) {
492                         if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
493                                 vpninfo->cert_type = CERT_TYPE_TPM;
494                                 break;
495                         } else if (!strcmp(buf, "-----BEGIN RSA PRIVATE KEY-----\n") ||
496                                    !strcmp(buf, "-----BEGIN DSA PRIVATE KEY-----\n") ||
497                                    !strcmp(buf, "-----BEGIN ENCRYPTED PRIVATE KEY-----\n")) {
498                                 vpninfo->cert_type = CERT_TYPE_PEM;
499                                 break;
500                         }
501                 }
502                 fclose(f);
503                 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
504                         vpn_progress(vpninfo, PRG_ERR,
505                                      _("Failed to identify private key type in '%s'\n"),
506                                      vpninfo->sslkey);
507                         return -EINVAL;
508                 }
509         }
510
511         if (vpninfo->cert_type == CERT_TYPE_TPM)
512                 return load_tpm_certificate(vpninfo);
513
514         /* Standard PEM certificate */
515         SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx, pem_pw_cb);
516         SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx, vpninfo);
517  again:
518         if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx, vpninfo->sslkey,
519                                             SSL_FILETYPE_PEM)) {
520                 unsigned long err = ERR_peek_error();
521                 
522                 openconnect_report_ssl_errors(vpninfo);
523
524 #ifndef EVP_F_EVP_DECRYPTFINAL_EX
525 #define EVP_F_EVP_DECRYPTFINAL_EX EVP_F_EVP_DECRYPTFINAL
526 #endif
527                 /* If the user fat-fingered the passphrase, try again */
528                 if (ERR_GET_LIB(err) == ERR_LIB_EVP &&
529                     ERR_GET_FUNC(err) == EVP_F_EVP_DECRYPTFINAL_EX &&
530                     ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT) {
531                         vpn_progress(vpninfo, PRG_ERR,
532                                      _("Loading private key failed (wrong passphrase?)\n"));
533                         goto again;
534                 }
535                 
536                 vpn_progress(vpninfo, PRG_ERR,
537                              _("Loading private key failed (see above errors)\n"));
538                 return -EINVAL;
539         }
540         return 0;
541 }
542
543 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
544                                 X509 *cert, const EVP_MD *type,
545                                 char *buf)
546 {
547         unsigned char md[EVP_MAX_MD_SIZE];
548         unsigned int i, n;
549
550         if (!X509_digest(cert, type, md, &n))
551                 return -ENOMEM;
552
553         for (i=0; i < n; i++)
554                 sprintf(&buf[i*2], "%02X", md[i]);
555
556         return 0;
557 }
558
559 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
560                              X509 *cert, char *buf)
561 {
562         return get_cert_fingerprint(vpninfo, cert, EVP_md5(), buf);
563 }
564
565 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
566                               X509 *cert, char *buf)
567 {
568         return get_cert_fingerprint(vpninfo, cert, EVP_sha1(), buf);
569 }
570
571 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
572 {
573         char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
574         int ret;
575
576         ret = openconnect_get_cert_sha1(vpninfo, cert, fingerprint);
577         if (ret)
578                 return ret;
579
580         if (strcasecmp(vpninfo->servercert, fingerprint)) {
581                 vpn_progress(vpninfo, PRG_ERR,
582                              _("Server SSL certificate didn't match: %s\n"), fingerprint);
583                 return -EINVAL;
584         }
585         return 0;
586 }
587
588 static int match_hostname_elem(const char *hostname, int helem_len,
589                                const char *match, int melem_len)
590 {
591         if (!helem_len && !melem_len)
592                 return 0;
593
594         if (!helem_len || !melem_len)
595                 return -1;
596
597
598         if (match[0] == '*') {
599                 int i;
600
601                 for (i = 1 ; i <= helem_len; i++) {
602                         if (!match_hostname_elem(hostname + i, helem_len - i,
603                                                  match + 1, melem_len - 1))
604                                 return 0;
605                 }
606                 return -1;
607         }
608
609         /* From the NetBSD (5.1) man page for ctype(3):
610            Values of type char or signed char must first be cast to unsigned char,
611            to ensure that the values are within the correct range.  The result
612            should then be cast to int to avoid warnings from some compilers.
613            We do indeed get warning "array subscript has type 'char'" without
614            the casts. Ick. */
615         if (toupper((int)(unsigned char)hostname[0]) ==
616             toupper((int)(unsigned char)match[0]))
617                 return match_hostname_elem(hostname + 1, helem_len - 1,
618                                            match + 1, melem_len - 1);
619
620         return -1;
621 }
622
623 static int match_hostname(const char *hostname, const char *match)
624 {
625         while (*match) {
626                 const char *h_dot, *m_dot;
627                 int helem_len, melem_len;
628
629                 h_dot = strchr(hostname, '.');
630                 m_dot = strchr(match, '.');
631                 
632                 if (h_dot && m_dot) {
633                         helem_len = h_dot - hostname + 1;
634                         melem_len = m_dot - match + 1;
635                 } else if (!h_dot && !m_dot) {
636                         helem_len = strlen(hostname);
637                         melem_len = strlen(match);
638                 } else
639                         return -1;
640
641
642                 if (match_hostname_elem(hostname, helem_len,
643                                         match, melem_len))
644                         return -1;
645
646                 hostname += helem_len;
647                 match += melem_len;
648         }
649         if (*hostname)
650                 return -1;
651
652         return 0;
653 }
654
655 /* cf. RFC2818 and RFC2459 */
656 static int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
657 {
658         STACK_OF(GENERAL_NAME) *altnames;
659         X509_NAME *subjname;
660         ASN1_STRING *subjasn1;
661         char *subjstr = NULL;
662         int addrlen = 0;
663         int i, altdns = 0;
664         char addrbuf[sizeof(struct in6_addr)];
665         int ret;
666
667         /* Allow GEN_IP in the certificate only if we actually connected
668            by IP address rather than by name. */
669         if (inet_pton(AF_INET, vpninfo->hostname, addrbuf) > 0)
670                 addrlen = 4;
671         else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
672                 addrlen = 16;
673         else if (vpninfo->hostname[0] == '[' &&
674                  vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
675                 char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
676                 *p = 0;
677                 if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
678                         addrlen = 16;
679                 *p = ']';
680         }
681
682         altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
683                                     NULL, NULL);
684         for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
685                 const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);
686
687                 if (this->type == GEN_DNS) {
688                         char *str;
689
690                         int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
691                         if (len < 0)
692                                 continue;
693
694                         altdns = 1;
695
696                         /* We don't like names with embedded NUL */
697                         if (strlen(str) != len)
698                                 continue;
699
700                         if (!match_hostname(vpninfo->hostname, str)) {
701                                 vpn_progress(vpninfo, PRG_TRACE,
702                                              _("Matched DNS altname '%s'\n"),
703                                              str);
704                                 GENERAL_NAMES_free(altnames);
705                                 OPENSSL_free(str);
706                                 return 0;
707                         } else {
708                                 vpn_progress(vpninfo, PRG_TRACE,
709                                              _("No match for altname '%s'\n"),
710                                              str);
711                         }
712                         OPENSSL_free(str);
713                 } else if (this->type == GEN_IPADD && addrlen) {
714                         char host[80];
715                         int family;
716
717                         if (this->d.ip->length == 4) {
718                                 family = AF_INET;
719                         } else if (this->d.ip->length == 16) {
720                                 family = AF_INET6;
721                         } else {
722                                 vpn_progress(vpninfo, PRG_ERR,
723                                              _("Certificate has GEN_IPADD altname with bogus length %d\n"),
724                                              this->d.ip->length);
725                                 continue;
726                         }
727                         
728                         /* We only do this for the debug messages */
729                         inet_ntop(family, this->d.ip->data, host, sizeof(host));
730
731                         if (this->d.ip->length == addrlen &&
732                             !memcmp(addrbuf, this->d.ip->data, addrlen)) {
733                                 vpn_progress(vpninfo, PRG_TRACE,
734                                              _("Matched %s address '%s'\n"),
735                                              (family == AF_INET6)?"IPv6":"IPv4",
736                                              host);
737                                 GENERAL_NAMES_free(altnames);
738                                 return 0;
739                         } else {
740                                 vpn_progress(vpninfo, PRG_TRACE,
741                                              _("No match for %s address '%s'\n"),
742                                              (family == AF_INET6)?"IPv6":"IPv4",
743                                              host);
744                         }
745                 } else if (this->type == GEN_URI) {
746                         char *str;
747                         char *url_proto, *url_host, *url_path, *url_host2;
748                         int url_port;
749                         int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
750
751                         if (len < 0)
752                                 continue;
753
754                         /* We don't like names with embedded NUL */
755                         if (strlen(str) != len)
756                                 continue;
757
758                         if (internal_parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
759                                 OPENSSL_free(str);
760                                 continue;
761                         }
762
763                         if (!url_proto || strcasecmp(url_proto, "https"))
764                                 goto no_uri_match;
765
766                         if (url_port != vpninfo->port)
767                                 goto no_uri_match;
768
769                         /* Leave url_host as it was so that it can be freed */
770                         url_host2 = url_host;
771                         if (addrlen == 16 && vpninfo->hostname[0] != '[' &&
772                             url_host[0] == '[' && url_host[strlen(url_host)-1] == ']') {
773                                 /* Cope with https://[IPv6]/ when the hostname is bare IPv6 */
774                                 url_host[strlen(url_host)-1] = 0;
775                                 url_host2++;
776                         }
777
778                         if (strcasecmp(vpninfo->hostname, url_host2))
779                                 goto no_uri_match;
780
781                         if (url_path) {
782                                 vpn_progress(vpninfo, PRG_TRACE,
783                                              _("URI '%s' has non-empty path; ignoring\n"),
784                                              str);
785                                 goto no_uri_match_silent;
786                         }
787                         vpn_progress(vpninfo, PRG_TRACE,
788                                      _("Matched URI '%s'\n"),
789                                      str);
790                         free(url_proto);
791                         free(url_host);
792                         free(url_path);
793                         OPENSSL_free(str);
794                         GENERAL_NAMES_free(altnames);
795                         return 0;
796
797                 no_uri_match:
798                         vpn_progress(vpninfo, PRG_TRACE,
799                                      _("No match for URI '%s'\n"),
800                                      str);
801                 no_uri_match_silent:
802                         free(url_proto);
803                         free(url_host);
804                         free(url_path);
805                         OPENSSL_free(str);
806                 }
807         }
808         GENERAL_NAMES_free(altnames);
809
810         /* According to RFC2818, we don't use the legacy subject name if
811            there was an altname with DNS type. */
812         if (altdns) {
813                 vpn_progress(vpninfo, PRG_ERR,
814                              _("No altname in peer cert matched '%s'\n"),
815                              vpninfo->hostname);
816                 return -EINVAL;
817         }
818
819         subjname = X509_get_subject_name(peer_cert);
820         if (!subjname) {
821                 vpn_progress(vpninfo, PRG_ERR,
822                              _("No subject name in peer cert!\n"));
823                 return -EINVAL;
824         }
825
826         /* Find the _last_ (most specific) commonName */
827         i = -1;
828         while (1) {
829                 int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
830                 if (j >= 0)
831                         i = j;
832                 else
833                         break;
834         }
835
836         subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));
837
838         i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);
839
840         if (!subjstr || strlen(subjstr) != i) {
841                 vpn_progress(vpninfo, PRG_ERR,
842                              _("Failed to parse subject name in peer cert\n"));
843                 return -EINVAL;
844         }
845         ret = 0;
846
847         if (match_hostname(vpninfo->hostname, subjstr)) {
848                 vpn_progress(vpninfo, PRG_ERR,
849                              _("Peer cert subject mismatch ('%s' != '%s')\n"),
850                              subjstr, vpninfo->hostname);
851                 ret = -EINVAL;
852         } else {
853                 vpn_progress(vpninfo, PRG_TRACE,
854                              _("Matched peer certificate subject name '%s'\n"),
855                              subjstr);
856         }
857
858         OPENSSL_free(subjstr);                    
859         return ret;
860 }
861
862 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
863 {
864         X509 *peer_cert;
865         int ret;
866
867         peer_cert = SSL_get_peer_certificate(https_ssl);
868
869         if (vpninfo->servercert) {
870                 /* If given a cert fingerprint on the command line, that's
871                    all we look for */
872                 ret = check_server_cert(vpninfo, peer_cert);
873         } else {
874                 int vfy = SSL_get_verify_result(https_ssl);
875                 const char *err_string = NULL;
876
877                 if (vfy != X509_V_OK)
878                         err_string = X509_verify_cert_error_string(vfy);
879                 else if (match_cert_hostname(vpninfo, peer_cert))
880                         err_string = _("certificate does not match hostname");
881
882                 if (err_string) {
883                         vpn_progress(vpninfo, PRG_INFO,
884                                      _("Server certificate verify failed: %s\n"),
885                                      err_string);
886
887                         if (vpninfo->validate_peer_cert)
888                                 ret = vpninfo->validate_peer_cert(vpninfo->cbdata,
889                                                                   peer_cert,
890                                                                   err_string);
891                         else
892                                 ret = -EINVAL;
893                 } else {
894                         ret = 0;
895                 }
896         }
897         X509_free(peer_cert);
898
899         return ret;
900 }
901
902 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
903                                              SSL *ssl)
904 {
905         /* OpenSSL has problems with certificate chains -- if there are
906            multiple certs with the same name, it doesn't necessarily
907            choose the _right_ one. (RT#1942)
908            Pick the right ones for ourselves and add them manually. */
909         X509 *cert = SSL_get_certificate(ssl);
910         X509 *cert2;
911         X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
912         X509_STORE_CTX ctx;
913
914         if (!cert || !store)
915                 return;
916
917         /* If we already have 'supporting' certs, don't add them again */
918         if (vpninfo->https_ctx->extra_certs)
919                 return;
920
921         if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
922                 return;
923
924         while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
925                 char buf[200];
926                 if (cert2 == cert)
927                         break;
928                 if (X509_check_issued(cert2, cert2) == X509_V_OK)
929                         break;
930                 cert = cert2;
931                 X509_NAME_oneline(X509_get_subject_name(cert),
932                                   buf, sizeof(buf));
933                 vpn_progress(vpninfo, PRG_DEBUG,
934                              _("Extra cert from cafile: '%s'\n"), buf);
935                 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
936         }
937         X509_STORE_CTX_cleanup(&ctx);
938 }
939
940 #if OPENSSL_VERSION_NUMBER >= 0x00908000
941 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
942 {
943         /* We've seen certificates in the wild which don't have the
944            purpose fields filled in correctly */
945         X509_VERIFY_PARAM_set_purpose(ctx->param, X509_PURPOSE_ANY);
946         return X509_verify_cert(ctx);
947 }
948 #endif
949
950 static int check_certificate_expiry(struct openconnect_info *vpninfo)
951 {
952         ASN1_TIME *notAfter;
953         const char *reason = NULL;
954         time_t t;
955         int i;
956
957         if (!vpninfo->cert_x509)
958                 return 0;
959
960         t = time(NULL);
961         notAfter = X509_get_notAfter(vpninfo->cert_x509);
962         i = X509_cmp_time(notAfter, &t);
963         if (!i) {
964                 vpn_progress(vpninfo, PRG_ERR,
965                              _("Error in client cert notAfter field\n"));
966                 return -EINVAL;
967         } else if (i < 0) {
968                 reason = _("Client certificate has expired at");
969         } else {
970                 t += vpninfo->cert_expire_warning;
971                 i = X509_cmp_time(notAfter, &t);
972                 if (i < 0) {
973                         reason = _("Client certificate expires soon at");
974                 }
975         }
976         if (reason) {
977                 BIO *bp = BIO_new(BIO_s_mem());
978                 BUF_MEM *bm;
979                 const char *expiry = _("<error>");
980                 char zero = 0;
981
982                 if (bp) {
983                         ASN1_TIME_print(bp, notAfter);
984                         BIO_write(bp, &zero, 1);
985                         BIO_get_mem_ptr(bp, &bm);
986                         expiry = bm->data;
987                 }
988                 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, expiry);
989                 if (bp)
990                         BIO_free(bp);
991         }
992         return 0;
993 }
994 int openconnect_open_https(struct openconnect_info *vpninfo)
995 {
996         method_const SSL_METHOD *ssl3_method;
997         SSL *https_ssl;
998         BIO *https_bio;
999         int ssl_sock;
1000         int err;
1001
1002         if (vpninfo->https_ssl)
1003                 return 0;
1004
1005         if (vpninfo->peer_cert) {
1006                 X509_free(vpninfo->peer_cert);
1007                 vpninfo->peer_cert = NULL;
1008         }
1009
1010         ssl_sock = connect_https_socket(vpninfo);
1011         if (ssl_sock < 0)
1012                 return ssl_sock;
1013
1014         ssl3_method = TLSv1_client_method();
1015         if (!vpninfo->https_ctx) {
1016                 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
1017
1018                 /* Some servers (or their firewalls) really don't like seeing
1019                    extensions. */
1020 #ifdef SSL_OP_NO_TICKET
1021                 SSL_CTX_set_options (vpninfo->https_ctx, SSL_OP_NO_TICKET);
1022 #endif
1023
1024                 if (vpninfo->cert) {
1025                         err = load_certificate(vpninfo);
1026                         if (err) {
1027                                 vpn_progress(vpninfo, PRG_ERR,
1028                                              _("Loading certificate failed. Aborting.\n"));
1029                                 return err;
1030                         }
1031                         check_certificate_expiry(vpninfo);
1032                 }
1033
1034                 /* We just want to do:
1035                    SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY); 
1036                    ... but it doesn't work with OpenSSL < 0.9.8k because of 
1037                    problems with inheritance (fixed in v1.1.4.6 of
1038                    crypto/x509/x509_vpm.c) so we have to play silly buggers
1039                    instead. This trick doesn't work _either_ in < 0.9.7 but
1040                    I don't know of _any_ workaround which will, and can't
1041                    be bothered to find out either. */
1042 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1043                 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx,
1044                                                  ssl_app_verify_callback, NULL);
1045 #endif
1046                 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
1047
1048                 if (vpninfo->cafile) {
1049                         if (!SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL)) {
1050                                 vpn_progress(vpninfo, PRG_ERR,
1051                                              _("Failed to open CA file '%s'\n"),
1052                                              vpninfo->cafile);
1053                                 openconnect_report_ssl_errors(vpninfo);
1054                                 close(ssl_sock);
1055                                 return -EINVAL;
1056                         }
1057                 }
1058
1059         }
1060         https_ssl = SSL_new(vpninfo->https_ctx);
1061         workaround_openssl_certchain_bug(vpninfo, https_ssl);
1062
1063         https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
1064         BIO_set_nbio(https_bio, 1);
1065         SSL_set_bio(https_ssl, https_bio, https_bio);
1066
1067         vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1068                      vpninfo->hostname);
1069
1070         while ((err = SSL_connect(https_ssl)) <= 0) {
1071                 fd_set wr_set, rd_set;
1072                 int maxfd = ssl_sock;
1073                 
1074                 FD_ZERO(&wr_set);
1075                 FD_ZERO(&rd_set);
1076
1077                 err = SSL_get_error(https_ssl, err);
1078                 if (err == SSL_ERROR_WANT_READ)
1079                         FD_SET(ssl_sock, &rd_set);
1080                 else if (err == SSL_ERROR_WANT_WRITE)
1081                         FD_SET(ssl_sock, &wr_set);
1082                 else {
1083                         vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n"));
1084                         openconnect_report_ssl_errors(vpninfo);
1085                         SSL_free(https_ssl);
1086                         close(ssl_sock);
1087                         return -EINVAL;
1088                 }
1089
1090                 if (vpninfo->cancel_fd != -1) {
1091                         FD_SET(vpninfo->cancel_fd, &rd_set);
1092                         if (vpninfo->cancel_fd > ssl_sock)
1093                                 maxfd = vpninfo->cancel_fd;
1094                 }
1095                 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1096                 if (vpninfo->cancel_fd != -1 &&
1097                     FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1098                         vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1099                         SSL_free(https_ssl);
1100                         close(ssl_sock);
1101                         return -EINVAL;
1102                 }
1103         }
1104
1105         if (verify_peer(vpninfo, https_ssl)) {
1106                 SSL_free(https_ssl);
1107                 close(ssl_sock);
1108                 return -EINVAL;
1109         }
1110
1111         vpninfo->ssl_fd = ssl_sock;
1112         vpninfo->https_ssl = https_ssl;
1113
1114         /* Stash this now, because it might not be available later if the
1115            server has disconnected. */
1116         vpninfo->peer_cert = SSL_get_peer_certificate(vpninfo->https_ssl);
1117
1118         vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1119                      vpninfo->hostname);
1120
1121         return 0;
1122 }
1123
1124 void openconnect_close_https(struct openconnect_info *vpninfo)
1125 {
1126         if (vpninfo->peer_cert) {
1127                 X509_free(vpninfo->peer_cert);
1128                 vpninfo->peer_cert = NULL;
1129         }
1130         if (vpninfo->https_ssl) {
1131                 SSL_free(vpninfo->https_ssl);
1132                 vpninfo->https_ssl = NULL;
1133         }
1134         if (vpninfo->ssl_fd != -1) {
1135                 close(vpninfo->ssl_fd);
1136                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1137                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1138                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1139                 vpninfo->ssl_fd = -1;
1140         }
1141 }
1142
1143 void openconnect_init_openssl(void)
1144 {
1145         SSL_library_init ();
1146         ERR_clear_error ();
1147         SSL_load_error_strings ();
1148         OpenSSL_add_all_algorithms ();
1149 }
1150
1151 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
1152                                    struct x509_st *cert)
1153 {
1154         BIO *bp = BIO_new(BIO_s_mem());
1155         BUF_MEM *certinfo;
1156         char zero = 0;
1157         char *ret;
1158
1159         X509_print_ex(bp, cert, 0, 0);
1160         BIO_write(bp, &zero, 1);
1161         BIO_get_mem_ptr(bp, &certinfo);
1162
1163         ret = strdup(certinfo->data);
1164         BIO_free(bp);
1165         return ret;
1166 }
1167
1168
1169 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1170                                char *buf)
1171 {
1172         buf[0] = 0;
1173
1174         if (!vpninfo->cert_x509)
1175                 return -EIO;
1176
1177         if (get_cert_md5_fingerprint(vpninfo, vpninfo->cert_x509, buf))
1178                 return -EIO;
1179
1180         return 0;
1181 }