Add support to crypto/tls for client cert and CA cert from smartcard

This commit is contained in:
David Smith 2008-05-23 10:49:59 +03:00 committed by Jouni Malinen
parent 29222cd303
commit e59c91af82
2 changed files with 157 additions and 16 deletions

View file

@ -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,8 @@ struct tls_connection_params {
const char *engine_id;
const char *pin;
const char *key_id;
const char *cert_id;
const char *ca_cert_id;
};

View file

@ -777,7 +777,8 @@ 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 +815,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 +825,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:
@ -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, &params, 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)
{
#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));
}
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))
return -1;
if (tls_connection_client_cert(conn, params->client_cert,
params->client_cert_blob,
params->client_cert_blob_len))
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 (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->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 && 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,