1
0
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:
Witold Filipczyk 2024-09-23 20:42:15 +02:00
parent 2e210a79cf
commit 0cbc3d4a5c
6 changed files with 193 additions and 1 deletions

135
src/cache/cache.c vendored
View File

@ -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
View File

@ -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

View File

@ -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. */

View File

@ -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;

View File

@ -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) {

View File

@ -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