summaryrefslogtreecommitdiff
path: root/src/IO/tls.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/IO/tls.c')
-rw-r--r--src/IO/tls.c199
1 files changed, 113 insertions, 86 deletions
diff --git a/src/IO/tls.c b/src/IO/tls.c
index dfe76744..cfe050ec 100644
--- a/src/IO/tls.c
+++ b/src/IO/tls.c
@@ -427,6 +427,106 @@ int a_Tls_certificate_is_clean(const DilloUrl *url)
return Tls_cert_status(url) == CERT_STATUS_CLEAN;
}
+/*
+ * We are both checking whether the certificates are using a strong enough
+ * hash algorithm and key as well as printing out certificate information the
+ * first time that we see it. Mixing these two actions together is generally
+ * not good practice, but feels justified by the fact that it's so much
+ * trouble to get this information out of openssl even once.
+ *
+ * Return FALSE if MD5 (MD*) hash is found and user does not accept it,
+ * otherwise TRUE.
+ */
+static bool_t Tls_check_cert_strength(SSL *ssl, Server_t *srv, int *choice)
+{
+ /* print for first connection to server */
+ const bool_t print_chain = srv->cert_status == CERT_STATUS_RECEIVING;
+ bool_t success = TRUE;
+
+ STACK_OF(X509) *sk = SSL_get_peer_cert_chain(ssl);
+
+ if (sk) {
+ const uint_t buflen = 4096;
+ char buf[buflen];
+ int rc, i, n = sk_X509_num(sk);
+ X509 *cert = NULL;
+ EVP_PKEY *public_key;
+ int key_type, key_bits;
+ const char *type_str;
+ BIO *b;
+
+ for (i = 0; i < n; i++) {
+ cert = sk_X509_value(sk, i);
+ public_key = X509_get_pubkey(cert);
+
+ /* We are trying to find a way to get the hash function used
+ * with a certificate. This way, which is not very pleasant, puts
+ * a string such as "sha256WithRSAEncryption" in our buffer and we
+ * then trim off the "With..." part.
+ */
+ b = BIO_new(BIO_s_mem());
+ rc = i2a_ASN1_OBJECT(b, cert->sig_alg->algorithm);
+
+ if (rc > 0) {
+ rc = BIO_gets(b, buf, buflen);
+ }
+ if (rc <= 0) {
+ strcpy(buf, "(unknown)");
+ buf[buflen-1] = '\0';
+ } else {
+ char *s = strstr(buf, "With");
+
+ if (s) {
+ *s = '\0';
+ if (!strcmp(buf, "sha1")) {
+ if (print_chain)
+ MSG_WARN("In 2015, browsers have begun to deprecate SHA1 "
+ "certificates.\n");
+ } else if (!strncmp(buf, "md", 2) && success == TRUE) {
+ const char *msg = "A certificate in the chain uses the MD5 "
+ "signature algorithm, which is too weak "
+ "to trust.";
+ *choice = a_Dialog_choice("Dillo TLS security warning", msg,
+ "Continue", "Cancel", NULL);
+ if (*choice != 1)
+ success = FALSE;
+ }
+ }
+ }
+ BIO_free(b);
+
+ if (print_chain)
+ MSG("%s ", buf);
+
+ key_type = EVP_PKEY_type(public_key->type);
+ type_str = key_type == EVP_PKEY_RSA ? "RSA" :
+ key_type == EVP_PKEY_DSA ? "DSA" :
+ key_type == EVP_PKEY_DH ? "DH" :
+ key_type == EVP_PKEY_EC ? "EC" : "???";
+ key_bits = EVP_PKEY_bits(public_key);
+ X509_NAME_oneline(X509_get_subject_name(cert), buf, buflen);
+ buf[buflen-1] = '\0';
+ if (print_chain)
+ MSG("%d-bit %s: %s\n", key_bits, type_str, buf);
+ EVP_PKEY_free(public_key);
+
+ if (key_type == EVP_PKEY_RSA && key_bits <= 1024) {
+ if (print_chain)
+ MSG_WARN("In 2014/5, browsers have been deprecating 1024-bit "
+ "RSA keys.\n");
+ }
+ }
+
+ if (cert) {
+ X509_NAME_oneline(X509_get_issuer_name(cert), buf, buflen);
+ buf[buflen-1] = '\0';
+ if (print_chain)
+ MSG("root: %s\n", buf);
+ }
+ }
+ return success;
+}
+
/******************** BEGINNING OF STUFF DERIVED FROM wget-1.16.3 */
#define ASTERISK_EXCLUDES_DOT /* mandated by rfc2818 */
@@ -728,8 +828,8 @@ static int Tls_examine_certificate(SSL *ssl, Server_t *srv,const char *host)
if (choice == 1){
ret = 0;
}
-
- } else if (Tls_check_cert_hostname(remote_cert, host, &choice)) {
+ } else if (Tls_check_cert_strength(ssl, srv, &choice) &&
+ Tls_check_cert_hostname(remote_cert, host, &choice)) {
/* Figure out if (and why) the remote system can't be trusted */
st = SSL_get_verify_result(ssl);
switch (st) {
@@ -902,13 +1002,17 @@ static int Tls_examine_certificate(SSL *ssl, Server_t *srv,const char *host)
}
dFree(title);
- if (choice == 2)
+ if (choice == -1) {
+ srv->cert_status = CERT_STATUS_CLEAN; /* no warning popups */
+ } else if (choice == 1) {
+ srv->cert_status = CERT_STATUS_USER_ACCEPTED; /* clicked Continue */
+ } else {
+ /* 2 for Cancel, or 0 when window closed. Treating 0 as meaning 'No' is
+ * probably not exactly correct, but adding complexity to handle this
+ * obscure case does not seem justifiable.
+ */
srv->cert_status = CERT_STATUS_BAD;
- else if (choice == -1)
- srv->cert_status = CERT_STATUS_CLEAN;
- else
- srv->cert_status = CERT_STATUS_USER_ACCEPTED;
-
+ }
return ret;
}
@@ -949,82 +1053,6 @@ static void Tls_close_by_key(int connkey)
}
}
-static void Tls_print_cert_chain(SSL *ssl)
-{
- STACK_OF(X509) *sk = SSL_get_peer_cert_chain(ssl);
-
- if (sk) {
- const uint_t buflen = 4096;
- char buf[buflen];
- int rc, i, n = sk_X509_num(sk);
- X509 *cert = NULL;
- EVP_PKEY *public_key;
- int key_type, key_bits;
- const char *type_str;
- BIO *b;
-
- for (i = 0; i < n; i++) {
- cert = sk_X509_value(sk, i);
- public_key = X509_get_pubkey(cert);
-
- /* We are trying to find a way to get the hash function used
- * with a certificate. This way, which is not very pleasant, puts
- * a string such as "sha256WithRSAEncryption" in our buffer and we
- * then trim off the "With..." part.
- */
- b = BIO_new(BIO_s_mem());
- rc = i2a_ASN1_OBJECT(b, cert->sig_alg->algorithm);
-
- if (rc > 0) {
- rc = BIO_gets(b, buf, buflen);
- }
- if (rc <= 0) {
- strcpy(buf, "(unknown)");
- buf[buflen-1] = '\0';
- } else {
- char *s = strstr(buf, "With");
-
- if (s) {
- *s = '\0';
- if (!strcmp(buf, "sha1")) {
- MSG_WARN("In 2015, browsers have begun to deprecate SHA1 "
- "certificates.\n");
- } else if (!strncmp(buf, "md", 2)) {
- MSG_ERR("Browsers stopped accepting MD5 certificates around "
- "2012.\n");
- }
- }
- }
- BIO_free(b);
- MSG("%s ", buf);
-
-
- key_type = EVP_PKEY_type(public_key->type);
- type_str = key_type == EVP_PKEY_RSA ? "RSA" :
- key_type == EVP_PKEY_DSA ? "DSA" :
- key_type == EVP_PKEY_DH ? "DH" :
- key_type == EVP_PKEY_EC ? "EC" : "???";
- key_bits = EVP_PKEY_bits(public_key);
- X509_NAME_oneline(X509_get_subject_name(cert), buf, buflen);
- buf[buflen-1] = '\0';
- MSG("%d-bit %s: %s\n", key_bits, type_str, buf);
- EVP_PKEY_free(public_key);
-
- if (key_type == EVP_PKEY_RSA && key_bits <= 1024) {
- /* TODO: Gather warnings into one popup. */
- MSG_WARN("In 2014/5, browsers have been deprecating 1024-bit RSA "
- "keys.\n");
- }
- }
-
- if (cert) {
- X509_NAME_oneline(X509_get_issuer_name(cert), buf, buflen);
- buf[buflen-1] = '\0';
- MSG("root: %s\n", buf);
- }
- }
-}
-
/*
* Connect, set a callback if it's still not completed. If completed, check
* the certificate and report back to http.
@@ -1093,14 +1121,13 @@ static void Tls_connect(int fd, int connkey)
Tls_servers_by_url_cmp);
if (srv->cert_status == CERT_STATUS_RECEIVING) {
- /* Making first connection with the server. Show some information. */
+ /* Making first connection with the server. Show cipher used. */
SSL *ssl = conn->ssl;
const char *version = SSL_get_version(ssl);
const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
MSG("%s: %s, cipher %s\n", URL_AUTHORITY(conn->url), version,
SSL_CIPHER_get_name(cipher));
- Tls_print_cert_chain(ssl);
}
if (srv->cert_status == CERT_STATUS_USER_ACCEPTED ||