Add support to crypto/tls for client cert and CA cert from smartcard
This commit is contained in:
parent
29222cd303
commit
e59c91af82
2 changed files with 157 additions and 16 deletions
|
@ -63,7 +63,10 @@ struct tls_config {
|
||||||
* @engine_id: engine id string (this is OpenSSL specific for now)
|
* @engine_id: engine id string (this is OpenSSL specific for now)
|
||||||
* @ppin: pointer to the pin variable in the configuration
|
* @ppin: pointer to the pin variable in the configuration
|
||||||
* (this is OpenSSL specific for now)
|
* (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_ia: Whether to enable TLS/IA (for EAP-TTLSv1)
|
||||||
*
|
*
|
||||||
* TLS connection parameters to be configured with tls_connection_set_params()
|
* TLS connection parameters to be configured with tls_connection_set_params()
|
||||||
|
@ -98,6 +101,8 @@ struct tls_connection_params {
|
||||||
const char *engine_id;
|
const char *engine_id;
|
||||||
const char *pin;
|
const char *pin;
|
||||||
const char *key_id;
|
const char *key_id;
|
||||||
|
const char *cert_id;
|
||||||
|
const char *ca_cert_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -777,7 +777,8 @@ void tls_deinit(void *ssl_ctx)
|
||||||
|
|
||||||
|
|
||||||
static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
|
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
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
@ -814,6 +815,7 @@ static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
|
||||||
ERR_error_string(ERR_get_error(), NULL));
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
/* load private key first in-case PIN is required for cert */
|
||||||
conn->private_key = ENGINE_load_private_key(conn->engine,
|
conn->private_key = ENGINE_load_private_key(conn->engine,
|
||||||
key_id, NULL, NULL);
|
key_id, NULL, NULL);
|
||||||
if (!conn->private_key) {
|
if (!conn->private_key) {
|
||||||
|
@ -823,6 +825,21 @@ static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
|
||||||
ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
|
ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
|
||||||
goto err;
|
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;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
@ -1495,6 +1512,112 @@ static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
static int tls_connection_engine_private_key(struct tls_connection *conn)
|
||||||
{
|
{
|
||||||
#ifndef OPENSSL_NO_ENGINE
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
|
@ -2233,26 +2356,39 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
||||||
__func__, ERR_error_string(err, NULL));
|
__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,
|
if (tls_connection_set_subject_match(conn,
|
||||||
params->subject_match,
|
params->subject_match,
|
||||||
params->altsubject_match))
|
params->altsubject_match))
|
||||||
return -1;
|
return -1;
|
||||||
if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
|
|
||||||
|
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,
|
||||||
params->ca_cert_blob_len,
|
params->ca_cert_blob_len,
|
||||||
params->ca_path))
|
params->ca_path))
|
||||||
return -1;
|
return -1;
|
||||||
if (tls_connection_client_cert(conn, params->client_cert,
|
|
||||||
|
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,
|
||||||
params->client_cert_blob_len))
|
params->client_cert_blob_len))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (params->engine) {
|
if (params->engine && params->key_id) {
|
||||||
wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
|
wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
|
||||||
ret = tls_engine_init(conn, params->engine_id, params->pin,
|
|
||||||
params->key_id);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
if (tls_connection_engine_private_key(conn))
|
if (tls_connection_engine_private_key(conn))
|
||||||
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
|
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
|
||||||
} else if (tls_connection_private_key(tls_ctx, conn,
|
} else if (tls_connection_private_key(tls_ctx, conn,
|
||||||
|
|
Loading…
Reference in a new issue