From: David Woodhouse Date: Fri, 7 May 2021 14:44:37 +0000 (+0100) Subject: OpenSSL: Pass certinfo through load_certificate() functions X-Git-Tag: v8.20~212 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=13e08b4b005b48f9cac5d3060d9852d8f3e896f3;p=users%2Fdwmw2%2Fopenconnect.git OpenSSL: Pass certinfo through load_certificate() functions Much like in GnuTLS except in GnuTLS we already separated out the bit which installs the key/certs into the https_cred while all these OpenSSL functions are still just installing directly into the SSL_CTX so we're going to want to fix that separately. Signed-off-by: David Woodhouse --- diff --git a/openconnect-internal.h b/openconnect-internal.h index aa682c9f..79ceeb18 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -412,6 +412,7 @@ struct oc_tpm1_ctx; struct oc_tpm2_ctx; struct cert_info { + struct openconnect_info *vpninfo; char *cert; char *key; char *password; @@ -1143,8 +1144,8 @@ int cancellable_send(struct openconnect_info *vpninfo, int fd, int cancellable_recv(struct openconnect_info *vpninfo, int fd, char *buf, size_t len); /* openssl-pkcs11.c */ -int load_pkcs11_key(struct openconnect_info *vpninfo); -int load_pkcs11_certificate(struct openconnect_info *vpninfo); +int load_pkcs11_key(struct openconnect_info *vpninfo, struct cert_info *certinfo); +int load_pkcs11_certificate(struct openconnect_info *vpninfo, struct cert_info *certinfo); /* esp.c */ int verify_packet_seqno(struct openconnect_info *vpninfo, diff --git a/openssl-pkcs11.c b/openssl-pkcs11.c index d0cd165f..fc97e4e7 100644 --- a/openssl-pkcs11.c +++ b/openssl-pkcs11.c @@ -181,7 +181,8 @@ static int parse_pkcs11_uri(const char *uri, PKCS11_TOKEN **p_tok, 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; @@ -191,9 +192,9 @@ static int request_pin(struct openconnect_info *vpninfo, struct pin_cache *cache 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)); @@ -218,7 +219,8 @@ static int request_pin(struct openconnect_info *vpninfo, struct pin_cache *cache 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; @@ -246,7 +248,7 @@ static int slot_login(struct openconnect_info *vpninfo, PKCS11_CTX *ctx, PKCS11_ vpninfo->pin_cache = cache; } if (!cache->pin) { - ret = request_pin(vpninfo, cache, retrying); + ret = request_pin(vpninfo, certinfo, cache, retrying); if (ret) return ret; } @@ -324,7 +326,7 @@ static PKCS11_CERT *slot_find_cert(struct openconnect_info *vpninfo, PKCS11_CTX 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; @@ -340,11 +342,11 @@ int load_pkcs11_certificate(struct openconnect_info *vpninfo) 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; } @@ -386,7 +388,7 @@ int load_pkcs11_certificate(struct openconnect_info *vpninfo) 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; @@ -395,7 +397,7 @@ int load_pkcs11_certificate(struct openconnect_info *vpninfo) 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 @@ -408,7 +410,7 @@ int load_pkcs11_certificate(struct openconnect_info *vpninfo) } 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)) { @@ -421,7 +423,7 @@ int load_pkcs11_certificate(struct openconnect_info *vpninfo) /* 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; @@ -546,7 +548,7 @@ static int validate_ecdsa_key(struct openconnect_info *vpninfo, EC_KEY *priv_ec) } #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; @@ -563,11 +565,11 @@ int load_pkcs11_key(struct openconnect_info *vpninfo) 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; } @@ -609,7 +611,7 @@ int load_pkcs11_key(struct openconnect_info *vpninfo) 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; @@ -620,7 +622,7 @@ int load_pkcs11_key(struct openconnect_info *vpninfo) 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; @@ -628,7 +630,7 @@ int load_pkcs11_key(struct openconnect_info *vpninfo) /* 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); @@ -640,12 +642,12 @@ int load_pkcs11_key(struct openconnect_info *vpninfo) 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) { @@ -708,13 +710,13 @@ int load_pkcs11_key(struct openconnect_info *vpninfo) 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")); diff --git a/openssl.c b/openssl.c index 7c6afd16..25b2ac11 100644 --- a/openssl.c +++ b/openssl.c @@ -498,15 +498,16 @@ static UI_METHOD *create_openssl_ui(void) } #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; @@ -560,7 +561,8 @@ static int install_extra_certs(struct openconnect_info *vpninfo, const char *sou 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; @@ -568,8 +570,8 @@ static int load_pkcs12_certificate(struct openconnect_info *vpninfo, PKCS12 *p12 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 @@ -640,7 +642,7 @@ static int load_pkcs12_certificate(struct openconnect_info *vpninfo, PKCS12 *p12 #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; @@ -667,20 +669,20 @@ static int load_tpm_certificate(struct openconnect_info *vpninfo, 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) { @@ -703,7 +705,7 @@ static int load_tpm_certificate(struct openconnect_info *vpninfo, } #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")); @@ -733,17 +735,17 @@ static int load_tpm_certificate(struct openconnect_info *vpninfo, * 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; } @@ -867,37 +869,39 @@ static int is_pem_password_error(struct openconnect_info *vpninfo) 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(); @@ -905,11 +909,11 @@ static int load_certificate(struct openconnect_info *vpninfo) /* 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, @@ -928,21 +932,21 @@ static int load_certificate(struct openconnect_info *vpninfo) } 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)) @@ -961,14 +965,14 @@ static int load_certificate(struct openconnect_info *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; } @@ -976,11 +980,11 @@ static int load_certificate(struct openconnect_info *vpninfo) 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") || @@ -997,7 +1001,7 @@ static int load_certificate(struct openconnect_info *vpninfo) } 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; @@ -1044,7 +1048,7 @@ static int load_certificate(struct openconnect_info *vpninfo) if (p8) { PKCS8_PRIV_KEY_INFO *p8inf; - char *pass = vpninfo->certinfo[0].password; + char *pass = certinfo->password; fclose(f); @@ -1073,13 +1077,13 @@ static int load_certificate(struct openconnect_info *vpninfo) } 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); @@ -1106,7 +1110,7 @@ static int load_certificate(struct openconnect_info *vpninfo) fclose(f); vpn_progress(vpninfo, PRG_ERR, _("Failed to identify private key type in '%s'\n"), - vpninfo->certinfo[0].key); + certinfo->key); return -EINVAL; } @@ -1815,7 +1819,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo) #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"));