[project @ 2006-02-23 15:06:53 by jmb]

Handle invalid SSL certificates better - UI still needs work.
Modify fetch callback data parameter type to remove compiler warnings.
Constify things.
Lose global ssl_verify_certificates option.
Fix issue when closing a dialog without input focus.

svn path=/import/netsurf/; revision=2092
This commit is contained in:
John Mark Bell 2006-02-23 15:06:54 +00:00
parent 70fbf97688
commit d4d3e5ee1c
23 changed files with 744 additions and 66 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

154
content/certdb.c Normal file
View File

@ -0,0 +1,154 @@
/*
* This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2006 John M Bell <jmb202@ecs.soton.ac.uk>
*/
/** \file
* HTTPS certificate verification database (implementation)
*
* URLs of servers with invalid SSL certificates are stored hashed by
* canonical root URI (absoluteURI with no abs_path part - see RFC 2617)
* for fast lookup.
*/
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "netsurf/utils/config.h"
#include "netsurf/content/certdb.h"
#define NDEBUG
#include "netsurf/utils/log.h"
#include "netsurf/utils/url.h"
#define HASH_SIZE 77
#ifdef WITH_SSL
struct cert_entry {
char *root_url; /**< Canonical root URL */
struct cert_entry *next;
};
static struct cert_entry *cert_table[HASH_SIZE];
static unsigned int certdb_hash(const char *s);
static void certdb_dump(void);
/**
* Insert an entry into the database
*
* \param url Absolute URL to resource
* \return true on success, false on error.
*/
bool certdb_insert(const char *url)
{
char *canon;
unsigned int hash;
struct cert_entry *entry;
url_func_result ret;
assert(url);
LOG(("Adding '%s'", url));
ret = url_canonical_root(url, &canon);
if (ret != URL_FUNC_OK)
return false;
LOG(("'%s'", canon));
hash = certdb_hash(canon);
/* Look for existing entry */
for (entry = cert_table[hash]; entry; entry = entry->next) {
if (strcmp(entry->root_url, canon) == 0) {
free(canon);
return true;
}
}
/* not found => create new */
entry = malloc(sizeof(struct cert_entry));
if (!entry) {
free(canon);
return false;
}
entry->root_url = canon;
entry->next = cert_table[hash];
cert_table[hash] = entry;
return true;
}
/**
* Retrieve certificate details for an URL from the database
*
* \param url Absolute URL to consider
* \return certificate details, or NULL if none found.
*/
const char *certdb_get(const char *url)
{
char *canon;
struct cert_entry *entry;
url_func_result ret;
assert(url);
LOG(("Searching for '%s'", url));
certdb_dump();
ret = url_canonical_root(url, &canon);
if (ret != URL_FUNC_OK)
return NULL;
/* Find cert entry */
for (entry = cert_table[certdb_hash(canon)]; entry;
entry = entry->next) {
if (strcmp(entry->root_url, canon) == 0) {
free(canon);
return entry->root_url;
}
}
return NULL;
}
/**
* Hash function for keys.
*/
unsigned int certdb_hash(const char *s)
{
unsigned int i, z = 0, m;
if (!s)
return 0;
m = strlen(s);
for (i = 0; i != m && s[i]; i++)
z += s[i] & 0x1f; /* lower 5 bits, case insensitive */
return z % HASH_SIZE;
}
/**
* Dump contents of auth db to stderr
*/
void certdb_dump(void)
{
#ifndef NDEBUG
int i;
struct cert_entry *e;
for (i = 0; i != HASH_SIZE; i++) {
LOG(("%d:", i));
for (e = cert_table[i]; e; e = e->next) {
LOG(("\t%s", e->root_url));
}
}
#endif
}
#endif

18
content/certdb.h Normal file
View File

@ -0,0 +1,18 @@
/*
* This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2006 John M Bell <jmb202@ecs.soton.ac.uk>
*/
/** \file
* HTTPS certificate verification database (interface)
*/
#ifndef _NETSURF_CONTENT_CERTDB_H_
#define _NETSURF_CONTENT_CERTDB_H_
bool certdb_insert(const char *url);
const char *certdb_get(const char *url);
#endif

View File

@ -139,6 +139,7 @@ struct cache_data;
struct content;
struct fetch;
struct object_params;
struct ssl_cert_info;
/** Used in callbacks to indicate what has occurred. */
@ -154,7 +155,10 @@ typedef enum {
CONTENT_MSG_NEWPTR, /**< address of structure has changed */
CONTENT_MSG_REFRESH, /**< wants refresh */
#ifdef WITH_AUTH
CONTENT_MSG_AUTH /**< authentication required */
CONTENT_MSG_AUTH, /**< authentication required */
#endif
#ifdef WITH_SSL
CONTENT_MSG_SSL /**< SSL cert verify failed */
#endif
} content_msg;
@ -175,8 +179,13 @@ union content_msg_data {
/** Dimensions to plot object with. */
float object_width, object_height;
} redraw;
char *auth_realm; /**< Realm, for CONTENT_MSG_AUTH. */
const char *auth_realm; /**< Realm, for CONTENT_MSG_AUTH. */
int delay; /**< Minimum delay, for CONTENT_MSG_REFRESH */
struct {
/** Certificate chain (certs[0] == server) */
const struct ssl_cert_info *certs;
unsigned long num; /**< Number of certs in chain */
} ssl;
};
/** Linked list of users of a content. */

View File

