/*********************************************************************
*
- * File : $Source: $
+ * File : $Source: /cvsroot/ijbswa/current/openssl.c,v $
*
* Purpose : File with TLS/SSL extension. Contains methods for
* creating, using and closing TLS/SSL connections.
*
* Copyright : Written by and Copyright (c) 2020 Maxim Antonov <mantonov@gmail.com>
+ * Copyright (C) 2017 Vaclav Svec. FIT CVUT.
+ * Copyright (C) 2018-2020 by Fabian Keil <fk@fabiankeil.de>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
#define CERTIFICATE_AUTHORITY_KEY "keyid:always"
#define CERTIFICATE_ALT_NAME_PREFIX "DNS:"
#define CERTIFICATE_VERSION 2
-#define VALID_DATETIME_FMT "%Y%m%d%H%M%SZ"
+#define VALID_DATETIME_FMT "%y%m%d%H%M%SZ"
#define VALID_DATETIME_BUFLEN 16
static int generate_webpage_certificate(struct client_state *csp);
static int ssl_inited = 0;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#define X509_set1_notBefore X509_set_notBefore
+#define X509_set1_notAfter X509_set_notAfter
+#define X509_get0_serialNumber X509_get_serialNumber
+#define X509_get0_notBefore X509_get_notBefore
+#define X509_get0_notAfter X509_get_notAfter
+#endif
+
/*********************************************************************
*
* Function : openssl_init
extern int ssl_send_data(struct ssl_attr *ssl_attr, const unsigned char *buf, size_t len)
{
BIO *bio = ssl_attr->openssl_attr.bio;
+ SSL *ssl;
int ret = 0;
int pos = 0; /* Position of unsent part in buffer */
+ int fd = -1;
if (len == 0)
{
return 0;
}
+ if (BIO_get_ssl(bio, &ssl) == 1)
+ {
+ fd = SSL_get_fd(ssl);
+ }
+
while (pos < len)
{
int send_len = (int)len - pos;
- log_error(LOG_LEVEL_WRITING, "TLS: %N", send_len, buf+pos);
+ log_error(LOG_LEVEL_WRITING, "TLS on socket %d: %N",
+ fd, send_len, buf+pos);
/*
* Sending one part of the buffer
*/
while ((ret = BIO_write(bio,
(const unsigned char *)(buf + pos),
- send_len)) < 0)
+ send_len)) <= 0)
{
if (!BIO_should_retry(bio))
{
log_ssl_errors(LOG_LEVEL_ERROR,
- "Sending data over TLS/SSL failed");
+ "Sending data on socket %d over TLS/SSL failed", fd);
return -1;
}
}
extern int ssl_recv_data(struct ssl_attr *ssl_attr, unsigned char *buf, size_t max_length)
{
BIO *bio = ssl_attr->openssl_attr.bio;
+ SSL *ssl;
int ret = 0;
+ int fd = -1;
+
memset(buf, 0, max_length);
/*
if (ret < 0)
{
log_ssl_errors(LOG_LEVEL_ERROR,
- "Receiving data over TLS/SSL failed");
+ "Receiving data on socket %d over TLS/SSL failed", fd);
return -1;
}
- log_error(LOG_LEVEL_RECEIVED, "TLS: %N", ret, buf);
+ if (BIO_get_ssl(bio, &ssl) == 1)
+ {
+ fd = SSL_get_fd(ssl);
+ }
+
+ log_error(LOG_LEVEL_RECEIVED, "TLS from socket %d: %N",
+ fd, ret, buf);
return ret;
}
*
* Function : ssl_store_cert
*
- * Description : This is a callback function for certificate verification.
- * It's called once for each certificate in the server's
- * certificate trusted chain and prepares information about
- * the certificate. The information can be used to inform
- * the user about invalid certificates.
+ * Description : This function is called once for each certificate in the
+ * server's certificate trusted chain and prepares
+ * information about the certificate. The information can
+ * be used to inform the user about invalid certificates.
*
* Parameters :
* 1 : csp = Current client state (buffers, headers, etc...)
- * 2 : crt = certificate from trusted chain
+ * 2 : crt = certificate from trusted chain
*
* Returns : 0 on success and negative value on error
*
char *encoded_text;
long l;
const ASN1_INTEGER *bs;
+#if OPENSSL_VERSION_NUMBER > 0x10100000L
const X509_ALGOR *tsig_alg;
+#endif
int loc;
if (!bio)
if (len > (sizeof(last->file_buf) - 1))
{
log_error(LOG_LEVEL_ERROR,
- "X509 PEM cert len %d is larger then buffer len %s",
+ "X509 PEM cert len %ld is larger than buffer len %lu",
len, sizeof(last->file_buf) - 1);
len = sizeof(last->file_buf) - 1;
}
if (BIO_puts(bio, "serial number : ") <= 0)
{
- log_ssl_errors(LOG_LEVEL_ERROR, "BIO_write() for serial failed");
+ log_ssl_errors(LOG_LEVEL_ERROR, "BIO_puts() for serial failed");
ret = -1;
goto exit;
}
if (BIO_puts(bio, "\nsubject name : ") <= 0)
{
- log_ssl_errors(LOG_LEVEL_ERROR, "BIO_puts() for sublect failed");
+ log_ssl_errors(LOG_LEVEL_ERROR, "BIO_puts() for subject failed");
ret = -1;
goto exit;
}
goto exit;
}
+#if OPENSSL_VERSION_NUMBER > 0x10100000L
if (BIO_puts(bio, "\nsigned using : ") <= 0)
{
log_ssl_errors(LOG_LEVEL_ERROR, "BIO_puts() for signed using failed");
tsig_alg = X509_get0_tbs_sigalg(crt);
if (!i2a_ASN1_OBJECT(bio, tsig_alg->algorithm))
{
- log_ssl_errors(LOG_LEVEL_ERROR, "i2a_ASN1_OBJECT() for signed using on failed");
+ log_ssl_errors(LOG_LEVEL_ERROR, "i2a_ASN1_OBJECT() for signed using failed");
ret = -1;
goto exit;
}
+#endif
pkey = X509_get_pubkey(crt);
if (!pkey)
{
len = BIO_get_mem_data(bio, &bio_mem_data);
encoded_text = html_encode(bio_mem_data);
+ if (encoded_text == NULL)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Failed to HTML-encode the certificate information");
+ ret = -1;
+ goto exit;
+ }
+
strlcpy(last->info_buf, encoded_text, sizeof(last->info_buf));
freez(encoded_text);
ret = 0;
char *ca_file = NULL;
char *cert_file = NULL;
int ret = 0;
- SSL* ssl;
+ SSL *ssl;
/*
* Initializing OpenSSL structures for TLS/SSL connection
goto exit;
}
+ if (csp->config->cipher_list != NULL)
+ {
+ if (!SSL_set_cipher_list(ssl, csp->config->cipher_list))
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR,
+ "Setting the cipher list '%s' for the client connection failed",
+ csp->config->cipher_list);
+ ret = -1;
+ goto exit;
+ }
+ }
+
/*
* Handshake with client
*/
csp->http->hash_of_host_hex);
if (BIO_do_handshake(ssl_attr->openssl_attr.bio) != 1)
{
- log_ssl_errors(LOG_LEVEL_ERROR, "BIO_do_handshake failed");
+ log_ssl_errors(LOG_LEVEL_ERROR,
+ "The TLS/SSL handshake with the client failed");
ret = -1;
goto exit;
}
extern void close_client_ssl_connection(struct client_state *csp)
{
struct ssl_attr *ssl_attr = &csp->ssl_client_attr;
+ SSL *ssl;
if (csp->ssl_with_client_is_opened == 0)
{
* Notifying the peer that the connection is being closed.
*/
BIO_ssl_shutdown(ssl_attr->openssl_attr.bio);
+ if (BIO_get_ssl(ssl_attr->openssl_attr.bio, &ssl) != 1)
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR,
+ "BIO_get_ssl() failed in close_client_ssl_connection()");
+ }
+ else
+ {
+ /*
+ * Pretend we received a shutdown alert so
+ * the BIO_free_all() call later on returns
+ * quickly.
+ */
+ SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
+ }
free_client_ssl_structures(csp);
csp->ssl_with_client_is_opened = 0;
}
extern void close_server_ssl_connection(struct client_state *csp)
{
struct ssl_attr *ssl_attr = &csp->ssl_server_attr;
+ SSL *ssl;
if (csp->ssl_with_server_is_opened == 0)
{
* Notifying the peer that the connection is being closed.
*/
BIO_ssl_shutdown(ssl_attr->openssl_attr.bio);
+ if (BIO_get_ssl(ssl_attr->openssl_attr.bio, &ssl) != 1)
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR,
+ "BIO_get_ssl() failed in close_server_ssl_connection()");
+ }
+ else
+ {
+ /*
+ * Pretend we received a shutdown alert so
+ * the BIO_free_all() call later on returns
+ * quickly.
+ */
+ SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
+ }
free_server_ssl_structures(csp);
csp->ssl_with_server_is_opened = 0;
}
goto exit;
}
+ if (csp->config->cipher_list != NULL)
+ {
+ if (!SSL_set_cipher_list(ssl, csp->config->cipher_list))
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR,
+ "Setting the cipher list '%s' for the server connection failed",
+ csp->config->cipher_list);
+ ret = -1;
+ goto exit;
+ }
+ }
+
/*
* Set the hostname to check against the received server certificate
*/
+#if OPENSSL_VERSION_NUMBER > 0x10100000L
if (!SSL_set1_host(ssl, csp->http->host))
{
log_ssl_errors(LOG_LEVEL_ERROR, "SSL_set1_host failed");
ret = -1;
goto exit;
}
-
+#else
+ if (host_is_ip_address(csp->http->host))
+ {
+ if (X509_VERIFY_PARAM_set1_ip_asc(ssl->param, csp->http->host) != 1)
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR,
+ "X509_VERIFY_PARAM_set1_ip_asc() failed");
+ ret = -1;
+ goto exit;
+ }
+ }
+ else
+ {
+ if (X509_VERIFY_PARAM_set1_host(ssl->param, csp->http->host, 0) != 1)
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR,
+ "X509_VERIFY_PARAM_set1_host() failed");
+ ret = -1;
+ goto exit;
+ }
+ }
+#endif
/* SNI extension */
if (!SSL_set_tlsext_host_name(ssl, csp->http->host))
{
if (BIO_do_handshake(ssl_attrs->bio) != 1)
{
- log_ssl_errors(LOG_LEVEL_ERROR, "BIO_do_handshake failed");
+ log_ssl_errors(LOG_LEVEL_ERROR,
+ "The TLS/SSL handshake with the server failed");
ret = -1;
goto exit;
}
else
{
csp->server_cert_verification_result = verify_result;
- log_error(LOG_LEVEL_ERROR, "SSL_get_verify_result failed: %s",
- X509_verify_cert_error_string(verify_result));
+ log_error(LOG_LEVEL_ERROR,
+ "X509 certificate verification for %s failed: %s",
+ csp->http->hostport, X509_verify_cert_error_string(verify_result));
ret = -1;
goto exit;
}
va_end(args);
/*
* In case if called by mistake and there were
- * no SSL errors let's report it to the log.
+ * no TLS/SSL errors let's report it to the log.
*/
if (!reported)
{
- log_error(debuglevel, "%s: no ssl errors detected", prefix);
+ log_error(debuglevel, "%s: no TLS/SSL errors detected", prefix);
}
}
goto exit;
}
- BN_set_word(exp, RSA_KEY_PUBLIC_EXPONENT);
+ if (BN_set_word(exp, RSA_KEY_PUBLIC_EXPONENT) != 1)
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR, "Setting RSA key exponent failed");
+ ret = -1;
+ goto exit;
+ }
key_file_path = make_certs_path(csp->config->certificate_directory,
(char *)csp->http->hash_of_host_hex, KEY_FILE_TYPE);
{
log_ssl_errors(LOG_LEVEL_ERROR,
"Error checking certificate %s validity", cert_file);
+ ret = -1;
}
X509_free(cert);
* 1 => It worked
*
*********************************************************************/
-static int set_x509_ext(X509 *cert, X509 *issuer, int nid, const char *value)
+static int set_x509_ext(X509 *cert, X509 *issuer, int nid, char *value)
{
X509_EXTENSION *ext = NULL;
X509V3_CTX ctx;
{
log_ssl_errors(LOG_LEVEL_ERROR,
"X509 subject name (code: %s, val: %s) error",
- CERT_PARAM_COMMON_NAME_FCODE, csp->http->host);
+ CERT_PARAM_ORGANIZATION_FCODE, csp->http->host);
ret = -1;
goto exit;
}
{
log_ssl_errors(LOG_LEVEL_ERROR,
"X509 subject name (code: %s, val: %s) error",
- CERT_PARAM_COMMON_NAME_FCODE, csp->http->host);
+ CERT_PARAM_ORG_UNIT_FCODE, csp->http->host);
ret = -1;
goto exit;
}
{
log_ssl_errors(LOG_LEVEL_ERROR,
"X509 subject name (code: %s, val: %s) error",
- CERT_PARAM_COMMON_NAME_FCODE, csp->http->host);
+ CERT_PARAM_COUNTRY_FCODE, csp->http->host);
ret = -1;
goto exit;
}
if (!X509_set_pubkey(cert, loaded_subject_key))
{
log_ssl_errors(LOG_LEVEL_ERROR,
- "Setting issuer name in signed certificate failed");
+ "Setting public key in signed certificate failed");
ret = -1;
goto exit;
}
if (!X509_set_subject_name(cert, subject_name))
{
log_ssl_errors(LOG_LEVEL_ERROR,
- "Setting issuer name in signed certificate failed");
+ "Setting subject name in signed certificate failed");
ret = -1;
goto exit;
}
if (!X509_set1_notBefore(cert, asn_time))
{
log_ssl_errors(LOG_LEVEL_ERROR,
- "Setting valid not befre in signed certificate failed");
+ "Setting valid not before in signed certificate failed");
ret = -1;
goto exit;
}
if (!set_x509_ext(cert, issuer_cert, NID_subject_key_identifier, CERTIFICATE_SUBJECT_KEY))
{
log_ssl_errors(LOG_LEVEL_ERROR,
- "Setting the Subject Key Identifie extension failed");
+ "Setting the Subject Key Identifier extension failed");
ret = -1;
goto exit;
}
if (!host_is_ip_address(csp->http->host) &&
!set_subject_alternative_name(cert, issuer_cert, csp->http->host))
{
- log_ssl_errors(LOG_LEVEL_ERROR, "Setting the Subject Alt Nameextension failed");
+ log_ssl_errors(LOG_LEVEL_ERROR,
+ "Setting the Subject Alt Name extension failed");
ret = -1;
goto exit;
}
{
if (ssl_inited == 1)
{
+#ifndef OPENSSL_NO_COMP
SSL_COMP_free_compression_methods();
-
+#endif
CONF_modules_free();
CONF_modules_unload(1);
-
+#ifndef OPENSSL_NO_COMP
COMP_zlib_cleanup();
+#endif
ERR_free_strings();
EVP_cleanup();