X-Git-Url: https://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Feap-tls.c;h=d70557ee7b189d8921ba58af0888c3c662ba4765;hp=4759764ff206d0ca56312758d807c159d180bec0;hb=HEAD;hpb=b2a4275ba78b07a4e47dcefb8c9bf2fd8456184a diff --git a/pppd/eap-tls.c b/pppd/eap-tls.c index 4759764..d70557e 100644 --- a/pppd/eap-tls.c +++ b/pppd/eap-tls.c @@ -29,6 +29,10 @@ * */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include @@ -37,87 +41,53 @@ #include #include +#ifndef OPENSSL_NO_ENGINE #include +#endif +#include #include #include #include #include +#include -#include "pppd.h" +#include "pppd-private.h" +#include "tls.h" #include "eap.h" #include "eap-tls.h" #include "fsm.h" #include "lcp.h" +#include "chap_ms.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; const char *prompt_info; } PW_CB_DATA; +#ifndef OPENSSL_NO_ENGINE /* The openssl configuration file and engines can be loaded only once */ static CONF *ssl_config = NULL; static ENGINE *cert_engine = NULL; static ENGINE *pkey_engine = NULL; +#endif /* 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); - -#ifdef MPPE - +#ifdef PPP_WITH_MPPE #define EAPTLS_MPPE_KEY_LEN 32 -/* - * 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 */ - - /* * Generate keys according to RFC 2716 and add to reply */ @@ -159,36 +129,15 @@ void eaptls_gen_mppe_keys(struct eaptls_session *ets, int client) */ if (client) { - p = out; - BCOPY( p, mppe_send_key, sizeof(mppe_send_key) ); - p += EAPTLS_MPPE_KEY_LEN; - BCOPY( p, mppe_recv_key, sizeof(mppe_recv_key) ); + mppe_set_keys(out, out + EAPTLS_MPPE_KEY_LEN, EAPTLS_MPPE_KEY_LEN); } else { - p = out; - BCOPY( p, mppe_recv_key, sizeof(mppe_recv_key) ); - p += EAPTLS_MPPE_KEY_LEN; - BCOPY( p, mppe_send_key, sizeof(mppe_send_key) ); - } - - mppe_keys_set = 1; -} - -#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(); + mppe_set_keys(out + EAPTLS_MPPE_KEY_LEN, out, EAPTLS_MPPE_KEY_LEN); } } +#endif /* PPP_WITH_MPPE */ int password_callback (char *buf, int size, int rwflag, void *u) { @@ -209,30 +158,33 @@ CONF *eaptls_ssl_load_config( void ) 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(); } dbglog( "Loading OpenSSL built-ins" ); +#ifndef OPENSSL_NO_ENGINE ENGINE_load_builtin_engines(); +#endif OPENSSL_load_builtin_modules(); dbglog( "Loading OpenSSL configured modules" ); if (CONF_modules_load( config, NULL, 0 ) <= 0 ) { warn( "EAP-TLS: Error loading OpenSSL modules" ); - log_ssl_errors(); + tls_log_sslerr(); config = NULL; } return config; } +#ifndef OPENSSL_NO_ENGINE ENGINE *eaptls_ssl_load_engine( char *engine_name ) { ENGINE *e = NULL; @@ -252,7 +204,7 @@ ENGINE *eaptls_ssl_load_engine( char *engine_name ) || !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; } @@ -269,7 +221,7 @@ ENGINE *eaptls_ssl_load_engine( char *engine_name ) 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; } @@ -277,90 +229,103 @@ ENGINE *eaptls_ssl_load_engine( char *engine_name ) return e; } +#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 *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; + EVP_PKEY *pkey = NULL; + STACK_OF(X509) *chain = NULL; + BIO *input; int ret; -#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 + int reason; /* * Without these can't continue */ - if (!(cacertfile[0] || capath[0])) + if (!pkcs12[0]) { - error("EAP-TLS: CA certificate file or path missing"); - return NULL; - } + if (!(cacertfile[0] || capath[0])) + { + error("EAP-TLS: CA certificate file or path missing"); + return NULL; + } - if (!certfile[0]) - { - error("EAP-TLS: Certificate missing"); - return NULL; - } + if (!certfile[0]) + { + error("EAP-TLS: Certificate missing"); + return NULL; + } - if (!privkeyfile[0]) - { - error("EAP-TLS: Private key missing"); - return NULL; + if (!privkeyfile[0]) + { + error("EAP-TLS: Private key missing"); + return NULL; + } } - 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 the loading of a global openssl config file via SSL_CTX_new() */ if (!ssl_config) 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; } +#ifndef OPENSSL_NO_ENGINE /* if the certificate filename is of the form engine:id. e.g. pkcs11:12345 then we try to load and use this engine. 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, ':' ); - - if (cert_identifier) - { - cert_engine_name = certfile; - *cert_identifier = '\0'; - cert_identifier++; + cert_engine_name = strdup( certfile ); + cert_engine_name[idx - certfile] = 0; - 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. @@ -369,39 +334,33 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath, 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, ':' ); - - if (pkey_identifier) - { - pkey_engine_name = privkeyfile; - *pkey_identifier = '\0'; - pkey_identifier++; + pkey_engine_name = strdup( privkeyfile ); + pkey_engine_name[idx - privkeyfile] = 0; - 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; } } } @@ -418,22 +377,24 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath, pkey_engine = eaptls_ssl_load_engine( pkey_engine_name ); } - SSL_CTX_set_default_passwd_cb (ctx, password_callback); + if (cert_engine_name) + free(cert_engine_name); - if (strlen(cacertfile) == 0) cacertfile = NULL; - if (strlen(capath) == 0) capath = NULL; + if (pkey_engine_name) + free(pkey_engine_name); - 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); +#endif + + SSL_CTX_set_default_passwd_cb (ctx, password_callback); + + if (tls_set_ca(ctx, capath, cacertfile) != 0) { goto fail; } if (init_server) SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(cacertfile)); +#ifndef OPENSSL_NO_ENGINE if (cert_engine) { struct @@ -442,40 +403,87 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath, 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; } if (cert_info.cert) { - dbglog( "Got the certificate, adding it to SSL context" ); + dbglog( "Got the certificate" ); dbglog( "subject = %s", X509_NAME_oneline( X509_get_subject_name( cert_info.cert ), NULL, 0 ) ); - if (SSL_CTX_use_certificate(ctx, cert_info.cert) <= 0) + cert = cert_info.cert; + } + else + { + warn("EAP-TLS: Cannot load key with URI: '%s'", certfile ); + tls_log_sslerr(); + } + } + else +#endif + { + if (pkcs12[0]) + { + input = BIO_new_file(pkcs12, "r"); + if (input == NULL) + { + error("EAP-TLS: Cannot open `%s' PKCS12 for input", pkcs12); + goto fail; + } + + p12 = d2i_PKCS12_bio(input, NULL); + BIO_free(input); + if (!p12) + { + error("EAP-TLS: Cannot load PKCS12 certificate"); + goto fail; + } + + if (PKCS12_parse(p12, passwd, &pkey, &cert, &chain) != 1) { - error("EAP-TLS: Cannot use PKCS11 certificate %s", cert_identifier); + error("EAP-TLS: Cannot parse PKCS12 certificate, invalid password"); + PKCS12_free(p12); goto fail; } + + PKCS12_free(p12); } - else + else { - warn("EAP-TLS: Cannot load PKCS11 key %s", cert_identifier); - log_ssl_errors(); + if (!SSL_CTX_use_certificate_chain_file(ctx, certfile)) + { + error( "EAP-TLS: Cannot load certificate %s", certfile ); + goto fail; + } } } - else + + if (cert) { - if (!SSL_CTX_use_certificate_chain_file(ctx, certfile)) + if (!SSL_CTX_use_certificate(ctx, cert)) { - error( "EAP-TLS: Cannot use public certificate %s", certfile ); + error("EAP-TLS: Cannot use load certificate"); goto fail; } - } + if (chain) + { + int i; + for (i = 0; i < sk_X509_num(chain); i++) + { + if (!SSL_CTX_add_extra_chain_cert(ctx, sk_X509_value(chain, i))) + { + error("EAP-TLS: Cannot add extra chain certificate"); + goto fail; + } + } + } + } /* * Check the Before and After dates of the certificate @@ -504,86 +512,70 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath, } SSL_free(ssl); +#ifndef OPENSSL_NO_ENGINE if (pkey_engine) { - EVP_PKEY *pkey = NULL; 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); } - if (pkey) + } + else +#endif + { + if (!pkey) { - dbglog( "Got the private key, adding it to SSL context" ); - if (SSL_CTX_use_PrivateKey(ctx, pkey) <= 0) + input = BIO_new_file(privkeyfile, "r"); + if (!input) { - error("EAP-TLS: Cannot use PKCS11 key %s", pkey_identifier); + error("EAP-TLS: Could not open private key, %s", privkeyfile); + goto fail; + } + + pkey = PEM_read_bio_PrivateKey(input, NULL, password_callback, NULL); + BIO_free(input); + if (!pkey) + { + error("EAP-TLS: Cannot load private key, %s", privkeyfile); goto fail; } - } - else - { - warn("EAP-TLS: Cannot load PKCS11 key %s", pkey_identifier); - log_ssl_errors(); } } - else + + if (SSL_CTX_use_PrivateKey(ctx, pkey) != 1) { - if (!SSL_CTX_use_PrivateKey_file(ctx, privkeyfile, SSL_FILETYPE_PEM)) - { - error("EAP-TLS: Cannot use private key %s", privkeyfile); - goto fail; - } + error("EAP-TLS: Cannot use private key"); + goto fail; } - if (SSL_CTX_check_private_key(ctx) != 1) { - error("EAP-TLS: Private key %s fails security check", privkeyfile); + if (SSL_CTX_check_private_key(ctx) != 1) + { + error("EAP-TLS: Private key fails security check"); 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 @@ -595,100 +587,33 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath, 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); + /* Configure the maximum SSL version */ + tls_set_version(ctx, max_tls_version); - 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); + /* Configure the callback */ + if (tls_set_verify(ctx, 5)) { + goto fail; } - if (crl_file) { - FILE *fp = NULL; - X509_CRL *crl = NULL; + /* Configure CRL check (if any) */ + if (tls_set_crl(ctx, crl_dir, crl_file)) { + goto fail; + } - fp = fopen(crl_file, "r"); - if (!fp) { - error("EAP-TLS: Cannot open CRL file '%s'", crl_file); - goto fail; - } + return ctx; - crl = PEM_read_X509_CRL(fp, NULL, NULL, NULL); - if (!crl) { - error("EAP-TLS: Cannot read CRL file '%s'", crl_file); - goto fail; - } +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); + if (cert) + X509_free(cert); - } + if (pkey) + EVP_PKEY_free(pkey); - /* - * 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); - } + if (chain) + sk_X509_pop_free(chain, X509_free); - return ctx; - -fail: - log_ssl_errors(); + tls_log_sslerr(); SSL_CTX_free(ctx); return NULL; } @@ -726,6 +651,8 @@ int eaptls_init_ssl_server(eap_state * esp) char cacertfile[MAXWORDLEN]; char capath[MAXWORDLEN]; char pkfile[MAXWORDLEN]; + char pkcs12[MAXWORDLEN]; + /* * Allocate new eaptls session */ @@ -733,19 +660,16 @@ int eaptls_init_ssl_server(eap_state * esp) 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, - servcertfile, cacertfile, capath, pkfile, 1)) { + servcertfile, cacertfile, capath, pkfile, pkcs12, 1)) { error( "EAP-TLS: Cannot get secret/password for client \"%s\", server \"%s\"", esp->es_server.ea_peer, esp->es_server.ea_name ); return 0; @@ -753,13 +677,17 @@ int eaptls_init_ssl_server(eap_state * esp) ets->mtu = eaptls_get_mtu(esp->es_unit); - ets->ctx = eaptls_init_ssl(1, cacertfile, capath, servcertfile, clicertfile, pkfile); + 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 */ @@ -775,12 +703,6 @@ int eaptls_init_ssl_server(eap_state * esp) 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; @@ -789,16 +711,6 @@ int eaptls_init_ssl_server(eap_state * esp) 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: @@ -817,6 +729,7 @@ int eaptls_init_ssl_client(eap_state * esp) char cacertfile[MAXWORDLEN]; char capath[MAXWORDLEN]; char pkfile[MAXWORDLEN]; + char pkcs12[MAXWORDLEN]; /* * Allocate new eaptls session @@ -825,38 +738,30 @@ int eaptls_init_ssl_client(eap_state * esp) 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, - servcertfile, cacertfile, capath, pkfile, 0)) { + 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); + 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 */ @@ -867,13 +772,6 @@ int eaptls_init_ssl_client(eap_state * esp) 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; @@ -882,17 +780,6 @@ int eaptls_init_ssl_client(eap_state * esp) 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: @@ -910,6 +797,9 @@ void eaptls_free_session(struct eaptls_session *ets) if (ets->ctx) SSL_CTX_free(ets->ctx); + if (ets->info) + tls_free_verify_info(&ets->info); + free(ets); } @@ -1019,7 +909,7 @@ int eaptls_receive(struct eaptls_session *ets, u_char * inp, int len) } if (BIO_write(ets->into_ssl, ets->data, ets->datalen) == -1) - log_ssl_errors(); + tls_log_sslerr(); SSL_read(ets->ssl, dummy, 65536); @@ -1134,168 +1024,6 @@ void eaptls_retransmit(struct eaptls_session *ets, u_char ** outp) 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 (!ets->peer[0] || !strcmp(tls_verify_method, TLS_VERIFY_NONE)) { - 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