return ret;
}
-static int request_pin(struct openconnect_info *vpninfo, struct pin_cache *cache, int retrying)
+static int request_pin(struct openconnect_info *vpninfo, struct cert_info *certinfo,
+ struct pin_cache *cache, int retrying)
{
struct oc_auth_form f;
struct oc_form_opt o;
if (!vpninfo || !vpninfo->process_auth_form)
return -EINVAL;
- if (vpninfo->certinfo[0].password) {
- cache->pin = vpninfo->certinfo[0].password;
- vpninfo->certinfo[0].password = NULL;
+ if (certinfo->password) {
+ cache->pin = certinfo->password;
+ certinfo->password = NULL;
return 0;
}
memset(&f, 0, sizeof(f));
return 0;
}
-static int slot_login(struct openconnect_info *vpninfo, PKCS11_CTX *ctx, PKCS11_SLOT *slot)
+static int slot_login(struct openconnect_info *vpninfo, struct cert_info *certinfo,
+ PKCS11_CTX *ctx, PKCS11_SLOT *slot)
{
PKCS11_TOKEN *token = slot->token;
struct pin_cache *cache = vpninfo->pin_cache;
vpninfo->pin_cache = cache;
}
if (!cache->pin) {
- ret = request_pin(vpninfo, cache, retrying);
+ ret = request_pin(vpninfo, certinfo, cache, retrying);
if (ret)
return ret;
}
return NULL;
}
-int load_pkcs11_certificate(struct openconnect_info *vpninfo)
+int load_pkcs11_certificate(struct openconnect_info *vpninfo, struct cert_info *certinfo)
{
PKCS11_CTX *ctx;
PKCS11_TOKEN *match_tok = NULL;
if (!ctx)
return -EIO;
- if (parse_pkcs11_uri(vpninfo->certinfo[0].cert, &match_tok, &cert_id,
- &cert_id_len, &cert_label, &vpninfo->certinfo[0].password) < 0) {
+ if (parse_pkcs11_uri(certinfo->cert, &match_tok, &cert_id,
+ &cert_id_len, &cert_label, &certinfo->password) < 0) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to parse PKCS#11 URI '%s'\n"),
- vpninfo->certinfo[0].cert);
+ certinfo->cert);
return -EINVAL;
}
vpn_progress(vpninfo, PRG_INFO,
_("Logging in to PKCS#11 slot '%s'\n"),
slot->description);
- if (!slot_login(vpninfo, ctx, slot)) {
+ if (!slot_login(vpninfo, certinfo, ctx, slot)) {
cert = slot_find_cert(vpninfo, ctx, slot, cert_label, cert_id, cert_id_len);
if (cert)
goto got_cert;
ret = -EINVAL;
vpn_progress(vpninfo, PRG_ERR,
_("Failed to find PKCS#11 cert '%s'\n"),
- vpninfo->certinfo[0].cert);
+ certinfo->cert);
got_cert:
if (cert) {
/* This happens if the cert is too large for the fixed buffer
}
vpn_progress(vpninfo, PRG_DEBUG,
- _("Using PKCS#11 certificate %s\n"), vpninfo->certinfo[0].cert);
+ _("Using PKCS#11 certificate %s\n"), certinfo->cert);
vpninfo->cert_x509 = X509_dup(cert->x509);
if (!SSL_CTX_use_certificate(vpninfo->https_ctx, vpninfo->cert_x509)) {
/* If the key is in PKCS#11 too (which is likely), then keep the slot around.
We might want to know which slot the certificate was found in, so we can
log into it to find the key. */
- if (!strncmp(vpninfo->certinfo[0].key, "pkcs11:", 7)) {
+ if (!strncmp(certinfo->key, "pkcs11:", 7)) {
vpninfo->pkcs11_slot_list = slot_list;
vpninfo->pkcs11_slot_count = slot_count;
vpninfo->pkcs11_cert_slot = slot;
}
#endif
-int load_pkcs11_key(struct openconnect_info *vpninfo)
+int load_pkcs11_key(struct openconnect_info *vpninfo, struct cert_info *certinfo)
{
PKCS11_CTX *ctx;
PKCS11_TOKEN *match_tok = NULL;
if (!ctx)
return -EIO;
- if (parse_pkcs11_uri(vpninfo->certinfo[0].key, &match_tok, &key_id,
- &key_id_len, &key_label, &vpninfo->certinfo[0].password) < 0) {
+ if (parse_pkcs11_uri(certinfo->key, &match_tok, &key_id,
+ &key_id_len, &key_label, &certinfo->password) < 0) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to parse PKCS#11 URI '%s'\n"),
- vpninfo->certinfo[0].key);
+ certinfo->key);
return -EINVAL;
}
the cert was found in and the key wasn't separately specified, then
try that slot. */
if (matching_slots != 1 && vpninfo->pkcs11_cert_slot &&
- vpninfo->certinfo[0].key == vpninfo->certinfo[0].cert) {
+ certinfo->key == certinfo->cert) {
/* Use the slot the cert was found in, if one specifier was given for both */
matching_slots = 1;
login_slot = vpninfo->pkcs11_cert_slot;
vpn_progress(vpninfo, PRG_INFO,
_("Logging in to PKCS#11 slot '%s'\n"),
slot->description);
- if (!slot_login(vpninfo, ctx, slot)) {
+ if (!slot_login(vpninfo, certinfo, ctx, slot)) {
key = slot_find_key(vpninfo, ctx, slot, key_label, key_id, key_id_len);
if (key)
goto got_key;
/* We still haven't found it. If we weren't explicitly given a URI for
the key and we're inferring the location of the key from the cert,
then drop the label and try matching the CKA_ID of the cert. */
- if (vpninfo->certinfo[0].cert == vpninfo->certinfo[0].key && vpninfo->pkcs11_cert_id &&
+ if (certinfo->cert == certinfo->key && vpninfo->pkcs11_cert_id &&
(key_label || !key_id)) {
key = slot_find_key(vpninfo, ctx, slot, NULL, vpninfo->pkcs11_cert_id,
vpninfo->pkcs11_cert_id_len);
ret = -EINVAL;
vpn_progress(vpninfo, PRG_ERR,
_("Failed to find PKCS#11 key '%s'\n"),
- vpninfo->certinfo[0].key);
+ certinfo->key);
got_key:
if (key) {
vpn_progress(vpninfo, PRG_DEBUG,
- _("Using PKCS#11 key %s\n"), vpninfo->certinfo[0].key);
+ _("Using PKCS#11 key %s\n"), certinfo->key);
pkey = PKCS11_get_private_key(key);
if (!pkey) {
return ret;
}
#else
-int load_pkcs11_key(struct openconnect_info *vpninfo)
+int load_pkcs11_key(struct openconnect_info *vpninfo, struct cert_info *certinfo)
{
vpn_progress(vpninfo, PRG_ERR,
_("This version of OpenConnect was built without PKCS#11 support\n"));
return -EINVAL;
}
-int load_pkcs11_certificate(struct openconnect_info *vpninfo)
+int load_pkcs11_certificate(struct openconnect_info *vpninfo, struct cert_info *certinfo)
{
vpn_progress(vpninfo, PRG_ERR,
_("This version of OpenConnect was built without PKCS#11 support\n"));
}
#endif
-static int pem_pw_cb(char *buf, int len, int w, void *v)
+static int pem_pw_cb(char *buf, int len, int w, void *ci)
{
- struct openconnect_info *vpninfo = v;
+ struct cert_info *certinfo = ci;
+ struct openconnect_info *vpninfo = certinfo->vpninfo;
char *pass = NULL;
int plen;
- if (vpninfo->certinfo[0].password) {
- pass = vpninfo->certinfo[0].password;
- vpninfo->certinfo[0].password = NULL;
+ if (certinfo->password) {
+ pass = certinfo->password;
+ certinfo->password = NULL;
} else if (request_passphrase(vpninfo, "openconnect_pem",
&pass, _("Enter PEM pass phrase:")))
return -1;
return 0;
}
-static int load_pkcs12_certificate(struct openconnect_info *vpninfo, PKCS12 *p12)
+static int load_pkcs12_certificate(struct openconnect_info *vpninfo, struct cert_info *certinfo,
+ PKCS12 *p12)
{
EVP_PKEY *pkey = NULL;
X509 *cert = NULL;
int ret = 0;
char *pass;
- pass = vpninfo->certinfo[0].password;
- vpninfo->certinfo[0].password = NULL;
+ pass = certinfo->password;
+ certinfo->password = NULL;
retrypass:
/* We do this every time round the loop, to work around a bug in
OpenSSL < 1.0.0-beta2 -- where the stack at *ca will be freed
#ifdef HAVE_ENGINE
static int load_tpm_certificate(struct openconnect_info *vpninfo,
- const char *engine)
+ struct cert_info *certinfo, const char *engine)
{
ENGINE *e;
EVP_PKEY *key;
return -EINVAL;
}
- if (vpninfo->certinfo[0].password) {
- if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->certinfo[0].password),
- vpninfo->certinfo[0].password, NULL, 0)) {
+ if (certinfo->password) {
+ if (!ENGINE_ctrl_cmd(e, "PIN", strlen(certinfo->password),
+ certinfo->password, NULL, 0)) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to set TPM SRK password\n"));
openconnect_report_ssl_errors(vpninfo);
}
- free_pass(&vpninfo->certinfo[0].password);
+ free_pass(&certinfo->password);
}
/* Provide our own UI method to handle the PIN callback. */
meth = create_openssl_ui();
- key = ENGINE_load_private_key(e, vpninfo->certinfo[0].key, meth, vpninfo);
+ key = ENGINE_load_private_key(e, certinfo->key, meth, vpninfo);
if (meth)
UI_destroy_method(meth);
if (!key) {
}
#else
static int load_tpm_certificate(struct openconnect_info *vpninfo,
- const char *engine)
+ struct cert_info *certinfo, const char *engine)
{
vpn_progress(vpninfo, PRG_ERR,
_("This version of OpenConnect was built without TPM support\n"));
* allows us to explicitly print the supporting certs that we're using,
* which may assist in diagnosing problems.
*/
-static int load_cert_chain_file(struct openconnect_info *vpninfo)
+static int load_cert_chain_file(struct openconnect_info *vpninfo, struct cert_info *certinfo)
{
BIO *b;
- FILE *f = openconnect_fopen_utf8(vpninfo, vpninfo->certinfo[0].cert, "rb");
+ FILE *f = openconnect_fopen_utf8(vpninfo, certinfo->cert, "rb");
STACK_OF(X509) *extra_certs = NULL;
char buf[200];
if (!f) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to open certificate file %s: %s\n"),
- vpninfo->certinfo[0].cert, strerror(errno));
+ certinfo->cert, strerror(errno));
return -ENOENT;
}
return 0;
}
-static int load_certificate(struct openconnect_info *vpninfo)
+static int load_certificate(struct openconnect_info *vpninfo, struct cert_info *certinfo)
{
EVP_PKEY *key;
FILE *f;
char buf[256];
int ret;
- if (!strncmp(vpninfo->certinfo[0].cert, "pkcs11:", 7)) {
- int ret = load_pkcs11_certificate(vpninfo);
+ certinfo->vpninfo = vpninfo;
+
+ if (!strncmp(certinfo->cert, "pkcs11:", 7)) {
+ int ret = load_pkcs11_certificate(vpninfo, certinfo);
if (ret)
return ret;
goto got_cert;
}
vpn_progress(vpninfo, PRG_DEBUG,
- _("Using certificate file %s\n"), vpninfo->certinfo[0].cert);
+ _("Using certificate file %s\n"), certinfo->cert);
- if (strncmp(vpninfo->certinfo[0].cert, "keystore:", 9)) {
+ if (strncmp(certinfo->cert, "keystore:", 9)) {
PKCS12 *p12;
- f = openconnect_fopen_utf8(vpninfo, vpninfo->certinfo[0].cert, "rb");
+ f = openconnect_fopen_utf8(vpninfo, certinfo->cert, "rb");
if (!f) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to open certificate file %s: %s\n"),
- vpninfo->certinfo[0].cert, strerror(errno));
+ certinfo->cert, strerror(errno));
return -ENOENT;
}
p12 = d2i_PKCS12_fp(f, NULL);
fclose(f);
if (p12)
- return load_pkcs12_certificate(vpninfo, p12);
+ return load_pkcs12_certificate(vpninfo, certinfo, p12);
/* Not PKCS#12. Clear error and fall through to see if it's a PEM file... */
ERR_clear_error();
/* It's PEM or TPM now, and either way we need to load the plain cert: */
#ifdef ANDROID_KEYSTORE
- if (!strncmp(vpninfo->certinfo[0].cert, "keystore:", 9)) {
- BIO *b = BIO_from_keystore(vpninfo, vpninfo->certinfo[0].cert);
+ if (!strncmp(certinfo->cert, "keystore:", 9)) {
+ BIO *b = BIO_from_keystore(vpninfo, certinfo->cert);
if (!b)
return -EINVAL;
- vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, pem_pw_cb, vpninfo);
+ vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, pem_pw_cb, certinfo);
BIO_free(b);
if (!vpninfo->cert_x509) {
vpn_progress(vpninfo, PRG_ERR,
} else
#endif /* ANDROID_KEYSTORE */
{
- int ret = load_cert_chain_file(vpninfo);
+ int ret = load_cert_chain_file(vpninfo, certinfo);
if (ret)
return ret;
}
got_cert:
#ifdef ANDROID_KEYSTORE
- if (!strncmp(vpninfo->certinfo[0].key, "keystore:", 9)) {
+ if (!strncmp(certinfo->key, "keystore:", 9)) {
BIO *b;
again_android:
- b = BIO_from_keystore(vpninfo, vpninfo->certinfo[0].key);
+ b = BIO_from_keystore(vpninfo, certinfo->key);
if (!b)
return -EINVAL;
- key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, vpninfo);
+ key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, certinfo);
BIO_free(b);
if (!key) {
if (is_pem_password_error(vpninfo))
return 0;
}
#endif /* ANDROID_KEYSTORE */
- if (!strncmp(vpninfo->certinfo[0].key, "pkcs11:", 7))
- return load_pkcs11_key(vpninfo);
+ if (!strncmp(certinfo->key, "pkcs11:", 7))
+ return load_pkcs11_key(vpninfo, certinfo);
- f = openconnect_fopen_utf8(vpninfo, vpninfo->certinfo[0].key, "rb");
+ f = openconnect_fopen_utf8(vpninfo, certinfo->key, "rb");
if (!f) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to open private key file %s: %s\n"),
- vpninfo->certinfo[0].key, strerror(errno));
+ certinfo->key, strerror(errno));
return -ENOENT;
}
while (fgets(buf, 255, f)) {
if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
fclose(f);
- return load_tpm_certificate(vpninfo, "tpm");
+ return load_tpm_certificate(vpninfo, certinfo, "tpm");
} else if (!strcmp(buf, "-----BEGIN TSS2 KEY BLOB-----\n") ||
!strcmp(buf, "-----BEGIN TSS2 PRIVATE KEY-----\n")) {
fclose(f);
- return load_tpm_certificate(vpninfo, "tpm2");
+ return load_tpm_certificate(vpninfo, certinfo, "tpm2");
} else if (!strcmp(buf, "-----BEGIN RSA PRIVATE KEY-----\n") ||
!strcmp(buf, "-----BEGIN DSA PRIVATE KEY-----\n") ||
!strcmp(buf, "-----BEGIN EC PRIVATE KEY-----\n") ||
}
again:
fseek(f, 0, SEEK_SET);
- key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, vpninfo);
+ key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, certinfo);
if (!key) {
if (is_pem_password_error(vpninfo))
goto again;
if (p8) {
PKCS8_PRIV_KEY_INFO *p8inf;
- char *pass = vpninfo->certinfo[0].password;
+ char *pass = certinfo->password;
fclose(f);
}
free_pass(&pass);
- vpninfo->certinfo[0].password = NULL;
+ certinfo->password = NULL;
X509_SIG_free(p8);
return -EINVAL;
}
free_pass(&pass);
- vpninfo->certinfo[0].password = NULL;
+ certinfo->password = NULL;
key = EVP_PKCS82PKEY(p8inf);
fclose(f);
vpn_progress(vpninfo, PRG_ERR,
_("Failed to identify private key type in '%s'\n"),
- vpninfo->certinfo[0].key);
+ certinfo->key);
return -EINVAL;
}
#endif
if (vpninfo->certinfo[0].cert) {
- err = load_certificate(vpninfo);
+ err = load_certificate(vpninfo, &vpninfo->certinfo[0]);
if (!err && !SSL_CTX_check_private_key(vpninfo->https_ctx)) {
vpn_progress(vpninfo, PRG_ERR,
_("SSL certificate and key do not match\n"));