DVT_STATUS CERTIFICATE_FILE_CLASS::importPem(const char* filename, bool certificatesOnly, const char* password) // DESCRIPTION : Import certificates from a PEM formated file. // PRECONDITIONS : // POSTCONDITIONS : // EXCEPTIONS : // NOTES : Returns MSG_OK, MSG_ERROR, MSG_FILE_NOT_EXIST, MSG_NO_VALUE, MSG_INVALID_PASSWORD //<<=========================================================================== { DVT_STATUS status = MSG_ERROR; STACK_OF(X509_INFO)* infoList_ptr = NULL; X509_INFO* x509Info_ptr; int count = 0; // read the file status = openSslM_ptr->readPemFile(filename, &infoList_ptr, OPENSSL_CLASS::openSslPasswordCallback, (void *)password, loggerM_ptr); switch (status) { case MSG_FILE_NOT_EXIST: case MSG_ERROR: case MSG_INVALID_PASSWORD: goto end; } // for each certificate in the import file, add the certificate to this file's list while ((x509Info_ptr = sk_X509_INFO_shift(infoList_ptr)) != NULL) { if ((x509Info_ptr->x509 == NULL) && certificatesOnly) { // not a certificate and only intested in certificates, just free it X509_INFO_free(x509Info_ptr); } else { // add to the certificate list sk_X509_INFO_push(x509InfoListM_ptr, x509Info_ptr); count++; } } if (count == 0) { status = MSG_NO_VALUE; } else { status = MSG_OK; } end: if (infoList_ptr != NULL) sk_X509_INFO_pop_free(infoList_ptr, X509_INFO_free); return status; }
/* * This function is used to load an X509_STORE using raw * data from a buffer. The data is expected to be PEM * encoded. * * Returns the number of certs added to the store */ static int ossl_init_cert_store_from_raw (X509_STORE *store, unsigned char *raw, int size) { STACK_OF(X509_INFO) * sk = NULL; X509_INFO *xi; BIO *in; int cert_cnt = 0; in = BIO_new_mem_buf(raw, size); if (in == NULL) { EST_LOG_ERR("Unable to open the raw CA cert buffer"); return 0; } /* This loads from a file, a stack of x509/crl/pkey sets */ sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL); if (sk == NULL) { EST_LOG_ERR("Unable to read PEM encoded certs from BIO"); BIO_free(in); return 0; } BIO_free(in); /* scan over it and pull out the CRL's */ while (sk_X509_INFO_num(sk)) { xi = sk_X509_INFO_shift(sk); if (xi->x509 != NULL) { EST_LOG_INFO("Adding cert to store (%s)", xi->x509->name); X509_STORE_add_cert(store, xi->x509); cert_cnt++; } if (xi->crl != NULL) { EST_LOG_INFO("Adding CRL to store"); X509_STORE_add_crl(store, xi->crl); } X509_INFO_free(xi); } if (sk != NULL) { sk_X509_INFO_pop_free(sk, X509_INFO_free); } return (cert_cnt); }
int openconnect_open_https(struct openconnect_info *vpninfo) { method_const SSL_METHOD *ssl3_method; SSL *https_ssl; BIO *https_bio; int ssl_sock; int err; if (vpninfo->https_ssl) return 0; if (vpninfo->peer_cert) { X509_free(vpninfo->peer_cert); vpninfo->peer_cert = NULL; } ssl_sock = connect_https_socket(vpninfo); if (ssl_sock < 0) return ssl_sock; ssl3_method = TLSv1_client_method(); if (!vpninfo->https_ctx) { vpninfo->https_ctx = SSL_CTX_new(ssl3_method); /* Some servers (or their firewalls) really don't like seeing extensions. */ #ifdef SSL_OP_NO_TICKET SSL_CTX_set_options(vpninfo->https_ctx, SSL_OP_NO_TICKET); #endif if (vpninfo->cert) { err = load_certificate(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); } /* We just want to do: SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY); ... but it doesn't work with OpenSSL < 0.9.8k because of problems with inheritance (fixed in v1.1.4.6 of crypto/x509/x509_vpm.c) so we have to play silly buggers instead. This trick doesn't work _either_ in < 0.9.7 but I don't know of _any_ workaround which will, and can't be bothered to find out either. */ #if OPENSSL_VERSION_NUMBER >= 0x00908000 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx, ssl_app_verify_callback, NULL); #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; } } } https_ssl = SSL_new(vpninfo->https_ctx); workaround_openssl_certchain_bug(vpninfo, https_ssl); https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE); BIO_set_nbio(https_bio, 1); SSL_set_bio(https_ssl, https_bio, https_bio); vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"), vpninfo->hostname); 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); err = SSL_get_error(https_ssl, err); if (err == SSL_ERROR_WANT_READ) FD_SET(ssl_sock, &rd_set); else if (err == SSL_ERROR_WANT_WRITE) FD_SET(ssl_sock, &wr_set); else { vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n")); openconnect_report_ssl_errors(vpninfo); SSL_free(https_ssl); close(ssl_sock); return -EINVAL; } cmd_fd_set(vpninfo, &rd_set, &maxfd); select(maxfd + 1, &rd_set, &wr_set, NULL, NULL); if (is_cancel_pending(vpninfo, &rd_set)) { vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n")); SSL_free(https_ssl); close(ssl_sock); return -EINVAL; } } if (verify_peer(vpninfo, https_ssl)) { SSL_free(https_ssl); close(ssl_sock); return -EINVAL; } vpninfo->ssl_fd = ssl_sock; vpninfo->https_ssl = https_ssl; /* Stash this now, because it might not be available later if the server has disconnected. */ vpninfo->peer_cert = SSL_get_peer_certificate(vpninfo->https_ssl); vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"), vpninfo->hostname); return 0; }