Add Android keystore support for --cafile
authorDavid Woodhouse <David.Woodhouse@intel.com>
Sun, 17 Jun 2012 22:42:53 +0000 (23:42 +0100)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Sun, 17 Jun 2012 22:44:28 +0000 (23:44 +0100)
Based on a patch from Vilmos Nebehaj <v.nebehaj@gmail.com>

Signed-off-by: Vilmos Nebehaj <v.nebehaj@gmail.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
gnutls.c
openssl.c

index e6bf879..b4034d0 100644 (file)
--- 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;
                        }
                }
index d865de1..851a711 100644 (file)
--- 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,