diff options
Diffstat (limited to 'desktop')
-rw-r--r-- | desktop/browser_private.h | 15 | ||||
-rw-r--r-- | desktop/browser_window.c | 46 | ||||
-rw-r--r-- | desktop/gui_factory.c | 3 | ||||
-rw-r--r-- | desktop/sslcert_viewer.c | 184 | ||||
-rw-r--r-- | desktop/sslcert_viewer.h | 14 |
5 files changed, 208 insertions, 54 deletions
diff --git a/desktop/browser_private.h b/desktop/browser_private.h index 6e45052d7..41b8fefd4 100644 --- a/desktop/browser_private.h +++ b/desktop/browser_private.h @@ -89,13 +89,6 @@ struct browser_fetch_parameters { bool parent_quirks; /**< Optional parent quirks */ }; -/** - * The SSL context for a fetch, as provided by the fetchers - */ -struct browser_ssl_info { - struct ssl_cert_info certs[MAX_SSL_CERTS]; /**< The certificate chain */ - size_t num; /**< The number of certificates in the chain */ -}; /** * Browser window data. @@ -113,9 +106,9 @@ struct browser_window { struct browser_fetch_parameters current_parameters; /** - * The SSL information for the current content + * The certificate chain for the current content */ - struct browser_ssl_info current_ssl_info; + struct cert_chain *current_cert_chain; /** * Content handle of page in process of being loaded or NULL @@ -129,9 +122,9 @@ struct browser_window { struct browser_fetch_parameters loading_parameters; /** - * The SSL information for the loading content + * The certificate chain for the loading content */ - struct browser_ssl_info loading_ssl_info; + struct cert_chain *loading_cert_chain; /** * Favicon diff --git a/desktop/browser_window.c b/desktop/browser_window.c index 06f41ddf3..6defe0182 100644 --- a/desktop/browser_window.c +++ b/desktop/browser_window.c @@ -743,9 +743,10 @@ static nserror browser_window_content_ready(struct browser_window *bw) browser_window__free_fetch_parameters(&bw->current_parameters); bw->current_parameters = bw->loading_parameters; memset(&bw->loading_parameters, 0, sizeof(bw->loading_parameters)); - /* Transfer the SSL info */ - bw->current_ssl_info = bw->loading_ssl_info; - bw->loading_ssl_info.num = 0; + /* Transfer the certificate chain */ + cert_chain_free(bw->current_cert_chain); + bw->current_cert_chain = bw->loading_cert_chain; + bw->loading_cert_chain = NULL; } /* Format the new content to the correct dimensions */ @@ -1136,7 +1137,7 @@ browser_window__handle_bad_certs(struct browser_window *bw, nserror err; /* Initially we don't know WHY the SSL cert was bad */ const char *reason = messages_get_sslcode(SSL_CERT_ERR_UNKNOWN); - size_t n; + size_t depth; memset(¶ms, 0, sizeof(params)); @@ -1151,12 +1152,14 @@ browser_window__handle_bad_certs(struct browser_window *bw, goto out; } - for (n = 0; n < bw->loading_ssl_info.num; ++n) { - size_t idx = bw->loading_ssl_info.num - (n + 1); - ssl_cert_err err = bw->loading_ssl_info.certs[idx].err; - if (err != SSL_CERT_ERR_OK) { - reason = messages_get_sslcode(err); - break; + if (bw->loading_cert_chain != NULL) { + for (depth = 0; depth < bw->loading_cert_chain->depth; ++depth) { + size_t idx = bw->loading_cert_chain->depth - (depth + 1); + ssl_cert_err err = bw->loading_cert_chain->certs[idx].err; + if (err != SSL_CERT_ERR_OK) { + reason = messages_get_sslcode(err); + break; + } } } @@ -1175,8 +1178,7 @@ browser_window__handle_bad_certs(struct browser_window *bw, } err = guit->misc->cert_verify(url, - bw->loading_ssl_info.certs, - bw->loading_ssl_info.num, + bw->loading_cert_chain, browser_window__handle_ssl_query_response, bw); @@ -1352,11 +1354,8 @@ browser_window_callback(hlcache_handle *c, const hlcache_event *event, void *pw) switch (event->type) { case CONTENT_MSG_SSL_CERTS: /* SSL certificate information has arrived, store it */ - assert(event->data.certs.num < MAX_SSL_CERTS); - memcpy(&bw->loading_ssl_info.certs[0], - event->data.certs.certs, - sizeof(struct ssl_cert_info) * event->data.certs.num); - bw->loading_ssl_info.num = event->data.certs.num; + cert_chain_free(bw->loading_cert_chain); + cert_chain_dup(event->data.chain, &bw->loading_cert_chain); break; case CONTENT_MSG_LOG: @@ -3431,7 +3430,8 @@ navigate_internal_real(struct browser_window *bw, fetch_is_post = (params->post_urlenc != NULL || params->post_multipart != NULL); /* Clear SSL info for load */ - bw->loading_ssl_info.num = 0; + cert_chain_free(bw->loading_cert_chain); + bw->loading_cert_chain = NULL; /* Set up retrieval parameters */ if (!(params->flags & BW_NAVIGATE_UNVERIFIABLE)) { @@ -4707,17 +4707,17 @@ browser_window_page_info_state browser_window_get_page_info_state( } /* Exported interface, documented in browser_window.h */ -nserror browser_window_get_ssl_chain(struct browser_window *bw, size_t *num, - struct ssl_cert_info **chain) +nserror +browser_window_get_ssl_chain(struct browser_window *bw, + struct cert_chain **chain) { assert(bw != NULL); - if (bw->current_ssl_info.num == 0) { + if (bw->current_cert_chain == NULL) { return NSERROR_NOT_FOUND; } - *num = bw->current_ssl_info.num; - *chain = &(bw->current_ssl_info.certs[0]); + *chain = bw->current_cert_chain; return NSERROR_OK; } diff --git a/desktop/gui_factory.c b/desktop/gui_factory.c index 8b52e5469..7ef457a7a 100644 --- a/desktop/gui_factory.c +++ b/desktop/gui_factory.c @@ -639,8 +639,7 @@ static nserror gui_default_launch_url(struct nsurl *url) static nserror gui_default_cert_verify(nsurl *url, - const struct ssl_cert_info *certs, - unsigned long num, + const struct cert_chain *chain, nserror (*cb)(bool proceed, void *pw), void *cbpw) { diff --git a/desktop/sslcert_viewer.c b/desktop/sslcert_viewer.c index 4d8725757..ec0fd3431 100644 --- a/desktop/sslcert_viewer.c +++ b/desktop/sslcert_viewer.c @@ -52,6 +52,21 @@ enum sslcert_viewer_field { typedef nserror (*response_cb)(bool proceed, void *pw); /** + * ssl certificate information for certificate error message + */ +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 */ + char serialnum[64]; /**< Serial number */ + char issuer[256]; /**< Issuer details */ + char subject[256]; /**< Subject details */ + int cert_type; /**< Certificate type */ + ssl_cert_err err; /**< Whatever is wrong with this certificate */ +}; + +/** * ssl certificate verification context. */ struct sslcert_session_data { @@ -473,38 +488,183 @@ nserror sslcert_viewer_fini(struct sslcert_session_data *ssl_d) return err; } +#ifdef WITH_OPENSSL + +#include <openssl/ssl.h> +#include <openssl/x509v3.h> + +static nserror +der_to_certinfo(const uint8_t *der, + size_t der_length, + struct ssl_cert_info *info) +{ + BIO *mem; + BUF_MEM *buf; + const ASN1_INTEGER *asn1_num; + BIGNUM *bignum; + X509 *cert; /**< Pointer to certificate */ + + if (der == NULL) { + return NSERROR_OK; + } + + cert = d2i_X509(NULL, &der, der_length); + if (cert == NULL) { + return NSERROR_INVALID; + } + + /* get certificate version */ + info->version = X509_get_version(cert); + + /* not before date */ + mem = BIO_new(BIO_s_mem()); + ASN1_TIME_print(mem, X509_get_notBefore(cert)); + BIO_get_mem_ptr(mem, &buf); + (void) BIO_set_close(mem, BIO_NOCLOSE); + BIO_free(mem); + memcpy(info->not_before, + buf->data, + min(sizeof(info->not_before) - 1, (unsigned)buf->length)); + info->not_before[min(sizeof(info->not_before) - 1, (unsigned)buf->length)] = 0; + BUF_MEM_free(buf); + + /* not after date */ + mem = BIO_new(BIO_s_mem()); + ASN1_TIME_print(mem, + X509_get_notAfter(cert)); + BIO_get_mem_ptr(mem, &buf); + (void) BIO_set_close(mem, BIO_NOCLOSE); + BIO_free(mem); + memcpy(info->not_after, + buf->data, + min(sizeof(info->not_after) - 1, (unsigned)buf->length)); + info->not_after[min(sizeof(info->not_after) - 1, (unsigned)buf->length)] = 0; + BUF_MEM_free(buf); + + /* signature type */ + info->sig_type = X509_get_signature_type(cert); + + /* serial number */ + asn1_num = X509_get_serialNumber(cert); + if (asn1_num != NULL) { + bignum = ASN1_INTEGER_to_BN(asn1_num, NULL); + if (bignum != NULL) { + char *tmp = BN_bn2hex(bignum); + if (tmp != NULL) { + strncpy(info->serialnum, + tmp, + sizeof(info->serialnum)); + info->serialnum[sizeof(info->serialnum)-1] = '\0'; + OPENSSL_free(tmp); + } + BN_free(bignum); + bignum = NULL; + } + } + + /* issuer name */ + mem = BIO_new(BIO_s_mem()); + X509_NAME_print_ex(mem, + X509_get_issuer_name(cert), + 0, XN_FLAG_SEP_CPLUS_SPC | + XN_FLAG_DN_REV | XN_FLAG_FN_NONE); + BIO_get_mem_ptr(mem, &buf); + (void) BIO_set_close(mem, BIO_NOCLOSE); + BIO_free(mem); + memcpy(info->issuer, + buf->data, + min(sizeof(info->issuer) - 1, (unsigned) buf->length)); + info->issuer[min(sizeof(info->issuer) - 1, (unsigned) buf->length)] = 0; + BUF_MEM_free(buf); + + /* subject */ + mem = BIO_new(BIO_s_mem()); + X509_NAME_print_ex(mem, + X509_get_subject_name(cert), + 0, + XN_FLAG_SEP_CPLUS_SPC | + XN_FLAG_DN_REV | + XN_FLAG_FN_NONE); + BIO_get_mem_ptr(mem, &buf); + (void) BIO_set_close(mem, BIO_NOCLOSE); + BIO_free(mem); + memcpy(info->subject, + buf->data, + min(sizeof(info->subject) - 1, (unsigned)buf->length)); + info->subject[min(sizeof(info->subject) - 1, (unsigned) buf->length)] = 0; + BUF_MEM_free(buf); + + /* type of certificate */ + info->cert_type = X509_certificate_type(cert, X509_get_pubkey(cert)); + + X509_free(cert); + + return NSERROR_OK; +} +#else +static nserror +der_to_certinfo(uint8_t *der, size_t der_length, struct ssl_cert_info *info) +{ + return NSERROR_NOT_IMPLEMENTED; +} +#endif + +/* copy certificate data */ +static nserror +convert_chain_to_cert_info(const struct cert_chain *chain, + struct ssl_cert_info **cert_info_out) +{ + struct ssl_cert_info *certs; + size_t depth; + nserror res; + + certs = calloc(chain->depth, sizeof(struct ssl_cert_info)); + if (certs == NULL) { + return NSERROR_NOMEM; + } + + for (depth = 0; depth < chain->depth;depth++) { + res = der_to_certinfo(chain->certs[depth].der, + chain->certs[depth].der_length, + certs + depth); + if (res != NSERROR_OK) { + free(certs); + return res; + } + certs[depth].err = chain->certs[depth].err; + } + + *cert_info_out = certs; + return NSERROR_OK; +} /* Exported interface, documented in sslcert_viewer.h */ nserror -sslcert_viewer_create_session_data(unsigned long num, - struct nsurl *url, +sslcert_viewer_create_session_data(struct nsurl *url, nserror (*cb)(bool proceed, void *pw), void *cbpw, - const struct ssl_cert_info *certs, + const struct cert_chain *chain, struct sslcert_session_data **ssl_d) { struct sslcert_session_data *data; - + nserror res; assert(url != NULL); - assert(certs != NULL); + assert(chain != NULL); data = malloc(sizeof(struct sslcert_session_data)); if (data == NULL) { *ssl_d = NULL; return NSERROR_NOMEM; } - - /* copy certificate data */ - data->certs = malloc(num * sizeof(struct ssl_cert_info)); - if (data->certs == NULL) { + res = convert_chain_to_cert_info(chain, &data->certs); + if (res != NSERROR_OK) { free(data); *ssl_d = NULL; - return NSERROR_NOMEM; + return res; } - memcpy(data->certs, certs, num * sizeof(struct ssl_cert_info)); data->url = nsurl_ref(url); - data->num = num; + data->num = chain->depth; data->cb = cb; data->cbpw = cbpw; diff --git a/desktop/sslcert_viewer.h b/desktop/sslcert_viewer.h index 6955e0167..854284083 100644 --- a/desktop/sslcert_viewer.h +++ b/desktop/sslcert_viewer.h @@ -32,16 +32,15 @@ struct redraw_context; struct core_window_callback_table; struct rect; struct nsurl; -struct ssl_cert_info; +struct cert_chain; /** * Create ssl certificate viewer session data. * - * \param num The number of certificates in the chain * \param url Address of the page we're inspecting certificates of * \param cb Low level cache callback * \param cbpw Low level cache private data - * \param certs The SSL certificates + * \param chain The SSL certificate chain * \param ssl_d Updated to SSL certificate session data * \return NSERROR_OK on success, appropriate error otherwise * @@ -49,8 +48,10 @@ struct ssl_cert_info; * sslcert_viewer_fini destroys the session data. */ nserror sslcert_viewer_create_session_data( - unsigned long num, struct nsurl *url, nserror (*cb)(bool proceed, void *pw), - void *cbpw, const struct ssl_cert_info *certs, + struct nsurl *url, + nserror (*cb)(bool proceed, void *pw), + void *cbpw, + const struct cert_chain *chain, struct sslcert_session_data **ssl_d); @@ -65,7 +66,8 @@ nserror sslcert_viewer_create_session_data( * \return NSERROR_OK on success, appropriate error otherwise */ nserror sslcert_viewer_init(struct core_window_callback_table *cw_t, - void *core_window_handle, struct sslcert_session_data *ssl_d); + void *core_window_handle, + struct sslcert_session_data *ssl_d); /** |