/* zentific-poll: statistics collection daemon for Zentific * Copyright (C) 2007, 2008 * Steven Maresca, Justin Demaris, * and Zentific LLC * * All rights reserved. * Use is subject to license terms. * * Please visit http://zentific.com for news and updates * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ #include "ssl_send.h" /** * Sends a message over an SSL encrypted connection to the given destination * * NOTE: when using fallback, plaintext will be used only if the initial set of connection preparation fails, or * loading the trust store fails. After this is completed, the function will return an error and handle * itself based on ignore_trust_error. * * @param char* message The message to send * @param char* destination Where to send the message (e.g. zentific.com:443) * @param char* response Pointer to string to hold the reply * @param int length The max length to place into response (including '\0') * @param char* trust Where to load the .pem for trusted certs * @param int ignore_trust_error 0 to fail on trust errors, 1 to ignore them * @param int fallback 0 to fail on SSL fail, 1 to use plaintext if SSL fail. * @return int 0 on success, error code otherwise */ int ssl_send(char *message, char *destination, char *response, int length, char *trust, int ignore_trust_error, int fallback) { BIO * bio; // prepare libraries SSL_load_error_strings(); ERR_load_BIO_strings(); SSLeay_add_ssl_algorithms(); SSL_load_error_strings(); ERR_print_errors_fp(stderr); SSL_CTX * ctx = SSL_CTX_new(SSLv23_client_method()); SSL * ssl; if ( ctx == NULL ) { if ( fallback ) return plaintext_send(message, destination, response, length); else { fprintf(stderr, "Error preparing client\n"); return 1; } } // Load certificate trust store if ( !SSL_CTX_load_verify_locations(ctx, trust, NULL) && ignore_trust_error == 0 ) { if ( fallback ) return plaintext_send(message, destination, response, length); else { fprintf(stderr, "Error loading trust store\n"); return 2; } } // connect bio = BIO_new_ssl_connect(ctx); BIO_get_ssl(bio, & ssl); SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); BIO_set_conn_hostname(bio, destination); if ( bio == NULL ) { if ( fallback ) return plaintext_send(message, destination, response, length); else { fprintf(stderr, "Error connecting to host\n"); return 3; } } if ( BIO_do_connect(bio) <= 0 ) { if ( fallback ) return plaintext_send(message, destination, response, length); else { fprintf(stderr, "Connection failed\n"); return 4; } } // Check for certificate trust issues if(SSL_get_verify_result(ssl) != X509_V_OK && ignore_trust_error == 0) { fprintf(stderr, "FATAL ERROR: CERTIFICATE VALIDATION FAILED!\n"); return 5; } // Send a the message if ( BIO_write(bio, message, strlen(message)) <= 0 ) { fprintf(stderr, "Write failed\n"); return 6; } if ( BIO_read(bio, response, length) <= 0) { fprintf(stderr, "Read failed\n"); return 7; } // Close connection BIO_free_all(bio); SSL_CTX_free(ctx); return 0; } /** * Sends a message to the given destination without using SSL encryption * @param char* message The message to send * @param char* destination Where to send the message (e.g. zentific.com:443) * @param char* response Pointer to string to hold the reply * @param int length The max length to place into response (including '\0') * @return int 0 on success, error code on failure */ int plaintext_send(char *message, char *destination, char *response, int length) { BIO * bio; // prepare libraries //SSL_load_error_strings(); ERR_load_BIO_strings(); //SSLeay_add_ssl_algorithms(); //SSL_load_error_strings(); ERR_print_errors_fp(stderr); // create the connection bio = BIO_new_connect(destination); if ( bio == NULL ) { fprintf(stderr, "Error connecting to host\n"); return 3; } // open the connection if ( BIO_do_connect(bio) <= 0 ) { fprintf(stderr, "Connection failed\n"); return 4; } // send our message if ( BIO_write(bio, message, strlen(message)) <= 0 ) { fprintf(stderr, "Write failed\n"); return 6; } // read the response if ( BIO_read(bio, response, length) <= 0) { fprintf(stderr, "Read failed\n"); return 7; } // close the connection BIO_free_all(bio); // success return 0; }