mirror of
https://github.com/rkd77/elinks.git
synced 2025-02-02 15:09:23 -05:00
[cache] Added integrity check for scripts. Refs #284
Now only for Spidermonkey and OpenSSL. SHA512, SHA384 or SHA256 were added. URIs are stored in map, which is not cleared yet.
This commit is contained in:
parent
2e210a79cf
commit
0cbc3d4a5c
135
src/cache/cache.c
vendored
135
src/cache/cache.c
vendored
@ -6,6 +6,10 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef CONFIG_OPENSSL
|
||||
#include <openssl/sha.h>
|
||||
#endif
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "bfu/dialog.h"
|
||||
@ -21,6 +25,7 @@
|
||||
#ifdef CONFIG_SCRIPTING_SPIDERMONKEY
|
||||
# include "scripting/smjs/smjs.h"
|
||||
#endif
|
||||
#include "util/base64.h"
|
||||
#include "util/error.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
@ -926,3 +931,133 @@ shrinked_enough:
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OPENSSL
|
||||
static int
|
||||
check_sha512(const void *data, size_t len, const char *checksum)
|
||||
{
|
||||
unsigned char digest[SHA512_DIGEST_LENGTH] = {0};
|
||||
SHA512_CTX ctx;
|
||||
SHA512_Init(&ctx);
|
||||
SHA512_Update(&ctx, data, len);
|
||||
SHA512_Final(digest, &ctx);
|
||||
|
||||
int outlen = 0;
|
||||
unsigned char *b64 = base64_encode_bin(digest, SHA512_DIGEST_LENGTH, &outlen);
|
||||
int res = 0;
|
||||
|
||||
if (b64) {
|
||||
res = !memcmp(b64, checksum, outlen);
|
||||
mem_free(b64);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
check_sha384(const void *data, size_t len, const char *checksum)
|
||||
{
|
||||
unsigned char digest[SHA384_DIGEST_LENGTH] = {0};
|
||||
SHA512_CTX ctx;
|
||||
SHA384_Init(&ctx);
|
||||
SHA384_Update(&ctx, data, len);
|
||||
SHA384_Final(digest, &ctx);
|
||||
|
||||
int outlen = 0;
|
||||
unsigned char *b64 = base64_encode_bin(digest, SHA384_DIGEST_LENGTH, &outlen);
|
||||
int res = 0;
|
||||
|
||||
if (b64) {
|
||||
res = !memcmp(b64, checksum, outlen);
|
||||
mem_free(b64);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
check_sha256(const void *data, size_t len, const char *checksum)
|
||||
{
|
||||
unsigned char digest[SHA256_DIGEST_LENGTH] = {0};
|
||||
SHA256_CTX ctx;
|
||||
SHA256_Init(&ctx);
|
||||
SHA256_Update(&ctx, data, len);
|
||||
SHA256_Final(digest, &ctx);
|
||||
|
||||
int outlen = 0;
|
||||
unsigned char *b64 = base64_encode_bin(digest, SHA256_DIGEST_LENGTH, &outlen);
|
||||
int res = 0;
|
||||
|
||||
if (b64) {
|
||||
res = !memcmp(b64, checksum, outlen);
|
||||
mem_free(b64);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
enum alg {
|
||||
EL_SHA512 = 1,
|
||||
EL_SHA384 = 2,
|
||||
EL_SHA256 = 3
|
||||
};
|
||||
|
||||
int
|
||||
validate_cache_integrity(struct cache_entry *cached, const char *integrity)
|
||||
{
|
||||
struct fragment *frag = get_cache_fragment(cached);
|
||||
const char *ch = integrity;
|
||||
int ret = 1;
|
||||
|
||||
if (!frag) {
|
||||
return 0;
|
||||
}
|
||||
while (1) {
|
||||
int alg = 0;
|
||||
skip_space(ch);
|
||||
|
||||
if (!ch) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!strncmp("sha512-", ch, 7)) {
|
||||
alg = EL_SHA512;
|
||||
ch += 7;
|
||||
} else if (!strncmp("sha384-", ch, 7)) {
|
||||
alg = EL_SHA384;
|
||||
ch += 7;
|
||||
} else if (!strncmp("sha256-", ch, 7)) {
|
||||
alg = EL_SHA256;
|
||||
ch += 7;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (alg) {
|
||||
case EL_SHA512:
|
||||
ret = check_sha512(frag->data, (size_t)frag->length, ch);
|
||||
break;
|
||||
case EL_SHA384:
|
||||
ret = check_sha384(frag->data, (size_t)frag->length, ch);
|
||||
break;
|
||||
case EL_SHA256:
|
||||
ret = check_sha256(frag->data, (size_t)frag->length, ch);
|
||||
break;
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
skip_nonspace(ch);
|
||||
}
|
||||
}
|
||||
#else
|
||||
int
|
||||
validate_cache_integrity(struct cache_entry *cached, const char *integrity)
|
||||
{
|
||||
struct fragment *frag = get_cache_fragment(cached);
|
||||
|
||||
if (!frag) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
3
src/cache/cache.h
vendored
3
src/cache/cache.h
vendored
@ -73,6 +73,7 @@ struct cache_entry {
|
||||
* an entry with this set to 1 in wild nature ;-). */
|
||||
unsigned int gc_target:1; /* The GC touch of death */
|
||||
unsigned int cgi:1; /* Is a CGI output? */
|
||||
unsigned int integrity_valid:1; /* Was integrity checked and valid */
|
||||
|
||||
cache_mode_T cache_mode; /* Reload condition */
|
||||
};
|
||||
@ -155,6 +156,8 @@ int get_cache_entry_count(void);
|
||||
int get_cache_entry_used_count(void);
|
||||
int get_cache_entry_loading_count(void);
|
||||
|
||||
int validate_cache_integrity(struct cache_entry *cached, const char *integrity);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -336,8 +336,10 @@ not_processed:
|
||||
uri = get_uri(import_url, URI_BASE);
|
||||
if (!uri) goto imported;
|
||||
|
||||
char *integrity = get_attr_val(a, "integrity", html_context->doc_cp);
|
||||
/* Request the imported script as part of the document ... */
|
||||
html_context->special_f(html_context, SP_SCRIPT, uri);
|
||||
html_context->special_f(html_context, SP_SCRIPT, uri, integrity);
|
||||
mem_free_if(integrity);
|
||||
done_uri(uri);
|
||||
|
||||
/* Create URL reference onload snippet. */
|
||||
|
@ -40,6 +40,11 @@
|
||||
#include "document/options.h"
|
||||
#include "document/refresh.h"
|
||||
#include "document/renderer.h"
|
||||
|
||||
#ifdef CONFIG_ECMASCRIPT_SMJS
|
||||
#include "ecmascript/ecmascript-c.h"
|
||||
#endif
|
||||
|
||||
#include "intl/charsets.h"
|
||||
#include "osdep/types.h"
|
||||
#include "protocol/uri.h"
|
||||
@ -2392,8 +2397,13 @@ html_special(struct html_context *html_context, html_special_type_T c, ...)
|
||||
#ifdef CONFIG_ECMASCRIPT
|
||||
if (document) {
|
||||
struct uri *uri = va_arg(l, struct uri *);
|
||||
char *integrity = va_arg(l, char *);
|
||||
|
||||
add_to_uri_list(&document->ecmascript_imports, uri);
|
||||
|
||||
if (uri && integrity) {
|
||||
save_integrity_in_map(uri, integrity);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
@ -39,9 +39,35 @@
|
||||
#include "viewer/text/form.h"
|
||||
#include "viewer/text/view.h"
|
||||
|
||||
#ifdef CONFIG_ECMASCRIPT_SMJS
|
||||
#include <map>
|
||||
std::map<struct uri *, char *> map_integrity;
|
||||
#endif
|
||||
|
||||
extern int interpreter_count;
|
||||
extern int ecmascript_enabled;
|
||||
|
||||
void
|
||||
save_integrity_in_map(struct uri *uri, char *integrity)
|
||||
{
|
||||
#ifdef CONFIG_ECMASCRIPT_SMJS
|
||||
map_integrity[uri] = null_or_stracpy(integrity);
|
||||
#endif
|
||||
}
|
||||
|
||||
char *
|
||||
get_integrity_from_map(struct uri *uri)
|
||||
{
|
||||
#ifdef CONFIG_ECMASCRIPT_SMJS
|
||||
auto e = map_integrity.find(uri);
|
||||
|
||||
if (e != map_integrity.end()) {
|
||||
return e->second;
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
ecmascript_get_interpreter_count(void)
|
||||
{
|
||||
@ -198,6 +224,19 @@ process_snippets(struct ecmascript_interpreter *interpreter,
|
||||
if (!uri) continue;
|
||||
|
||||
cached = get_redirected_cache_entry(uri);
|
||||
|
||||
#ifdef CONFIG_ECMASCRIPT_SMJS
|
||||
if (cached) {
|
||||
char *integrity = get_integrity_from_map(uri);
|
||||
|
||||
if (integrity) {
|
||||
if (!validate_cache_integrity(cached, integrity)) {
|
||||
cached = NULL;
|
||||
fprintf(stderr, "Integrity failed for %s\n", struri(uri));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
done_uri(uri);
|
||||
|
||||
if (!cached) {
|
||||
|
@ -81,6 +81,9 @@ void ecmascript_walk_tree(struct string *buf, void *nod, bool start, bool toSort
|
||||
|
||||
void free_el_dom_collection(void *ctx);
|
||||
|
||||
void save_integrity_in_map(struct uri *uri, char *integrity);
|
||||
char *get_integrity_from_map(struct uri *uri);
|
||||
|
||||
extern struct module ecmascript_module;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
Loading…
x
Reference in New Issue
Block a user