[njs] Adding support for Buffer objects in crypto methods.
Dmitry Volyntsev
xeioex at nginx.com
Wed Sep 23 14:17:31 UTC 2020
details: https://hg.nginx.org/njs/rev/eef4ab1bee70
branches:
changeset: 1527:eef4ab1bee70
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Tue Sep 22 18:42:21 2020 +0000
description:
Adding support for Buffer objects in crypto methods.
diffstat:
src/njs_buffer.c | 212 +++++++++++-------------
src/njs_buffer.h | 22 ++
src/njs_crypto.c | 402 +++++++++++++++++++++-------------------------
src/test/njs_unit_test.c | 291 ++++++++++++++++++---------------
4 files changed, 463 insertions(+), 464 deletions(-)
diffs (truncated from 1417 to 1000 lines):
diff -r 00fcf5b00ce3 -r eef4ab1bee70 src/njs_buffer.c
--- a/src/njs_buffer.c Mon Sep 21 17:15:10 2020 +0000
+++ b/src/njs_buffer.c Tue Sep 22 18:42:21 2020 +0000
@@ -17,19 +17,6 @@
((size << 2) | (sign << 1) | little)
-typedef njs_int_t (*njs_buffer_encode)(njs_vm_t *vm, njs_value_t *value,
- const njs_str_t *src);
-typedef size_t (*njs_buffer_encode_length)(const njs_str_t *src,
- size_t *out_size);
-
-typedef struct {
- njs_str_t name;
- njs_buffer_encode encode;
- njs_buffer_encode decode;
- njs_buffer_encode_length decode_length;
-} njs_buffer_encoding_t;
-
-
static njs_buffer_encoding_t njs_buffer_encodings[] =
{
{
@@ -83,18 +70,15 @@ static njs_int_t njs_buffer_write_string
njs_typed_array_t *array, const njs_buffer_encoding_t *encoding,
uint64_t offset, uint64_t length);
static njs_int_t njs_buffer_fill(njs_vm_t *vm, njs_typed_array_t *array,
- njs_value_t *value, const njs_buffer_encoding_t *encoding, uint64_t offset,
+ const njs_value_t *fill, const njs_value_t *encoding, uint64_t offset,
uint64_t end);
-static njs_int_t njs_buffer_fill_string(njs_vm_t *vm, njs_value_t *value,
+static njs_int_t njs_buffer_fill_string(njs_vm_t *vm, const njs_value_t *value,
njs_typed_array_t *array, const njs_buffer_encoding_t *encoding,
uint8_t *start, uint8_t *end);
-static njs_int_t njs_buffer_fill_typed_array(njs_vm_t *vm, njs_value_t *value,
- njs_typed_array_t *array, uint8_t *start, uint8_t *end);
-static const njs_buffer_encoding_t *njs_buffer_encoding(njs_vm_t *vm,
- njs_value_t *value);
-static njs_int_t njs_buffer_decode_string(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *dst, const njs_buffer_encoding_t *encoding);
-static void njs_buffer_decode_destroy(njs_vm_t *vm, njs_value_t *source,
+static njs_int_t njs_buffer_fill_typed_array(njs_vm_t *vm,
+ const njs_value_t *value, njs_typed_array_t *array, uint8_t *start,
+ uint8_t *end);
+static void njs_buffer_decode_destroy(njs_vm_t *vm, const njs_value_t *source,
njs_value_t *target);
@@ -149,8 +133,8 @@ njs_buffer_set(njs_vm_t *vm, njs_value_t
}
-static njs_typed_array_t *
-njs_buffer_alloc_array(njs_vm_t *vm, size_t size, njs_bool_t zeroing)
+njs_typed_array_t *
+njs_buffer_alloc(njs_vm_t *vm, size_t size, njs_bool_t zeroing)
{
njs_value_t value;
njs_typed_array_t *array;
@@ -169,6 +153,25 @@ njs_buffer_alloc_array(njs_vm_t *vm, siz
}
+njs_int_t
+njs_buffer_new(njs_vm_t *vm, njs_value_t *value, const u_char *start,
+ uint32_t size)
+{
+ njs_typed_array_t *buffer;
+
+ buffer = njs_buffer_alloc(vm, size, 0);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
+ memcpy(njs_typed_array_buffer(buffer)->u.u8, start, size);
+
+ njs_set_typed_array(value, buffer);
+
+ return NJS_OK;
+}
+
+
static njs_int_t
njs_buffer_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
@@ -180,13 +183,13 @@ njs_buffer_constructor(njs_vm_t *vm, njs
static njs_int_t
-njs_buffer_alloc(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+njs_buffer_alloc_safe(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t safe)
{
- double size;
- njs_int_t ret;
- njs_typed_array_t *array;
- const njs_buffer_encoding_t *encoding;
+ double size;
+ njs_int_t ret;
+ njs_typed_array_t *array;
+ const njs_value_t *fill;
if (njs_slow_path(!njs_is_number(njs_arg(args, nargs, 1)))) {
njs_type_error(vm, "\"size\" argument must be of type number");
@@ -199,22 +202,15 @@ njs_buffer_alloc(njs_vm_t *vm, njs_value
return NJS_ERROR;
}
- array = njs_buffer_alloc_array(vm, size, safe || nargs <= 2);
+ array = njs_buffer_alloc(vm, size, safe || nargs <= 2);
if (njs_slow_path(array == NULL)) {
return NJS_ERROR;
}
- if (safe && nargs > 2) {
- encoding = njs_buffer_utf8_encoding();
-
- if (nargs > 3 && njs_is_string(njs_argument(args, 2))) {
- encoding = njs_buffer_encoding(vm, njs_argument(args, 3));
- if (njs_slow_path(encoding == NULL)) {
- return NJS_ERROR;
- }
- }
-
- ret = njs_buffer_fill(vm, array, njs_argument(args, 2), encoding, 0,
+ fill = njs_arg(args, nargs, 2);
+
+ if (safe && njs_is_defined(fill)) {
+ ret = njs_buffer_fill(vm, array, fill, njs_arg(args, nargs, 3), 0,
array->byte_length);
if (njs_slow_path(ret != NJS_OK)) {
return NJS_ERROR;
@@ -246,13 +242,9 @@ njs_buffer_from(njs_vm_t *vm, njs_value_
njs_arg(args, nargs, 3));
case NJS_STRING:
- encoding = njs_buffer_utf8_encoding();
-
- if (nargs > 2) {
- encoding = njs_buffer_encoding(vm, njs_argument(args, 2));
- if (njs_slow_path(encoding == NULL)) {
- return NJS_ERROR;
- }
+ encoding = njs_buffer_encoding(vm, njs_arg(args, nargs, 2));
+ if (njs_slow_path(encoding == NULL)) {
+ return NJS_ERROR;
}
return njs_buffer_from_string(vm, value, encoding);
@@ -334,7 +326,7 @@ next:
return ret;
}
- buffer = njs_buffer_alloc_array(vm, len, 0);
+ buffer = njs_buffer_alloc(vm, len, 0);
if (njs_slow_path(buffer == NULL)) {
return NJS_ERROR;
}
@@ -448,7 +440,7 @@ njs_buffer_from_typed_array(njs_vm_t *vm
length = njs_typed_array_length(array);
- buffer = njs_buffer_alloc_array(vm, length, 0);
+ buffer = njs_buffer_alloc(vm, length, 0);
if (njs_slow_path(buffer == NULL)) {
return NJS_ERROR;
}
@@ -481,7 +473,7 @@ njs_buffer_from_string(njs_vm_t *vm, njs
njs_string_get(&dst, &str);
- buffer = njs_buffer_alloc_array(vm, str.length, 0);
+ buffer = njs_buffer_alloc(vm, str.length, 0);
if (njs_slow_path(buffer == NULL)) {
return NJS_ERROR;
}
@@ -812,7 +804,7 @@ njs_buffer_concat(njs_vm_t *vm, njs_valu
}
}
- buffer = njs_buffer_alloc_array(vm, len, 0);
+ buffer = njs_buffer_alloc(vm, len, 0);
if (njs_slow_path(buffer == NULL)) {
return NJS_ERROR;
}
@@ -884,8 +876,11 @@ static njs_int_t
njs_buffer_is_encoding(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
- njs_set_boolean(&vm->retval,
- njs_buffer_encoding(vm, njs_arg(args, nargs, 1)) != NULL);
+ const njs_value_t *value;
+
+ value = njs_arg(args, nargs, 1);
+ njs_set_boolean(&vm->retval, njs_is_defined(value)
+ && njs_buffer_encoding(vm, value) != NULL);
return NJS_OK;
}
@@ -1563,12 +1558,11 @@ static njs_int_t
njs_buffer_prototype_fill(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
- uint64_t offset, end;
- njs_int_t ret;
- njs_value_t *this, *value, *value_offset, *value_end,
- *encode;
- njs_typed_array_t *array;
- const njs_buffer_encoding_t *encoding;
+ uint64_t offset, end;
+ njs_int_t ret;
+ njs_value_t *this, *value, *value_offset, *value_end,
+ *encode;
+ njs_typed_array_t *array;
this = njs_argument(args, 0);
if (njs_slow_path(nargs < 2)) {
@@ -1584,8 +1578,6 @@ njs_buffer_prototype_fill(njs_vm_t *vm,
value_offset = njs_arg(args, nargs, 2);
value_end = njs_arg(args, nargs, 3);
encode = njs_arg(args, nargs, 4);
- encoding = njs_buffer_utf8_encoding();
-
offset = 0;
end = array->byte_length;
@@ -1593,7 +1585,7 @@ njs_buffer_prototype_fill(njs_vm_t *vm,
if (njs_is_defined(value_offset)) {
if (njs_is_string(value) && njs_is_string(value_offset)) {
encode = value_offset;
- goto encoding;
+ goto fill;
}
ret = njs_value_to_index(vm, value_offset, &offset);
@@ -1605,7 +1597,7 @@ njs_buffer_prototype_fill(njs_vm_t *vm,
if (njs_is_defined(value_end)) {
if (njs_is_string(value) && njs_is_string(value_end)) {
encode = value_end;
- goto encoding;
+ goto fill;
}
ret = njs_value_to_index(vm, value_end, &end);
@@ -1614,21 +1606,9 @@ njs_buffer_prototype_fill(njs_vm_t *vm,
}
}
- if (njs_is_defined(encode)) {
- if (njs_slow_path(!njs_is_string(encode))) {
- njs_type_error(vm, "\"encoding\" argument must be of type string");
- return NJS_ERROR;
- }
-
- encoding:
-
- encoding = njs_buffer_encoding(vm, encode);
- if (njs_slow_path(encoding == NULL)) {
- return NJS_ERROR;
- }
- }
-
- ret = njs_buffer_fill(vm, array, value, encoding, offset, end);
+fill:
+
+ ret = njs_buffer_fill(vm, array, value, encode, offset, end);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
@@ -1642,13 +1622,14 @@ done:
static njs_int_t
-njs_buffer_fill(njs_vm_t *vm, njs_typed_array_t *array, njs_value_t *value,
- const njs_buffer_encoding_t *encoding, uint64_t offset, uint64_t end)
+njs_buffer_fill(njs_vm_t *vm, njs_typed_array_t *array, const njs_value_t *fill,
+ const njs_value_t *encode, uint64_t offset, uint64_t end)
{
- double num;
- uint8_t *start, *stop;
- njs_int_t ret;
- njs_array_buffer_t *buffer;
+ double num;
+ uint8_t *start, *stop;
+ njs_int_t ret;
+ njs_array_buffer_t *buffer;
+ const njs_buffer_encoding_t *encoding;
buffer = njs_typed_array_writable(vm, array);
if (njs_slow_path(buffer == NULL)) {
@@ -1672,15 +1653,20 @@ njs_buffer_fill(njs_vm_t *vm, njs_typed_
start = &buffer->u.u8[array->offset + offset];
stop = &buffer->u.u8[array->offset + end];
- switch (value->type) {
+ switch (fill->type) {
case NJS_STRING:
- return njs_buffer_fill_string(vm, value, array, encoding, start, stop);
+ encoding = njs_buffer_encoding(vm, encode);
+ if (njs_slow_path(encoding == NULL)) {
+ return NJS_ERROR;
+ }
+
+ return njs_buffer_fill_string(vm, fill, array, encoding, start, stop);
case NJS_TYPED_ARRAY:
- return njs_buffer_fill_typed_array(vm, value, array, start, stop);
+ return njs_buffer_fill_typed_array(vm, fill, array, start, stop);
default:
- ret = njs_value_to_number(vm, value, &num);
+ ret = njs_value_to_number(vm, njs_value_arg(fill), &num);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
@@ -1698,7 +1684,7 @@ njs_buffer_fill(njs_vm_t *vm, njs_typed_
static njs_int_t
-njs_buffer_fill_string(njs_vm_t *vm, njs_value_t *value,
+njs_buffer_fill_string(njs_vm_t *vm, const njs_value_t *value,
njs_typed_array_t *array, const njs_buffer_encoding_t *encoding,
uint8_t *start, uint8_t *end)
{
@@ -1733,7 +1719,7 @@ done:
static njs_int_t
-njs_buffer_fill_typed_array(njs_vm_t *vm, njs_value_t *value,
+njs_buffer_fill_typed_array(njs_vm_t *vm, const njs_value_t *value,
njs_typed_array_t *array, uint8_t *to, uint8_t *end)
{
size_t byte_length;
@@ -1773,7 +1759,7 @@ njs_buffer_prototype_to_string(njs_vm_t
uint64_t start, end;
njs_int_t ret;
njs_str_t str;
- njs_value_t *this, *enc, *value_start, *value_end;
+ njs_value_t *this, *value_start, *value_end;
njs_typed_array_t *array;
const njs_buffer_encoding_t *encoding;
@@ -1783,7 +1769,6 @@ njs_buffer_prototype_to_string(njs_vm_t
return NJS_ERROR;
}
- enc = njs_arg(args, nargs, 1);
value_start = njs_arg(args, nargs, 2);
value_end = njs_arg(args, nargs, 3);
@@ -1791,11 +1776,9 @@ njs_buffer_prototype_to_string(njs_vm_t
end = array->byte_length;
encoding = njs_buffer_utf8_encoding();
- if (njs_is_defined(enc)) {
- encoding = njs_buffer_encoding(vm, njs_argument(args, 1));
- if (njs_slow_path(encoding == NULL)) {
- return NJS_ERROR;
- }
+ encoding = njs_buffer_encoding(vm, njs_arg(args, nargs, 1));
+ if (njs_slow_path(encoding == NULL)) {
+ return NJS_ERROR;
}
if (njs_is_defined(value_start)) {
@@ -2265,40 +2248,41 @@ njs_buffer_prototype_to_json(njs_vm_t *v
}
-static const njs_buffer_encoding_t *
-njs_buffer_encoding(njs_vm_t *vm, njs_value_t *value)
+const njs_buffer_encoding_t *
+njs_buffer_encoding(njs_vm_t *vm, const njs_value_t *value)
{
- njs_str_t str;
- njs_int_t ret;
+ njs_str_t name;
njs_buffer_encoding_t *encoding;
if (njs_slow_path(!njs_is_string(value))) {
- ret = njs_value_to_string(vm, value, value);
- if (njs_slow_path(ret != NJS_OK)) {
+ if (njs_is_defined(value)) {
+ njs_type_error(vm, "encoding must be a string");
return NULL;
}
+
+ return &njs_buffer_encodings[0];
}
- njs_string_get(value, &str);
+ njs_string_get(value, &name);
for (encoding = &njs_buffer_encodings[0];
encoding->name.length != 0;
encoding++)
{
- if (njs_strstr_eq(&str, &encoding->name)) {
+ if (njs_strstr_eq(&name, &encoding->name)) {
return encoding;
}
}
- njs_type_error(vm, "\"%V\" encoding is not supported", &str);
+ njs_type_error(vm, "\"%V\" encoding is not supported", &name);
return NULL;
}
-static njs_int_t
-njs_buffer_decode_string(njs_vm_t *vm, njs_value_t *value, njs_value_t *dst,
- const njs_buffer_encoding_t *encoding)
+njs_int_t
+njs_buffer_decode_string(njs_vm_t *vm, const njs_value_t *value,
+ njs_value_t *dst, const njs_buffer_encoding_t *encoding)
{
njs_int_t ret;
njs_str_t str;
@@ -2325,7 +2309,7 @@ njs_buffer_decode_string(njs_vm_t *vm, n
static void
-njs_buffer_decode_destroy(njs_vm_t *vm, njs_value_t *source,
+njs_buffer_decode_destroy(njs_vm_t *vm, const njs_value_t *source,
njs_value_t *target)
{
njs_str_t src, trg;
@@ -2833,7 +2817,7 @@ static const njs_object_prop_t njs_buff
{
.type = NJS_PROPERTY,
.name = njs_string("alloc"),
- .value = njs_native_function2(njs_buffer_alloc, 0, 1),
+ .value = njs_native_function2(njs_buffer_alloc_safe, 0, 1),
.writable = 1,
.configurable = 1,
},
@@ -2841,7 +2825,7 @@ static const njs_object_prop_t njs_buff
{
.type = NJS_PROPERTY,
.name = njs_string("allocUnsafe"),
- .value = njs_native_function2(njs_buffer_alloc, 1, 0),
+ .value = njs_native_function2(njs_buffer_alloc_safe, 1, 0),
.writable = 1,
.configurable = 1,
},
@@ -2849,7 +2833,7 @@ static const njs_object_prop_t njs_buff
{
.type = NJS_PROPERTY,
.name = njs_long_string("allocUnsafeSlow"),
- .value = njs_native_function2(njs_buffer_alloc, 1, 0),
+ .value = njs_native_function2(njs_buffer_alloc_safe, 1, 0),
.writable = 1,
.configurable = 1,
},
diff -r 00fcf5b00ce3 -r eef4ab1bee70 src/njs_buffer.h
--- a/src/njs_buffer.h Mon Sep 21 17:15:10 2020 +0000
+++ b/src/njs_buffer.h Tue Sep 22 18:42:21 2020 +0000
@@ -8,8 +8,30 @@
#define _NJS_BUFFER_H_INCLUDED_
+typedef njs_int_t (*njs_buffer_encode_t)(njs_vm_t *vm, njs_value_t *value,
+ const njs_str_t *src);
+typedef size_t (*njs_buffer_encode_length_t)(const njs_str_t *src,
+ size_t *out_size);
+
+typedef struct {
+ njs_str_t name;
+ njs_buffer_encode_t encode;
+ njs_buffer_encode_t decode;
+ njs_buffer_encode_length_t decode_length;
+} njs_buffer_encoding_t;
+
+
njs_int_t njs_buffer_set(njs_vm_t *vm, njs_value_t *value, const u_char *start,
uint32_t size);
+njs_int_t njs_buffer_new(njs_vm_t *vm, njs_value_t *value, const u_char *start,
+ uint32_t size);
+njs_typed_array_t *njs_buffer_alloc(njs_vm_t *vm, size_t size,
+ njs_bool_t zeroing);
+
+const njs_buffer_encoding_t *njs_buffer_encoding(njs_vm_t *vm,
+ const njs_value_t *value);
+njs_int_t njs_buffer_decode_string(njs_vm_t *vm, const njs_value_t *value,
+ njs_value_t *dst, const njs_buffer_encoding_t *encoding);
extern const njs_object_type_init_t njs_buffer_type_init;
diff -r 00fcf5b00ce3 -r eef4ab1bee70 src/njs_crypto.c
--- a/src/njs_crypto.c Mon Sep 21 17:15:10 2020 +0000
+++ b/src/njs_crypto.c Tue Sep 22 18:42:21 2020 +0000
@@ -56,6 +56,14 @@ typedef struct {
} njs_crypto_enc_t;
+static njs_hash_alg_t *njs_crypto_algorithm(njs_vm_t *vm,
+ const njs_value_t *value);
+static njs_crypto_enc_t *njs_crypto_encoding(njs_vm_t *vm,
+ const njs_value_t *value);
+static njs_int_t njs_buffer_digest(njs_vm_t *vm, njs_value_t *value,
+ const njs_str_t *src);
+
+
static njs_hash_alg_t njs_hash_algorithms[] = {
{
@@ -92,9 +100,15 @@ static njs_hash_alg_t njs_hash_algorithm
};
+
static njs_crypto_enc_t njs_encodings[] = {
{
+ njs_str("buffer"),
+ njs_buffer_digest
+ },
+
+ {
njs_str("hex"),
njs_string_hex
},
@@ -116,11 +130,6 @@ static njs_crypto_enc_t njs_encodings[]
};
-static njs_hash_alg_t *njs_crypto_alg(njs_vm_t *vm, const njs_str_t *name);
-static njs_crypto_enc_t *njs_crypto_encoding(njs_vm_t *vm,
- const njs_str_t *name);
-
-
static njs_object_value_t *
njs_crypto_object_value_alloc(njs_vm_t *vm, njs_object_type_t type)
{
@@ -152,19 +161,11 @@ static njs_int_t
njs_crypto_create_hash(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
- njs_str_t alg_name;
njs_digest_t *dgst;
njs_hash_alg_t *alg;
njs_object_value_t *hash;
- if (njs_slow_path(nargs < 2 || !njs_is_string(&args[1]))) {
- njs_type_error(vm, "algorithm must be a string");
- return NJS_ERROR;
- }
-
- njs_string_get(&args[1], &alg_name);
-
- alg = njs_crypto_alg(vm, &alg_name);
+ alg = njs_crypto_algorithm(vm, njs_arg(args, nargs, 1));
if (njs_slow_path(alg == NULL)) {
return NJS_ERROR;
}
@@ -193,34 +194,79 @@ njs_crypto_create_hash(njs_vm_t *vm, njs
static njs_int_t
njs_hash_prototype_update(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
+ njs_index_t tag)
{
- njs_str_t data;
- njs_value_t *this;
- njs_digest_t *dgst;
-
- if (njs_slow_path(nargs < 2 || !njs_is_string(&args[1]))) {
- njs_type_error(vm, "data must be a string");
- return NJS_ERROR;
- }
+ njs_str_t data;
+ njs_int_t ret;
+ njs_hmac_t *ctx;
+ njs_value_t *this, dst;
+ njs_digest_t *dgst;
+ njs_typed_array_t *array;
+ const njs_value_t *value;
+ njs_array_buffer_t *buffer;
+ const njs_buffer_encoding_t *encoding;
this = njs_argument(args, 0);
-
- if (njs_slow_path(!njs_is_object_data(this, NJS_DATA_TAG_CRYPTO_HASH))) {
+ if (njs_slow_path(!njs_is_object_data(this, tag))) {
njs_type_error(vm, "\"this\" is not a hash object");
return NJS_ERROR;
}
- njs_string_get(&args[1], &data);
+ value = njs_arg(args, nargs, 1);
+
+ switch (value->type) {
+ case NJS_STRING:
+ encoding = njs_buffer_encoding(vm, njs_arg(args, nargs, 2));
+ if (njs_slow_path(encoding == NULL)) {
+ return NJS_ERROR;
+ }
+
+ ret = njs_buffer_decode_string(vm, value, &dst, encoding);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ njs_string_get(&dst, &data);
+ break;
- dgst = njs_object_data(this);
+ case NJS_TYPED_ARRAY:
+ case NJS_DATA_VIEW:
+ array = njs_typed_array(value);
+ buffer = array->buffer;
+ if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+ njs_type_error(vm, "detached buffer");
+ return NJS_ERROR;
+ }
- if (njs_slow_path(dgst->alg == NULL)) {
- njs_error(vm, "Digest already called");
+ data.start = &buffer->u.u8[array->offset];
+ data.length = array->byte_length;
+ break;
+
+ default:
+ njs_type_error(vm, "data argument \"%s\" is not a string "
+ "or Buffer-like object", njs_type_string(value->type));
+
return NJS_ERROR;
}
- dgst->alg->update(&dgst->u, data.start, data.length);
+ if (tag == NJS_DATA_TAG_CRYPTO_HASH) {
+ dgst = njs_object_data(this);
+ if (njs_slow_path(dgst->alg == NULL)) {
+ njs_error(vm, "Digest already called");
+ return NJS_ERROR;
+ }
+
+ dgst->alg->update(&dgst->u, data.start, data.length);
+
+ } else {
+ ctx = njs_object_data(this);
+ if (njs_slow_path(ctx->alg == NULL)) {
+ njs_error(vm, "Digest already called");
+ return NJS_ERROR;
+ }
+
+ ctx->alg->update(&ctx->u, data.start, data.length);
+ }
vm->retval = *this;
@@ -230,71 +276,62 @@ njs_hash_prototype_update(njs_vm_t *vm,
static njs_int_t
njs_hash_prototype_digest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
+ njs_index_t tag)
{
- u_char digest[32], *p;
- njs_int_t ret;
- njs_str_t enc_name, str;
+ njs_str_t str;
+ njs_hmac_t *ctx;
njs_value_t *this;
njs_digest_t *dgst;
njs_hash_alg_t *alg;
njs_crypto_enc_t *enc;
-
- if (njs_slow_path(nargs > 1 && !njs_is_string(&args[1]))) {
- njs_type_error(vm, "encoding must be a string");
- return NJS_ERROR;
- }
+ u_char hash1[32], digest[32];
this = njs_argument(args, 0);
-
- if (njs_slow_path(!njs_is_object_data(this, NJS_DATA_TAG_CRYPTO_HASH))) {
+ if (njs_slow_path(!njs_is_object_data(this, tag))) {
njs_type_error(vm, "\"this\" is not a hash object");
return NJS_ERROR;
}
- enc = NULL;
-
- if (nargs > 1) {
- njs_string_get(&args[1], &enc_name);
-
- enc = njs_crypto_encoding(vm, &enc_name);
- if (njs_slow_path(enc == NULL)) {
- return NJS_ERROR;
- }
- }
-
- dgst = njs_object_data(this);
-
- if (njs_slow_path(dgst->alg == NULL)) {
- njs_error(vm, "Digest already called");
+ enc = njs_crypto_encoding(vm, njs_arg(args, nargs, 1));
+ if (njs_slow_path(enc == NULL)) {
return NJS_ERROR;
}
- alg = dgst->alg;
+ if (tag == NJS_DATA_TAG_CRYPTO_HASH) {
+ dgst = njs_object_data(this);
+ if (njs_slow_path(dgst->alg == NULL)) {
+ goto exception;
+ }
+
+ alg = dgst->alg;
+ alg->final(digest, &dgst->u);
+ dgst->alg = NULL;
- alg->final(digest, &dgst->u);
+ } else {
+ ctx = njs_object_data(this);
+ if (njs_slow_path(ctx->alg == NULL)) {
+ goto exception;
+ }
+
+ alg = ctx->alg;
+ alg->final(hash1, &ctx->u);
+
+ alg->init(&ctx->u);
+ alg->update(&ctx->u, ctx->opad, 64);
+ alg->update(&ctx->u, hash1, alg->size);
+ alg->final(digest, &ctx->u);
+ ctx->alg = NULL;
+ }
str.start = digest;
str.length = alg->size;
- if (enc == NULL) {
- p = njs_string_alloc(vm, &vm->retval, str.length, 0);
-
- if (njs_fast_path(p != NULL)) {
- memcpy(p, str.start, str.length);
- ret = NJS_OK;
+ return enc->encode(vm, &vm->retval, &str);
- } else {
- ret = NJS_ERROR;
- }
+exception:
- } else {
- ret = enc->encode(vm, &vm->retval, &str);
- }
-
- dgst->alg = NULL;
-
- return ret;
+ njs_error(vm, "Digest already called");
+ return NJS_ERROR;
}
@@ -317,7 +354,8 @@ static const njs_object_prop_t njs_hash
{
.type = NJS_PROPERTY,
.name = njs_string("update"),
- .value = njs_native_function(njs_hash_prototype_update, 0),
+ .value = njs_native_function2(njs_hash_prototype_update, 0,
+ NJS_DATA_TAG_CRYPTO_HASH),
.writable = 1,
.configurable = 1,
},
@@ -325,7 +363,8 @@ static const njs_object_prop_t njs_hash
{
.type = NJS_PROPERTY,
.name = njs_string("digest"),
- .value = njs_native_function(njs_hash_prototype_digest, 0),
+ .value = njs_native_function2(njs_hash_prototype_digest, 0,
+ NJS_DATA_TAG_CRYPTO_HASH),
.writable = 1,
.configurable = 1,
},
@@ -397,31 +436,47 @@ static njs_int_t
njs_crypto_create_hmac(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
- u_char digest[32], key_buf[64];
- njs_str_t alg_name, key;
+ njs_str_t key;
njs_uint_t i;
njs_hmac_t *ctx;
njs_hash_alg_t *alg;
+ njs_typed_array_t *array;
+ const njs_value_t *value;
+ njs_array_buffer_t *buffer;
njs_object_value_t *hmac;
-
- if (njs_slow_path(nargs < 2 || !njs_is_string(&args[1]))) {
- njs_type_error(vm, "algorithm must be a string");
- return NJS_ERROR;
- }
+ u_char digest[32], key_buf[64];
- if (njs_slow_path(nargs < 3 || !njs_is_string(&args[2]))) {
- njs_type_error(vm, "key must be a string");
- return NJS_ERROR;
- }
-
- njs_string_get(&args[1], &alg_name);
-
- alg = njs_crypto_alg(vm, &alg_name);
+ alg = njs_crypto_algorithm(vm, njs_arg(args, nargs, 1));
if (njs_slow_path(alg == NULL)) {
return NJS_ERROR;
}
- njs_string_get(&args[2], &key);
+ value = njs_arg(args, nargs, 2);
+
+ switch (value->type) {
+ case NJS_STRING:
+ njs_string_get(value, &key);
+ break;
+
+ case NJS_TYPED_ARRAY:
+ case NJS_DATA_VIEW:
+ array = njs_typed_array(value);
+ buffer = array->buffer;
+ if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+ njs_type_error(vm, "detached buffer");
+ return NJS_ERROR;
+ }
+
+ key.start = &buffer->u.u8[array->offset];
+ key.length = array->byte_length;
+ break;
+
+ default:
+ njs_type_error(vm, "key argument \"%s\" is not a string "
+ "or Buffer-like object", njs_type_string(value->type));
+
+ return NJS_ERROR;
+ }
ctx = njs_mp_alloc(vm->mem_pool, sizeof(njs_hmac_t));
if (njs_slow_path(ctx == NULL)) {
@@ -468,118 +523,6 @@ njs_crypto_create_hmac(njs_vm_t *vm, njs
}
-static njs_int_t
-njs_hmac_prototype_update(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- njs_str_t data;
- njs_hmac_t *ctx;
- njs_value_t *this;
-
- if (njs_slow_path(nargs < 2 || !njs_is_string(&args[1]))) {
- njs_type_error(vm, "data must be a string");
- return NJS_ERROR;
- }
-
- this = njs_argument(args, 0);
-
- if (njs_slow_path(!njs_is_object_data(this, NJS_DATA_TAG_CRYPTO_HMAC))) {
- njs_type_error(vm, "\"this\" is not a hash object");
- return NJS_ERROR;
- }
-
- njs_string_get(&args[1], &data);
-
- ctx = njs_object_data(this);
-
- if (njs_slow_path(ctx->alg == NULL)) {
- njs_error(vm, "Digest already called");
- return NJS_ERROR;
- }
-
- ctx->alg->update(&ctx->u, data.start, data.length);
-
- vm->retval = *this;
-
- return NJS_OK;
-}
-
-
-static njs_int_t
-njs_hmac_prototype_digest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- u_char hash1[32], digest[32], *p;
- njs_str_t enc_name, str;
- njs_int_t ret;
- njs_hmac_t *ctx;
- njs_value_t *this;
- njs_hash_alg_t *alg;
- njs_crypto_enc_t *enc;
-
- if (njs_slow_path(nargs > 1 && !njs_is_string(&args[1]))) {
- njs_type_error(vm, "encoding must be a string");
- return NJS_ERROR;
- }
-
- this = njs_argument(args, 0);
-
- if (njs_slow_path(!njs_is_object_data(this, NJS_DATA_TAG_CRYPTO_HMAC))) {
- njs_type_error(vm, "\"this\" is not a hash object");
- return NJS_ERROR;
- }
-
- enc = NULL;
-
- if (nargs > 1) {
- njs_string_get(&args[1], &enc_name);
-
- enc = njs_crypto_encoding(vm, &enc_name);
- if (njs_slow_path(enc == NULL)) {
- return NJS_ERROR;
- }
- }
-
- ctx = njs_object_data(this);
-
- if (njs_slow_path(ctx->alg == NULL)) {
- njs_error(vm, "Digest already called");
- return NJS_ERROR;
- }
-
- alg = ctx->alg;
-
- alg->final(hash1, &ctx->u);
-
- alg->init(&ctx->u);
- alg->update(&ctx->u, ctx->opad, 64);
- alg->update(&ctx->u, hash1, alg->size);
- alg->final(digest, &ctx->u);
-
- str.start = digest;
- str.length = alg->size;
-
- if (enc == NULL) {
- p = njs_string_alloc(vm, &vm->retval, str.length, 0);
-
- if (njs_fast_path(p != NULL)) {
- memcpy(p, str.start, str.length);
- ret = NJS_OK;
-
- } else {
- ret = NJS_ERROR;
- }
-
- } else {
- ret = enc->encode(vm, &vm->retval, &str);
- }
-
- ctx->alg = NULL;
-
- return ret;
-}
-
-
static const njs_object_prop_t njs_hmac_prototype_properties[] =
{
{
@@ -599,7 +542,8 @@ static const njs_object_prop_t njs_hmac
{
.type = NJS_PROPERTY,
.name = njs_string("update"),
- .value = njs_native_function(njs_hmac_prototype_update, 0),
+ .value = njs_native_function2(njs_hash_prototype_update, 0,
+ NJS_DATA_TAG_CRYPTO_HMAC),
.writable = 1,
.configurable = 1,
},
@@ -607,7 +551,8 @@ static const njs_object_prop_t njs_hmac
{
.type = NJS_PROPERTY,
.name = njs_string("digest"),
- .value = njs_native_function(njs_hmac_prototype_digest, 0),
+ .value = njs_native_function2(njs_hash_prototype_digest, 0,
+ NJS_DATA_TAG_CRYPTO_HMAC),
.writable = 1,
.configurable = 1,
},
@@ -716,34 +661,61 @@ const njs_object_type_init_t njs_hmac_t
static njs_hash_alg_t *
-njs_crypto_alg(njs_vm_t *vm, const njs_str_t *name)
+njs_crypto_algorithm(njs_vm_t *vm, const njs_value_t *value)
{
- njs_hash_alg_t *e;
+ njs_str_t name;
+ njs_hash_alg_t *e;
+
+ if (njs_slow_path(!njs_is_string(value))) {
+ njs_type_error(vm, "algorithm must be a string");
+ return NULL;
+ }
+
+ njs_string_get(value, &name);
More information about the nginx-devel
mailing list