Move openconnect_SSL_printf() to ssl.c
[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
324                                 X509_NAME_oneline(X509_get_subject_name(cert2),
325                                                   buf, sizeof(buf));
326                                 vpn_progress(vpninfo, PRG_DEBUG,
327                                              _("Extra cert from PKCS#12: '%s'\n"), buf);
328                                 CRYPTO_add(&cert2->references, 1, CRYPTO_LOCK_X509);
329                                 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert2);
330                                 cert = cert2;
331                                 goto next;
332                         }
333                 }
334                 sk_X509_pop_free(ca, X509_free);
335         }
336
337         PKCS12_free(p12);
338         return ret;
339 }
340
341 #ifdef HAVE_ENGINE
342 static int load_tpm_certificate(struct openconnect_info *vpninfo)
343 {
344         ENGINE *e;
345         EVP_PKEY *key;
346         ENGINE_load_builtin_engines();
347
348         e = ENGINE_by_id("tpm");
349         if (!e) {
350                 vpn_progress(vpninfo, PRG_ERR, _("Can't load TPM engine.\n"));
351                 openconnect_report_ssl_errors(vpninfo);
352                 return -EINVAL;
353         }
354         if (!ENGINE_init(e) || !ENGINE_set_default_RSA(e) ||
355             !ENGINE_set_default_RAND(e)) {
356                 vpn_progress(vpninfo, PRG_ERR, _("Failed to init TPM engine\n"));
357                 openconnect_report_ssl_errors(vpninfo);
358                 ENGINE_free(e);
359                 return -EINVAL;
360         }
361
362         if (vpninfo->cert_password) {
363                 if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->cert_password),
364                                      vpninfo->cert_password, NULL, 0)) {
365                         vpn_progress(vpninfo, PRG_ERR,
366                                      _("Failed to set TPM SRK password\n"));
367                         openconnect_report_ssl_errors(vpninfo);
368                 }
369         }
370         key = ENGINE_load_private_key(e, vpninfo->sslkey, NULL, NULL);
371         if (!key) {
372                 vpn_progress(vpninfo, PRG_ERR,
373                              _("Failed to load TPM private key\n"));
374                 openconnect_report_ssl_errors(vpninfo);
375                 ENGINE_free(e);
376                 ENGINE_finish(e);
377                 return -EINVAL;
378         }
379         if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
380                 vpn_progress(vpninfo, PRG_ERR, _("Add key from TPM failed\n"));
381                 openconnect_report_ssl_errors(vpninfo);
382                 ENGINE_free(e);
383                 ENGINE_finish(e);
384                 return -EINVAL;
385         }
386         return 0;
387 }
388 #else
389 static int load_tpm_certificate(struct openconnect_info *vpninfo)
390 {
391         vpn_progress(vpninfo, PRG_ERR,
392                      _("This version of OpenConnect was built without TPM support\n"));
393         return -EINVAL;
394 }
395 #endif
396
397 static int reload_pem_cert(struct openconnect_info *vpninfo)
398 {
399         BIO *b = BIO_new(BIO_s_file_internal());
400
401         if (!b)
402                 return -ENOMEM;
403
404         if (BIO_read_filename(b, vpninfo->cert) <= 0) {
405         err:
406                 BIO_free(b);
407                 vpn_progress(vpninfo, PRG_ERR,
408                              _("Failed to reload X509 cert for expiry check\n"));
409                 openconnect_report_ssl_errors(vpninfo);
410                 return -EIO;
411         }
412         vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, NULL, NULL);
413         if (!vpninfo->cert_x509)
414                 goto err;
415
416         return 0;
417 }
418
419 static int load_certificate(struct openconnect_info *vpninfo)
420 {
421         vpn_progress(vpninfo, PRG_TRACE,
422                      _("Using certificate file %s\n"), vpninfo->cert);
423
424         if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
425             vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
426                 FILE *f;
427                 PKCS12 *p12;
428
429                 f = fopen(vpninfo->cert, "r");
430                 if (!f) {
431                         vpn_progress(vpninfo, PRG_ERR,
432                                      _("Failed to open certificate file %s: %s\n"),
433                                      vpninfo->cert, strerror(errno));
434                         return -ENOENT;
435                 }
436                 p12 = d2i_PKCS12_fp(f, NULL);
437                 fclose(f);
438                 if (p12)
439                         return load_pkcs12_certificate(vpninfo, p12);
440
441                 /* Not PKCS#12 */
442                 if (vpninfo->cert_type == CERT_TYPE_PKCS12) {
443                         vpn_progress(vpninfo, PRG_ERR, _("Read PKCS#12 failed\n"));
444                         openconnect_report_ssl_errors(vpninfo);
445                         return -EINVAL;
446                 }
447                 /* Clear error and fall through to see if it's a PEM file... */
448                 ERR_clear_error();
449         }
450
451         /* It's PEM or TPM now, and either way we need to load the plain cert: */
452         if (!SSL_CTX_use_certificate_chain_file(vpninfo->https_ctx,
453                                                 vpninfo->cert)) {
454                 vpn_progress(vpninfo, PRG_ERR,
455                              _("Loading certificate failed\n"));
456                 openconnect_report_ssl_errors(vpninfo);
457                 return -EINVAL;
458         }
459
460         /* Ew, we can't get it back from the OpenSSL CTX in any sane fashion */
461         reload_pem_cert(vpninfo);
462
463         if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
464                 FILE *f = fopen(vpninfo->sslkey, "r");
465                 char buf[256];
466
467                 if (!f) {
468                         vpn_progress(vpninfo, PRG_ERR,
469                                      _("Failed to open private key file %s: %s\n"),
470                                      vpninfo->cert, strerror(errno));
471                         return -ENOENT;
472                 }
473
474                 buf[255] = 0;
475                 while (fgets(buf, 255, f)) {
476                         if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
477                                 vpninfo->cert_type = CERT_TYPE_TPM;
478                                 break;
479                         } else if (!strcmp(buf, "-----BEGIN RSA PRIVATE KEY-----\n") ||
480                                    !strcmp(buf, "-----BEGIN DSA PRIVATE KEY-----\n") ||
481                                    !strcmp(buf, "-----BEGIN ENCRYPTED PRIVATE KEY-----\n")) {
482                                 vpninfo->cert_type = CERT_TYPE_PEM;
483                                 break;
484                         }
485                 }
486                 fclose(f);
487                 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
488                         vpn_progress(vpninfo, PRG_ERR,
489                                      _("Failed to identify private key type in '%s'\n"),
490                                      vpninfo->sslkey);
491                         return -EINVAL;
492                 }
493         }
494
495         if (vpninfo->cert_type == CERT_TYPE_TPM)
496                 return load_tpm_certificate(vpninfo);
497
498         /* Standard PEM certificate */
499         if (vpninfo->cert_password) {
500                 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx,
501                                               pem_pw_cb);
502                 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx,
503                                                        vpninfo);
504         }
505  again:
506         if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx, vpninfo->sslkey,
507                                             SSL_FILETYPE_PEM)) {
508                 unsigned long err = ERR_peek_error();
509                 
510                 openconnect_report_ssl_errors(vpninfo);
511
512 #ifndef EVP_F_EVP_DECRYPTFINAL_EX
513 #define EVP_F_EVP_DECRYPTFINAL_EX EVP_F_EVP_DECRYPTFINAL
514 #endif
515                 /* If the user fat-fingered the passphrase, try again */
516                 if (ERR_GET_LIB(err) == ERR_LIB_EVP &&
517                     ERR_GET_FUNC(err) == EVP_F_EVP_DECRYPTFINAL_EX &&
518                     ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT) {
519                         vpn_progress(vpninfo, PRG_ERR,
520                                      _("Loading private key failed (wrong passphrase?)\n"));
521                         goto again;
522                 }
523                 
524                 vpn_progress(vpninfo, PRG_ERR,
525                              _("Loading private key failed (see above errors)\n"));
526                 return -EINVAL;
527         }
528         return 0;
529 }
530
531 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
532                                 X509 *cert, const EVP_MD *type,
533                                 char *buf)
534 {
535         unsigned char md[EVP_MAX_MD_SIZE];
536         unsigned int i, n;
537
538         if (!X509_digest(cert, type, md, &n))
539                 return -ENOMEM;
540
541         for (i=0; i < n; i++)
542                 sprintf(&buf[i*2], "%02X", md[i]);
543
544         return 0;
545 }
546
547 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
548                              X509 *cert, char *buf)
549 {
550         return get_cert_fingerprint(vpninfo, cert, EVP_md5(), buf);
551 }
552
553 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
554                               X509 *cert, char *buf)
555 {
556         return get_cert_fingerprint(vpninfo, cert, EVP_sha1(), buf);
557 }
558
559 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
560 {
561         char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
562         int ret;
563
564         ret = openconnect_get_cert_sha1(vpninfo, cert, fingerprint);
565         if (ret)
566                 return ret;
567
568         if (strcasecmp(vpninfo->servercert, fingerprint)) {
569                 vpn_progress(vpninfo, PRG_ERR,
570                              _("Server SSL certificate didn't match: %s\n"), fingerprint);
571                 return -EINVAL;
572         }
573         return 0;
574 }
575
576 static int match_hostname_elem(const char *hostname, int helem_len,
577                                const char *match, int melem_len)
578 {
579         if (!helem_len && !melem_len)
580                 return 0;
581
582         if (!helem_len || !melem_len)
583                 return -1;
584
585
586         if (match[0] == '*') {
587                 int i;
588
589                 for (i = 1 ; i <= helem_len; i++) {
590                         if (!match_hostname_elem(hostname + i, helem_len - i,
591                                                  match + 1, melem_len - 1))
592                                 return 0;
593                 }
594                 return -1;
595         }
596
597         /* From the NetBSD (5.1) man page for ctype(3):
598            Values of type char or signed char must first be cast to unsigned char,
599            to ensure that the values are within the correct range.  The result
600            should then be cast to int to avoid warnings from some compilers.
601            We do indeed get warning "array subscript has type 'char'" without
602            the casts. Ick. */
603         if (toupper((int)(unsigned char)hostname[0]) ==
604             toupper((int)(unsigned char)match[0]))
605                 return match_hostname_elem(hostname + 1, helem_len - 1,
606                                            match + 1, melem_len - 1);
607
608         return -1;
609 }
610
611 static int match_hostname(const char *hostname, const char *match)
612 {
613         while (*match) {
614                 const char *h_dot, *m_dot;
615                 int helem_len, melem_len;
616
617                 h_dot = strchr(hostname, '.');
618                 m_dot = strchr(match, '.');
619                 
620                 if (h_dot && m_dot) {
621                         helem_len = h_dot - hostname + 1;
622                         melem_len = m_dot - match + 1;
623                 } else if (!h_dot && !m_dot) {
624                         helem_len = strlen(hostname);
625                         melem_len = strlen(match);
626                 } else
627                         return -1;
628
629
630                 if (match_hostname_elem(hostname, helem_len,
631                                         match, melem_len))
632                         return -1;
633
634                 hostname += helem_len;
635                 match += melem_len;
636         }
637         if (*hostname)
638                 return -1;
639
640         return 0;
641 }
642
643 /* cf. RFC2818 and RFC2459 */
644 static int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
645 {
646         STACK_OF(GENERAL_NAME) *altnames;
647         X509_NAME *subjname;
648         ASN1_STRING *subjasn1;
649         char *subjstr = NULL;
650         int addrlen = 0;
651         int i, altdns = 0;
652         char addrbuf[sizeof(struct in6_addr)];
653         int ret;
654
655         /* Allow GEN_IP in the certificate only if we actually connected
656            by IP address rather than by name. */
657         if (inet_pton(AF_INET, vpninfo->hostname, addrbuf) > 0)
658                 addrlen = 4;
659         else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
660                 addrlen = 16;
661         else if (vpninfo->hostname[0] == '[' &&
662                  vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
663                 char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
664                 *p = 0;
665                 if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
666                         addrlen = 16;
667                 *p = ']';
668         }
669
670         altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
671                                     NULL, NULL);
672         for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
673                 const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);
674
675                 if (this->type == GEN_DNS) {
676                         char *str;
677
678                         int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
679                         if (len < 0)
680                                 continue;
681
682                         altdns = 1;
683
684                         /* We don't like names with embedded NUL */
685                         if (strlen(str) != len)
686                                 continue;
687
688                         if (!match_hostname(vpninfo->hostname, str)) {
689                                 vpn_progress(vpninfo, PRG_TRACE,
690                                              _("Matched DNS altname '%s'\n"),
691                                              str);
692                                 GENERAL_NAMES_free(altnames);
693                                 OPENSSL_free(str);
694                                 return 0;
695                         } else {
696                                 vpn_progress(vpninfo, PRG_TRACE,
697                                              _("No match for altname '%s'\n"),
698                                              str);
699                         }
700                         OPENSSL_free(str);
701                 } else if (this->type == GEN_IPADD && addrlen) {
702                         char host[80];
703                         int family;
704
705                         if (this->d.ip->length == 4) {
706                                 family = AF_INET;
707                         } else if (this->d.ip->length == 16) {
708                                 family = AF_INET6;
709                         } else {
710                                 vpn_progress(vpninfo, PRG_ERR,
711                                              _("Certificate has GEN_IPADD altname with bogus length %d\n"),
712                                              this->d.ip->length);
713                                 continue;
714                         }
715                         
716                         /* We only do this for the debug messages */
717                         inet_ntop(family, this->d.ip->data, host, sizeof(host));
718
719                         if (this->d.ip->length == addrlen &&
720                             !memcmp(addrbuf, this->d.ip->data, addrlen)) {
721                                 vpn_progress(vpninfo, PRG_TRACE,
722                                              _("Matched %s address '%s'\n"),
723                                              (family == AF_INET6)?"IPv6":"IPv4",
724                                              host);
725                                 GENERAL_NAMES_free(altnames);
726                                 return 0;
727                         } else {
728                                 vpn_progress(vpninfo, PRG_TRACE,
729                                              _("No match for %s address '%s'\n"),
730                                              (family == AF_INET6)?"IPv6":"IPv4",
731                                              host);
732                         }
733                 } else if (this->type == GEN_URI) {
734                         char *str;
735                         char *url_proto, *url_host, *url_path, *url_host2;
736                         int url_port;
737                         int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
738
739                         if (len < 0)
740                                 continue;
741
742                         /* We don't like names with embedded NUL */
743                         if (strlen(str) != len)
744                                 continue;
745
746                         if (internal_parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
747                                 OPENSSL_free(str);
748                                 continue;
749                         }
750
751                         if (!url_proto || strcasecmp(url_proto, "https"))
752                                 goto no_uri_match;
753
754                         if (url_port != vpninfo->port)
755                                 goto no_uri_match;
756
757                         /* Leave url_host as it was so that it can be freed */
758                         url_host2 = url_host;
759                         if (addrlen == 16 && vpninfo->hostname[0] != '[' &&
760                             url_host[0] == '[' && url_host[strlen(url_host)-1] == ']') {
761                                 /* Cope with https://[IPv6]/ when the hostname is bare IPv6 */
762                                 url_host[strlen(url_host)-1] = 0;
763                                 url_host2++;
764                         }
765
766                         if (strcasecmp(vpninfo->hostname, url_host2))
767                                 goto no_uri_match;
768
769                         if (url_path) {
770                                 vpn_progress(vpninfo, PRG_TRACE,
771                                              _("URI '%s' has non-empty path; ignoring\n"),
772                                              str);
773                                 goto no_uri_match_silent;
774                         }
775                         vpn_progress(vpninfo, PRG_TRACE,
776                                      _("Matched URI '%s'\n"),
777                                      str);
778                         free(url_proto);
779                         free(url_host);
780                         free(url_path);
781                         OPENSSL_free(str);
782                         GENERAL_NAMES_free(altnames);
783                         return 0;
784
785                 no_uri_match:
786                         vpn_progress(vpninfo, PRG_TRACE,
787                                      _("No match for URI '%s'\n"),
788                                      str);
789                 no_uri_match_silent:
790                         free(url_proto);
791                         free(url_host);
792                         free(url_path);
793                         OPENSSL_free(str);
794                 }
795         }
796         GENERAL_NAMES_free(altnames);
797
798         /* According to RFC2818, we don't use the legacy subject name if
799            there was an altname with DNS type. */
800         if (altdns) {
801                 vpn_progress(vpninfo, PRG_ERR,
802                              _("No altname in peer cert matched '%s'\n"),
803                              vpninfo->hostname);
804                 return -EINVAL;
805         }
806
807         subjname = X509_get_subject_name(peer_cert);
808         if (!subjname) {
809                 vpn_progress(vpninfo, PRG_ERR,
810                              _("No subject name in peer cert!\n"));
811                 return -EINVAL;
812         }
813
814         /* Find the _last_ (most specific) commonName */
815         i = -1;
816         while (1) {
817                 int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
818                 if (j >= 0)
819                         i = j;
820                 else
821                         break;
822         }
823
824         subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));
825
826         i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);
827
828         if (!subjstr || strlen(subjstr) != i) {
829                 vpn_progress(vpninfo, PRG_ERR,
830                              _("Failed to parse subject name in peer cert\n"));
831                 return -EINVAL;
832         }
833         ret = 0;
834
835         if (match_hostname(vpninfo->hostname, subjstr)) {
836                 vpn_progress(vpninfo, PRG_ERR,
837                              _("Peer cert subject mismatch ('%s' != '%s')\n"),
838                              subjstr, vpninfo->hostname);
839                 ret = -EINVAL;
840         } else {
841                 vpn_progress(vpninfo, PRG_TRACE,
842                              _("Matched peer certificate subject name '%s'\n"),
843                              subjstr);
844         }
845
846         OPENSSL_free(subjstr);                    
847         return ret;
848 }
849
850 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
851 {
852         X509 *peer_cert;
853         int ret;
854
855         peer_cert = SSL_get_peer_certificate(https_ssl);
856
857         if (vpninfo->servercert) {
858                 /* If given a cert fingerprint on the command line, that's
859                    all we look for */
860                 ret = check_server_cert(vpninfo, peer_cert);
861         } else {
862                 int vfy = SSL_get_verify_result(https_ssl);
863                 const char *err_string = NULL;
864
865                 if (vfy != X509_V_OK)
866                         err_string = X509_verify_cert_error_string(vfy);
867                 else if (match_cert_hostname(vpninfo, peer_cert))
868                         err_string = _("certificate does not match hostname");
869
870                 if (err_string) {
871                         vpn_progress(vpninfo, PRG_INFO,
872                                      _("Server certificate verify failed: %s\n"),
873                                      err_string);
874
875                         if (vpninfo->validate_peer_cert)
876                                 ret = vpninfo->validate_peer_cert(vpninfo->cbdata,
877                                                                   peer_cert,
878                                                                   err_string);
879                         else
880                                 ret = -EINVAL;
881                 } else {
882                         ret = 0;
883                 }
884         }
885         X509_free(peer_cert);
886
887         return ret;
888 }
889
890 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
891                                              SSL *ssl)
892 {
893         /* OpenSSL has problems with certificate chains -- if there are
894            multiple certs with the same name, it doesn't necessarily
895            choose the _right_ one. (RT#1942)
896            Pick the right ones for ourselves and add them manually. */
897         X509 *cert = SSL_get_certificate(ssl);
898         X509 *cert2;
899         X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
900         X509_STORE_CTX ctx;
901
902         if (!cert || !store)
903                 return;
904
905         /* If we already have 'supporting' certs, don't add them again */
906         if (vpninfo->https_ctx->extra_certs)
907                 return;
908
909         if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
910                 return;
911
912         while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
913                 char buf[200];
914                 if (cert2 == cert)
915                         break;
916                 cert = cert2;
917                 X509_NAME_oneline(X509_get_subject_name(cert),
918                                   buf, sizeof(buf));
919                 vpn_progress(vpninfo, PRG_DEBUG,
920                              _("Extra cert from cafile: '%s'\n"), buf);
921                 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
922         }
923         X509_STORE_CTX_cleanup(&ctx);
924 }
925
926 #if OPENSSL_VERSION_NUMBER >= 0x00908000
927 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
928 {
929         /* We've seen certificates in the wild which don't have the
930            purpose fields filled in correctly */
931         X509_VERIFY_PARAM_set_purpose(ctx->param, X509_PURPOSE_ANY);
932         return X509_verify_cert(ctx);
933 }
934 #endif
935
936 static int check_certificate_expiry(struct openconnect_info *vpninfo)
937 {
938         ASN1_TIME *notAfter;
939         const char *reason = NULL;
940         time_t t;
941         int i;
942
943         if (!vpninfo->cert_x509)
944                 return 0;
945
946         t = time(NULL);
947         notAfter = X509_get_notAfter(vpninfo->cert_x509);
948         i = X509_cmp_time(notAfter, &t);
949         if (!i) {
950                 vpn_progress(vpninfo, PRG_ERR,
951                              _("Error in client cert notAfter field\n"));
952                 return -EINVAL;
953         } else if (i < 0) {
954                 reason = _("Client certificate has expired at");
955         } else {
956                 t += vpninfo->cert_expire_warning;
957                 i = X509_cmp_time(notAfter, &t);
958                 if (i < 0) {
959                         reason = _("Client certificate expires soon at");
960                 }
961         }
962         if (reason) {
963                 BIO *bp = BIO_new(BIO_s_mem());
964                 BUF_MEM *bm;
965                 const char *expiry = _("<error>");
966                 char zero = 0;
967
968                 if (bp) {
969                         ASN1_TIME_print(bp, notAfter);
970                         BIO_write(bp, &zero, 1);
971                         BIO_get_mem_ptr(bp, &bm);
972                         expiry = bm->data;
973                 }
974                 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, expiry);
975                 if (bp)
976                         BIO_free(bp);
977         }
978         return 0;
979 }
980 int openconnect_open_https(struct openconnect_info *vpninfo)
981 {
982         method_const SSL_METHOD *ssl3_method;
983         SSL *https_ssl;
984         BIO *https_bio;
985         int ssl_sock;
986         int err;
987
988         if (vpninfo->https_ssl)
989                 return 0;
990
991         if (vpninfo->peer_cert) {
992                 X509_free(vpninfo->peer_cert);
993                 vpninfo->peer_cert = NULL;
994         }
995
996         ssl_sock = connect_https_socket(vpninfo);
997         if (ssl_sock < 0)
998                 return ssl_sock;
999
1000         ssl3_method = TLSv1_client_method();
1001         if (!vpninfo->https_ctx) {
1002                 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
1003
1004                 /* Some servers (or their firewalls) really don't like seeing
1005                    extensions. */
1006 #ifdef SSL_OP_NO_TICKET
1007                 SSL_CTX_set_options (vpninfo->https_ctx, SSL_OP_NO_TICKET);
1008 #endif
1009
1010                 if (vpninfo->cert) {
1011                         err = load_certificate(vpninfo);
1012                         if (err) {
1013                                 vpn_progress(vpninfo, PRG_ERR,
1014                                              _("Loading certificate failed. Aborting.\n"));
1015                                 return err;
1016                         }
1017                         check_certificate_expiry(vpninfo);
1018                 }
1019
1020                 /* We just want to do:
1021                    SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY); 
1022                    ... but it doesn't work with OpenSSL < 0.9.8k because of 
1023                    problems with inheritance (fixed in v1.1.4.6 of
1024                    crypto/x509/x509_vpm.c) so we have to play silly buggers
1025                    instead. This trick doesn't work _either_ in < 0.9.7 but
1026                    I don't know of _any_ workaround which will, and can't
1027                    be bothered to find out either. */
1028 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1029                 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx,
1030                                                  ssl_app_verify_callback, NULL);
1031 #endif
1032                 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
1033
1034                 if (vpninfo->cafile) {
1035                         if (!SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL)) {
1036                                 vpn_progress(vpninfo, PRG_ERR,
1037                                              _("Failed to open CA file '%s'\n"),
1038                                              vpninfo->cafile);
1039                                 openconnect_report_ssl_errors(vpninfo);
1040                                 close(ssl_sock);
1041                                 return -EINVAL;
1042                         }
1043                 }
1044
1045         }
1046         https_ssl = SSL_new(vpninfo->https_ctx);
1047         workaround_openssl_certchain_bug(vpninfo, https_ssl);
1048
1049         https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
1050         BIO_set_nbio(https_bio, 1);
1051         SSL_set_bio(https_ssl, https_bio, https_bio);
1052
1053         vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1054                      vpninfo->hostname);
1055
1056         while ((err = SSL_connect(https_ssl)) <= 0) {
1057                 fd_set wr_set, rd_set;
1058                 int maxfd = ssl_sock;
1059                 
1060                 FD_ZERO(&wr_set);
1061                 FD_ZERO(&rd_set);
1062
1063                 err = SSL_get_error(https_ssl, err);
1064                 if (err == SSL_ERROR_WANT_READ)
1065                         FD_SET(ssl_sock, &rd_set);
1066                 else if (err == SSL_ERROR_WANT_WRITE)
1067                         FD_SET(ssl_sock, &wr_set);
1068                 else {
1069                         vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n"));
1070                         openconnect_report_ssl_errors(vpninfo);
1071                         SSL_free(https_ssl);
1072                         close(ssl_sock);
1073                         return -EINVAL;
1074                 }
1075
1076                 if (vpninfo->cancel_fd != -1) {
1077                         FD_SET(vpninfo->cancel_fd, &rd_set);
1078                         if (vpninfo->cancel_fd > ssl_sock)
1079                                 maxfd = vpninfo->cancel_fd;
1080                 }
1081                 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1082                 if (vpninfo->cancel_fd != -1 &&
1083                     FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1084                         vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1085                         SSL_free(https_ssl);
1086                         close(ssl_sock);
1087                         return -EINVAL;
1088                 }
1089         }
1090
1091         if (verify_peer(vpninfo, https_ssl)) {
1092                 SSL_free(https_ssl);
1093                 close(ssl_sock);
1094                 return -EINVAL;
1095         }
1096
1097         vpninfo->ssl_fd = ssl_sock;
1098         vpninfo->https_ssl = https_ssl;
1099
1100         /* Stash this now, because it might not be available later if the
1101            server has disconnected. */
1102         vpninfo->peer_cert = SSL_get_peer_certificate(vpninfo->https_ssl);
1103
1104         vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1105                      vpninfo->hostname);
1106
1107         return 0;
1108 }
1109
1110 void openconnect_close_https(struct openconnect_info *vpninfo)
1111 {
1112         if (vpninfo->peer_cert) {
1113                 X509_free(vpninfo->peer_cert);
1114                 vpninfo->peer_cert = NULL;
1115         }
1116         if (vpninfo->https_ssl) {
1117                 SSL_free(vpninfo->https_ssl);
1118                 vpninfo->https_ssl = NULL;
1119         }
1120         if (vpninfo->ssl_fd != -1) {
1121                 close(vpninfo->ssl_fd);
1122                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1123                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1124                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1125                 vpninfo->ssl_fd = -1;
1126         }
1127 }
1128
1129 void openconnect_init_openssl(void)
1130 {
1131         SSL_library_init ();
1132         ERR_clear_error ();
1133         SSL_load_error_strings ();
1134         OpenSSL_add_all_algorithms ();
1135 }
1136
1137 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
1138                                    struct x509_st *cert)
1139 {
1140         BIO *bp = BIO_new(BIO_s_mem());
1141         BUF_MEM *certinfo;
1142         char zero = 0;
1143         char *ret;
1144
1145         X509_print_ex(bp, cert, 0, 0);
1146         BIO_write(bp, &zero, 1);
1147         BIO_get_mem_ptr(bp, &certinfo);
1148
1149         ret = strdup(certinfo->data);
1150         BIO_free(bp);
1151         return ret;
1152 }
1153
1154
1155 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1156                                char *buf)
1157 {
1158         buf[0] = 0;
1159
1160         if (!vpninfo->cert_x509)
1161                 return -EIO;
1162
1163         if (get_cert_md5_fingerprint(vpninfo, vpninfo->cert_x509, buf))
1164                 return -EIO;
1165
1166         return 0;
1167 }