| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 6262fa4 commit 2d9c3cc
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,15 +1,14 @@ | |||
| 1 | 1 | 'use strict'; | |
| 2 | 2 | ||
| 3 | + const { AsyncWrap, Providers } = process.binding('async_wrap'); | ||
| 4 | + const { Buffer } = require('buffer'); | ||
| 5 | + const { randomBytes: _randomBytes } = process.binding('crypto'); | ||
| 3 | 6 | const { | |
| 4 | 7 | ERR_INVALID_ARG_TYPE, | |
| 5 | 8 | ERR_INVALID_CALLBACK, | |
| 6 | 9 | ERR_OUT_OF_RANGE | |
| 7 | 10 | } = require('internal/errors').codes; | |
| 8 | 11 | const { isArrayBufferView } = require('internal/util/types'); | |
| 9 | - const { | ||
| 10 | - randomBytes: _randomBytes, | ||
| 11 | - randomFill: _randomFill | ||
| 12 | - } = process.binding('crypto'); | ||
| 13 | 12 | ||
| 14 | 13 | const { kMaxLength } = require('buffer'); | |
| 15 | 14 | const kMaxUint32 = Math.pow(2, 32) - 1; | |
@@ -27,7 +26,7 @@ function assertOffset(offset, elementSize, length) { | |||
| 27 | 26 | throw new ERR_OUT_OF_RANGE('offset', `>= 0 && <= ${maxLength}`, offset); | |
| 28 | 27 | } | |
| 29 | 28 | ||
| 30 | - return offset; | ||
| 29 | + return offset >>> 0; // Convert to uint32. | ||
| 31 | 30 | } | |
| 32 | 31 | ||
| 33 | 32 | function assertSize(size, elementSize, offset, length) { | |
@@ -46,14 +45,25 @@ function assertSize(size, elementSize, offset, length) { | |||
| 46 | 45 | throw new ERR_OUT_OF_RANGE('size + offset', `<= ${length}`, size + offset); | |
| 47 | 46 | } | |
| 48 | 47 | ||
| 49 | - return size; | ||
| 48 | + return size >>> 0; // Convert to uint32. | ||
| 50 | 49 | } | |
| 51 | 50 | ||
| 52 | 51 | function randomBytes(size, cb) { | |
| 53 | - assertSize(size, 1, 0, Infinity); | ||
| 52 | + size = assertSize(size, 1, 0, Infinity); | ||
| 54 | 53 | if (cb !== undefined && typeof cb !== 'function') | |
| 55 | 54 | throw new ERR_INVALID_CALLBACK(); | |
| 56 | - return _randomBytes(size, cb); | ||
| 55 | + | ||
| 56 | + const buf = Buffer.alloc(size); | ||
| 57 | + | ||
| 58 | + if (!cb) return handleError(buf, 0, size); | ||
| 59 | + | ||
| 60 | + const wrap = new AsyncWrap(Providers.RANDOMBYTESREQUEST); | ||
| 61 | + wrap.ondone = (ex) => { // Retains buf while request is in flight. | ||
| 62 | + if (ex) return cb.call(wrap, ex); | ||
| 63 | + cb.call(wrap, null, buf); | ||
| 64 | + }; | ||
| 65 | + | ||
| 66 | + _randomBytes(buf, 0, size, wrap); | ||
| 57 | 67 | } | |
| 58 | 68 | ||
| 59 | 69 | function randomFillSync(buf, offset = 0, size) { | |
@@ -71,7 +81,7 @@ function randomFillSync(buf, offset = 0, size) { | |||
| 71 | 81 | size = assertSize(size, elementSize, offset, buf.byteLength); | |
| 72 | 82 | } | |
| 73 | 83 | ||
| 74 | - return _randomFill(buf, offset, size); | ||
| 84 | + return handleError(buf, offset, size); | ||
| 75 | 85 | } | |
| 76 | 86 | ||
| 77 | 87 | function randomFill(buf, offset, size, cb) { | |
@@ -100,7 +110,19 @@ function randomFill(buf, offset, size, cb) { | |||
| 100 | 110 | size = assertSize(size, elementSize, offset, buf.byteLength); | |
| 101 | 111 | } | |
| 102 | 112 | ||
| 103 | - return _randomFill(buf, offset, size, cb); | ||
| 113 | + const wrap = new AsyncWrap(Providers.RANDOMBYTESREQUEST); | ||
| 114 | + wrap.ondone = (ex) => { // Retains buf while request is in flight. | ||
| 115 | + if (ex) return cb.call(wrap, ex); | ||
| 116 | + cb.call(wrap, null, buf); | ||
| 117 | + }; | ||
| 118 | + | ||
| 119 | + _randomBytes(buf, offset, size, wrap); | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + function handleError(buf, offset, size) { | ||
| 123 | + const ex = _randomBytes(buf, offset, size); | ||
| 124 | + if (ex) throw ex; | ||
| 125 | + return buf; | ||
| 104 | 126 | } | |
| 105 | 127 | ||
| 106 | 128 | module.exports = { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -344,7 +344,6 @@ struct PackageConfig { | |||
| 344 | 344 | V(promise_reject_unhandled_function, v8::Function) \ | |
| 345 | 345 | V(promise_wrap_template, v8::ObjectTemplate) \ | |
| 346 | 346 | V(push_values_to_array_function, v8::Function) \ | |
| 347 | - V(randombytes_constructor_template, v8::ObjectTemplate) \ | ||
| 348 | 347 | V(sab_lifetimepartner_constructor_template, v8::FunctionTemplate) \ | |
| 349 | 348 | V(script_context_constructor_template, v8::FunctionTemplate) \ | |
| 350 | 349 | V(script_data_constructor_function, v8::Function) \ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -82,7 +82,6 @@ using v8::NewStringType; | |||
| 82 | 82 | using v8::Nothing; | |
| 83 | 83 | using v8::Null; | |
| 84 | 84 | using v8::Object; | |
| 85 | - using v8::ObjectTemplate; | ||
| 86 | 85 | using v8::PropertyAttribute; | |
| 87 | 86 | using v8::ReadOnly; | |
| 88 | 87 | using v8::Signature; | |
@@ -4589,208 +4588,50 @@ inline void CopyBuffer(Local<Value> buf, std::vector<char>* vec) { | |||
| 4589 | 4588 | } | |
| 4590 | 4589 | ||
| 4591 | 4590 | ||
| 4592 | - // Only instantiate within a valid HandleScope. | ||
| 4593 | - class RandomBytesRequest : public AsyncWrap, public ThreadPoolWork { | ||
| 4594 | - public: | ||
| 4595 | - enum FreeMode { FREE_DATA, DONT_FREE_DATA }; | ||
| 4596 | - | ||
| 4597 | - RandomBytesRequest(Environment* env, | ||
| 4598 | - Local<Object> object, | ||
| 4599 | - size_t size, | ||
| 4600 | - char* data, | ||
| 4601 | - FreeMode free_mode) | ||
| 4602 | - : AsyncWrap(env, object, AsyncWrap::PROVIDER_RANDOMBYTESREQUEST), | ||
| 4603 | - ThreadPoolWork(env), | ||
| 4604 | - error_(0), | ||
| 4605 | - size_(size), | ||
| 4606 | - data_(data), | ||
| 4607 | - free_mode_(free_mode) { | ||
| 4608 | - } | ||
| 4609 | - | ||
| 4610 | - inline size_t size() const { | ||
| 4611 | - return size_; | ||
| 4612 | - } | ||
| 4613 | - | ||
| 4614 | - inline char* data() const { | ||
| 4615 | - return data_; | ||
| 4616 | - } | ||
| 4617 | - | ||
| 4618 | - inline void set_data(char* data) { | ||
| 4619 | - data_ = data; | ||
| 4620 | - } | ||
| 4591 | + struct RandomBytesJob : public CryptoJob { | ||
| 4592 | + unsigned char* data; | ||
| 4593 | + size_t size; | ||
| 4594 | + CryptoErrorVector errors; | ||
| 4595 | + Maybe<int> rc; | ||
| 4621 | 4596 | ||
| 4622 | - inline void release() { | ||
| 4623 | - size_ = 0; | ||
| 4624 | - if (free_mode_ == FREE_DATA) { | ||
| 4625 | - free(data_); | ||
| 4626 | - data_ = nullptr; | ||
| 4627 | - } | ||
| 4628 | - } | ||
| 4597 | + inline explicit RandomBytesJob(Environment* env) | ||
| 4598 | + : CryptoJob(env), rc(Nothing<int>()) {} | ||
| 4629 | 4599 | ||
| 4630 | - inline void return_memory(char** d, size_t* len) { | ||
| 4631 | - *d = data_; | ||
| 4632 | - data_ = nullptr; | ||
| 4633 | - *len = size_; | ||
| 4634 | - size_ = 0; | ||
| 4600 | + inline void DoThreadPoolWork() override { | ||
| 4601 | + CheckEntropy(); // Ensure that OpenSSL's PRNG is properly seeded. | ||
| 4602 | + rc = Just(RAND_bytes(data, size)); | ||
| 4603 | + if (0 == rc.FromJust()) errors.Capture(); | ||
| 4635 | 4604 | } | |
| 4636 | 4605 | ||
| 4637 | - inline unsigned long error() const { // NOLINT(runtime/int) | ||
| 4638 | - return error_; | ||
| 4606 | + inline void AfterThreadPoolWork() override { | ||
| 4607 | + Local<Value> arg = ToResult(); | ||
| 4608 | + async_wrap->MakeCallback(env->ondone_string(), 1, &arg); | ||
| 4639 | 4609 | } | |
| 4640 | 4610 | ||
| 4641 | - inline void set_error(unsigned long err) { // NOLINT(runtime/int) | ||
| 4642 | - error_ = err; | ||
| 4611 | + inline Local<Value> ToResult() const { | ||
| 4612 | + if (errors.empty()) return Undefined(env->isolate()); | ||
| 4613 | + return errors.ToException(env); | ||
| 4643 | 4614 | } | |
| 4644 | - | ||
| 4645 | - size_t self_size() const override { return sizeof(*this); } | ||
| 4646 | - | ||
| 4647 | - void DoThreadPoolWork() override; | ||
| 4648 | - void AfterThreadPoolWork(int status) override; | ||
| 4649 | - | ||
| 4650 | - private: | ||
| 4651 | - unsigned long error_; // NOLINT(runtime/int) | ||
| 4652 | - size_t size_; | ||
| 4653 | - char* data_; | ||
| 4654 | - const FreeMode free_mode_; | ||
| 4655 | 4615 | }; | |
| 4656 | 4616 | ||
| 4657 | 4617 | ||
| 4658 | - void RandomBytesRequest::DoThreadPoolWork() { | ||
| 4659 | - // Ensure that OpenSSL's PRNG is properly seeded. | ||
| 4660 | - CheckEntropy(); | ||
| 4661 | - | ||
| 4662 | - const int r = RAND_bytes(reinterpret_cast<unsigned char*>(data_), size_); | ||
| 4663 | - | ||
| 4664 | - // RAND_bytes() returns 0 on error. | ||
| 4665 | - if (r == 0) { | ||
| 4666 | - set_error(ERR_get_error()); // NOLINT(runtime/int) | ||
| 4667 | - } else if (r == -1) { | ||
| 4668 | - set_error(static_cast<unsigned long>(-1)); // NOLINT(runtime/int) | ||
| 4669 | - } | ||
| 4670 | - } | ||
| 4671 | - | ||
| 4672 | - | ||
| 4673 | - // don't call this function without a valid HandleScope | ||
| 4674 | - void RandomBytesCheck(RandomBytesRequest* req, Local<Value> (*argv)[2]) { | ||
| 4675 | - if (req->error()) { | ||
| 4676 | - char errmsg[256] = "Operation not supported"; | ||
| 4677 | - | ||
| 4678 | - if (req->error() != static_cast<unsigned long>(-1)) // NOLINT(runtime/int) | ||
| 4679 | - ERR_error_string_n(req->error(), errmsg, sizeof errmsg); | ||
| 4680 | - | ||
| 4681 | - (*argv)[0] = Exception::Error(OneByteString(req->env()->isolate(), errmsg)); | ||
| 4682 | - (*argv)[1] = Null(req->env()->isolate()); | ||
| 4683 | - req->release(); | ||
| 4684 | - } else { | ||
| 4685 | - char* data = nullptr; | ||
| 4686 | - size_t size; | ||
| 4687 | - req->return_memory(&data, &size); | ||
| 4688 | - (*argv)[0] = Null(req->env()->isolate()); | ||
| 4689 | - Local<Value> buffer = | ||
| 4690 | - req->object()->Get(req->env()->context(), | ||
| 4691 | - req->env()->buffer_string()).ToLocalChecked(); | ||
| 4692 | - | ||
| 4693 | - if (buffer->IsArrayBufferView()) { | ||
| 4694 | - CHECK_LE(req->size(), Buffer::Length(buffer)); | ||
| 4695 | - char* buf = Buffer::Data(buffer); | ||
| 4696 | - memcpy(buf, data, req->size()); | ||
| 4697 | - (*argv)[1] = buffer; | ||
| 4698 | - } else { | ||
| 4699 | - (*argv)[1] = Buffer::New(req->env(), data, size) | ||
| 4700 | - .ToLocalChecked(); | ||
| 4701 | - } | ||
| 4702 | - } | ||
| 4703 | - } | ||
| 4704 | - | ||
| 4705 | - | ||
| 4706 | - void RandomBytesRequest::AfterThreadPoolWork(int status) { | ||
| 4707 | - std::unique_ptr<RandomBytesRequest> req(this); | ||
| 4708 | - if (status == UV_ECANCELED) | ||
| 4709 | - return; | ||
| 4710 | - CHECK_EQ(status, 0); | ||
| 4711 | - HandleScope handle_scope(env()->isolate()); | ||
| 4712 | - Context::Scope context_scope(env()->context()); | ||
| 4713 | - Local<Value> argv[2]; | ||
| 4714 | - RandomBytesCheck(this, &argv); | ||
| 4715 | - MakeCallback(env()->ondone_string(), arraysize(argv), argv); | ||
| 4716 | - } | ||
| 4717 | - | ||
| 4718 | - | ||
| 4719 | - void RandomBytesProcessSync(Environment* env, | ||
| 4720 | - std::unique_ptr<RandomBytesRequest> req, | ||
| 4721 | - Local<Value> (*argv)[2]) { | ||
| 4722 | - env->PrintSyncTrace(); | ||
| 4723 | - req->DoThreadPoolWork(); | ||
| 4724 | - RandomBytesCheck(req.get(), argv); | ||
| 4725 | - | ||
| 4726 | - if (!(*argv)[0]->IsNull()) | ||
| 4727 | - env->isolate()->ThrowException((*argv)[0]); | ||
| 4728 | - } | ||
| 4729 | - | ||
| 4730 | - | ||
| 4731 | 4618 | void RandomBytes(const FunctionCallbackInfo<Value>& args) { | |
| 4619 | + CHECK(args[0]->IsArrayBufferView()); // buffer; wrap object retains ref. | ||
| 4620 | + CHECK(args[1]->IsUint32()); // offset | ||
| 4621 | + CHECK(args[2]->IsUint32()); // size | ||
| 4622 | + CHECK(args[3]->IsObject() || args[3]->IsUndefined()); // wrap object | ||
| 4623 | + const uint32_t offset = args[1].As<Uint32>()->Value(); | ||
| 4624 | + const uint32_t size = args[2].As<Uint32>()->Value(); | ||
| 4625 | + CHECK_GE(offset + size, offset); // Overflow check. | ||
| 4626 | + CHECK_LE(offset + size, Buffer::Length(args[0])); // Bounds check. | ||
| 4732 | 4627 | Environment* env = Environment::GetCurrent(args); | |
| 4733 | - | ||
| 4734 | - const int64_t size = args[0]->IntegerValue(); | ||
| 4735 | - CHECK(size <= Buffer::kMaxLength); | ||
| 4736 | - | ||
| 4737 | - Local<Object> obj = env->randombytes_constructor_template()-> | ||
| 4738 | - NewInstance(env->context()).ToLocalChecked(); | ||
| 4739 | - char* data = node::Malloc(size); | ||
| 4740 | - std::unique_ptr<RandomBytesRequest> req( | ||
| 4741 | - new RandomBytesRequest(env, | ||
| 4742 | - obj, | ||
| 4743 | - size, | ||
| 4744 | - data, | ||
| 4745 | - RandomBytesRequest::FREE_DATA)); | ||
| 4746 | - | ||
| 4747 | - if (args[1]->IsFunction()) { | ||
| 4748 | - obj->Set(env->context(), env->ondone_string(), args[1]).FromJust(); | ||
| 4749 | - | ||
| 4750 | - req.release()->ScheduleWork(); | ||
| 4751 | - args.GetReturnValue().Set(obj); | ||
| 4752 | - } else { | ||
| 4753 | - Local<Value> argv[2]; | ||
| 4754 | - RandomBytesProcessSync(env, std::move(req), &argv); | ||
| 4755 | - if (argv[0]->IsNull()) | ||
| 4756 | - args.GetReturnValue().Set(argv[1]); | ||
| 4757 | - } | ||
| 4758 | - } | ||
| 4759 | - | ||
| 4760 | - | ||
| 4761 | - void RandomBytesBuffer(const FunctionCallbackInfo<Value>& args) { | ||
| 4762 | - Environment* env = Environment::GetCurrent(args); | ||
| 4763 | - | ||
| 4764 | - CHECK(args[0]->IsArrayBufferView()); | ||
| 4765 | - CHECK(args[1]->IsUint32()); | ||
| 4766 | - CHECK(args[2]->IsUint32()); | ||
| 4767 | - | ||
| 4768 | - int64_t offset = args[1]->IntegerValue(); | ||
| 4769 | - int64_t size = args[2]->IntegerValue(); | ||
| 4770 | - | ||
| 4771 | - Local<Object> obj = env->randombytes_constructor_template()-> | ||
| 4772 | - NewInstance(env->context()).ToLocalChecked(); | ||
| 4773 | - obj->Set(env->context(), env->buffer_string(), args[0]).FromJust(); | ||
| 4774 | - char* data = Buffer::Data(args[0]); | ||
| 4775 | - data += offset; | ||
| 4776 | - | ||
| 4777 | - std::unique_ptr<RandomBytesRequest> req( | ||
| 4778 | - new RandomBytesRequest(env, | ||
| 4779 | - obj, | ||
| 4780 | - size, | ||
| 4781 | - data, | ||
| 4782 | - RandomBytesRequest::DONT_FREE_DATA)); | ||
| 4783 | - if (args[3]->IsFunction()) { | ||
| 4784 | - obj->Set(env->context(), env->ondone_string(), args[3]).FromJust(); | ||
| 4785 | - | ||
| 4786 | - req.release()->ScheduleWork(); | ||
| 4787 | - args.GetReturnValue().Set(obj); | ||
| 4788 | - } else { | ||
| 4789 | - Local<Value> argv[2]; | ||
| 4790 | - RandomBytesProcessSync(env, std::move(req), &argv); | ||
| 4791 | - if (argv[0]->IsNull()) | ||
| 4792 | - args.GetReturnValue().Set(argv[1]); | ||
| 4793 | - } | ||
| 4628 | + std::unique_ptr<RandomBytesJob> job(new RandomBytesJob(env)); | ||
| 4629 | + job->data = reinterpret_cast<unsigned char*>(Buffer::Data(args[0])) + offset; | ||
| 4630 | + job->size = size; | ||
| 4631 | + if (args[3]->IsObject()) return RandomBytesJob::Run(std::move(job), args[3]); | ||
| 4632 | + env->PrintSyncTrace(); | ||
| 4633 | + job->DoThreadPoolWork(); | ||
| 4634 | + args.GetReturnValue().Set(job->ToResult()); | ||
| 4794 | 4635 | } | |
| 4795 | 4636 | ||
| 4796 | 4637 | ||
@@ -5355,7 +5196,6 @@ void Initialize(Local<Object> target, | |||
| 5355 | 5196 | ||
| 5356 | 5197 | env->SetMethod(target, "pbkdf2", PBKDF2); | |
| 5357 | 5198 | env->SetMethod(target, "randomBytes", RandomBytes); | |
| 5358 | - env->SetMethod(target, "randomFill", RandomBytesBuffer); | ||
| 5359 | 5199 | env->SetMethod(target, "timingSafeEqual", TimingSafeEqual); | |
| 5360 | 5200 | env->SetMethod(target, "getSSLCiphers", GetSSLCiphers); | |
| 5361 | 5201 | env->SetMethod(target, "getCiphers", GetCiphers); | |
@@ -5380,13 +5220,6 @@ void Initialize(Local<Object> target, | |||
| 5380 | 5220 | #ifndef OPENSSL_NO_SCRYPT | |
| 5381 | 5221 | env->SetMethod(target, "scrypt", Scrypt); | |
| 5382 | 5222 | #endif // OPENSSL_NO_SCRYPT | |
| 5383 | - | ||
| 5384 | - Local<FunctionTemplate> rb = FunctionTemplate::New(env->isolate()); | ||
| 5385 | - rb->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "RandomBytes")); | ||
| 5386 | - AsyncWrap::AddWrapMethods(env, rb); | ||
| 5387 | - Local<ObjectTemplate> rbt = rb->InstanceTemplate(); | ||
| 5388 | - rbt->SetInternalFieldCount(1); | ||
| 5389 | - env->set_randombytes_constructor_template(rbt); | ||
| 5390 | 5223 | } | |
| 5391 | 5224 | ||
| 5392 | 5225 | } // namespace crypto | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -120,7 +120,7 @@ if (common.hasCrypto) { // eslint-disable-line node-core/crypto-check | |||
| 120 | 120 | crypto.pbkdf2('password', 'salt', 1, 20, 'sha256', mc); | |
| 121 | 121 | ||
| 122 | 122 | crypto.randomBytes(1, common.mustCall(function rb() { | |
| 123 | - testInitialized(this, 'RandomBytes'); | ||
| 123 | + testInitialized(this, 'AsyncWrap'); | ||
| 124 | 124 | })); | |
| 125 | 125 | ||
| 126 | 126 | if (typeof process.binding('crypto').scrypt === 'function') { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments