*
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <fcntl.h>
#include <openssl/conf.h>
+#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
+#endif
+#include <openssl/ssl.h>
#include <openssl/hmac.h>
#include <openssl/err.h>
#include <openssl/ui.h>
#include <openssl/x509v3.h>
#include <openssl/pkcs12.h>
-#include "pppd.h"
+#include "pppd-private.h"
+#include "tls.h"
#include "eap.h"
#include "eap-tls.h"
#include "fsm.h"
#include "mppe.h"
#include "pathnames.h"
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#define SSL3_RT_HEADER 0x100
+#endif
+
typedef struct pw_cb_data
{
const void *password;
/* TLSv1.3 do we have a session ticket ? */
static int have_session_ticket = 0;
-int ssl_verify_callback(int, X509_STORE_CTX *);
void ssl_msg_callback(int write_p, int version, int ct, const void *buf,
size_t len, SSL * ssl, void *arg);
int ssl_new_session_cb(SSL *s, SSL_SESSION *sess);
-X509 *get_X509_from_file(char *filename);
-int ssl_cmp_certs(char *filename, X509 * a);
-
-/*
- * OpenSSL 1.1+ introduced a generic TLS_method()
- * For older releases we substitute the appropriate method
- */
-
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-
-#define TLS_method SSLv23_method
-
-#define SSL3_RT_HEADER 0x100
-
-#ifndef SSL_CTX_set_max_proto_version
-/** Mimics SSL_CTX_set_max_proto_version for OpenSSL < 1.1 */
-static inline int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, long tls_ver_max)
-{
- long sslopt = 0;
-
- if (tls_ver_max < TLS1_VERSION)
- {
- sslopt |= SSL_OP_NO_TLSv1;
- }
-#ifdef SSL_OP_NO_TLSv1_1
- if (tls_ver_max < TLS1_1_VERSION)
- {
- sslopt |= SSL_OP_NO_TLSv1_1;
- }
-#endif
-#ifdef SSL_OP_NO_TLSv1_2
- if (tls_ver_max < TLS1_2_VERSION)
- {
- sslopt |= SSL_OP_NO_TLSv1_2;
- }
-#endif
- SSL_CTX_set_options(ctx, sslopt);
-
- return 1;
-}
-#endif /* SSL_CTX_set_max_proto_version */
-
-#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
-
-#ifdef MPPE
+#ifdef PPP_WITH_MPPE
#define EAPTLS_MPPE_KEY_LEN 32
/*
}
}
-#endif /* MPPE */
-
-
-void log_ssl_errors( void )
-{
- unsigned long ssl_err = ERR_get_error();
-
- if (ssl_err != 0)
- dbglog("EAP-TLS SSL error stack:");
- while (ssl_err != 0) {
- dbglog( ERR_error_string( ssl_err, NULL ) );
- ssl_err = ERR_get_error();
- }
-}
-
+#endif /* PPP_WITH_MPPE */
int password_callback (char *buf, int size, int rwflag, void *u)
{
config = NCONF_new( NULL );
dbglog( "Loading OpenSSL config file" );
- ret_code = NCONF_load( config, _PATH_OPENSSLCONFFILE, &error_line );
+ ret_code = NCONF_load( config, PPP_PATH_OPENSSLCONFFILE, &error_line );
if (ret_code == 0)
{
- warn( "EAP-TLS: Error in OpenSSL config file %s at line %d", _PATH_OPENSSLCONFFILE, error_line );
+ warn( "EAP-TLS: Error in OpenSSL config file %s at line %d", PPP_PATH_OPENSSLCONFFILE, error_line );
NCONF_free( config );
config = NULL;
ERR_clear_error();
if (CONF_modules_load( config, NULL, 0 ) <= 0 )
{
warn( "EAP-TLS: Error loading OpenSSL modules" );
- log_ssl_errors();
+ tls_log_sslerr();
config = NULL;
}
|| !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0))
{
warn( "EAP-TLS: Error loading dynamic engine '%s'", engine_name );
- log_ssl_errors();
+ tls_log_sslerr();
ENGINE_free(e);
e = NULL;
}
if(!ENGINE_set_default(e, ENGINE_METHOD_ALL))
{
warn( "EAP-TLS: Cannot use that engine" );
- log_ssl_errors();
+ tls_log_sslerr();
ENGINE_free(e);
e = NULL;
}
#endif
+#ifndef OPENSSL_NO_ENGINE
+static int eaptls_UI_writer(UI *ui, UI_STRING *uis)
+{
+ PW_CB_DATA* cb_data = (PW_CB_DATA*)UI_get0_user_data(ui);
+ UI_set_result(ui, uis, cb_data->password);
+ return 1;
+}
+
+static int eaptls_UI_stub(UI* ui) {
+ return 1;
+}
+
+static int eaptls_UI_reader(UI *ui, UI_STRING *uis) {
+ return 1;
+}
+#endif
+
/*
* Initialize the SSL stacks and tests if certificates, key and crl
* for client or server use can be loaded.
*/
SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
- char *certfile, char *peer_certfile, char *privkeyfile, char *pkcs12)
+ char *certfile, char *privkeyfile, char *pkcs12)
{
#ifndef OPENSSL_NO_ENGINE
char *cert_engine_name = NULL;
- char *cert_identifier = NULL;
char *pkey_engine_name = NULL;
- char *pkey_identifier = NULL;
+ char *idx;
#endif
SSL_CTX *ctx;
SSL *ssl;
- X509_STORE *certstore;
- X509_LOOKUP *lookup;
X509 *tmp;
X509 *cert = NULL;
PKCS12 *p12 = NULL;
BIO *input;
int ret;
int reason;
-#if defined(TLS1_2_VERSION)
- long tls_version = TLS1_2_VERSION;
-#elif defined(TLS1_1_VERSION)
- long tls_version = TLS1_1_VERSION;
-#else
- long tls_version = TLS1_VERSION;
-#endif
/*
* Without these can't continue
}
}
- SSL_library_init();
- SSL_load_error_strings();
+ tls_init();
#ifndef OPENSSL_NO_ENGINE
/* load the openssl config file only once and load it before triggering
ssl_config = eaptls_ssl_load_config();
#endif
- ctx = SSL_CTX_new(TLS_method());
-
+ ctx = SSL_CTX_new(tls_method());
if (!ctx) {
error("EAP-TLS: Cannot initialize SSL CTX context");
goto fail;
If the certificate filename starts with a / or . then we
ALWAYS assume it is a file and not an engine/pkcs11 identifier
*/
- if ( index( certfile, '/' ) == NULL && index( certfile, '.') == NULL )
+ if ( (idx = index( certfile, ':' )) != NULL )
{
- cert_identifier = index( certfile, ':' );
+ cert_engine_name = strdup( certfile );
+ cert_engine_name[idx - certfile] = 0;
- if (cert_identifier)
- {
- cert_engine_name = certfile;
- *cert_identifier = '\0';
- cert_identifier++;
-
- dbglog( "Found certificate engine '%s'", cert_engine_name );
- dbglog( "Found certificate identifier '%s'", cert_identifier );
- }
+ dbglog( "Using engine '%s' for certificate, URI: '%s'",
+ cert_engine_name, certfile );
}
/* if the privatekey filename is of the form engine:id. e.g.
If the privatekey filename starts with a / or . then we
ALWAYS assume it is a file and not an engine/pkcs11 identifier
*/
- if ( index( privkeyfile, '/' ) == NULL && index( privkeyfile, '.') == NULL )
+ if ( (idx = index( privkeyfile, ':' )) != NULL )
{
- pkey_identifier = index( privkeyfile, ':' );
+ pkey_engine_name = strdup( privkeyfile );
+ pkey_engine_name[idx - privkeyfile] = 0;
- if (pkey_identifier)
- {
- pkey_engine_name = privkeyfile;
- *pkey_identifier = '\0';
- pkey_identifier++;
-
- dbglog( "Found privatekey engine '%s'", pkey_engine_name );
- dbglog( "Found privatekey identifier '%s'", pkey_identifier );
- }
+ dbglog( "Using engine '%s' for private key, URI: '%s'",
+ pkey_engine_name, privkeyfile );
}
- if (cert_identifier && pkey_identifier)
+ if (cert_engine_name && pkey_engine_name)
{
- if (strlen( cert_identifier ) == 0)
+ if (strlen( certfile ) - strlen( cert_engine_name ) == 1)
{
- if (strlen( pkey_identifier ) == 0)
+ if (strlen( privkeyfile ) - strlen( pkey_engine_name ) == 1)
error( "EAP-TLS: both the certificate and privatekey identifiers are missing!" );
else
{
dbglog( "Substituting privatekey identifier for certificate identifier" );
- cert_identifier = pkey_identifier;
+ certfile = privkeyfile;
}
}
else
{
- if (strlen( pkey_identifier ) == 0)
+ if (strlen( privkeyfile ) - strlen( pkey_engine_name ) == 1)
{
dbglog( "Substituting certificate identifier for privatekey identifier" );
- pkey_identifier = cert_identifier;
+ privkeyfile = certfile;
}
}
}
else
pkey_engine = eaptls_ssl_load_engine( pkey_engine_name );
}
+
+ if (cert_engine_name)
+ free(cert_engine_name);
+
+ if (pkey_engine_name)
+ free(pkey_engine_name);
+
#endif
SSL_CTX_set_default_passwd_cb (ctx, password_callback);
- if (strlen(cacertfile) == 0) cacertfile = NULL;
- if (strlen(capath) == 0) capath = NULL;
-
- if (!SSL_CTX_load_verify_locations(ctx, cacertfile, capath))
- {
- error("EAP-TLS: Cannot load verify locations");
- if (cacertfile) dbglog("CA certificate file = [%s]", cacertfile);
- if (capath) dbglog("CA certificate path = [%s]", capath);
+ if (tls_set_ca(ctx, capath, cacertfile) != 0) {
goto fail;
}
X509 *cert;
} cert_info;
- cert_info.s_slot_cert_id = cert_identifier;
+ cert_info.s_slot_cert_id = certfile;
cert_info.cert = NULL;
if (!ENGINE_ctrl_cmd( cert_engine, "LOAD_CERT_CTRL", 0, &cert_info, NULL, 0 ) )
{
- error( "EAP-TLS: Error loading certificate with id '%s' from engine", cert_identifier );
+ error( "EAP-TLS: Error loading certificate with URI '%s' from engine", certfile );
goto fail;
}
}
else
{
- warn("EAP-TLS: Cannot load PKCS11 key %s", cert_identifier);
- log_ssl_errors();
+ warn("EAP-TLS: Cannot load key with URI: '%s'", certfile );
+ tls_log_sslerr();
}
}
else
PW_CB_DATA cb_data;
cb_data.password = passwd;
- cb_data.prompt_info = pkey_identifier;
+ cb_data.prompt_info = privkeyfile;
if (passwd[0] != 0)
{
UI_METHOD* transfer_pin = UI_create_method("transfer_pin");
- int writer (UI *ui, UI_STRING *uis)
- {
- PW_CB_DATA* cb_data = (PW_CB_DATA*)UI_get0_user_data(ui);
- UI_set_result(ui, uis, cb_data->password);
- return 1;
- };
- int stub (UI* ui) {return 1;};
- int stub_reader (UI *ui, UI_STRING *uis) {return 1;};
-
- UI_method_set_writer(transfer_pin, writer);
- UI_method_set_opener(transfer_pin, stub);
- UI_method_set_closer(transfer_pin, stub);
- UI_method_set_flusher(transfer_pin, stub);
- UI_method_set_reader(transfer_pin, stub_reader);
-
- dbglog( "Using our private key '%s' in engine", pkey_identifier );
- pkey = ENGINE_load_private_key(pkey_engine, pkey_identifier, transfer_pin, &cb_data);
+ UI_method_set_writer(transfer_pin, eaptls_UI_writer);
+ UI_method_set_opener(transfer_pin, eaptls_UI_stub);
+ UI_method_set_closer(transfer_pin, eaptls_UI_stub);
+ UI_method_set_flusher(transfer_pin, eaptls_UI_stub);
+ UI_method_set_reader(transfer_pin, eaptls_UI_reader);
+
+ dbglog( "Using our private key URI: '%s' in engine", privkeyfile );
+ pkey = ENGINE_load_private_key(pkey_engine, privkeyfile, transfer_pin, &cb_data);
if (transfer_pin) UI_destroy_method(transfer_pin);
}
else {
- dbglog( "Loading private key '%s' from engine", pkey_identifier );
- pkey = ENGINE_load_private_key(pkey_engine, pkey_identifier, NULL, NULL);
+ dbglog( "Loading private key URI: '%s' from engine", privkeyfile );
+ pkey = ENGINE_load_private_key(pkey_engine, privkeyfile, NULL, NULL);
}
}
else
goto fail;
}
- /* Explicitly set the NO_TICKETS flag to support Win7/Win8 clients */
- SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3
-#ifdef SSL_OP_NO_TICKET
- | SSL_OP_NO_TICKET
-#endif
- );
-
- /* OpenSSL 1.1.1+ does not include RC4 ciphers by default.
- * This causes totally obsolete WinXP clients to fail. If you really
- * need ppp+EAP-TLS+openssl 1.1.1+WinXP then enable RC4 cipers and
- * make sure that you use an OpenSSL that supports them
-
- SSL_CTX_set_cipher_list(ctx, "RC4");
- */
-
+ /* Configure the default options */
+ tls_set_opts(ctx);
/* Set up a SSL Session cache with a callback. This is needed for TLSv1.3+.
* During the initial handshake the server signals to the client early on
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE);
SSL_CTX_sess_set_new_cb(ctx, ssl_new_session_cb);
- /* As EAP-TLS+TLSv1.3 is highly experimental we offer the user a chance to override */
- if (max_tls_version)
- {
- if (strncmp(max_tls_version, "1.0", 3) == 0)
- tls_version = TLS1_VERSION;
- else if (strncmp(max_tls_version, "1.1", 3) == 0)
- tls_version = TLS1_1_VERSION;
- else if (strncmp(max_tls_version, "1.2", 3) == 0)
-#ifdef TLS1_2_VERSION
- tls_version = TLS1_2_VERSION;
-#else
- {
- warn("TLSv1.2 not available. Defaulting to TLSv1.1");
- tls_version = TLS_1_1_VERSION;
- }
-#endif
- else if (strncmp(max_tls_version, "1.3", 3) == 0)
-#ifdef TLS1_3_VERSION
- tls_version = TLS1_3_VERSION;
-#else
- warn("TLSv1.3 not available.");
-#endif
- }
-
- dbglog("EAP-TLS: Setting max protocol version to 0x%X", tls_version);
- SSL_CTX_set_max_proto_version(ctx, tls_version);
-
- SSL_CTX_set_verify_depth(ctx, 5);
- SSL_CTX_set_verify(ctx,
- SSL_VERIFY_PEER |
- SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
- &ssl_verify_callback);
-
- if (crl_dir) {
- if (!(certstore = SSL_CTX_get_cert_store(ctx))) {
- error("EAP-TLS: Failed to get certificate store");
- goto fail;
- }
-
- if (!(lookup =
- X509_STORE_add_lookup(certstore, X509_LOOKUP_hash_dir()))) {
- error("EAP-TLS: Store lookup for CRL failed");
-
- goto fail;
- }
-
- X509_LOOKUP_add_dir(lookup, crl_dir, X509_FILETYPE_PEM);
- X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK);
- }
-
- if (crl_file) {
- FILE *fp = NULL;
- X509_CRL *crl = NULL;
-
- fp = fopen(crl_file, "r");
- if (!fp) {
- error("EAP-TLS: Cannot open CRL file '%s'", crl_file);
- goto fail;
- }
-
- crl = PEM_read_X509_CRL(fp, NULL, NULL, NULL);
- if (!crl) {
- error("EAP-TLS: Cannot read CRL file '%s'", crl_file);
- goto fail;
- }
-
- if (!(certstore = SSL_CTX_get_cert_store(ctx))) {
- error("EAP-TLS: Failed to get certificate store");
- goto fail;
- }
- if (!X509_STORE_add_crl(certstore, crl)) {
- error("EAP-TLS: Cannot add CRL to certificate store");
- goto fail;
- }
- X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK);
+ /* Configure the maximum SSL version */
+ tls_set_version(ctx, max_tls_version);
+ /* Configure the callback */
+ if (tls_set_verify(ctx, 5)) {
+ goto fail;
}
- /*
- * If a peer certificate file was specified, it must be valid, else fail
- */
- if (peer_certfile[0]) {
- if (!(tmp = get_X509_from_file(peer_certfile))) {
- error("EAP-TLS: Error loading client certificate from file %s",
- peer_certfile);
- goto fail;
- }
- X509_free(tmp);
+ /* Configure CRL check (if any) */
+ if (tls_set_crl(ctx, crl_dir, crl_file)) {
+ goto fail;
}
return ctx;
if (chain)
sk_X509_pop_free(chain, X509_free);
- log_ssl_errors();
+ tls_log_sslerr();
SSL_CTX_free(ctx);
return NULL;
}
if (!esp->es_server.ea_session)
fatal("Allocation error");
ets = esp->es_server.ea_session;
- ets->client = 0;
if (!esp->es_server.ea_peer) {
error("EAP-TLS: Error: client name not set (BUG)");
return 0;
}
- strlcpy(ets->peer, esp->es_server.ea_peer, MAXWORDLEN-1);
-
dbglog( "getting eaptls secret" );
if (!get_eaptls_secret(esp->es_unit, esp->es_server.ea_peer,
esp->es_server.ea_name, clicertfile,
ets->mtu = eaptls_get_mtu(esp->es_unit);
- ets->ctx = eaptls_init_ssl(1, cacertfile, capath, servcertfile, clicertfile, pkfile, pkcs12);
+ ets->ctx = eaptls_init_ssl(1, cacertfile, capath, servcertfile, pkfile, pkcs12);
if (!ets->ctx)
goto fail;
if (!(ets->ssl = SSL_new(ets->ctx)))
goto fail;
+ if (tls_set_verify_info(ets->ssl, esp->es_server.ea_peer,
+ clicertfile, 0, &ets->info))
+ goto fail;
+
/*
* Set auto-retry to avoid timeouts on BIO_read
*/
SSL_set_msg_callback(ets->ssl, ssl_msg_callback);
SSL_set_msg_callback_arg(ets->ssl, ets);
- /*
- * Attach the session struct to the connection, so we can later
- * retrieve it when doing certificate verification
- */
- SSL_set_ex_data(ets->ssl, 0, ets);
-
SSL_set_accept_state(ets->ssl);
ets->tls_v13 = 0;
ets->datalen = 0;
ets->alert_sent = 0;
ets->alert_recv = 0;
-
- /*
- * If we specified the client certificate file, store it in ets->peercertfile,
- * so we can check it later in ssl_verify_callback()
- */
- if (clicertfile[0])
- strlcpy(&ets->peercertfile[0], clicertfile, MAXWORDLEN);
- else
- ets->peercertfile[0] = 0;
-
return 1;
fail:
if (!esp->es_client.ea_session)
fatal("Allocation error");
ets = esp->es_client.ea_session;
- ets->client = 1;
-
- /*
- * If available, copy server name in ets; it will be used in cert
- * verify
- */
- if (esp->es_client.ea_peer)
- strlcpy(ets->peer, esp->es_client.ea_peer, MAXWORDLEN-1);
- else
- ets->peer[0] = 0;
-
ets->mtu = eaptls_get_mtu(esp->es_unit);
dbglog( "calling get_eaptls_secret" );
if (!get_eaptls_secret(esp->es_unit, esp->es_client.ea_name,
- ets->peer, clicertfile,
+ esp->es_client.ea_peer, clicertfile,
servcertfile, cacertfile, capath, pkfile, pkcs12, 0)) {
error( "EAP-TLS: Cannot get secret/password for client \"%s\", server \"%s\"",
- esp->es_client.ea_name, ets->peer );
+ esp->es_client.ea_name, esp->es_client.ea_peer);
return 0;
}
dbglog( "calling eaptls_init_ssl" );
- ets->ctx = eaptls_init_ssl(0, cacertfile, capath, clicertfile, servcertfile, pkfile, pkcs12);
+ ets->ctx = eaptls_init_ssl(0, cacertfile, capath, clicertfile, pkfile, pkcs12);
if (!ets->ctx)
goto fail;
ets->ssl = SSL_new(ets->ctx);
-
if (!ets->ssl)
goto fail;
+ if (tls_set_verify_info(ets->ssl, esp->es_client.ea_peer,
+ servcertfile, 0, &ets->info))
+ goto fail;
+
/*
* Initialize the BIOs we use to read/write to ssl engine
*/
SSL_set_msg_callback(ets->ssl, ssl_msg_callback);
SSL_set_msg_callback_arg(ets->ssl, ets);
-
- /*
- * Attach the session struct to the connection, so we can later
- * retrieve it when doing certificate verification
- */
- SSL_set_ex_data(ets->ssl, 0, ets);
-
SSL_set_connect_state(ets->ssl);
ets->tls_v13 = 0;
ets->datalen = 0;
ets->alert_sent = 0;
ets->alert_recv = 0;
-
- /*
- * If we specified the server certificate file, store it in
- * ets->peercertfile, so we can check it later in
- * ssl_verify_callback()
- */
- if (servcertfile[0])
- strlcpy(ets->peercertfile, servcertfile, MAXWORDLEN);
- else
- ets->peercertfile[0] = 0;
-
return 1;
fail:
if (ets->ctx)
SSL_CTX_free(ets->ctx);
+ if (ets->info)
+ tls_free_verify_info(&ets->info);
+
free(ets);
}
}
if (BIO_write(ets->into_ssl, ets->data, ets->datalen) == -1)
- log_ssl_errors();
+ tls_log_sslerr();
SSL_read(ets->ssl, dummy, 65536);
INCPTR(ets->rtx_len, *outp);
}
-/*
- * Verify a certificate.
- * Most of the work (signatures and issuer attributes checking)
- * is done by ssl; we check the CN in the peer certificate
- * against the peer name.
- */
-int ssl_verify_callback(int ok, X509_STORE_CTX * ctx)
-{
- char subject[256];
- char cn_str[256];
- X509 *peer_cert;
- int err, depth;
- SSL *ssl;
- struct eaptls_session *ets;
- char *ptr1 = NULL, *ptr2 = NULL;
-
- peer_cert = X509_STORE_CTX_get_current_cert(ctx);
- err = X509_STORE_CTX_get_error(ctx);
- depth = X509_STORE_CTX_get_error_depth(ctx);
-
- dbglog("certificate verify depth: %d", depth);
-
- if (auth_required && !ok) {
- X509_NAME_oneline(X509_get_subject_name(peer_cert),
- subject, 256);
-
- X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert),
- NID_commonName, cn_str, 256);
-
- dbglog("Certificate verification error:\n depth: %d CN: %s"
- "\n err: %d (%s)\n", depth, cn_str, err,
- X509_verify_cert_error_string(err));
-
- return 0;
- }
-
- ssl = X509_STORE_CTX_get_ex_data(ctx,
- SSL_get_ex_data_X509_STORE_CTX_idx());
-
- ets = (struct eaptls_session *)SSL_get_ex_data(ssl, 0);
-
- if (ets == NULL) {
- error("Error: SSL_get_ex_data returned NULL");
- return 0;
- }
-
- log_ssl_errors();
-
- if (!depth)
- {
- /* Verify certificate based on certificate type and extended key usage */
- if (tls_verify_key_usage) {
- int purpose = ets->client ? X509_PURPOSE_SSL_SERVER : X509_PURPOSE_SSL_CLIENT ;
- if (X509_check_purpose(peer_cert, purpose, 0) == 0) {
- error("Certificate verification error: nsCertType mismatch");
- return 0;
- }
-
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
- int flags = ets->client ? XKU_SSL_SERVER : XKU_SSL_CLIENT;
- if (!(X509_get_extended_key_usage(peer_cert) & flags)) {
- error("Certificate verification error: invalid extended key usage");
- return 0;
- }
-#endif
- info("Certificate key usage: OK");
- }
-
- /*
- * If acting as client and the name of the server wasn't specified
- * explicitely, we can't verify the server authenticity
- */
- if (!tls_verify_method)
- tls_verify_method = TLS_VERIFY_NONE;
-
- if (!ets->peer[0] || !strcmp(TLS_VERIFY_NONE, tls_verify_method)) {
- warn("Certificate verication disabled or no peer name was specified");
- return ok;
- }
-
- /* This is the peer certificate */
- X509_NAME_oneline(X509_get_subject_name(peer_cert),
- subject, 256);
-
- X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert),
- NID_commonName, cn_str, 256);
-
- /* Verify based on subject name */
- ptr1 = ets->peer;
- if (!strcmp(TLS_VERIFY_SUBJECT, tls_verify_method)) {
- ptr2 = subject;
- }
-
- /* Verify based on common name (default) */
- if (strlen(tls_verify_method) == 0 ||
- !strcmp(TLS_VERIFY_NAME, tls_verify_method)) {
- ptr2 = cn_str;
- }
-
- /* Match the suffix of common name */
- if (!strcmp(TLS_VERIFY_SUFFIX, tls_verify_method)) {
- int len = strlen(ptr1);
- int off = strlen(cn_str) - len;
- ptr2 = cn_str;
- if (off > 0) {
- ptr2 = cn_str + off;
- }
- }
-
- if (strcmp(ptr1, ptr2)) {
- error("Certificate verification error: CN (%s) != %s", ptr1, ptr2);
- return 0;
- }
-
- info("Certificate CN: %s, peer name %s", cn_str, ets->peer);
-
- /*
- * If a peer certificate file was specified, here we check it
- */
- if (ets->peercertfile[0]) {
- if (ssl_cmp_certs(&ets->peercertfile[0], peer_cert)
- != 0) {
- error
- ("Peer certificate doesn't match stored certificate");
- return 0;
- }
- }
- }
-
- return ok;
-}
-
-/*
- * Compare a certificate with the one stored in a file
- */
-int ssl_cmp_certs(char *filename, X509 * a)
-{
- X509 *b;
- int ret;
-
- if (!(b = get_X509_from_file(filename)))
- return 1;
-
- ret = X509_cmp(a, b);
- X509_free(b);
-
- return ret;
-
-}
-
-X509 *get_X509_from_file(char *filename)
-{
- FILE *fp;
- X509 *ret;
-
- if (!(fp = fopen(filename, "r")))
- return NULL;
-
- ret = PEM_read_X509(fp, NULL, NULL, NULL);
-
- fclose(fp);
-
- return ret;
-}
-
/*
* Every sent & received message this callback function is invoked,
* so we know when alert messages have arrived or are sent and