From c33f3e48897b1d0a36467824ad5ae343d6c4c544 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 17 Jun 2012 23:42:53 +0100 Subject: [PATCH] Add Android keystore support for --cafile Based on a patch from Vilmos Nebehaj Signed-off-by: Vilmos Nebehaj Signed-off-by: David Woodhouse --- gnutls.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ openssl.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/gnutls.c b/gnutls.c index e6bf879..b4034d0 100644 --- a/gnutls.c +++ b/gnutls.c @@ -1355,6 +1355,51 @@ int openconnect_open_https(struct openconnect_info *vpninfo) gnutls_certificate_set_verify_function (vpninfo->https_cred, verify_peer); +#ifdef ANDROID_KEYSTORE + if (vpninfo->cafile && !strncmp(vpninfo->cafile, "keystore:", 9)) { + gnutls_datum_t datum; + unsigned int nr_certs; + + err = load_datum(vpninfo, &datum, vpninfo->cafile); + if (err < 0) + return err; + + /* For GnuTLS 3.x We should use gnutls_x509_crt_list_import2() */ + nr_certs = count_x509_certificates(&datum); + if (nr_certs) { + gnutls_x509_crt *certs; + int i; + + certs = calloc(nr_certs, sizeof(*certs)); + if (!certs) { + vpn_progress(vpninfo, PRG_ERR, + _("Failed to allocate memory for cafile certs\n")); + gnutls_free(datum.data); + close(ssl_sock); + return -ENOMEM; + } + err = gnutls_x509_crt_list_import(certs, &nr_certs, &datum, + GNUTLS_X509_FMT_PEM, 0); + gnutls_free(datum.data); + if (err >= 0) { + nr_certs = err; + err = gnutls_certificate_set_x509_trust(vpninfo->https_cred, + certs, nr_certs); + } + for (i = 0; i < nr_certs; i++) + gnutls_x509_crt_deinit(certs[i]); + free(certs); + if (err < 0) { + /* From crt_list_import or set_x509_trust */ + vpn_progress(vpninfo, PRG_ERR, + _("Failed to read certs from cafile: %s\n"), + gnutls_strerror(err)); + close(ssl_sock); + return -EINVAL; + } + } + } else +#endif if (vpninfo->cafile) { err = gnutls_certificate_set_x509_trust_file(vpninfo->https_cred, vpninfo->cafile, @@ -1373,6 +1418,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo) if (err) { vpn_progress(vpninfo, PRG_ERR, _("Loading certificate failed. Aborting.\n")); + close(ssl_sock); return err; } } diff --git a/openssl.c b/openssl.c index d865de1..851a711 100644 --- a/openssl.c +++ b/openssl.c @@ -1317,6 +1317,42 @@ int openconnect_open_https(struct openconnect_info *vpninfo) #endif SSL_CTX_set_default_verify_paths(vpninfo->https_ctx); +#ifdef ANDROID_KEYSTORE + if (vpninfo->cafile && !strncmp(vpninfo->cafile, "keystore:", 9)) { + STACK_OF(X509_INFO) *stack; + X509_STORE *store; + X509_INFO *info; + BIO *b = BIO_from_keystore(vpninfo, vpninfo->cafile); + + if (!b) { + close(ssl_sock); + return -EINVAL; + } + + stack = PEM_X509_INFO_read_bio(b, NULL, NULL, NULL); + BIO_free(b); + + if (!stack) { + vpn_progress(vpninfo, PRG_ERR, + _("Failed to read certs from CA file '%s'\n"), + vpninfo->cafile); + openconnect_report_ssl_errors(vpninfo); + close(ssl_sock); + return -ENOENT; + } + + store = SSL_CTX_get_cert_store(vpninfo->https_ctx); + + while ((info = sk_X509_INFO_pop(stack))) { + if (info->x509) + X509_STORE_add_cert(store, info->x509); + if (info->crl) + X509_STORE_add_crl(store, info->crl); + X509_INFO_free(info); + } + sk_X509_INFO_free(stack); + } else +#endif if (vpninfo->cafile) { if (!SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL)) { vpn_progress(vpninfo, PRG_ERR, -- 2.7.4