45#include "../dialog.hh"
51#include <openssl/ssl.h>
52#include <openssl/rand.h>
53#include <openssl/err.h>
54#include <openssl/x509v3.h>
55#include <openssl/crypto.h>
57#define CERT_STATUS_NONE 0
58#define CERT_STATUS_RECEIVING 1
59#define CERT_STATUS_CLEAN 2
60#define CERT_STATUS_BAD 3
61#define CERT_STATUS_USER_ACCEPTED 4
104 const FdMapEntry_t *e = v1;
106 return (fd != e->fd);
111 FdMapEntry_t *e =
dNew0(FdMapEntry_t, 1);
113 e->connkey = connkey;
116 MSG_ERR(
"TLS FD ENTRY ALREADY FOUND FOR %d\n", e->fd);
136 MSG(
"TLS FD ENTRY NOT FOUND FOR %d\n", fd);
165 Conn_t *conn =
dNew0(Conn_t, 1);
169 conn->connecting =
TRUE;
170 conn->in_connect =
FALSE;
171 conn->do_shutdown =
TRUE;
185 if (where & SSL_CB_ALERT) {
186 const char *str = SSL_alert_desc_string_long(ret);
188 if (strcmp(str,
"close notify"))
189 MSG(
"TLS ALERT on %s: %s\n", (where & SSL_CB_READ) ?
"read" :
"write",
211 static const char *
const ca_files[] = {
212 "/etc/ssl/certs/ca-certificates.crt",
213 "/etc/pki/tls/certs/ca-bundle.crt",
214 "/usr/share/ssl/certs/ca-bundle.crt",
215 "/usr/local/share/certs/ca-root.crt",
217 "/etc/openssl/certs/ca-certificates.crt",
221 static const char *
const ca_paths[] = {
226 X509_STORE *store = SSL_CTX_get_cert_store(
ssl_context);
227 X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
229 for (u = 0; u <
sizeof(ca_files) /
sizeof(ca_files[0]); u++) {
231 X509_LOOKUP_load_file(lookup, ca_files[u], X509_FILETYPE_PEM);
234 lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
235 for (u = 0; u <
sizeof(ca_paths)/
sizeof(ca_paths[0]); u++) {
237 X509_LOOKUP_add_dir(lookup, ca_paths[u], X509_FILETYPE_PEM);
241 X509_LOOKUP_add_dir(lookup, userpath, X509_FILETYPE_PEM);
245 while(ERR_get_error())
253 const char *ver = OpenSSL_version(OPENSSL_VERSION);
254 if (snprintf(buf, n,
"%s", ver) >= n)
258 char *sp1 = strchr(ossl,
' ');
261 char *sp2 = strchr(ossl,
' ');
275 MSG(
"TLS library: %s\n", OpenSSL_version(OPENSSL_VERSION));
277 SSL_load_error_strings();
278 if (RAND_status() != 1) {
282 MSG_ERR(
"Disabling HTTPS: Insufficient entropy for openssl.\n");
289 MSG_ERR(
"Disabling HTTPS: Error creating SSL context.\n");
301 "ALL:!aNULL:!eNULL:!LOW:!EXPORT40:!RC4");
307 SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_COMPRESSION);
310 SSL_CTX_set_verify(
ssl_context, SSL_VERIFY_NONE, NULL);
333 snprintf(buf, 4096,
"%s/.dillo/certs/",
dGethomedir());
337 snprintf(buf, 4096,
"%s/.dillo/certs/%lx.%u",
345 MSG(
"Unable to open cert save file in home dir\n");
348 PEM_write_X509(fp, cert);
350 MSG(
"Wrote certificate\n");
369 const Server_t *s1 = (
const Server_t *)v1, *s2 = (
const Server_t *)v2;
373 cmp = s1->port - s2->port;
381 const Server_t *s = (
const Server_t *)v1;
415 s =
dNew(Server_t, 1);
466 STACK_OF(X509) *sk = SSL_get_peer_cert_chain(ssl);
469 const uint_t buflen = 4096;
471 int rc, i, n = sk_X509_num(sk);
473 int key_type, key_bits;
474 const char *type_str;
477 for (i = 0; i < n; i++) {
478 cert = sk_X509_value(sk, i);
485 b = BIO_new(BIO_s_mem());
486 const ASN1_OBJECT *algorithm;
487 X509_ALGOR_get0(&algorithm, NULL, NULL, X509_get0_tbs_sigalg(cert));
488 rc = i2a_ASN1_OBJECT(b, algorithm);
491 rc = BIO_gets(b, buf, buflen);
494 strcpy(buf,
"(unknown)");
495 buf[buflen-1] =
'\0';
497 char *s = strstr(buf,
"With");
501 if (!strcmp(buf,
"sha1")) {
503 MSG_WARN(
"In 2015, browsers have begun to deprecate SHA1 "
505 }
else if (!strncmp(buf,
"md", 2) && success ==
TRUE) {
506 const char *msg =
"A certificate in the chain uses the MD5 "
507 "signature algorithm, which is too weak "
510 "Continue",
"Cancel", NULL);
519 MSG(
" %d: %s ", i, buf);
521 EVP_PKEY *public_key = X509_get_pubkey(cert);
524 if (public_key == NULL) {
528 const char *err = ERR_error_string(ERR_get_error(), NULL);
529 MSG(
"Cannot parse public key: %s\n", err);
534 "The public key of a certificate in the chain cannot be decoded. "
535 "Cannot trust remote server, continue?";
538 "Continue",
"Cancel", NULL);
546#if OPENSSL_VERSION_NUMBER < 0x30000000L
547 key_type = EVP_PKEY_type(EVP_PKEY_id(public_key));
549 key_type = EVP_PKEY_type(EVP_PKEY_get_id(public_key));
551 type_str = key_type == EVP_PKEY_RSA ?
"RSA" :
552 key_type == EVP_PKEY_DSA ?
"DSA" :
553 key_type == EVP_PKEY_DH ?
"DH" :
554 key_type == EVP_PKEY_EC ?
"EC" :
"???";
555 key_bits = EVP_PKEY_bits(public_key);
556 X509_NAME_oneline(X509_get_subject_name(cert), buf, buflen);
557 buf[buflen-1] =
'\0';
559 MSG(
"%d-bit %s: %s\n", key_bits, type_str, buf);
560 EVP_PKEY_free(public_key);
562 if (key_type == EVP_PKEY_RSA && key_bits <= 1024) {
564 MSG_WARN(
"In 2014/5, browsers have been deprecating 1024-bit "
570 X509_NAME_oneline(X509_get_issuer_name(cert), buf, buflen);
571 buf[buflen-1] =
'\0';
573 MSG(
" root: %s\n", buf);
581#define ASTERISK_EXCLUDES_DOT
600 const char *p = pattern, *n = string;
602 for (; (c =
dTolower (*p++)) !=
'\0'; n++)
607 for (; *n !=
'\0'; n++)
610#ifdef ASTERISK_EXCLUDES_DOT
633 if (cert == NULL || host == NULL)
637 GENERAL_NAMES *subjectAltNames;
639 char common_name[256];
651 subjectAltNames = X509_get_ext_d2i (cert, NID_subject_alt_name, NULL, NULL);
658 dStr_sprintf(err,
"Hostname %s does not match any of certificate's "
659 "Subject Alternative Names: ", host);
663 ASN1_OCTET_STRING *host_in_octet_string = a2i_IPADDRESS (host);
665 int numaltnames = sk_GENERAL_NAME_num (subjectAltNames);
667 for (i=0; i < numaltnames; i++)
669 const GENERAL_NAME *name =
670 sk_GENERAL_NAME_value (subjectAltNames, i);
673 if (host_in_octet_string)
675 if (name->type == GEN_IPADD)
680 alt_name_checked =
TRUE;
681 if (!ASN1_STRING_cmp (host_in_octet_string,
687 else if (name->type == GEN_DNS)
691 unsigned char *name_in_utf8 = NULL;
694 alt_name_checked =
TRUE;
696 if (0 <= ASN1_STRING_to_UTF8 (&name_in_utf8, name->d.dNSName))
700 (strlen ((
char *)name_in_utf8) ==
701 (
size_t)ASN1_STRING_length (name->d.dNSName)))
703 OPENSSL_free (name_in_utf8);
707 OPENSSL_free (name_in_utf8);
712 sk_GENERAL_NAME_pop_free(subjectAltNames, GENERAL_NAME_free);
713 if (host_in_octet_string)
714 ASN1_OCTET_STRING_free(host_in_octet_string);
716 if (alt_name_checked ==
TRUE && i >= numaltnames)
720 err->
str,
"Continue",
"Cancel", NULL);
735 if (alt_name_checked ==
FALSE)
738 X509_NAME *xname = X509_get_subject_name(cert);
739 common_name[0] =
'\0';
740 X509_NAME_get_text_by_NID (xname, NID_commonName, common_name,
741 sizeof (common_name));
746 msg =
dStrconcat(
"Certificate common name ", common_name,
747 " doesn't match requested host name ", host, NULL);
749 msg,
"Continue",
"Cancel", NULL);
773 X509_NAME_ENTRY *xentry;
779 j = X509_NAME_get_index_by_NID (xname, NID_commonName, i);
785 xentry = X509_NAME_get_entry(xname,i);
786 sdata = X509_NAME_ENTRY_get_data(xentry);
787 if (strlen (common_name) != (
size_t)ASN1_STRING_length (sdata))
790 msg =
dStrconcat(
"Certificate common name is invalid (contains a NUL "
791 "character). This may be an indication that the "
792 "host is not who it claims to be -- that is, not "
793 "the real ", host, NULL);
795 msg,
"Continue",
"Cancel", NULL);
824 STACK_OF(X509) *sk = SSL_get_peer_cert_chain(ssl);
826 return sk ? sk_X509_value(sk, sk_X509_num(sk) - 1) : NULL;
832 X509_NAME_oneline(X509_get_issuer_name(cert), buf, buflen);
834 strcpy(buf,
"(unknown)");
835 buf[buflen-1] =
'\0';
841 ASN1_TIME *exp_date = X509_get_notAfter(cert);
842 BIO *b = BIO_new(BIO_s_mem());
843 int rc = ASN1_TIME_print(b, exp_date);
846 rc = BIO_gets(b, buf, buflen);
849 strcpy(buf,
"(unknown)");
850 buf[buflen-1] =
'\0';
864 const uint_t buflen = 4096;
865 char buf[buflen], *cn, *msg;
866 int choice = -1, ret = -1;
867 char *title =
dStrconcat(
"Dillo TLS security warning: ",srv->hostname,NULL);
869#if OPENSSL_VERSION_NUMBER < 0x30000000L
870 remote_cert = SSL_get_peer_certificate(ssl);
873 remote_cert = SSL_get1_peer_certificate(ssl);
875 if (remote_cert == NULL){
878 "The remote system is not presenting a certificate. "
879 "This site cannot be trusted. Sending data is not safe.",
880 "Continue",
"Cancel", NULL);
889 st = SSL_get_verify_result(ssl);
894 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
898 X509_NAME *subject_name = X509_get_subject_name(remote_cert);
899 char *subj = X509_NAME_oneline(subject_name, NULL, 0);
900 if ((cn = strstr(subj,
"/CN=")) == NULL) {
901 strcpy(buf,
"(no CN given)");
907 if ((cn_end = strstr(cn,
"/")) == NULL )
908 cn_end = cn + strlen(cn);
910 strncpy(buf, cn, (
size_t) (cn_end - cn));
911 buf[cn_end - cn] =
'\0';
914 msg =
dStrconcat(
"The remote certificate is self-signed and "
915 "untrusted. For address: ", buf, NULL);
917 msg,
"Continue",
"Cancel",
"Save Certificate", NULL);
935 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
936 case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
938 "The issuer for the remote certificate cannot be found. "
939 "The authenticity of the remote certificate cannot be trusted.",
940 "Continue",
"Cancel", NULL);
947 case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
948 case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
949 case X509_V_ERR_CERT_SIGNATURE_FAILURE:
950 case X509_V_ERR_CRL_SIGNATURE_FAILURE:
952 "The remote certificate signature could not be read "
953 "or is invalid and should not be trusted",
954 "Continue",
"Cancel", NULL);
960 case X509_V_ERR_CERT_NOT_YET_VALID:
961 case X509_V_ERR_CRL_NOT_YET_VALID:
963 "Part of the remote certificate is not yet valid. "
964 "Certificates usually have a range of dates over which "
965 "they are to be considered valid, and the certificate "
966 "presented has a starting validity after today's date "
967 "You should be cautious about using this site",
968 "Continue",
"Cancel", NULL);
974 case X509_V_ERR_CERT_HAS_EXPIRED:
975 case X509_V_ERR_CRL_HAS_EXPIRED:
977 msg =
dStrconcat(
"The remote certificate expired on: ", buf,
978 ". This site can no longer be trusted.", NULL);
986 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
987 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
988 case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
989 case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
991 "There was an error in the certificate presented. "
992 "Some of the certificate data was improperly formatted "
993 "making it impossible to determine if the certificate "
994 "is valid. You should not trust this certificate.",
995 "Continue",
"Cancel", NULL);
1000 case X509_V_ERR_INVALID_CA:
1001 case X509_V_ERR_INVALID_PURPOSE:
1002 case X509_V_ERR_CERT_UNTRUSTED:
1003 case X509_V_ERR_CERT_REJECTED:
1004 case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
1006 "One of the certificates in the chain is being used "
1007 "incorrectly (possibly due to configuration problems "
1008 "with the remote system. The connection should not "
1010 "Continue",
"Cancel", NULL);
1015 case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
1016 case X509_V_ERR_AKID_SKID_MISMATCH:
1017 case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
1019 "Some of the information presented by the remote system "
1020 "does not match other information presented. "
1021 "This may be an attempt to eavesdrop on communications",
1022 "Continue",
"Cancel", NULL);
1027 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
1029 msg =
dStrconcat(
"Certificate chain led to a self-signed certificate "
1030 "instead of a trusted root. Name: ", buf , NULL);
1037 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
1039 msg =
dStrconcat(
"The issuer certificate of an untrusted certificate "
1040 "cannot be found. Issuer: ", buf, NULL);
1049 "The remote certificate cannot be verified (code %ld)", st);
1051 buf,
"Continue",
"Cancel", NULL);
1057 X509_free(remote_cert);
1064 }
else if (choice == 1) {
1095 _MSG(
"Tls_close_by_key: connkey=%d\n", connkey);
1101 if (c->connecting) {
1105 if (c->do_shutdown && !SSL_in_init(c->ssl)) {
1109 if (SSL_shutdown(c->ssl) < 0) {
1111 for (
int e = ERR_get_error(); e; e = ERR_get_error()) {
1112 MSG(
"SSL_shutdown() failed with %s for url: %s\n",
1113 ERR_error_string(e, NULL),
URL_STR(c->url));
1117 MSG(
"Tls_close_by_key: Avoiding SSL shutdown for: %s\n",
URL_STR(c->url));
1138 _MSG(
"Tls_connect: fd=%d connkey=%d\n", fd, connkey);
1141 MSG(
"Tls_connect: conn for fd %d not valid\n", fd);
1145 if (conn->in_connect) {
1146 MSG(
"Tls_connect: nested call to Tls_connect(), aborting\n");
1149 conn->in_connect =
TRUE;
1152 if (ERR_peek_error()) {
1154 while ((err = ERR_get_error())) {
1155 MSG(
"Tls_connect: queued error: %s\n",
1156 ERR_error_string(err, NULL));
1161 ret = SSL_connect(conn->ssl);
1166 int err1_ret = SSL_get_error(conn->ssl, ret);
1167 if (err1_ret == SSL_ERROR_WANT_READ ||
1168 err1_ret == SSL_ERROR_WANT_WRITE) {
1171 _MSG(
"iowatching fd %d for tls -- want %s\n", fd,
1172 err1_ret == SSL_ERROR_WANT_READ ?
"read" :
"write");
1176 }
else if (err1_ret == SSL_ERROR_SYSCALL || err1_ret == SSL_ERROR_SSL) {
1181 conn->do_shutdown =
FALSE;
1183 unsigned long err2_ret = ERR_get_error();
1187 MSG(
"SSL_connect() failed: %s\n",
1188 ERR_error_string(err2_ret, NULL));
1189 }
while ((err2_ret = ERR_get_error()));
1193 MSG(
"TLS connect error: \"an EOF was observed that violates "
1194 "the protocol\"\n");
1199 }
else if (ret == -1) {
1205 assert(errno != EAGAIN && errno != EINTR);
1207 MSG_ERR(
"According to the man page for SSL_get_error(), this "
1208 "was not a possibility (ret %d).\n", ret);
1212 MSG(
"SSL_get_error() returned %d on a connect.\n", err1_ret);
1220 SSL *ssl = conn->ssl;
1221 const char *version = SSL_get_version(ssl);
1222 const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
1225 SSL_CIPHER_get_name(cipher));
1243 conn->connecting =
FALSE;
1245 conn->in_connect =
FALSE;
1253 MSG(
"Connection disappeared. Too long with a popup popped up?\n");
1258 conn->in_connect =
FALSE;
1271 _MSG(
"a_Tls_openssl_connect: fd=%d url=%s\n", fd,
URL_STR(url));
1284 if (ERR_peek_error()) {
1286 while ((err = ERR_get_error())) {
1287 MSG(
"a_Tls_openssl_connect: queued error: %s\n",
1288 ERR_error_string(err, NULL));
1294 unsigned long err_ret = ERR_get_error();
1296 MSG(
"SSL_new() failed: %s\n", ERR_error_string(err_ret, NULL));
1297 }
while ((err_ret = ERR_get_error()));
1302 if (success && !SSL_set_fd(ssl, fd)) {
1303 unsigned long err_ret = ERR_get_error();
1305 MSG(
"SSL_set_fd() failed: %s\n", ERR_error_string(err_ret, NULL));
1306 }
while ((err_ret = ERR_get_error()));
1313#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1318 SSL_set_tlsext_host_name(ssl,
URL_HOST(url));
1343 SSL *ssl = conn->ssl;
1344 int err1_ret = SSL_get_error(ssl, ret);
1345 if (err1_ret == SSL_ERROR_NONE) {
1348 }
else if (err1_ret == SSL_ERROR_ZERO_RETURN) {
1351 }
else if (err1_ret == SSL_ERROR_WANT_READ || err1_ret == SSL_ERROR_WANT_WRITE) {
1354 }
else if (err1_ret == SSL_ERROR_SYSCALL || err1_ret == SSL_ERROR_SSL) {
1355 conn->do_shutdown =
FALSE;
1356 unsigned long err2_ret = ERR_get_error();
1359 MSG(
"%s failed: %s\n", where, ERR_error_string(err2_ret, NULL));
1360 }
while ((err2_ret = ERR_get_error()));
1363 const char *which = err1_ret == SSL_ERROR_SYSCALL ?
"SYSCALL" :
"SSL";
1364 MSG(
"%s failed: SSL_ERROR_%s\n", where, which);
1370 MSG(
"%s failed: SSL_get_error() returned %d\n", where, err1_ret);
1380 Conn_t *c = (Conn_t*)conn;
1389 Conn_t *c = (Conn_t*)conn;
1409 for (i = 0; i < n; i++) {
1424 for (i = 0; i < n; i++) {
int a_Dialog_choice(const char *title, const char *msg,...)
Make a question-dialog with a question and alternatives.
char * dStrconcat(const char *s1,...)
Concatenate a NULL-terminated list of strings.
void dList_insert_sorted(Dlist *lp, void *data, dCompareFunc func)
Insert an element into a sorted list.
int dStrAsciiCasecmp(const char *s1, const char *s2)
void dStr_sprintfa(Dstr *ds, const char *format,...)
Printf-like function that appends.
char * dStrdup(const char *s)
Dlist * dList_new(int size)
Create a new empty list.
int dList_length(Dlist *lp)
For completing the ADT.
void * dList_nth_data(Dlist *lp, int n0)
Return the nth data item, NULL when not found or 'n0' is out of range.
void dList_remove_fast(Dlist *lp, const void *data)
Remove a data item without preserving order.
void dStr_free(Dstr *ds, int all)
Free a dillo string.
int dClose(int fd)
Close a FD handling EINTR.
void dStr_sprintf(Dstr *ds, const char *format,...)
Printf-like function.
Dstr * dStr_new(const char *s)
Create a new string.
void dList_append(Dlist *lp, void *data)
Append a data item to the list.
void * dList_find_sorted(Dlist *lp, const void *data, dCompareFunc func)
Search a sorted list.
void dList_free(Dlist *lp)
Free a list (not its elements)
void * dList_find_custom(Dlist *lp, const void *data, dCompareFunc func)
Search a data item using a custom function.
char * dGethomedir(void)
Return the home directory in a static string (don't free)
#define dNew0(type, count)
static int dTolower(unsigned char c)
#define dNew(type, count)
void a_Http_connect_done(int fd, bool_t success)
void a_IOwatch_add_fd(int fd, int when, Fl_FD_Handler Callback, void *usr_data=0)
Hook a Callback for a certain activities in a FD.
void a_IOwatch_remove_fd(int fd, int when)
Remove a Callback for a given FD (or just remove some events)
void a_Klist_remove(Klist_t *Klist, int Key)
Remove data by Key.
void * a_Klist_get_data(Klist_t *Klist, int Key)
Return the data pointer for a given Key (or NULL if not found)
int a_Klist_insert(Klist_t **Klist, void *Data)
Insert a data pointer and return a key for it.
#define TLS_CONNECT_NEVER
#define TLS_CONNECT_READY
#define TLS_CONNECT_NOT_YET
void a_Tls_openssl_reset_server_state(const DilloUrl *url)
static int Tls_examine_certificate(SSL *ssl, Server_t *srv)
static void Tls_fd_map_remove_all(void)
static void Tls_fd_map_remove_entry(int fd)
static void Tls_get_issuer_name(X509 *cert, char *buf, uint_t buflen)
static void Tls_servers_freeall(void)
int a_Tls_openssl_read(void *conn, void *buf, size_t len)
static X509 * Tls_get_end_of_chain(SSL *ssl)
static int Tls_servers_cmp(const void *v1, const void *v2)
static void Tls_info_cb(const SSL *ssl, int where, int ret)
void * a_Tls_openssl_connection(int fd)
static int Tls_handle_error(Conn_t *conn, int ret, const char *where)
int a_Tls_openssl_connect_ready(const DilloUrl *url)
#define CERT_STATUS_USER_ACCEPTED
static void Tls_fd_map_add_entry(int fd, int connkey)
static int Tls_fd_map_cmp(const void *v1, const void *v2)
static int Tls_user_said_no(const DilloUrl *url)
static int Tls_conn_new(int fd, const DilloUrl *url, SSL *ssl)
static void Tls_close_by_key(int connkey)
#define CERT_STATUS_RECEIVING
void a_Tls_openssl_init(void)
static void Tls_get_expiration_str(X509 *cert, char *buf, uint_t buflen)
#define CERT_STATUS_CLEAN
static SSL_CTX * ssl_context
static int Tls_servers_by_url_cmp(const void *v1, const void *v2)
static void Tls_connect_cb(int fd, void *vconnkey)
static void Tls_connect(int fd, int connkey)
void a_Tls_openssl_close_by_fd(int fd)
const char * a_Tls_openssl_version(char *buf, int n)
static bool_t Tls_check_cert_hostname(X509 *cert, const char *host, int *choice)
void a_Tls_openssl_connect(int fd, const DilloUrl *url)
static int Tls_save_certificate_home(X509 *cert)
static int Tls_cert_status(const DilloUrl *url)
static void Tls_load_certificates(void)
static Klist_t * conn_list
static bool_t Tls_check_cert_strength(SSL *ssl, Server_t *srv, int *choice)
int a_Tls_openssl_certificate_is_clean(const DilloUrl *url)
void a_Tls_openssl_freeall(void)
static bool_t pattern_match(const char *pattern, const char *string)
int a_Tls_openssl_write(void *conn, void *buf, size_t len)
void a_Url_free(DilloUrl *url)
Free a DilloUrl.
int a_Url_host_type(const char *host)
What type of host is this?
DilloUrl * a_Url_dup(const DilloUrl *ori)
Duplicate a Url structure.