X-Git-Url: https://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Feap-tls.c;h=69e34a1d7cc9023f37f9b0f18474b89bd80df438;hp=265f6d52d23b004cdd717ba63bc41c542540451d;hb=HEAD;hpb=2883dd07101bf851e2ea368f0c04c91aea85cff2 diff --git a/pppd/eap-tls.c b/pppd/eap-tls.c index 265f6d5..d70557e 100644 --- a/pppd/eap-tls.c +++ b/pppd/eap-tls.c @@ -44,13 +44,15 @@ #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" @@ -59,6 +61,10 @@ #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; @@ -75,56 +81,11 @@ static ENGINE *pkey_engine = NULL; /* 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 /* @@ -176,21 +137,7 @@ void eaptls_gen_mppe_keys(struct eaptls_session *ets, int client) } } -#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) { @@ -211,10 +158,10 @@ 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(); @@ -230,7 +177,7 @@ CONF *eaptls_ssl_load_config( void ) if (CONF_modules_load( config, NULL, 0 ) <= 0 ) { warn( "EAP-TLS: Error loading OpenSSL modules" ); - log_ssl_errors(); + tls_log_sslerr(); config = NULL; } @@ -257,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; } @@ -274,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; } @@ -285,12 +232,29 @@ ENGINE *eaptls_ssl_load_engine( char *engine_name ) #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; @@ -299,8 +263,6 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath, #endif SSL_CTX *ctx; SSL *ssl; - X509_STORE *certstore; - X509_LOOKUP *lookup; X509 *tmp; X509 *cert = NULL; PKCS12 *p12 = NULL; @@ -309,13 +271,6 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath, 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 @@ -341,8 +296,7 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath, } } - 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 @@ -352,8 +306,7 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath, 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; @@ -434,14 +387,7 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath, 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; } @@ -475,7 +421,7 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath, else { warn("EAP-TLS: Cannot load key with URI: '%s'", certfile ); - log_ssl_errors(); + tls_log_sslerr(); } } else @@ -578,20 +524,11 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath, { 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); + 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); @@ -637,21 +574,8 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath, 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 @@ -663,94 +587,17 @@ 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); - - 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; @@ -766,7 +613,7 @@ fail: if (chain) sk_X509_pop_free(chain, X509_free); - log_ssl_errors(); + tls_log_sslerr(); SSL_CTX_free(ctx); return NULL; } @@ -813,15 +660,12 @@ 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, @@ -833,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, 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 */ @@ -855,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; @@ -869,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: @@ -906,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, + 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 */ @@ -948,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; @@ -963,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: @@ -991,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); } @@ -1100,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); @@ -1215,171 +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 (!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