@ -31,9 +31,15 @@
#endif
#include "curl/curl.h"
#include "netsurf/utils/config.h"
#ifdef WITH_SSL
#include "openssl/ssl.h"
#endif
#ifdef WITH_AUTH
#include "netsurf/content/authdb.h"
#endif
#ifdef WITH_SSL
#include "netsurf/content/certdb.h"
#endif
#include "netsurf/content/fetch.h"
#include "netsurf/desktop/options.h"
#include "netsurf/render/form.h"
@ -46,10 +52,18 @@
bool fetch_active; /**< Fetches in progress, please call fetch_poll(). */
#ifdef WITH_SSL
/** SSL certificate info */
struct cert_info {
X509 *cert; /**< Pointer to certificate */
long err; /**< OpenSSL error code */
};
#endif
/** Information for a single fetch. */
struct fetch {
CURL * curl_handle; /**< cURL handle if being fetched, or 0. */
void (*callback)(fetch_msg msg, void *p, const char *data,
void (*callback)(fetch_msg msg, void *p, const void *data,
unsigned long size);
/**< Callback function. */
bool had_headers; /**< Headers have been processed. */
@ -70,6 +84,10 @@ struct fetch {
struct cache_data cachedata; /**< Cache control data */
time_t last_modified; /**< If-Modified-Since time */
time_t file_etag; /**< ETag for local objects */
#ifdef WITH_SSL
#define MAX_CERTS 10
struct cert_info cert_data[MAX_CERTS]; /**< HTTPS certificate data */
#endif
struct fetch *queue_prev; /**< Previous fetch for this host. */
struct fetch *queue_next; /**< Next fetch for this host. */
struct fetch *prev; /**< Previous active fetch in ::fetch_list. */
@ -86,6 +104,9 @@ static char fetch_progress_buffer[256]; /**< Progress buffer for cURL */
static char fetch_proxy_userpwd[100]; /**< Proxy authentication details. */
static CURLcode fetch_set_options(struct fetch *f);
#ifdef WITH_SSL
static CURLcode fetch_sslctxfun(CURL *curl_handle, SSL_CTX *sslctx, void *p);
#endif
static void fetch_free(struct fetch *f);
static void fetch_stop(struct fetch *f);
static void fetch_done(CURL *curl_handle, CURLcode result);
@ -98,6 +119,10 @@ static size_t fetch_curl_header(char *data, size_t size, size_t nmemb,
static bool fetch_process_headers(struct fetch *f);
static struct curl_httppost *fetch_post_convert(
struct form_successful_control *control);
#ifdef WITH_SSL
static int fetch_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx);
static int fetch_cert_verify_callback(X509_STORE_CTX *x509_ctx, void *parm);
#endif
/**
@ -148,14 +173,6 @@ void fetch_init(void)
if (option_ca_bundle)
SETOPT(CURLOPT_CAINFO, option_ca_bundle);
if (!option_ssl_verify_certificates) {
/* disable verification of SSL certificates.
* security? we've heard of it...
*/
SETOPT(CURLOPT_SSL_VERIFYPEER, 0L);
SETOPT(CURLOPT_SSL_VERIFYHOST, 0L);
}
return;
curl_easy_setopt_failed:
@ -207,7 +224,7 @@ void fetch_quit(void)
*/
struct fetch * fetch_start(char *url, char *referer,
void (*callback)(fetch_msg msg, void *p, const char *data,
void (*callback)(fetch_msg msg, void *p, const void *data,
unsigned long size),
void *p, bool only_2xx, char *post_urlenc,
struct form_successful_control *post_multipart, bool cookies,
@ -288,6 +305,9 @@ struct fetch * fetch_start(char *url, char *referer,
fetch->cachedata.last_modified = 0;
fetch->last_modified = 0;
fetch->file_etag = 0;
#ifdef WITH_SSL
memset(fetch->cert_data, 0, sizeof(fetch->cert_data));
#endif
fetch->queue_prev = 0;
fetch->queue_next = 0;
fetch->prev = 0;
@ -473,10 +493,37 @@ CURLcode fetch_set_options(struct fetch *f)
}
}
#ifdef WITH_SSL
if (certdb_get(f->url) != NULL) {
/* Disable certificate verification */
SETOPT(CURLOPT_SSL_VERIFYPEER, 0L);
SETOPT(CURLOPT_SSL_VERIFYHOST, 0L);
} else {
/* do verification */
SETOPT(CURLOPT_SSL_CTX_FUNCTION, fetch_sslctxfun);
SETOPT(CURLOPT_SSL_CTX_DATA, f);
}
#endif
return CURLE_OK;
}
#ifdef WITH_SSL
/**
* cURL SSL setup callback
*/
CURLcode fetch_sslctxfun(CURL *curl_handle, SSL_CTX *sslctx, void *parm)
{
SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, fetch_verify_callback);
SSL_CTX_set_cert_verify_callback(sslctx, fetch_cert_verify_callback,
parm);
return CURLE_OK;
}
#endif
/**
* Abort a fetch.
*/
@ -577,6 +624,10 @@ void fetch_stop(struct fetch *f)
void fetch_free(struct fetch *f)
{
#ifdef WITH_SSL
int i;
#endif
if (f->curl_handle)
curl_easy_cleanup(f->curl_handle);
free(f->url);
@ -590,6 +641,15 @@ void fetch_free(struct fetch *f)
if (f->post_multipart)
curl_formfree(f->post_multipart);
free(f->cachedata.etag);
#ifdef WITH_SSL
for (i = 0; i < MAX_CERTS && f->cert_data[i].cert; i++) {
f->cert_data[i].cert->references--;
if (f->cert_data[i].cert->references == 0)
X509_free(f->cert_data[i].cert);
}
#endif
free(f);
}
@ -641,13 +701,20 @@ void fetch_done(CURL *curl_handle, CURLcode result)
{
bool finished = false;
bool error = false;
#ifdef WITH_SSL
bool cert = false;
#endif
bool abort;
struct fetch *f;
void *p;
void (*callback)(fetch_msg msg, void *p, const char *data,
void (*callback)(fetch_msg msg, void *p, const void *data,
unsigned long size);
CURLcode code;
struct cache_data cachedata;
#ifdef WITH_SSL
struct cert_info certs[MAX_CERTS];
memset(certs, 0, sizeof(certs));
#endif
/* find the structure associated with this fetch */
code = curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &f);
@ -669,6 +736,14 @@ void fetch_done(CURL *curl_handle, CURLcode result)
/* CURLE_WRITE_ERROR occurs when fetch_curl_data
* returns 0, which we use to abort intentionally */
;
#ifdef WITH_SSL
else if (result == CURLE_SSL_PEER_CERTIFICATE ||
result == CURLE_SSL_CACERT) {
memcpy(certs, f->cert_data, sizeof(certs));
memset(f->cert_data, 0, sizeof(f->cert_data));
cert = true;
}
#endif
else
error = true;
@ -685,9 +760,91 @@ void fetch_done(CURL *curl_handle, CURLcode result)
if (abort)
; /* fetch was aborted: no callback */
else if (finished) {
callback(FETCH_FINISHED, p, (const char *)&cachedata, 0);
callback(FETCH_FINISHED, p, &cachedata, 0);
free(cachedata.etag);
}
#ifdef WITH_SSL
else if (cert) {
int i;
BIO *mem;
BUF_MEM *buf;
struct ssl_cert_info ssl_certs[MAX_CERTS];
for (i = 0; i < MAX_CERTS && certs[i].cert; i++) {
ssl_certs[i].version =
X509_get_version(certs[i].cert);
mem = BIO_new(BIO_s_mem());
ASN1_TIME_print(mem,
X509_get_notBefore(certs[i].cert));
BIO_get_mem_ptr(mem, &buf);
BIO_set_close(mem, BIO_NOCLOSE);
BIO_free(mem);
snprintf(ssl_certs[i].not_before,
min(sizeof ssl_certs[i].not_before,
(unsigned) buf->length + 1),
"%s", buf->data);
BUF_MEM_free(buf);
mem = BIO_new(BIO_s_mem());
ASN1_TIME_print(mem,
X509_get_notAfter(certs[i].cert));
BIO_get_mem_ptr(mem, &buf);
BIO_set_close(mem, BIO_NOCLOSE);
BIO_free(mem);
snprintf(ssl_certs[i].not_after,
min(sizeof ssl_certs[i].not_after,
(unsigned) buf->length + 1),
"%s", buf->data);
BUF_MEM_free(buf);
ssl_certs[i].sig_type =
X509_get_signature_type(certs[i].cert);
ssl_certs[i].serial =
ASN1_INTEGER_get(
X509_get_serialNumber(certs[i].cert));
mem = BIO_new(BIO_s_mem());
X509_NAME_print_ex(mem,
X509_get_issuer_name(certs[i].cert),
0, XN_FLAG_SEP_CPLUS_SPC |
XN_FLAG_DN_REV | XN_FLAG_FN_NONE);
BIO_get_mem_ptr(mem, &buf);
BIO_set_close(mem, BIO_NOCLOSE);
BIO_free(mem);
snprintf(ssl_certs[i].issuer,
min(sizeof ssl_certs[i].issuer,
(unsigned) buf->length + 1),
"%s", buf->data);
BUF_MEM_free(buf);
mem = BIO_new(BIO_s_mem());
X509_NAME_print_ex(mem,
X509_get_subject_name(certs[i].cert),
0, XN_FLAG_SEP_CPLUS_SPC |
XN_FLAG_DN_REV | XN_FLAG_FN_NONE);
BIO_get_mem_ptr(mem, &buf);
BIO_set_close(mem, BIO_NOCLOSE);
BIO_free(mem);
snprintf(ssl_certs[i].subject,
min(sizeof ssl_certs[i].subject,
(unsigned) buf->length + 1),
"%s", buf->data);
BUF_MEM_free(buf);
ssl_certs[i].cert_type =
X509_certificate_type(certs[i].cert,
X509_get_pubkey(certs[i].cert));
/* and clean up */
certs[i].cert->references--;
if (certs[i].cert->references == 0)
X509_free(certs[i].cert);
}
callback(FETCH_CERT_ERR, p, &ssl_certs, i);
}
#endif
else if (error)
callback(FETCH_ERROR, p, fetch_error_buffer, 0);
}
@ -1096,7 +1253,7 @@ bool fetch_can_fetch(const char *url)
*/
void fetch_change_callback(struct fetch *fetch,
void (*callback)(fetch_msg msg, void *p, const char *data,
void (*callback)(fetch_msg msg, void *p, const void *data,
unsigned long size),
void *p)
{
@ -1106,6 +1263,52 @@ void fetch_change_callback(struct fetch *fetch,
}
#ifdef WITH_SSL
/**
* OpenSSL Certificate verification callback
* Stores certificate details in fetch struct.
*/
int fetch_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
X509 *cert = X509_STORE_CTX_get_current_cert(x509_ctx);
int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
int err = X509_STORE_CTX_get_error(x509_ctx);
struct fetch *f = X509_STORE_CTX_get_app_data(x509_ctx);
/* save the certificate by incrementing the reference count and
* keeping a pointer */
if (depth < MAX_CERTS && !f->cert_data[depth].cert) {
f->cert_data[depth].cert = cert;
f->cert_data[depth].err = err;
cert->references++;
}
return preverify_ok;
}
/**
* OpenSSL certificate chain verification callback
* Verifies certificate chain, setting up context for fetch_verify_callback
*/
int fetch_cert_verify_callback(X509_STORE_CTX *x509_ctx, void *parm)
{
int ok;
/* Store fetch struct in context for verify callback */
ok = X509_STORE_CTX_set_app_data(x509_ctx, parm);
/* and verify the certificate chain */
if (ok)
ok = X509_verify_cert(x509_ctx);
return ok;
}
#endif
/**
* testing framework
*/

View File

@ -25,7 +25,10 @@ typedef enum {
FETCH_REDIRECT,
FETCH_NOTMODIFIED,
#ifdef WITH_AUTH
FETCH_AUTH
FETCH_AUTH,
#endif
#ifdef WITH_SSL
FETCH_CERT_ERR,
#endif
} fetch_msg;
@ -46,12 +49,25 @@ struct cache_data {
time_t last_modified; /**< Last-Modified: response header */
};
#ifdef WITH_SSL
struct ssl_cert_info {
long version; /**< Certificate version */
char not_before[32]; /**< Valid from date */
char not_after[32]; /**< Valid to date */
int sig_type; /**< Signature type */
long serial; /**< Serial number */
char issuer[256]; /**< Issuer details */
char subject[256]; /**< Subject details */
int cert_type; /**< Certificate type */
};
#endif
extern bool fetch_active;
extern CURLM *fetch_curl_multi;
void fetch_init(void);
struct fetch * fetch_start(char *url, char *referer,
void (*callback)(fetch_msg msg, void *p, const char *data,
void (*callback)(fetch_msg msg, void *p, const void *data,
unsigned long size),
void *p, bool only_2xx, char *post_urlenc,
struct form_successful_control *post_multipart,
@ -63,7 +79,7 @@ const char *fetch_filetype(const char *unix_path);
char *fetch_mimetype(const char *ro_path);
bool fetch_can_fetch(const char *url);
void fetch_change_callback(struct fetch *fetch,
void (*callback)(fetch_msg msg, void *p, const char *data,
void (*callback)(fetch_msg msg, void *p, const void *data,
unsigned long size),
void *p);

View File

@ -33,13 +33,13 @@
static char error_page[1000];
static regex_t re_content_type;
static void fetchcache_callback(fetch_msg msg, void *p, const char *data,
static void fetchcache_callback(fetch_msg msg, void *p, const void *data,
unsigned long size);
static char *fetchcache_parse_type(const char *s, char **params[]);
static void fetchcache_error_page(struct content *c, const char *error);
static void fetchcache_cache_update(struct content *c,
const struct cache_data *data);
static void fetchcache_notmodified(struct content *c, const char *data);
static void fetchcache_notmodified(struct content *c, const void *data);
/**
@ -307,7 +307,7 @@ void fetchcache_go(struct content *content, char *referer,
* This is called when the status of a fetch changes.
*/
void fetchcache_callback(fetch_msg msg, void *p, const char *data,
void fetchcache_callback(fetch_msg msg, void *p, const void *data,
unsigned long size)
{
bool res;
@ -375,7 +375,7 @@ void fetchcache_callback(fetch_msg msg, void *p, const char *data,
break;
case FETCH_ERROR:
LOG(("FETCH_ERROR, '%s'", data));
LOG(("FETCH_ERROR, '%s'", (const char *)data));
c->fetch = 0;
if (c->no_error_pages) {
c->status = CONTENT_STATUS_ERROR;
@ -425,7 +425,7 @@ void fetchcache_callback(fetch_msg msg, void *p, const char *data,
#ifdef WITH_AUTH
case FETCH_AUTH:
/* data -> string containing the Realm */
LOG(("FETCH_AUTH, '%s'", data));
LOG(("FETCH_AUTH, '%s'", (const char *)data));
c->fetch = 0;
msg_data.auth_realm = data;
content_broadcast(c, CONTENT_MSG_AUTH, msg_data);
@ -434,6 +434,20 @@ void fetchcache_callback(fetch_msg msg, void *p, const char *data,
c->status = CONTENT_STATUS_ERROR;
break;
#endif
#ifdef WITH_SSL
case FETCH_CERT_ERR:
c->fetch = 0;
/* set the status to ERROR so that the content is
* destroyed in content_clean() */
c->status = CONTENT_STATUS_ERROR;
msg_data.ssl.certs = data;
msg_data.ssl.num = size;
content_broadcast(c, CONTENT_MSG_SSL, msg_data);
break;
#endif
default:
assert(0);
}
@ -597,7 +611,7 @@ void fetchcache_cache_update(struct content *c,
* Not modified callback handler
*/
void fetchcache_notmodified(struct content *c, const char *data)
void fetchcache_notmodified(struct content *c, const void *data)
{
struct content *fb;
union content_msg_data msg_data;

View File

@ -15,7 +15,7 @@
#ifdef WITH_AUTH
void gui_401login_open(struct browser_window *bw, struct content *c,
char *realm);
const char *realm);
#endif

View File

@ -60,7 +60,7 @@ static void browser_window_stop_throbber(struct browser_window *bw);
static void browser_window_set_status(struct browser_window *bw,
const char *text);
static void browser_window_set_pointer(gui_pointer_shape shape);
static void download_window_callback(fetch_msg msg, void *p, const char *data,
static void download_window_callback(fetch_msg msg, void *p, const void *data,
unsigned long size);
static void browser_window_mouse_action_html(struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
@ -429,6 +429,24 @@ void browser_window_callback(content_msg msg, struct content *c,
break;
#endif
#ifdef WITH_SSL
case CONTENT_MSG_SSL:
gui_cert_verify(bw, c, data.ssl.certs, data.ssl.num);
if (c == bw->loading_content)
bw->loading_content = 0;
else if (c == bw->current_content) {
bw->current_content = 0;
bw->caret_callback = NULL;
bw->paste_callback = NULL;
bw->scrolling_box = NULL;
selection_init(bw->sel, NULL);
}
browser_window_stop_throbber(bw);
free(bw->referer);
bw->referer = 0;
break;
#endif
case CONTENT_MSG_REFRESH:
schedule(data.delay * 100,
browser_window_refresh, bw);
@ -689,7 +707,7 @@ void browser_window_destroy(struct browser_window *bw)
* Callback for fetch for download window fetches.
*/
void download_window_callback(fetch_msg msg, void *p, const char *data,
void download_window_callback(fetch_msg msg, void *p, const void *data,
unsigned long size)
{
struct gui_download_window *download_window = p;
@ -713,6 +731,9 @@ void download_window_callback(fetch_msg msg, void *p, const char *data,
case FETCH_REDIRECT:
case FETCH_NOTMODIFIED:
case FETCH_AUTH:
#ifdef WITH_SSL
case FETCH_CERT_ERR:
#endif
default:
/* not possible */
assert(0);

View File

@ -38,6 +38,7 @@ typedef enum { GUI_POINTER_DEFAULT, GUI_POINTER_POINT, GUI_POINTER_CARET,
GUI_POINTER_MOVE } gui_pointer_shape;
#include <stdbool.h>
#include "netsurf/utils/config.h"
#include "netsurf/content/content.h"
#include "netsurf/desktop/browser.h"
@ -106,5 +107,12 @@ bool gui_search_term_highlighted(struct gui_window *g,
unsigned start_offset, unsigned end_offset,
unsigned *start_idx, unsigned *end_idx);
#ifdef WITH_SSL
struct ssl_cert_info;
void gui_cert_verify(struct browser_window *bw, struct content *c,
const struct ssl_cert_info *certs, unsigned long num);
#endif
#endif

View File

@ -54,8 +54,6 @@ int option_font_size = 100;
int option_font_min_size = 70;
/** Accept-Language header. */
char *option_accept_language = 0;
/** Enable verification of SSL certificates. */
bool option_ssl_verify_certificates = true;
/** Preferred maximum size of memory cache / bytes. */
int option_memory_cache_size = 2 * 1024 * 1024;
/** Preferred expiry age of disc cache / days. */
@ -96,7 +94,6 @@ struct {
{ "font_size", OPTION_INTEGER, &option_font_size },
{ "font_min_size", OPTION_INTEGER, &option_font_min_size },
{ "accept_language", OPTION_STRING, &option_accept_language },
{ "ssl_verify_certificates", OPTION_BOOL, &option_ssl_verify_certificates },
{ "memory_cache_size", OPTION_INTEGER, &option_memory_cache_size },
{ "disc_cache_age", OPTION_INTEGER, &option_disc_cache_age },
{ "block_advertisements", OPTION_BOOL, &option_block_ads },

View File

@ -38,7 +38,6 @@ extern char *option_http_proxy_auth_pass;
extern int option_font_size;
extern int option_font_min_size;
extern char *option_accept_language;
extern bool option_ssl_verify_certificates;
extern int option_memory_cache_size;
extern int option_disc_cache_age;
extern bool option_block_ads;

View File

@ -17,8 +17,8 @@
# "riscos", "riscos_small", "ncos", and "riscos_debug" can be compiled under
# RISC OS, or cross-compiled using GCCSDK.
OBJECTS_COMMON = authdb.o content.o fetch.o fetchcache.o \
url_store.o # content/
OBJECTS_COMMON = authdb.o certdb.o content.o fetch.o \
fetchcache.o url_store.o # content/
OBJECTS_COMMON += css.o css_enum.o parser.o ruleset.o scanner.o # css/
OBJECTS_COMMON += box.o box_construct.o box_normalise.o form.o \
html.o html_redraw.o imagemap.o layout.o list.o \
@ -38,13 +38,15 @@ OBJECTS_RISCOS += 401login.o artworks.o assert.o awrender.o bitmap.o \
global_history.o gui.o help.o history.o hotlist.o image.o \
menus.o message.o mouseactions.o plotters.o plugin.o print.o \
query.o save.o save_complete.o save_draw.o save_text.o \
schedule.o search.o sprite.o textselection.o theme.o \
schedule.o search.o sprite.o sslcert.o textselection.o theme.o \
theme_install.o thumbnail.o treeview.o ucstables.o uri.o \
url_complete.o url_protocol.o wimp.o wimp_event.o window.o # riscos/
OBJECTS_RISCOS += con_cache.o con_fonts.o con_home.o con_image.o \
con_inter.o con_language.o con_memory.o con_theme.o # riscos/configure/
# OBJECTS_RISCOS += memdebug.o
OBJECTS_RISCOS_SMALL = $(OBJECTS_RISCOS)
OBJECTS_NCOS = $(OBJECTS_RISCOS)
OBJECTS_DEBUG = $(OBJECTS_COMMON) $(OBJECTS_IMAGE)
@ -69,6 +71,10 @@ OBJDIR_RISCOS = arm-riscos-aof
SOURCES_RISCOS=$(OBJECTS_RISCOS:.o=.c)
OBJS_RISCOS=$(OBJECTS_RISCOS:%.o=$(OBJDIR_RISCOS)/%.o)
OBJDIR_RISCOS_SMALL = arm-riscos-aof-small
SOURCES_RISCOS_SMALL=$(OBJECTS_RISCOS_SMALL:.o=.c)
OBJS_RISCOS_SMALL=$(OBJECTS_RISCOS_SMALL:%.o=$(OBJDIR_RISCOS_SMALL)/%.o)
OBJDIR_NCOS = arm-ncos-aof
SOURCES_NCOS=$(OBJECTS_NCOS:.o=.c)
OBJS_NCOS=$(OBJECTS_NCOS:%.o=$(OBJDIR_NCOS)/%.o)
@ -106,6 +112,7 @@ WARNFLAGS = -W -Wall -Wundef -Wpointer-arith -Wcast-qual \
CFLAGS_RISCOS = -std=c9x -D_BSD_SOURCE -Driscos -DBOOL_DEFINED -O \
$(WARNFLAGS) -I.. $(PLATFORM_CFLAGS_RISCOS) -mpoke-function-name \
# -include netsurf/utils/memdebug.h
CFLAGS_RISCOS_SMALL = $(CFLAGS_RISCOS) -Dsmall
CFLAGS_NCOS = $(CFLAGS_RISCOS) -Dncos
CFLAGS_DEBUG = -std=c9x -D_BSD_SOURCE -Ddebug $(WARNFLAGS) -I.. \
$(PLATFORM_CFLAGS_DEBUG) -g
@ -114,6 +121,7 @@ CFLAGS_GTK = -std=c9x -D_BSD_SOURCE -D_POSIX_C_SOURCE -Dgtk \
`pkg-config --cflags gtk+-2.0` `xml2-config --cflags`
AFLAGS_RISCOS = -I..,. $(PLATFORM_AFLAGS_RISCOS)
AFLAGS_RISCOS_SMALL = $(AFLAGS_RISCOS) -Dsmall
AFLAGS_NCOS = $(AFLAGS_RISCOS) -Dncos
# targets
@ -121,7 +129,7 @@ riscos: $(RUNIMAGE)
$(RUNIMAGE) : $(OBJS_RISCOS)
$(CC) -o $@ $(LDFLAGS_RISCOS) $^
riscos_small: u!RunImage,ff8
u!RunImage,ff8 : $(OBJS_RISCOS)
u!RunImage,ff8 : $(OBJS_RISCOS_SMALL)
$(CC) -o $@ $(LDFLAGS_SMALL) $^
ncos: $(NCRUNIMAGE)
@ -148,6 +156,9 @@ netsurf.zip: $(RUNIMAGE)
$(OBJDIR_RISCOS)/%.o : %.c
@echo "==> $<"
@$(CC) -o $@ -c $(CFLAGS_RISCOS) $<
$(OBJDIR_RISCOS_SMALL)/%.o : %.c
@echo "==> $<"
@$(CC) -o $@ -c $(CFLAGS_RISCOS_SMALL) $<
$(OBJDIR_NCOS)/%.o : %.c
@echo "==> $<"
@$(CC) -o $@ -c $(CFLAGS_NCOS) $<
@ -160,10 +171,13 @@ $(OBJDIR_GTK)/%.o : %.c
# pattern rules for asm source
$(OBJDIR_RISCOS)/%.o : %.s
@echo "== $<"
@echo "==> $<"
$(ASM) -o $@ -c $(AFLAGS_RISCOS) $<
$(OBJDIR_RISCOS_SMALL)/%.o : %.s
@echo "==> $<"
$(ASM) -o $@ -c $(AFLAGS_RISCOS_SMALL) $<
$(OBJDIR_NCOS)/%.o : %.s
@echo "== $<"
@echo "==> $<"
$(ASM) -o $@ -c $(AFLAGS_NCOS) $<
# special cases
@ -184,14 +198,14 @@ utils/translit.c: transtab
depend: */*.[ch]
@echo "--> modified files $?"
@echo "--> updating dependencies"
@-mkdir -p $(OBJDIR_RISCOS) $(OBJDIR_NCOS) $(OBJDIR_DEBUG) $(OBJDIR_GTK)
@perl scandeps netsurf $(OBJDIR_RISCOS) $(OBJDIR_NCOS) $(OBJDIR_DEBUG) $(OBJDIR_GTK) -- $^ > depend
@-mkdir -p $(OBJDIR_RISCOS) $(OBJDIR_RISCOS_SMALL) $(OBJDIR_NCOS) $(OBJDIR_DEBUG) $(OBJDIR_GTK)
@perl scandeps netsurf $(OBJDIR_RISCOS) $(OBJDIR_RISCOS_SMALL) $(OBJDIR_NCOS) $(OBJDIR_DEBUG) $(OBJDIR_GTK) -- $^ > depend
include depend
# remove generated files
clean:
-rm $(OBJDIR_RISCOS)/* $(OBJDIR_NCOS)/* \
-rm $(OBJDIR_RISCOS)/* $(OBJDIR_RISCOS_SMALL)/* $(OBJDIR_NCOS)/* \
$(OBJDIR_DEBUG)/* $(OBJDIR_GTK)/* \
css/css_enum.c css/css_enum.h \
css/parser.c css/parser.h css/scanner.c css/scanner.h

View File

@ -852,6 +852,14 @@ void html_convert_css_callback(content_msg msg, struct content *css,
break;
#endif
#ifdef WITH_SSL
case CONTENT_MSG_SSL:
c->data.html.stylesheet_content[i] = 0;
c->active--;
content_add_error(c, "?", 0);
break;
#endif
default:
assert(0);
}
@ -1127,6 +1135,14 @@ void html_object_callback(content_msg msg, struct content *object,
break;
#endif
#ifdef WITH_SSL
case CONTENT_MSG_SSL:
c->data.html.object[i].content = 0;
c->active--;
content_add_error(c, "?", 0);
break;
#endif
case CONTENT_MSG_REFRESH:
if (object->type == CONTENT_HTML)
/* only for HTML objects */

View File

@ -28,8 +28,8 @@
static void ro_gui_401login_close(wimp_w w);
static bool ro_gui_401login_apply(wimp_w w);
static void ro_gui_401login_open(struct browser_window *bw, char *host,
char *realm, char *fetchurl);
static void ro_gui_401login_open(struct browser_window *bw, const char *host,
const char *realm, const char *fetchurl);
static wimp_window *dialog_401_template;
@ -58,7 +58,7 @@ void ro_gui_401login_init(void)
* Open the login dialog
*/
void gui_401login_open(struct browser_window *bw, struct content *c,
char *realm)
const char *realm)
{
char *murl, *host;
url_func_result res;
@ -77,8 +77,8 @@ void gui_401login_open(struct browser_window *bw, struct content *c,
* Open a 401 login window.
*/
void ro_gui_401login_open(struct browser_window *bw, char *host, char *realm,
char *fetchurl)
void ro_gui_401login_open(struct browser_window *bw, const char *host,
const char *realm, const char *fetchurl)
{
struct session_401 *session;
wimp_w w;

View File

@ -91,6 +91,11 @@ void ro_gui_dialog_init(void)
ro_gui_401login_init();
#endif
/* certificate verification window */
#ifdef WITH_SSL
ro_gui_cert_init();
#endif
/* hotlist window */
ro_gui_hotlist_initialise();
@ -353,6 +358,15 @@ void ro_gui_dialog_close(wimp_w close)
wimp_caret caret;
os_error *error;
/* Check if we're a persistent window */
for (i = 0; i < MAX_PERSISTENT; i++) {
if (persistent_dialog[i].dialog == close) {
/* We are => invalidate record */
persistent_dialog[i].dialog = NULL;
break;
}
}
/* Give the caret back to the parent window. This code relies on
the fact that only tree windows and browser windows open
persistent dialogues, as the caret gets placed to no icon.
@ -363,24 +377,18 @@ void ro_gui_dialog_close(wimp_w close)
error->errnum, error->errmess));
warn_user("WimpError", error->errmess);
} else if (caret.w == close) {
/* Check if we are a persistent window
*/
for (i = 0; i < MAX_PERSISTENT; i++) {
if (persistent_dialog[i].dialog == close) {
persistent_dialog[i].dialog = NULL;
error = xwimp_set_caret_position(
persistent_dialog[i].parent,
wimp_ICON_WINDOW, -100, -100,
32, -1);
/* parent may have been closed first */
if ((error) && (error->errnum != 0x287)) {
LOG(("xwimp_set_caret_position: "
"0x%x: %s",
error->errnum,
error->errmess));
warn_user("WimpError", error->errmess);
}
break;
/* Check if we are a persistent window */
if (i < MAX_PERSISTENT) {
error = xwimp_set_caret_position(
persistent_dialog[i].parent,
wimp_ICON_WINDOW, -100, -100,
32, -1);
/* parent may have been closed first */
if ((error) && (error->errnum != 0x287)) {
LOG(("xwimp_set_caret_position: 0x%x: %s",
error->errnum,
error->errmess));
warn_user("WimpError", error->errmess);
}
}
}

View File

@ -124,6 +124,11 @@ void ro_gui_mouse_action(struct gui_window *g);
void ro_gui_401login_init(void);
#endif
/* in sslcert.c */
#ifdef WITH_SSL
void ro_gui_cert_init(void);
#endif
/* in window.c */
void ro_gui_window_quit(void);
void ro_gui_window_click(struct gui_window *g, wimp_pointer *mouse);
@ -302,7 +307,7 @@ bool ro_gui_theme_install_apply(wimp_w w);
#define ICON_SEARCH_CANCEL 4
#define ICON_SEARCH_STATUS 5
#define ICON_SEARCH_MENU 8
#define ICON_SEARCH_SHOW_ALL 9
#define ICON_SEARCH_SHOW_ALL 9
#define ICON_THEME_INSTALL_MESSAGE 0
#define ICON_THEME_INSTALL_INSTALL 1

View File

@ -164,7 +164,7 @@ static void plugin_stream_free(struct plugin_stream *p);
static bool plugin_start_fetch(struct plugin_stream *p, const char *url);
static void plugin_stream_callback(content_msg msg, struct content *c,
intptr_t p1, intptr_t p2, union content_msg_data data);
static void plugin_fetch_callback(fetch_msg msg, void *p, const char *data,
static void plugin_fetch_callback(fetch_msg msg, void *p, const void *data,
unsigned long size);
/**
@ -1707,6 +1707,12 @@ void plugin_stream_callback(content_msg msg, struct content *c,
/* ignore this */
break;
#ifdef WITH_SSL
case CONTENT_MSG_SSL:
plugin_destroy_stream(p, plugin_STREAM_DESTROY_ERROR);
break;
#endif
case CONTENT_MSG_READY:
case CONTENT_MSG_DONE:
case CONTENT_MSG_REFORMAT:
@ -1721,7 +1727,7 @@ void plugin_stream_callback(content_msg msg, struct content *c,
/**
* Callback for plugin fetch
*/
void plugin_fetch_callback(fetch_msg msg, void *p, const char *data,
void plugin_fetch_callback(fetch_msg msg, void *p, const void *data,
unsigned long size)
{
struct plugin_stream *s = p;
@ -1754,6 +1760,9 @@ void plugin_fetch_callback(fetch_msg msg, void *p, const char *data,
case FETCH_REDIRECT:
case FETCH_NOTMODIFIED:
case FETCH_AUTH:
#ifdef WITH_SSL
case FETCH_CERT_ERR:
#endif
default:
/* not possible */
assert(0);

182
riscos/sslcert.c Normal file
View File

@ -0,0 +1,182 @@
/*
* This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2006 John M Bell <jmb202@ecs.soton.ac.uk>
*/
/** \file
* SSL Certificate verification UI (implementation)
*/
#include "netsurf/utils/config.h"
#ifdef WITH_SSL
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "oslib/wimp.h"
#include "netsurf/content/certdb.h"
#include "netsurf/content/content.h"
#include "netsurf/content/fetch.h"
#include "netsurf/desktop/browser.h"
#include "netsurf/desktop/gui.h"
#include "netsurf/riscos/dialog.h"
#include "netsurf/riscos/wimp_event.h"
#include "netsurf/utils/log.h"
#include "netsurf/utils/utils.h"
#define ICON_CERT_VERSION 1
#define ICON_CERT_VALID_FROM 2
#define ICON_CERT_TYPE 3
#define ICON_CERT_VALID_TO 4
#define ICON_CERT_SERIAL 5
#define ICON_CERT_ISSUER 6
#define ICON_CERT_SUBJECT 7
#define ICON_CERT_REJECT 8
#define ICON_CERT_ACCEPT 9
static wimp_window *dialog_cert_template;
struct session_cert {
char version[16], valid_from[32], valid_to[32], type[8], serial[32],
issuer[256], subject[256];
char *url;
struct browser_window *bw;
};
static void ro_gui_cert_open(struct browser_window *bw, const char *url,
const struct ssl_cert_info *certdata);
static void ro_gui_cert_close(wimp_w w);
static bool ro_gui_cert_apply(wimp_w w);
/**
* Load the cert window template
*/
void ro_gui_cert_init(void)
{
dialog_cert_template = ro_gui_dialog_load_template("sslcert");
}
/**
* Open the certificate verification dialog
*/
void gui_cert_verify(struct browser_window *bw, struct content *c,
const struct ssl_cert_info *certs, unsigned long num)
{
assert(bw && c && certs);
/** \todo Display entire certificate chain */
ro_gui_cert_open(bw, c->url, certs);
}
void ro_gui_cert_open(struct browser_window *bw, const char *url,
const struct ssl_cert_info *certdata)
{
struct session_cert *session;
wimp_w w;
session = malloc(sizeof(struct session_cert));
if (!session) {
warn_user("NoMemory", 0);
return;
}
session->url = strdup(url);
if (!session->url) {
free(session);
warn_user("NoMemory", 0);
return;
}
session->bw = bw;
snprintf(session->version, sizeof session->version, "%ld",
certdata->version);
snprintf(session->valid_from, sizeof session->valid_from, "%s",
certdata->not_before);
snprintf(session->type, sizeof session->type, "%d",
certdata->cert_type);
snprintf(session->valid_to, sizeof session->valid_to, "%s",
certdata->not_after);
snprintf(session->serial, sizeof session->serial, "%ld",
certdata->serial);
snprintf(session->issuer, sizeof session->issuer, "%s",
certdata->issuer);
snprintf(session->subject, sizeof session->subject, "%s",
certdata->subject);
dialog_cert_template->icons[ICON_CERT_VERSION].data.indirected_text.text = session->version;
dialog_cert_template->icons[ICON_CERT_VERSION].data.indirected_text.size = strlen(session->version) + 1;
dialog_cert_template->icons[ICON_CERT_VALID_FROM].data.indirected_text.text = session->valid_from;
dialog_cert_template->icons[ICON_CERT_VALID_FROM].data.indirected_text.size = strlen(session->valid_from) + 1;
dialog_cert_template->icons[ICON_CERT_TYPE].data.indirected_text.text = session->type;
dialog_cert_template->icons[ICON_CERT_TYPE].data.indirected_text.size = strlen(session->type) + 1;
dialog_cert_template->icons[ICON_CERT_VALID_TO].data.indirected_text.text = session->valid_to;
dialog_cert_template->icons[ICON_CERT_VALID_TO].data.indirected_text.size = strlen(session->valid_to) + 1;
dialog_cert_template->icons[ICON_CERT_SERIAL].data.indirected_text.text = session->serial;
dialog_cert_template->icons[ICON_CERT_SERIAL].data.indirected_text.size = strlen(session->serial) + 1;
dialog_cert_template->icons[ICON_CERT_ISSUER].data.indirected_text.text = session->issuer;
dialog_cert_template->icons[ICON_CERT_ISSUER].data.indirected_text.size = strlen(session->issuer) + 1;
dialog_cert_template->icons[ICON_CERT_SUBJECT].data.indirected_text.text = session->subject;
dialog_cert_template->icons[ICON_CERT_SUBJECT].data.indirected_text.size = strlen(session->subject) + 1;
w = wimp_create_window(dialog_cert_template);
ro_gui_wimp_event_register_cancel(w, ICON_CERT_REJECT);
ro_gui_wimp_event_register_ok(w, ICON_CERT_ACCEPT, ro_gui_cert_apply);
ro_gui_wimp_event_register_close_window(w, ro_gui_cert_close);
ro_gui_wimp_event_set_user_data(w, session);
ro_gui_dialog_open_persistent(bw->window->window, w, false);
}
/**
* Handle closing of certificate verification dialog
*/
void ro_gui_cert_close(wimp_w w)
{
os_error *error;
struct session_cert *session;
session = (struct session_cert *)ro_gui_wimp_event_get_user_data(w);
assert(session);
free(session->url);
free(session);
ro_gui_wimp_event_finalise(w);
error = xwimp_delete_window(w);
if (error)
LOG(("xwimp_delete_window: 0x%x: %s",
error->errnum, error->errmess));
}
/**
* Handle acceptance of certificate
*/
bool ro_gui_cert_apply(wimp_w w)
{
struct session_cert *session;
session = (struct session_cert *)ro_gui_wimp_event_get_user_data(w);
assert(session);
if (!certdb_insert(session->url)) {
LOG(("certdb_insert failed"));
return false;
}
browser_window_go(session->bw, session->url, 0);
return true;
}
#endif

View File

@ -22,6 +22,11 @@
/* Cookies */
#define WITH_COOKIES
/* SSL */
#if !defined(small)
#define WITH_SSL
#endif
/* Image renderering modules */
#define WITH_JPEG
#define WITH_MNG