[PATCH] Add support to crypto/tls for client cert and CA cert from smartcard Remember to free the new X509 cert in error conditions
David Smith
dds
Thu May 1 09:07:29 PDT 2008
---
src/crypto/tls.h | 8 ++-
src/crypto/tls_openssl.c | 162 +++++++++++++++++++++++++++++++++++++++++----
2 files changed, 154 insertions(+), 16 deletions(-)
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 0a79166..2d21562 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -63,7 +63,10 @@ struct tls_config {
* @engine_id: engine id string (this is OpenSSL specific for now)
* @ppin: pointer to the pin variable in the configuration
* (this is OpenSSL specific for now)
- * @key_id: the private key's key id (this is OpenSSL specific for now)
+ * @key_id: the private key's id when using engine (this is OpenSSL
+ * specific for now)
+ * @cert_id: the certificate's id when using engine
+ * @ca_cert_id: the CA certificate's id when using engine
* @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1)
*
* TLS connection parameters to be configured with tls_connection_set_params()
@@ -98,6 +101,9 @@ struct tls_connection_params {
const char *engine_id;
const char *pin;
const char *key_id;
+ const char *cert_id;
+ const char *ca_cert_id;
+
};
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 22ec04c..8fddeb0 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -775,9 +775,9 @@ void tls_deinit(void *ssl_ctx)
}
}
-
static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
- const char *pin, const char *key_id)
+ const char *pin, const char *key_id,
+ const char *cert_id, const char *ca_cert_id)
{
#ifndef OPENSSL_NO_ENGINE
int ret = -1;
@@ -814,6 +814,7 @@ static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
ERR_error_string(ERR_get_error(), NULL));
goto err;
}
+ /* load private key first in-case PIN is required for cert */
conn->private_key = ENGINE_load_private_key(conn->engine,
key_id, NULL, NULL);
if (!conn->private_key) {
@@ -823,6 +824,21 @@ static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
goto err;
}
+
+ /* handle a certificate and/or CA certificate */
+ if (cert_id || ca_cert_id) {
+ const char *cmd_name = "LOAD_CERT_CTRL";
+
+ /* test if the engine supports a LOAD_CERT_CTRL */
+ if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
+ 0, (void *)cmd_name, NULL)) {
+ wpa_printf(MSG_ERROR, "ENGINE: engine does not support"
+ " loading certificates");
+ ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ goto err;
+ }
+ }
+
return 0;
err:
@@ -1490,6 +1506,109 @@ static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
#endif /* PKCS12_FUNCS */
}
+static int tls_engine_get_cert(struct tls_connection *conn,
+ const char *cert_id,
+ X509 **cert)
+{
+#ifndef OPENSSL_NO_ENGINE
+ /* this runs after the private key is loaded so no PIN is required */
+ struct {
+ const char *cert_id;
+ X509 *cert;
+ } params;
+ params.cert_id = cert_id;
+ params.cert = NULL;
+
+ if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL",
+ 0, ¶ms, NULL, 1)) {
+ wpa_printf(MSG_ERROR,"ENGINE: cannot load client cert with id"
+ " '%s' [%s]", cert_id,
+ ERR_error_string(ERR_get_error(), NULL));
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ }
+ if (!params.cert) {
+ wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id"
+ " '%s'", cert_id);
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ }
+ *cert = params.cert;
+ return 0;
+#else /* OPENSSL_NO_ENGINE */
+ return -1;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+static int tls_connection_engine_client_cert(struct tls_connection *conn,
+ const char *cert_id)
+{
+#ifndef OPENSSL_NO_ENGINE
+ X509 *cert;
+
+ if (tls_engine_get_cert(conn, cert_id, &cert))
+ return -1;
+
+ if (!SSL_use_certificate(conn->ssl, cert)) {
+ tls_show_errors(MSG_ERROR, __func__,
+ "SSL_use_certificate failed");
+ X509_free(cert);
+ return -1;
+ }
+ X509_free(cert);
+ wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> "
+ "OK");
+ return 0;
+
+#else /* OPENSSL_NO_ENGINE */
+ return -1;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+static int tls_connection_engine_ca_cert(void *_ssl_ctx,
+ struct tls_connection *conn,
+ const char *ca_cert_id)
+{
+#ifndef OPENSSL_NO_ENGINE
+ X509 *cert;
+ SSL_CTX *ssl_ctx = _ssl_ctx;
+
+ if (tls_engine_get_cert(conn, ca_cert_id, &cert))
+ return -1;
+
+ /* start off the same as tls_connection_ca_cert */
+ X509_STORE_free(ssl_ctx->cert_store);
+ ssl_ctx->cert_store = X509_STORE_new();
+ if (ssl_ctx->cert_store == NULL) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
+ "certificate store", __func__);
+ X509_free(cert);
+ return -1;
+ }
+ if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+ unsigned long err = ERR_peek_error();
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to add CA certificate from engine "
+ "to certificate store");
+ if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
+ ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert"
+ " already in hash table error",
+ __func__);
+ } else {
+ X509_free(cert);
+ return -1;
+ }
+ }
+ X509_free(cert);
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from"
+ " engine to certificate store", __func__);
+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+ return 0;
+
+#else /* OPENSSL_NO_ENGINE */
+ return -1;
+#endif /* OPENSSL_NO_ENGINE */
+}
static int tls_connection_engine_private_key(struct tls_connection *conn)
{
@@ -2229,26 +2348,39 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
__func__, ERR_error_string(err, NULL));
}
+ if (params->engine) {
+ wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
+ ret = tls_engine_init(conn, params->engine_id, params->pin,
+ params->key_id, params->cert_id,
+ params->ca_cert_id);
+ if (ret)
+ return ret;
+ }
if (tls_connection_set_subject_match(conn,
params->subject_match,
params->altsubject_match))
return -1;
- if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
- params->ca_cert_blob,
- params->ca_cert_blob_len,
- params->ca_path))
+
+ if (params->engine && params->ca_cert_id) {
+ if (tls_connection_engine_ca_cert(tls_ctx, conn,
+ params->ca_cert_id))
+ return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
+ } else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+ params->ca_cert_blob,
+ params->ca_cert_blob_len,
+ params->ca_path))
return -1;
- if (tls_connection_client_cert(conn, params->client_cert,
- params->client_cert_blob,
- params->client_cert_blob_len))
+
+ if (params->engine && params->cert_id) {
+ if (tls_connection_engine_client_cert(conn, params->cert_id))
+ return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
+ } else if (tls_connection_client_cert(conn, params->client_cert,
+ params->client_cert_blob,
+ params->client_cert_blob_len))
return -1;
- if (params->engine) {
- wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
- ret = tls_engine_init(conn, params->engine_id, params->pin,
- params->key_id);
- if (ret)
- return ret;
+ if (params->engine && params->key_id) {
+ wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
if (tls_connection_engine_private_key(conn))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_private_key(tls_ctx, conn,
--
1.5.4.3
--=-=-=--
More information about the Hostap
mailing list