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