#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# include <strings.h>
-#endif
+#include <string.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include "url.h"
#include "ssl.h"
-#ifndef errno
-extern int errno;
-#endif
-
/* Application-wide SSL context. This is common to all SSL
connections. */
-SSL_CTX *ssl_ctx;
+static SSL_CTX *ssl_ctx;
/* Initialize the SSL's PRNG using various methods. */
/* Create an SSL Context and set default paths etc. Called the first
time an HTTP download is attempted.
- Returns 1 on success, 0 otherwise. */
+ Returns true on success, false otherwise. */
-int
+bool
ssl_init ()
{
SSL_METHOD *meth;
if (ssl_ctx)
/* The SSL has already been initialized. */
- return 1;
+ return true;
/* Init the PRNG. If that fails, bail out. */
init_prng ();
handles them correctly), allow them in OpenSSL. */
SSL_CTX_set_mode (ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
- return 1;
+ return true;
error:
if (ssl_ctx)
SSL_CTX_free (ssl_ctx);
print_errors ();
- return 0;
+ return false;
}
static int
fd_register_transport, so that subsequent calls to fd_read,
fd_write, etc., will use the corresponding SSL functions.
- Returns 1 on success, 0 on failure. */
+ Returns true on success, false on failure. */
-int
+bool
ssl_connect (int fd)
{
SSL *ssl;
+ DEBUGP (("Initiating SSL handshake.\n"));
+
assert (ssl_ctx != NULL);
ssl = SSL_new (ssl_ctx);
if (!ssl)
functions are used for reading, writing, and polling. */
fd_register_transport (fd, openssl_read, openssl_write, openssl_poll,
openssl_peek, openssl_close, ssl);
- DEBUGP (("Connected %d to SSL 0x%0*lx\n", fd, 2 * sizeof (void *),
- (unsigned long) ssl));
- return 1;
+ DEBUGP (("Handshake successful; connected socket %d to SSL handle 0x%0*lx\n",
+ fd, PTR_FORMAT (ssl)));
+ return true;
error:
+ DEBUGP (("SSL handshake failed.\n"));
print_errors ();
if (ssl)
SSL_free (ssl);
- return 0;
+ return false;
}
#define ASTERISK_EXCLUDES_DOT /* mandated by rfc2818 */
-/* Return 1 is STRING (case-insensitively) matches PATTERN, 0
+/* Return true is STRING (case-insensitively) matches PATTERN, false
otherwise. The recognized wildcard character is "*", which matches
any character in STRING except ".". Any number of the "*" wildcard
may be present in the pattern.
If the pattern contain no wildcards, pattern_match(a, b) is
equivalent to !strcasecmp(a, b). */
-static int
+static bool
pattern_match (const char *pattern, const char *string)
{
const char *p = pattern, *n = string;
;
for (; *n != '\0'; n++)
if (TOLOWER (*n) == c && pattern_match (p, n))
- return 1;
+ return true;
#ifdef ASTERISK_EXCLUDES_DOT
else if (*n == '.')
- return 0;
+ return false;
#endif
return c == '\0';
}
else
{
if (c != TOLOWER (*n))
- return 0;
+ return false;
}
return *n == '\0';
}
the SSL handshake has been performed and that FD is connected to an
SSL handle.
- If opt.check_cert is non-zero (the default), this returns 1 if the
+ If opt.check_cert is true (the default), this returns 1 if the
certificate is valid, 0 otherwise. If opt.check_cert is 0, the
function always returns 1, but should still be called because it
warns the user about any problems with the certificate. */
-int
+bool
ssl_check_certificate (int fd, const char *host)
{
X509 *cert;
char common_name[256];
long vresult;
- int success;
+ bool success = true;
/* If the user has specified --no-check-cert, we still want to warn
him about problems with the server's certificate. */
{
logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
severity, escnonprint (host));
- success = 0;
- goto out;
+ success = false;
+ goto no_cert; /* must bail out since CERT is NULL */
}
-#ifdef ENABLE_DEBUG
- if (opt.debug)
+ IF_DEBUG
{
char *subject = X509_NAME_oneline (X509_get_subject_name (cert), 0, 0);
char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0);
OPENSSL_free (subject);
OPENSSL_free (issuer);
}
-#endif
vresult = SSL_get_verify_result (ssl);
if (vresult != X509_V_OK)
{
+ /* #### We might want to print saner (and translatable) error
+ messages for several frequently encountered errors. The
+ candidates would include
+ X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
+ X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
+ X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT,
+ X509_V_ERR_CERT_NOT_YET_VALID, X509_V_ERR_CERT_HAS_EXPIRED,
+ and possibly others. The current approach would still be
+ used for the less frequent failure cases. */
logprintf (LOG_NOTQUIET,
_("%s: Certificate verification error for %s: %s\n"),
severity, escnonprint (host),
X509_verify_cert_error_string (vresult));
- success = 0;
- goto out;
+ success = false;
+ /* Fall through, so that the user is warned about *all* issues
+ with the cert (important with --no-check-certificate.) */
}
/* Check that HOST matches the common name in the certificate.
common names and choose the most specific one, i.e. the last
one, not the first one, which the current code picks.
- - Make sure that the names are encoded as UTF-8 which, being
- ASCII-compatible, can be easily compared against HOST. */
+ - Ensure that ASN1 strings from the certificate are encoded as
+ UTF-8 which can be meaningfully compared to HOST. */
common_name[0] = '\0';
X509_NAME_get_text_by_NID (X509_get_subject_name (cert),
logprintf (LOG_NOTQUIET, _("\
%s: certificate common name `%s' doesn't match requested host name `%s'.\n"),
severity, escnonprint (common_name), escnonprint (host));
- success = 0;
- goto out;
+ success = false;
}
- /* The certificate was found, verified, and matched HOST. */
- success = 1;
-
- out:
- if (cert)
- X509_free (cert);
+ if (success)
+ DEBUGP (("X509 certificate successfully verified and matches host %s\n",
+ escnonprint (host)));
+ X509_free (cert);
+ no_cert:
if (opt.check_cert && !success)
logprintf (LOG_NOTQUIET, _("\
To connect to %s insecurely, use `--no-check-certificate'.\n"),
escnonprint (host));
/* Allow --no-check-cert to disable certificate checking. */
- return opt.check_cert ? success : 1;
+ return opt.check_cert ? success : true;
}