crypto: refactor randomBytes() · nodejs/node@2d9c3cc
@@ -82,7 +82,6 @@ using v8::NewStringType;
8282using v8::Nothing;
8383using v8::Null;
8484using v8::Object;
85-using v8::ObjectTemplate;
8685using v8::PropertyAttribute;
8786using v8::ReadOnly;
8887using v8::Signature;
@@ -4589,208 +4588,50 @@ inline void CopyBuffer(Local<Value> buf, std::vector<char>* vec) {
45894588}
45904589459145904592-// 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;
462145964622-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>()) {}
462945994630-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();
46354604 }
463646054637-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);
46394609 }
464046104641-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);
46434614 }
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_;
46554615};
46564616465746174658-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-47314618void 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.
47324627 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());
47944635}
4795463647964637@@ -5355,7 +5196,6 @@ void Initialize(Local<Object> target,
5355519653565197 env->SetMethod(target, "pbkdf2", PBKDF2);
53575198 env->SetMethod(target, "randomBytes", RandomBytes);
5358- env->SetMethod(target, "randomFill", RandomBytesBuffer);
53595199 env->SetMethod(target, "timingSafeEqual", TimingSafeEqual);
53605200 env->SetMethod(target, "getSSLCiphers", GetSSLCiphers);
53615201 env->SetMethod(target, "getCiphers", GetCiphers);
@@ -5380,13 +5220,6 @@ void Initialize(Local<Object> target,
53805220#ifndef OPENSSL_NO_SCRYPT
53815221 env->SetMethod(target, "scrypt", Scrypt);
53825222#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);
53905223}
5391522453925225} // namespace crypto