Add support to HTTPS SOAP request
This commit is contained in:
parent
9a57f2806d
commit
6b424c5406
@ -53,8 +53,8 @@ application: {
|
|||||||
|
|
||||||
presharedkey: {
|
presharedkey: {
|
||||||
hint = "esempio";
|
hint = "esempio";
|
||||||
identity = "prova";
|
identity = "prova";
|
||||||
pskkey = "123456";
|
pskkey = "123456";
|
||||||
};
|
};
|
||||||
|
|
||||||
x509: {
|
x509: {
|
||||||
@ -78,7 +78,8 @@ application: {
|
|||||||
|
|
||||||
backend: {
|
backend: {
|
||||||
server: (
|
server: (
|
||||||
{ url = "http://localhost/csoap.php"; }
|
{ url = "http://localhost/csoap.php"; },
|
||||||
|
{ url = "https://localhost/csoap.php"; x509: { calist = "/etc/capwap/ca.crt"; certificate = "/etc/capwap/ac.crt"; privatekey = "/etc/capwap/ac.key"; privatekeypassword = ""; }; }
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
74
src/ac/ac.c
74
src/ac/ac.c
@ -1,6 +1,7 @@
|
|||||||
#include "ac.h"
|
#include "ac.h"
|
||||||
#include "ac_soap.h"
|
#include "ac_soap.h"
|
||||||
#include "capwap_dtls.h"
|
#include "capwap_dtls.h"
|
||||||
|
#include "capwap_socket.h"
|
||||||
|
|
||||||
#include <libconfig.h>
|
#include <libconfig.h>
|
||||||
|
|
||||||
@ -570,7 +571,7 @@ static int ac_parsing_configuration_1_0(config_t* config) {
|
|||||||
|
|
||||||
/* Backend */
|
/* Backend */
|
||||||
configSetting = config_lookup(config, "backend.server");
|
configSetting = config_lookup(config, "backend.server");
|
||||||
if (configSetting != NULL) {
|
if (configSetting) {
|
||||||
int count = config_setting_length(configSetting);
|
int count = config_setting_length(configSetting);
|
||||||
|
|
||||||
/* Retrieve server */
|
/* Retrieve server */
|
||||||
@ -578,14 +579,79 @@ static int ac_parsing_configuration_1_0(config_t* config) {
|
|||||||
config_setting_t* configServer = config_setting_get_elem(configSetting, i);
|
config_setting_t* configServer = config_setting_get_elem(configSetting, i);
|
||||||
if (configServer != NULL) {
|
if (configServer != NULL) {
|
||||||
if (config_setting_lookup_string(configServer, "url", &configString) == CONFIG_TRUE) {
|
if (config_setting_lookup_string(configServer, "url", &configString) == CONFIG_TRUE) {
|
||||||
struct ac_http_soap_server** server = (struct ac_http_soap_server**)capwap_array_get_item_pointer(g_ac.availablebackends, g_ac.availablebackends->count);
|
struct ac_http_soap_server* server;
|
||||||
|
struct ac_http_soap_server** itemserver;
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
*server = ac_soapclient_create_server(configString);
|
server = ac_soapclient_create_server(configString);
|
||||||
if (!*server) {
|
if (!server) {
|
||||||
capwap_logging_error("Invalid configuration file, invalid backend.server value");
|
capwap_logging_error("Invalid configuration file, invalid backend.server value");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* HTTPS params */
|
||||||
|
if (server->protocol == SOAP_HTTPS_PROTOCOL) {
|
||||||
|
char* calist = NULL;
|
||||||
|
char* certificate = NULL;
|
||||||
|
char* privatekey = NULL;
|
||||||
|
char* privatekeypassword = NULL;
|
||||||
|
config_setting_t* configSSL;
|
||||||
|
|
||||||
|
/* */
|
||||||
|
configSSL = config_setting_get_member(configServer, "x509");
|
||||||
|
if (!configSSL) {
|
||||||
|
capwap_logging_error("Invalid configuration file, invalid backend.server.x509 value");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_setting_lookup_string(configSSL, "calist", &configString) == CONFIG_TRUE) {
|
||||||
|
if (strlen(configString) > 0) {
|
||||||
|
calist = capwap_duplicate_string(configString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_setting_lookup_string(configSSL, "certificate", &configString) == CONFIG_TRUE) {
|
||||||
|
if (strlen(configString) > 0) {
|
||||||
|
certificate = capwap_duplicate_string(configString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_setting_lookup_string(configSSL, "privatekey", &configString) == CONFIG_TRUE) {
|
||||||
|
if (strlen(configString) > 0) {
|
||||||
|
privatekey = capwap_duplicate_string(configString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_setting_lookup_string(configSSL, "privatekeypassword", &configString) == CONFIG_TRUE) {
|
||||||
|
if (strlen(configString) > 0) {
|
||||||
|
privatekeypassword = capwap_duplicate_string(configString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
if (calist && certificate && privatekey) {
|
||||||
|
server->sslcontext = capwap_socket_crypto_createcontext(calist, certificate, privatekey, privatekeypassword);
|
||||||
|
if (!server->sslcontext) {
|
||||||
|
capwap_logging_error("Invalid configuration file, invalid backend.server.x509 value");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
capwap_logging_error("Invalid configuration file, invalid backend.server.x509 value");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free SSL param */
|
||||||
|
capwap_free(calist);
|
||||||
|
capwap_free(certificate);
|
||||||
|
capwap_free(privatekey);
|
||||||
|
if (privatekeypassword) {
|
||||||
|
capwap_free(privatekeypassword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add item */
|
||||||
|
itemserver = (struct ac_http_soap_server**)capwap_array_get_item_pointer(g_ac.availablebackends, g_ac.availablebackends->count);
|
||||||
|
*itemserver= server;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,9 +105,8 @@ static int ac_soapclient_parsing_url(struct ac_http_soap_server* server, const c
|
|||||||
/* Parsing protocol */
|
/* Parsing protocol */
|
||||||
if (!strncasecmp(url, "http", protocol)) {
|
if (!strncasecmp(url, "http", protocol)) {
|
||||||
server->protocol = SOAP_HTTP_PROTOCOL;
|
server->protocol = SOAP_HTTP_PROTOCOL;
|
||||||
/* TODO: write code for SSL connection
|
|
||||||
} else if (!strncasecmp(url, "https", protocol)) {
|
} else if (!strncasecmp(url, "https", protocol)) {
|
||||||
server->protocol = SOAP_HTTPS_PROTOCOL;*/
|
server->protocol = SOAP_HTTPS_PROTOCOL;
|
||||||
} else {
|
} else {
|
||||||
/* Unknown protocol */
|
/* Unknown protocol */
|
||||||
return 0;
|
return 0;
|
||||||
@ -180,6 +179,26 @@ static int ac_soapclient_parsing_url(struct ac_http_soap_server* server, const c
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int ac_soapclient_connect(struct ac_http_soap_request* httprequest) {
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
if (httprequest->server->protocol == SOAP_HTTP_PROTOCOL) {
|
||||||
|
result = capwap_socket_connect(httprequest->sock, &httprequest->server->address, SOAP_PROTOCOL_CONNECT_TIMEOUT);
|
||||||
|
} else if (httprequest->server->protocol == SOAP_HTTPS_PROTOCOL) {
|
||||||
|
result = capwap_socket_connect(httprequest->sock, &httprequest->server->address, SOAP_PROTOCOL_CONNECT_TIMEOUT);
|
||||||
|
if (result) {
|
||||||
|
/* Establish SSL/TLS connection */
|
||||||
|
httprequest->sslsock = capwap_socket_ssl_connect(httprequest->sock, httprequest->server->sslcontext, SOAP_PROTOCOL_CONNECT_TIMEOUT);
|
||||||
|
if (!httprequest->sslsock) {
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
static int ac_soapclient_send_http(struct ac_http_soap_request* httprequest, char* soapaction, char* body, int length) {
|
static int ac_soapclient_send_http(struct ac_http_soap_request* httprequest, char* soapaction, char* body, int length) {
|
||||||
time_t ts;
|
time_t ts;
|
||||||
@ -225,11 +244,17 @@ static int ac_soapclient_send_http(struct ac_http_soap_request* httprequest, cha
|
|||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
result = 0;
|
result = 0;
|
||||||
} else {
|
} else {
|
||||||
if (capwap_socket_send_timeout(httprequest->sock, buffer, result, httprequest->requesttimeout) == result) {
|
int sendlength = -1;
|
||||||
result = 1;
|
|
||||||
} else {
|
/* Send packet */
|
||||||
result = 0;
|
if (httprequest->server->protocol == SOAP_HTTP_PROTOCOL) {
|
||||||
|
sendlength = capwap_socket_send(httprequest->sock, buffer, result, httprequest->requesttimeout);
|
||||||
|
} else if (httprequest->server->protocol == SOAP_HTTPS_PROTOCOL) {
|
||||||
|
sendlength = capwap_socket_crypto_send(httprequest->sslsock, buffer, result, httprequest->requesttimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check result */
|
||||||
|
result = ((sendlength == result) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
@ -244,8 +269,14 @@ static int ac_soapclient_http_readline(struct ac_http_soap_request* httprequest,
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* Receive packet into temporaly buffer */
|
/* Receive packet into temporaly buffer */
|
||||||
if (capwap_socket_recv_timeout(httprequest->sock, &buffer[bufferpos], 1, httprequest->responsetimeout) != 1) {
|
if (httprequest->server->protocol == SOAP_HTTP_PROTOCOL) {
|
||||||
break; /* Connection error */
|
if (capwap_socket_recv(httprequest->sock, &buffer[bufferpos], 1, httprequest->responsetimeout) != 1) {
|
||||||
|
break; /* Connection error */
|
||||||
|
}
|
||||||
|
} else if (httprequest->server->protocol == SOAP_HTTPS_PROTOCOL) {
|
||||||
|
if (capwap_socket_crypto_recv(httprequest->sslsock, &buffer[bufferpos], 1, httprequest->responsetimeout) != 1) {
|
||||||
|
break; /* Connection error */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update buffer size */
|
/* Update buffer size */
|
||||||
@ -349,7 +380,12 @@ static int ac_soapclient_xml_io_read(void* ctx, char* buffer, int len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Receive body directly into XML buffer */
|
/* Receive body directly into XML buffer */
|
||||||
result = capwap_socket_recv_timeout(httprequest->sock, buffer, len, httprequest->responsetimeout);
|
if (httprequest->server->protocol == SOAP_HTTP_PROTOCOL) {
|
||||||
|
result = capwap_socket_recv(httprequest->sock, buffer, len, httprequest->responsetimeout);
|
||||||
|
} else if (httprequest->server->protocol == SOAP_HTTPS_PROTOCOL) {
|
||||||
|
result = capwap_socket_crypto_recv(httprequest->sslsock, buffer, len, httprequest->responsetimeout);
|
||||||
|
}
|
||||||
|
|
||||||
if (result > 0) {
|
if (result > 0) {
|
||||||
httprequest->contentlength -= result;
|
httprequest->contentlength -= result;
|
||||||
}
|
}
|
||||||
@ -420,6 +456,10 @@ void ac_soapclient_free_server(struct ac_http_soap_server* server) {
|
|||||||
capwap_free(server->path);
|
capwap_free(server->path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (server->sslcontext) {
|
||||||
|
capwap_socket_crypto_freecontext(server->sslcontext);
|
||||||
|
}
|
||||||
|
|
||||||
capwap_free(server);
|
capwap_free(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -560,12 +600,6 @@ struct ac_http_soap_request* ac_soapclient_prepare_request(struct ac_soap_reques
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Non blocking socket */
|
|
||||||
if (!capwap_socket_nonblocking(httprequest->sock, 1)) {
|
|
||||||
ac_soapclient_close_request(httprequest, 0);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return httprequest;
|
return httprequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,7 +621,7 @@ int ac_soapclient_send_request(struct ac_http_soap_request* httprequest, char* s
|
|||||||
buffer = (char*)xmlBufferContent(xmlBuffer);
|
buffer = (char*)xmlBufferContent(xmlBuffer);
|
||||||
|
|
||||||
/* Connect to remote host */
|
/* Connect to remote host */
|
||||||
if (!capwap_socket_connect_timeout(httprequest->sock, &httprequest->server->address, SOAP_PROTOCOL_CONNECT_TIMEOUT)) {
|
if (!ac_soapclient_connect(httprequest)) {
|
||||||
xmlBufferFree(xmlBuffer);
|
xmlBufferFree(xmlBuffer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -607,9 +641,12 @@ int ac_soapclient_send_request(struct ac_http_soap_request* httprequest, char* s
|
|||||||
void ac_soapclient_shutdown_request(struct ac_http_soap_request* httprequest) {
|
void ac_soapclient_shutdown_request(struct ac_http_soap_request* httprequest) {
|
||||||
ASSERT(httprequest != NULL);
|
ASSERT(httprequest != NULL);
|
||||||
|
|
||||||
|
if (httprequest->sslsock) {
|
||||||
|
capwap_socket_ssl_shutdown(httprequest->sslsock, SOAP_PROTOCOL_CLOSE_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
if (httprequest->sock >= 0) {
|
if (httprequest->sock >= 0) {
|
||||||
capwap_socket_nonblocking(httprequest->sock, 0);
|
capwap_socket_shutdown(httprequest->sock);
|
||||||
shutdown(httprequest->sock, SHUT_RDWR);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -622,10 +659,16 @@ void ac_soapclient_close_request(struct ac_http_soap_request* httprequest, int c
|
|||||||
ac_soapclient_free_request(httprequest->request);
|
ac_soapclient_free_request(httprequest->request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
if (httprequest->sslsock) {
|
||||||
|
capwap_socket_ssl_shutdown(httprequest->sslsock, SOAP_PROTOCOL_CLOSE_TIMEOUT);
|
||||||
|
capwap_socket_ssl_close(httprequest->sslsock);
|
||||||
|
capwap_free(httprequest->sslsock);
|
||||||
|
}
|
||||||
|
|
||||||
/* Close socket */
|
/* Close socket */
|
||||||
if (httprequest->sock >= 0) {
|
if (httprequest->sock >= 0) {
|
||||||
ac_soapclient_shutdown_request(httprequest);
|
capwap_socket_close(httprequest->sock);
|
||||||
close(httprequest->sock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
capwap_free(httprequest);
|
capwap_free(httprequest);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#define SOAP_PROTOCOL_REQUEST_TIMEOUT 10000
|
#define SOAP_PROTOCOL_REQUEST_TIMEOUT 10000
|
||||||
#define SOAP_PROTOCOL_RESPONSE_TIMEOUT 10000
|
#define SOAP_PROTOCOL_RESPONSE_TIMEOUT 10000
|
||||||
|
#define SOAP_PROTOCOL_CLOSE_TIMEOUT 10000
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
struct ac_http_soap_server {
|
struct ac_http_soap_server {
|
||||||
@ -24,6 +25,9 @@ struct ac_http_soap_server {
|
|||||||
|
|
||||||
char* host;
|
char* host;
|
||||||
char* path;
|
char* path;
|
||||||
|
|
||||||
|
/* SSL/TLS context */
|
||||||
|
void* sslcontext;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
@ -45,6 +49,9 @@ struct ac_http_soap_request {
|
|||||||
int requesttimeout;
|
int requesttimeout;
|
||||||
int responsetimeout;
|
int responsetimeout;
|
||||||
|
|
||||||
|
/* SSL info */
|
||||||
|
struct capwap_socket_ssl* sslsock;
|
||||||
|
|
||||||
/* Information for SOAP Response */
|
/* Information for SOAP Response */
|
||||||
int httpstate;
|
int httpstate;
|
||||||
int responsecode;
|
int responsecode;
|
||||||
|
@ -1,8 +1,17 @@
|
|||||||
#include "capwap.h"
|
#include "capwap.h"
|
||||||
#include "capwap_socket.h"
|
#include "capwap_socket.h"
|
||||||
|
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/engine.h>
|
||||||
|
#include <openssl/conf.h>
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
int capwap_socket_nonblocking(int sock, int nonblocking) {
|
#define OPENSSL_EXDATA_PRIVATE_KEY_PASSWORD 1
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int capwap_socket_nonblocking(int sock, int nonblocking) {
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
ASSERT(sock >= 0);
|
ASSERT(sock >= 0);
|
||||||
@ -27,7 +36,7 @@ int capwap_socket_nonblocking(int sock, int nonblocking) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
int capwap_socket_connect_timeout(int sock, struct sockaddr_storage* address, int timeout) {
|
int capwap_socket_connect(int sock, struct sockaddr_storage* address, int timeout) {
|
||||||
int result;
|
int result;
|
||||||
struct pollfd fds;
|
struct pollfd fds;
|
||||||
socklen_t size;
|
socklen_t size;
|
||||||
@ -35,6 +44,11 @@ int capwap_socket_connect_timeout(int sock, struct sockaddr_storage* address, in
|
|||||||
ASSERT(sock >= 0);
|
ASSERT(sock >= 0);
|
||||||
ASSERT(address != NULL);
|
ASSERT(address != NULL);
|
||||||
|
|
||||||
|
/* Non blocking socket */
|
||||||
|
if (!capwap_socket_nonblocking(sock, 1)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
result = connect(sock, (struct sockaddr*)address, sizeof(struct sockaddr_storage));
|
result = connect(sock, (struct sockaddr*)address, sizeof(struct sockaddr_storage));
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
@ -73,7 +87,319 @@ int capwap_socket_connect_timeout(int sock, struct sockaddr_storage* address, in
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
int capwap_socket_send_timeout(int sock, void* buffer, size_t length, int timeout) {
|
static int capwap_socket_crypto_checkpasswd(char* buffer, int size, int rwflag, void* userdata) {
|
||||||
|
if (!userdata) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
strncpy(buffer, (char*)userdata, size);
|
||||||
|
buffer[size - 1] = 0;
|
||||||
|
return strlen(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int capwap_socket_crypto_verifycertificate(int preverify_ok, X509_STORE_CTX* ctx) {
|
||||||
|
int err;
|
||||||
|
X509* err_cert;
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
err_cert = X509_STORE_CTX_get_current_cert(ctx);
|
||||||
|
err = X509_STORE_CTX_get_error(ctx);
|
||||||
|
X509_verify_cert_error_string(err);
|
||||||
|
|
||||||
|
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
|
||||||
|
|
||||||
|
if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) {
|
||||||
|
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
return preverify_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
void* capwap_socket_crypto_createcontext(char* calist, char* cert, char* privatekey, char* privatekeypasswd) {
|
||||||
|
SSL_CTX* context = NULL;
|
||||||
|
|
||||||
|
ASSERT(calist != NULL);
|
||||||
|
ASSERT(cert != NULL);
|
||||||
|
ASSERT(privatekey != NULL);
|
||||||
|
|
||||||
|
/* Create SSL context */
|
||||||
|
context = (void*)SSL_CTX_new(SSLv23_client_method());
|
||||||
|
if (context) {
|
||||||
|
char* privkey = NULL;
|
||||||
|
|
||||||
|
/* Public certificate */
|
||||||
|
if (!SSL_CTX_use_certificate_file(context, cert, SSL_FILETYPE_PEM)) {
|
||||||
|
capwap_logging_debug("Error to load certificate file");
|
||||||
|
capwap_socket_crypto_freecontext(context);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save private key */
|
||||||
|
if (privatekeypasswd && *privatekeypasswd) {
|
||||||
|
privkey = capwap_duplicate_string(privatekeypasswd);
|
||||||
|
SSL_CTX_set_ex_data(context, OPENSSL_EXDATA_PRIVATE_KEY_PASSWORD, (void*)privkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
SSL_CTX_set_default_passwd_cb(context, capwap_socket_crypto_checkpasswd);
|
||||||
|
SSL_CTX_set_default_passwd_cb_userdata(context, privkey);
|
||||||
|
|
||||||
|
/* Private key */
|
||||||
|
if (!SSL_CTX_use_PrivateKey_file(context, privatekey, SSL_FILETYPE_PEM)) {
|
||||||
|
capwap_logging_debug("Error to load private key file");
|
||||||
|
capwap_socket_crypto_freecontext(context);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SSL_CTX_check_private_key(context)) {
|
||||||
|
capwap_logging_debug("Error to check private key");
|
||||||
|
capwap_socket_crypto_freecontext(context);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Certificate Authority */
|
||||||
|
if (!SSL_CTX_load_verify_locations(context, calist, NULL)) {
|
||||||
|
capwap_logging_debug("Error to load ca file");
|
||||||
|
capwap_socket_crypto_freecontext(context);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify certificate callback */
|
||||||
|
SSL_CTX_set_verify(context, SSL_VERIFY_PEER, capwap_socket_crypto_verifycertificate);
|
||||||
|
|
||||||
|
/* Set only high security cipher list */
|
||||||
|
if (!SSL_CTX_set_cipher_list(context, "HIGH:!DSS:!aNULL@STRENGTH")) {
|
||||||
|
capwap_logging_debug("Error to select cipher list");
|
||||||
|
capwap_socket_crypto_freecontext(context);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
SSL_CTX_set_mode(context, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void*)context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
void capwap_socket_crypto_freecontext(void* context) {
|
||||||
|
char* privkey;
|
||||||
|
SSL_CTX* sslcontext = (SSL_CTX*)context;
|
||||||
|
|
||||||
|
if (sslcontext) {
|
||||||
|
privkey = (char*)SSL_CTX_get_ex_data(sslcontext, OPENSSL_EXDATA_PRIVATE_KEY_PASSWORD);
|
||||||
|
if (privkey) {
|
||||||
|
capwap_free(privkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
SSL_CTX_free(sslcontext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
struct capwap_socket_ssl* capwap_socket_ssl_connect(int sock, void* sslcontext, int timeout) {
|
||||||
|
int result;
|
||||||
|
struct pollfd fds;
|
||||||
|
struct capwap_socket_ssl* sslsock;
|
||||||
|
|
||||||
|
ASSERT(sock >= 0);
|
||||||
|
ASSERT(sslcontext != NULL);
|
||||||
|
|
||||||
|
/* */
|
||||||
|
sslsock = capwap_alloc(sizeof(struct capwap_socket_ssl));
|
||||||
|
if (!sslsock) {
|
||||||
|
capwap_outofmemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create SSL session */
|
||||||
|
sslsock->sock = sock;
|
||||||
|
sslsock->sslcontext = sslcontext;
|
||||||
|
sslsock->sslsession = (void*)SSL_new((SSL_CTX*)sslcontext);
|
||||||
|
if (!sslsock->sslsession) {
|
||||||
|
capwap_free(sslsock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set socket to SSL session */
|
||||||
|
if (!SSL_set_fd((SSL*)sslsock->sslsession, sock)) {
|
||||||
|
SSL_free((SSL*)sslsock->sslsession);
|
||||||
|
capwap_free(sslsock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Establish SSL connection */
|
||||||
|
for (;;) {
|
||||||
|
ERR_clear_error();
|
||||||
|
result = SSL_connect((SSL*)sslsock->sslsession);
|
||||||
|
if (result == 1) {
|
||||||
|
break; /* Connection complete */
|
||||||
|
} else {
|
||||||
|
int error = SSL_get_error((SSL*)sslsock->sslsession, result);
|
||||||
|
if ((error == SSL_ERROR_WANT_READ) || (error == SSL_ERROR_WANT_WRITE)) {
|
||||||
|
memset(&fds, 0, sizeof(struct pollfd));
|
||||||
|
fds.fd = sock;
|
||||||
|
fds.events = ((error == SSL_ERROR_WANT_READ) ? POLLIN : POLLOUT);
|
||||||
|
|
||||||
|
result = poll(&fds, 1, timeout);
|
||||||
|
if (((result < 0) && (errno != EINTR)) || ((result > 0) && (fds.events != fds.revents))) {
|
||||||
|
SSL_free((SSL*)sslsock->sslsession);
|
||||||
|
capwap_free(sslsock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SSL_free((SSL*)sslsock->sslsession);
|
||||||
|
capwap_free(sslsock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sslsock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
int capwap_socket_crypto_send(struct capwap_socket_ssl* sslsock, void* buffer, size_t length, int timeout) {
|
||||||
|
int result;
|
||||||
|
struct pollfd fds;
|
||||||
|
size_t sendlength;
|
||||||
|
|
||||||
|
ASSERT(sslsock != NULL);
|
||||||
|
ASSERT(sslsock->sslsession != NULL);
|
||||||
|
ASSERT(sslsock->sock >= 0);
|
||||||
|
ASSERT(buffer != NULL);
|
||||||
|
ASSERT(length > 0);
|
||||||
|
|
||||||
|
sendlength = 0;
|
||||||
|
while (sendlength < length) {
|
||||||
|
size_t leftlength = length - sendlength;
|
||||||
|
|
||||||
|
ERR_clear_error();
|
||||||
|
result = SSL_write((SSL*)sslsock->sslsession, &((char*)buffer)[sendlength], leftlength);
|
||||||
|
if (result > 0) {
|
||||||
|
sendlength += result;
|
||||||
|
} else {
|
||||||
|
int error = SSL_get_error((SSL*)sslsock->sslsession, result);
|
||||||
|
if ((error == SSL_ERROR_WANT_READ) || (error == SSL_ERROR_WANT_WRITE)) {
|
||||||
|
memset(&fds, 0, sizeof(struct pollfd));
|
||||||
|
fds.fd = sslsock->sock;
|
||||||
|
fds.events = ((error == SSL_ERROR_WANT_READ) ? POLLIN : POLLOUT);
|
||||||
|
|
||||||
|
result = poll(&fds, 1, timeout);
|
||||||
|
if (((result < 0) && (errno != EINTR)) || ((result > 0) && (fds.events != fds.revents))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendlength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
int capwap_socket_crypto_recv(struct capwap_socket_ssl* sslsock, void* buffer, size_t length, int timeout) {
|
||||||
|
int result;
|
||||||
|
struct pollfd fds;
|
||||||
|
|
||||||
|
ASSERT(sslsock != NULL);
|
||||||
|
ASSERT(sslsock->sslsession != NULL);
|
||||||
|
ASSERT(sslsock->sock >= 0);
|
||||||
|
ASSERT(buffer != NULL);
|
||||||
|
ASSERT(length > 0);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
ERR_clear_error();
|
||||||
|
result = SSL_read((SSL*)sslsock->sslsession, buffer, length);
|
||||||
|
if (result >= 0) {
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
int error = SSL_get_error((SSL*)sslsock->sslsession, result);
|
||||||
|
if ((error == SSL_ERROR_WANT_READ) || (error == SSL_ERROR_WANT_WRITE)) {
|
||||||
|
memset(&fds, 0, sizeof(struct pollfd));
|
||||||
|
fds.fd = sslsock->sock;
|
||||||
|
fds.events = ((error == SSL_ERROR_WANT_READ) ? POLLIN : POLLOUT);
|
||||||
|
|
||||||
|
result = poll(&fds, 1, timeout);
|
||||||
|
if (((result < 0) && (errno != EINTR)) || ((result > 0) && (fds.events != fds.revents))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
void capwap_socket_ssl_shutdown(struct capwap_socket_ssl* sslsock, int timeout) {
|
||||||
|
int result;
|
||||||
|
struct pollfd fds;
|
||||||
|
|
||||||
|
ASSERT(sslsock != NULL);
|
||||||
|
ASSERT(sslsock->sslsession != NULL);
|
||||||
|
ASSERT(sslsock->sock >= 0);
|
||||||
|
|
||||||
|
/* */
|
||||||
|
for (;;) {
|
||||||
|
ERR_clear_error();
|
||||||
|
result = SSL_shutdown((SSL*)sslsock->sslsession);
|
||||||
|
if (result >= 0) {
|
||||||
|
break; /* Shutdown complete */
|
||||||
|
} else {
|
||||||
|
int error = SSL_get_error((SSL*)sslsock->sslsession, result);
|
||||||
|
if ((error == SSL_ERROR_WANT_READ) || (error == SSL_ERROR_WANT_WRITE)) {
|
||||||
|
memset(&fds, 0, sizeof(struct pollfd));
|
||||||
|
fds.fd = sslsock->sock;
|
||||||
|
fds.events = ((error == SSL_ERROR_WANT_READ) ? POLLIN : POLLOUT);
|
||||||
|
|
||||||
|
result = poll(&fds, 1, timeout);
|
||||||
|
if (((result < 0) && (errno != EINTR)) || ((result > 0) && (fds.events != fds.revents))) {
|
||||||
|
break; /* Shutdown error */
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break; /* Shutdown error */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
void capwap_socket_ssl_close(struct capwap_socket_ssl* sslsock) {
|
||||||
|
ASSERT(sslsock != NULL);
|
||||||
|
ASSERT(sslsock->sslsession != NULL);
|
||||||
|
|
||||||
|
SSL_free((SSL*)sslsock->sslsession);
|
||||||
|
sslsock->sslsession = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
void capwap_socket_shutdown(int sock) {
|
||||||
|
ASSERT(sock >= 0);
|
||||||
|
|
||||||
|
shutdown(sock, SHUT_RDWR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
void capwap_socket_close(int sock) {
|
||||||
|
ASSERT(sock >= 0);
|
||||||
|
|
||||||
|
capwap_socket_shutdown(sock);
|
||||||
|
capwap_socket_nonblocking(sock, 0);
|
||||||
|
close(sock);
|
||||||
|
|
||||||
|
/* */
|
||||||
|
ERR_clear_error();
|
||||||
|
ERR_remove_state(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
int capwap_socket_send(int sock, void* buffer, size_t length, int timeout) {
|
||||||
int result;
|
int result;
|
||||||
struct pollfd fds;
|
struct pollfd fds;
|
||||||
size_t sendlength;
|
size_t sendlength;
|
||||||
@ -111,7 +437,7 @@ int capwap_socket_send_timeout(int sock, void* buffer, size_t length, int timeou
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
int capwap_socket_recv_timeout(int sock, void* buffer, size_t length, int timeout) {
|
int capwap_socket_recv(int sock, void* buffer, size_t length, int timeout) {
|
||||||
int result;
|
int result;
|
||||||
struct pollfd fds;
|
struct pollfd fds;
|
||||||
|
|
||||||
@ -126,19 +452,17 @@ int capwap_socket_recv_timeout(int sock, void* buffer, size_t length, int timeou
|
|||||||
|
|
||||||
result = poll(&fds, 1, timeout);
|
result = poll(&fds, 1, timeout);
|
||||||
if ((result < 0) && (errno != EINTR)) {
|
if ((result < 0) && (errno != EINTR)) {
|
||||||
return -1;
|
break;
|
||||||
} else if (result > 0) {
|
} else if (result > 0) {
|
||||||
if (fds.revents == POLLIN) {
|
if (fds.revents == POLLIN) {
|
||||||
result = recv(sock, buffer, length, 0);
|
result = recv(sock, buffer, length, 0);
|
||||||
if ((result < 0) && (errno != EINTR)) {
|
if ((result < 0) && (errno != EINTR)) {
|
||||||
return -1;
|
break;
|
||||||
} else if (!result) {
|
} else if (result >= 0) {
|
||||||
return 0;
|
|
||||||
} else if (result > 0) {
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,29 @@
|
|||||||
#define __CAPWAP_SOCKET_HEADER__
|
#define __CAPWAP_SOCKET_HEADER__
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
int capwap_socket_nonblocking(int sock, int nonblocking);
|
int capwap_socket_connect(int sock, struct sockaddr_storage* address, int timeout);
|
||||||
|
void capwap_socket_shutdown(int sock);
|
||||||
|
void capwap_socket_close(int sock);
|
||||||
|
|
||||||
/* */
|
/* Plain send/recv */
|
||||||
int capwap_socket_connect_timeout(int sock, struct sockaddr_storage* address, int timeout);
|
int capwap_socket_send(int sock, void* buffer, size_t length, int timeout);
|
||||||
int capwap_socket_send_timeout(int sock, void* buffer, size_t length, int timeout);
|
int capwap_socket_recv(int sock, void* buffer, size_t length, int timeout);
|
||||||
int capwap_socket_recv_timeout(int sock, void* buffer, size_t length, int timeout);
|
|
||||||
|
|
||||||
|
/* SSL send/recv */
|
||||||
|
struct capwap_socket_ssl {
|
||||||
|
int sock;
|
||||||
|
void* sslcontext;
|
||||||
|
void* sslsession;
|
||||||
|
};
|
||||||
|
|
||||||
|
void* capwap_socket_crypto_createcontext(char* calist, char* cert, char* privatekey, char* privatekeypasswd);
|
||||||
|
void capwap_socket_crypto_freecontext(void* context);
|
||||||
|
|
||||||
|
int capwap_socket_crypto_send(struct capwap_socket_ssl* sslsock, void* buffer, size_t length, int timeout);
|
||||||
|
int capwap_socket_crypto_recv(struct capwap_socket_ssl* sslsock, void* buffer, size_t length, int timeout);
|
||||||
|
|
||||||
|
struct capwap_socket_ssl* capwap_socket_ssl_connect(int sock, void* sslcontext, int timeout);
|
||||||
|
void capwap_socket_ssl_shutdown(struct capwap_socket_ssl* sslsock, int timeout);
|
||||||
|
void capwap_socket_ssl_close(struct capwap_socket_ssl* sslsock);
|
||||||
|
|
||||||
#endif /* __CAPWAP_SOCKET_HEADER__ */
|
#endif /* __CAPWAP_SOCKET_HEADER__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user