📄 tls_openssl.c
字号:
/* * WPA Supplicant / SSL/TLS interface functions for openssl * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include <stdlib.h>#include <stdio.h>#include <string.h>#ifndef CONFIG_SMARTCARD#ifndef OPENSSL_NO_ENGINE#define OPENSSL_NO_ENGINE#endif#endif#include <openssl/ssl.h>#include <openssl/err.h>#include <openssl/pkcs12.h>#include <openssl/x509v3.h>#ifndef OPENSSL_NO_ENGINE#include <openssl/engine.h>#endif /* OPENSSL_NO_ENGINE */#include "common.h"#include "tls.h"struct tls_connection { SSL *ssl; BIO *ssl_in, *ssl_out;#ifndef OPENSSL_NO_ENGINE ENGINE *engine; /* functional reference to the engine */ EVP_PKEY *private_key; /* the private key if using engine */#endif /* OPENSSL_NO_ENGINE */ char *subject_match, *altsubject_match; int read_alerts, write_alerts, failed;};static void ssl_info_cb(const SSL *ssl, int where, int ret){ const char *str; int w; wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret); w = where & ~SSL_ST_MASK; if (w & SSL_ST_CONNECT) str = "SSL_connect"; else if (w & SSL_ST_ACCEPT) str = "SSL_accept"; else str = "undefined"; if (where & SSL_CB_LOOP) { wpa_printf(MSG_DEBUG, "SSL: %s:%s", str, SSL_state_string_long(ssl)); } else if (where & SSL_CB_ALERT) { wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s", where & SSL_CB_READ ? "read (remote end reported an error)" : "write (local SSL3 detected an error)", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); if ((ret >> 8) == SSL3_AL_FATAL) { struct tls_connection *conn = SSL_get_app_data((SSL *) ssl); if (where & SSL_CB_READ) conn->read_alerts++; else conn->write_alerts++; } } else if (where & SSL_CB_EXIT && ret <= 0) { wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s", str, ret == 0 ? "failed" : "error", SSL_state_string_long(ssl)); }}#ifndef OPENSSL_NO_ENGINE/** * tls_engine_load_dynamic_generic - load any openssl engine * @pre: an array of commands and values that load an engine initialized * in the engine specific function * @post: an array of commands and values that initialize an already loaded * engine (or %NULL if not required) * @id: the engine id of the engine to load (only required if post is not %NULL * * This function is a generic function that loads any openssl engine. * * Returns: 0 on success, -1 on failure */static int tls_engine_load_dynamic_generic(const char *pre[], const char *post[], const char *id){ ENGINE *engine; const char *dynamic_id = "dynamic"; engine = ENGINE_by_id(id); if (engine) { ENGINE_free(engine); wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already " "available", id); return 0; } ERR_clear_error(); engine = ENGINE_by_id(dynamic_id); if (engine == NULL) { wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", dynamic_id, ERR_error_string(ERR_get_error(), NULL)); return -1; } /* Perform the pre commands. This will load the engine. */ while (pre && pre[0]) { wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]); if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) { wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: " "%s %s [%s]", pre[0], pre[1], ERR_error_string(ERR_get_error(), NULL)); ENGINE_free(engine); return -1; } pre += 2; } /* * Free the reference to the "dynamic" engine. The loaded engine can * now be looked up using ENGINE_by_id(). */ ENGINE_free(engine); engine = ENGINE_by_id(id); if (engine == NULL) { wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", id, ERR_error_string(ERR_get_error(), NULL)); return -1; } while (post && post[0]) { wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]); if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) { wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:" " %s %s [%s]", post[0], post[1], ERR_error_string(ERR_get_error(), NULL)); ENGINE_remove(engine); ENGINE_free(engine); return -1; } post += 2; } ENGINE_free(engine); return 0;}/** * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc * @pkcs11_so_path: pksc11_so_path from the configuration * @pcks11_module_path: pkcs11_module_path from the configuration */static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path, const char *pkcs11_module_path){ char *engine_id = "pkcs11"; const char *pre_cmd[] = { "SO_PATH", pkcs11_so_path, "ID", engine_id, "LIST_ADD", "1", /* "NO_VCHECK", "1", */ "LOAD", NULL, NULL, NULL }; const char *post_cmd[] = { "MODULE_PATH", pkcs11_module_path, NULL, NULL }; if (!pkcs11_so_path || !pkcs11_module_path) return 0; wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s", pkcs11_so_path); return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id);}/** * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc * @opensc_so_path: opensc_so_path from the configuration */static int tls_engine_load_dynamic_opensc(const char *opensc_so_path){ char *engine_id = "opensc"; const char *pre_cmd[] = { "SO_PATH", opensc_so_path, "ID", engine_id, "LIST_ADD", "1", "LOAD", NULL, NULL, NULL }; if (!opensc_so_path) return 0; wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s", opensc_so_path); return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id);}#endif /* OPENSSL_NO_ENGINE */void * tls_init(const struct tls_config *conf){ SSL_CTX *ssl; SSL_load_error_strings(); SSL_library_init(); /* TODO: if /dev/urandom is available, PRNG is seeded automatically. * If this is not the case, random data should be added here. */#ifdef PKCS12_FUNCS PKCS12_PBE_add();#endif /* PKCS12_FUNCS */ ssl = SSL_CTX_new(TLSv1_method()); if (ssl == NULL) return NULL; SSL_CTX_set_info_callback(ssl, ssl_info_cb);#ifndef OPENSSL_NO_ENGINE if (conf && (conf->opensc_engine_path || conf->pkcs11_engine_path || conf->pkcs11_module_path)) { wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine"); ERR_load_ENGINE_strings(); ENGINE_load_dynamic(); if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) || tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path, conf->pkcs11_module_path)) { tls_deinit(ssl); return NULL; } }#endif /* OPENSSL_NO_ENGINE */ return ssl;}void tls_deinit(void *ssl_ctx){ SSL_CTX *ssl = ssl_ctx; SSL_CTX_free(ssl);#ifndef OPENSSL_NO_ENGINE ENGINE_cleanup();#endif /* OPENSSL_NO_ENGINE */ ERR_free_strings(); EVP_cleanup();}int tls_engine_init(struct tls_connection *conn, const char *engine_id, char **ppin, const char *key_id){#ifndef OPENSSL_NO_ENGINE if (ppin == NULL) { wpa_printf(MSG_DEBUG, "ENGINE: %s - ppin is NULL", __func__); return -1; } if (engine_id == NULL) { wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set"); return -1; } if (*ppin == NULL) { wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set"); return -1; } if (key_id == NULL) { wpa_printf(MSG_ERROR, "ENGINE: Key Id not set"); return -1; } ERR_clear_error(); conn->engine = ENGINE_by_id(engine_id); if (!conn->engine) { char *error = ERR_error_string(ERR_get_error(), NULL); wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]", engine_id, error); goto err; } if (ENGINE_init(conn->engine) != 1) { char *error = ERR_error_string(ERR_get_error(), NULL); wpa_printf(MSG_ERROR, "ENGINE: engine init failed " "(engine: %s) [%s]", engine_id, error); goto err; } wpa_printf(MSG_DEBUG, "ENGINE: engine initialized"); if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", *ppin, 0) == 0) { char *error = ERR_error_string(ERR_get_error(), NULL); wpa_printf(MSG_ERROR, "ENGINE: can't set pin [%s]", error); goto err; } conn->private_key = ENGINE_load_private_key(conn->engine, key_id, NULL, NULL); if (!conn->private_key) { char *error = ERR_error_string(ERR_get_error(), NULL); wpa_printf(MSG_ERROR, "ENGINE: can't load private key with id" " '%s' [%s]", key_id, error); /* At this point with the pkcs11 engine the PIN might be wrong. * We reset the PIN in the configuration to be sure to not use * it again and the calling function must request a new one */ free(*ppin); *ppin = NULL; goto err; } return 0;err: if (conn->engine) { ENGINE_free(conn->engine); conn->engine = NULL; } if (conn->private_key) { EVP_PKEY_free(conn->private_key); conn->private_key = NULL; } return -1;#else /* OPENSSL_NO_ENGINE */ return 0;#endif /* OPENSSL_NO_ENGINE */}static void tls_engine_deinit(struct tls_connection *conn){#ifndef OPENSSL_NO_ENGINE wpa_printf(MSG_DEBUG, "ENGINE: engine deinit"); if (conn->private_key) { EVP_PKEY_free(conn->private_key); conn->private_key = NULL; } if (conn->engine) { ENGINE_finish(conn->engine); conn->engine = NULL; }#endif /* OPENSSL_NO_ENGINE */}int tls_get_errors(void *ssl_ctx){ int count = 0; unsigned long err; while ((err = ERR_get_error())) { wpa_printf(MSG_INFO, "TLS - SSL error: %s", ERR_error_string(err, NULL)); count++; } return count;}struct tls_connection * tls_connection_init(void *ssl_ctx){ SSL_CTX *ssl = ssl_ctx; struct tls_connection *conn; conn = malloc(sizeof(*conn)); if (conn == NULL) return NULL; memset(conn, 0, sizeof(*conn)); conn->ssl = SSL_new(ssl); if (conn->ssl == NULL) { wpa_printf(MSG_INFO, "TLS: Failed to initialize new SSL " "connection: %s", ERR_error_string(ERR_get_error(), NULL)); free(conn); return NULL; } SSL_set_app_data(conn->ssl, conn); SSL_set_options(conn->ssl, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE); conn->ssl_in = BIO_new(BIO_s_mem()); if (!conn->ssl_in) { wpa_printf(MSG_INFO, "SSL: Failed to create a new BIO for " "ssl_in: %s", ERR_error_string(ERR_get_error(), NULL)); SSL_free(conn->ssl); free(conn); return NULL; } conn->ssl_out = BIO_new(BIO_s_mem()); if (!conn->ssl_out) { wpa_printf(MSG_INFO, "SSL: Failed to create a new BIO for " "ssl_out: %s", ERR_error_string(ERR_get_error(), NULL)); SSL_free(conn->ssl); BIO_free(conn->ssl_in); free(conn); return NULL; } SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out); return conn;}void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn){ if (conn == NULL) return; SSL_free(conn->ssl); tls_engine_deinit(conn);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -