auth: Introduce new XML helper functions for parse_auth_node()
[platform/upstream/openconnect.git] / openssl.c
index a03b20e..6acdf5c 100644 (file)
--- a/openssl.c
+++ b/openssl.c
@@ -107,7 +107,7 @@ int openconnect_SSL_write(struct openconnect_info *vpninfo, char *buf, size_t le
                        else if (err == SSL_ERROR_WANT_WRITE)
                                FD_SET(vpninfo->ssl_fd, &wr_set);
                        else {
-                               vpn_progress(vpninfo, PRG_ERR, _("Failed to write to SSL socket"));
+                               vpn_progress(vpninfo, PRG_ERR, _("Failed to write to SSL socket\n"));
                                openconnect_report_ssl_errors(vpninfo);
                                return -EIO;
                        }
@@ -603,7 +603,7 @@ static int reload_pem_cert(struct openconnect_info *vpninfo)
 #ifdef ANDROID_KEYSTORE
 static BIO *BIO_from_keystore(struct openconnect_info *vpninfo, const char *item)
 {
-       char content[KEYSTORE_MESSAGE_SIZE];
+       unsigned char *content;
        BIO *b;
        int len;
        const char *p = item + 9;
@@ -614,20 +614,23 @@ static BIO *BIO_from_keystore(struct openconnect_info *vpninfo, const char *item
                p++;
        if (*p == '/')
                p++;
-       len = keystore_get(p, strlen(p), content);
+
+       len = keystore_fetch(p, &content);
        if (len < 0) {
                vpn_progress(vpninfo, PRG_ERR,
-                            _("Failed to lead item '%s' from keystore\n"),
-                            p);
+                            _("Failed to load item '%s' from keystore: %s\n"),
+                            p, keystore_strerror(len));
                return NULL;
        }
        if (!(b = BIO_new(BIO_s_mem())) || BIO_write(b, content, len) != len) {
                vpn_progress(vpninfo, PRG_ERR,
                             _("Failed to create BIO for keystore item '%s'\n"),
                               p);
+               free(content);
                BIO_free(b);
                return NULL;
        }
+       free(content);
        return b;
 }
 #endif
@@ -708,7 +711,6 @@ static int load_certificate(struct openconnect_info *vpninfo)
                        vpn_progress(vpninfo, PRG_ERR,
                                     _("Failed to load X509 certificate from keystore\n"));
                        openconnect_report_ssl_errors(vpninfo);
-                       BIO_free(b);
                        return -EINVAL;
                }
                if (!SSL_CTX_use_certificate(vpninfo->https_ctx, vpninfo->cert_x509)) {
@@ -1296,6 +1298,9 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
                        if (err) {
                                vpn_progress(vpninfo, PRG_ERR,
                                             _("Loading certificate failed. Aborting.\n"));
+                               SSL_CTX_free(vpninfo->https_ctx);
+                               vpninfo->https_ctx = NULL;
+                               close(ssl_sock);
                                return err;
                        }
                        check_certificate_expiry(vpninfo);
@@ -1315,12 +1320,54 @@ 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) {
+                               SSL_CTX_free(vpninfo->https_ctx);
+                               vpninfo->https_ctx = NULL;
+                               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);
+                               SSL_CTX_free(vpninfo->https_ctx);
+                               vpninfo->https_ctx = NULL;
+                               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,
                                             _("Failed to open CA file '%s'\n"),
                                             vpninfo->cafile);
                                openconnect_report_ssl_errors(vpninfo);
+                               SSL_CTX_free(vpninfo->https_ctx);
+                               vpninfo->https_ctx = NULL;
                                close(ssl_sock);
                                return -EINVAL;
                        }
@@ -1340,7 +1387,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
        while ((err = SSL_connect(https_ssl)) <= 0) {
                fd_set wr_set, rd_set;
                int maxfd = ssl_sock;
-               
+
                FD_ZERO(&wr_set);
                FD_ZERO(&rd_set);