Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve error reporting in JsThemis #384

Merged
merged 27 commits into from
Feb 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
db104c1
Error reporting helpers
ilammy Feb 18, 2019
2c17f16
Secure Message: use new error reporting functions
ilammy Feb 18, 2019
9a1f5de
Secure Message: length and type checks for arguments
ilammy Feb 18, 2019
9a9d27e
Secure Message: tests for empty keys and messages
ilammy Feb 18, 2019
8bba743
Secure Cell: use new error reporting functions
ilammy Feb 18, 2019
6bafbb4
Secure Cell: length and type checks for arguments
ilammy Feb 18, 2019
39f753a
Secure Cell: tests for empty arguments
ilammy Feb 18, 2019
a41d268
Use THEMIS_FAIL as initial status value
vixentael Feb 18, 2019
fe575d8
Use full sentence in messages
vixentael Feb 18, 2019
cc6d699
Use full sentences in error messages
ilammy Feb 18, 2019
4a1b5bd
Improve error messages, simplify calls
ilammy Feb 18, 2019
67b1299
Don't check exception content
ilammy Feb 18, 2019
27fe0dc
Return original Themis status code
ilammy Feb 18, 2019
765f2ec
Retain status code for early errors
ilammy Feb 18, 2019
3f187da
Secure Session: use new error reporting functions
ilammy Feb 18, 2019
f6b733e
Secure Session: length and type checks for arguments
ilammy Feb 18, 2019
74aaa6f
Secure Session: tests for invalid arguments
ilammy Feb 18, 2019
bc9786b
Secure Comparator: use new error reporting functions
ilammy Feb 18, 2019
af03452
Secure Comparator: length and type checks for arguments
ilammy Feb 18, 2019
755e2d4
Secure Comparator: tests for invalid arguments
ilammy Feb 18, 2019
7b29e2c
Key generation: update error reporting and checks
ilammy Feb 18, 2019
5ae5d6f
Merge branch 'master' into js-errors
ilammy Feb 18, 2019
d24b49a
Use specific error code for Secure Session and Comparator
ilammy Feb 18, 2019
6caa83c
Pin mocha to 5.2.0
ilammy Feb 19, 2019
593dedb
Avoid using deprecated NAN methods
ilammy Feb 19, 2019
6a6b540
Secure Session: add checks to pubkey callback
ilammy Feb 19, 2019
a437395
Revert accidental changes
ilammy Feb 19, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/wrappers/themis/jsthemis/addon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

#include <node.h>
#include "errors.hpp"
#include "secure_message.hpp"
#include "secure_keygen.hpp"
#include "secure_session.hpp"
Expand All @@ -24,6 +25,7 @@
#include "secure_comparator.hpp"

void InitAll(v8::Handle<v8::Object> exports) {
jsthemis::Errors::Init(exports);
jsthemis::SecureMessage::Init(exports);
jsthemis::KeyPair::Init(exports);
jsthemis::SecureSession::Init(exports);
Expand Down
4 changes: 2 additions & 2 deletions src/wrappers/themis/jsthemis/binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"targets": [
{
"target_name": "jsthemis",
"sources": [ "addon.cpp", "secure_message.cpp", "secure_keygen.cpp", "secure_session.cpp", "secure_cell_seal.cpp", "secure_cell_context_imprint.cpp", "secure_cell_token_protect.cpp", "secure_comparator.cpp" ],
"sources": [ "addon.cpp", "errors.cpp", "secure_message.cpp", "secure_keygen.cpp", "secure_session.cpp", "secure_cell_seal.cpp", "secure_cell_context_imprint.cpp", "secure_cell_token_protect.cpp", "secure_comparator.cpp" ],
"libraries": ["-L/usr/local/lib/", "-L/usr/lib/", "-lsoter", "-lthemis"],
"include_dirs": [
"<!(node -e \"require('nan')\")"
]
}
]
}
}
136 changes: 136 additions & 0 deletions src/wrappers/themis/jsthemis/errors.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* Copyright (c) 2019 Cossack Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "errors.hpp"

#include <string>

#include <nan.h>
#include <node.h>

namespace jsthemis {

static inline void ExportStatusCode(v8::Handle<v8::Object>& exports, const char* name, themis_status_t status) {
exports->Set(Nan::New(name).ToLocalChecked(), Nan::New(status));
}

void Errors::Init(v8::Handle<v8::Object> exports) {
ExportStatusCode(exports, "SUCCESS", THEMIS_SUCCESS);
ExportStatusCode(exports, "FAIL", THEMIS_FAIL);
ExportStatusCode(exports, "INVALID_PARAMETER", THEMIS_INVALID_PARAMETER);
ExportStatusCode(exports, "NO_MEMORY", THEMIS_NO_MEMORY);
ExportStatusCode(exports, "BUFFER_TOO_SMALL", THEMIS_BUFFER_TOO_SMALL);
ExportStatusCode(exports, "DATA_CORRUPT", THEMIS_DATA_CORRUPT);
ExportStatusCode(exports, "INVALID_SIGNATURE", THEMIS_INVALID_SIGNATURE);
ExportStatusCode(exports, "NOT_SUPPORTED", THEMIS_NOT_SUPPORTED);
ExportStatusCode(exports, "SSESSION_KA_NOT_FINISHED", THEMIS_SSESSION_KA_NOT_FINISHED);
ExportStatusCode(exports, "SSESSION_TRANSPORT_ERROR", THEMIS_SSESSION_TRANSPORT_ERROR);
ExportStatusCode(exports, "SSESSION_GET_PUB_FOR_ID_CALLBACK_ERROR", THEMIS_SSESSION_GET_PUB_FOR_ID_CALLBACK_ERROR);
ExportStatusCode(exports, "SCOMPARE_NOT_READY", THEMIS_SCOMPARE_NOT_READY);
}

static const char* ErrorDescription(themis_status_t status) {
switch (status) {
case THEMIS_SUCCESS:
return "success";
case THEMIS_FAIL:
return "failure";
case THEMIS_INVALID_PARAMETER:
return "invalid parameter";
case THEMIS_NO_MEMORY:
return "out of memory";
case THEMIS_BUFFER_TOO_SMALL:
return "buffer too small";
case THEMIS_DATA_CORRUPT:
return "corrupted data";
case THEMIS_INVALID_SIGNATURE:
return "invalid signature";
case THEMIS_NOT_SUPPORTED:
return "operation not supported";
default:
return "unknown error";
}
}

static const char* ErrorDescriptionSecureSession(themis_status_t status) {
switch (status) {
case THEMIS_SSESSION_SEND_OUTPUT_TO_PEER:
return "send key agreement data to peer";
case THEMIS_SSESSION_KA_NOT_FINISHED:
return "key agreement not finished";
case THEMIS_SSESSION_TRANSPORT_ERROR:
return "transport layer error";
case THEMIS_SSESSION_GET_PUB_FOR_ID_CALLBACK_ERROR:
return "failed to get public key for ID";
default:
return ErrorDescription(status);
}
}

static const char* ErrorDescriptionSecureComparator(themis_status_t status) {
switch (status) {
case THEMIS_SCOMPARE_SEND_OUTPUT_TO_PEER:
return "send comparison data to peer";
case THEMIS_SCOMPARE_NOT_READY:
return "comparator not ready";
case THEMIS_SCOMPARE_MATCH:
return "data matches";
case THEMIS_SCOMPARE_NO_MATCH:
return "data does not match";
default:
return ErrorDescription(status);
}
}

static v8::Local<v8::Value> WithStatus(v8::Local<v8::Value> error, themis_status_t status) {
v8::Local<v8::Object> object = error.As<v8::Object>();
object->Set(Nan::New("code").ToLocalChecked(), Nan::New(status));
return error;
}

void ThrowError(const char* domain, themis_status_t status) {
std::string message;
message += domain;
message += ": ";
message += ErrorDescription(status);
Nan::ThrowError(WithStatus(Nan::Error(message.c_str()), status));
}

void ThrowParameterError(const char* domain, const char* description) {
std::string message;
message += domain;
message += ": ";
message += description;
Nan::ThrowError(WithStatus(Nan::Error(message.c_str()), THEMIS_INVALID_PARAMETER));
}

void ThrowSecureSessionError(const char* domain, themis_status_t status) {
std::string message;
message += domain;
message += ": ";
message += ErrorDescriptionSecureSession(status);
Nan::ThrowError(WithStatus(Nan::Error(message.c_str()), status));
}

void ThrowSecureComparatorError(const char* domain, themis_status_t status) {
std::string message;
message += domain;
message += ": ";
message += ErrorDescriptionSecureComparator(status);
Nan::ThrowError(WithStatus(Nan::Error(message.c_str()), status));
}

} // namespace jsthemis
42 changes: 42 additions & 0 deletions src/wrappers/themis/jsthemis/errors.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2019 Cossack Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef JSTHEMIS_ERRORS_HPP_
#define JSTHEMIS_ERRORS_HPP_

#include <nan.h>

#include <themis/themis.h>

namespace jsthemis {

namespace Errors {

void Init(v8::Handle<v8::Object> exports);

} // namespace Errors

void ThrowError(const char* domain, themis_status_t status);

void ThrowParameterError(const char* domain, const char* description);

void ThrowSecureSessionError(const char* domain, themis_status_t status);

void ThrowSecureComparatorError(const char* domain, themis_status_t status);

} // namespace jsthemis

#endif /* JSTHEMIS_ERRORS_HPP_ */
88 changes: 80 additions & 8 deletions src/wrappers/themis/jsthemis/secure_cell_context_imprint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <node_buffer.h>
#include <themis/themis.h>
#include <vector>
#include "errors.hpp"
#include "secure_cell_context_imprint.hpp"

namespace jsthemis {
Expand All @@ -42,6 +43,21 @@ namespace jsthemis {

void SecureCellContextImprint::New(const Nan::FunctionCallbackInfo<v8::Value>& args) {
if (args.IsConstructCall()) {
if(args.Length()<1){
ThrowParameterError("Secure Cell (Context Imprint) constructor", "not enough arguments, expected master key");
args.GetReturnValue().SetUndefined();
vixentael marked this conversation as resolved.
Show resolved Hide resolved
return;
}
if(!args[0]->IsUint8Array()){
ThrowParameterError("Secure Cell (Context Imprint) constructor", "master key is not a byte buffer");
args.GetReturnValue().SetUndefined();
return;
}
if(node::Buffer::Length(args[0])==0){
ThrowParameterError("Secure Cell (Context Imprint) constructor", "master key is empty");
args.GetReturnValue().SetUndefined();
return;
}
std::vector<uint8_t> key((uint8_t*)(node::Buffer::Data(args[0])), (uint8_t*)(node::Buffer::Data(args[0])+node::Buffer::Length(args[0])));
SecureCellContextImprint* obj = new SecureCellContextImprint(key);
obj->Wrap(args.This());
Expand All @@ -55,18 +71,46 @@ namespace jsthemis {
}

void SecureCellContextImprint::encrypt(const Nan::FunctionCallbackInfo<v8::Value>& args) {
themis_status_t status = THEMIS_FAIL;
SecureCellContextImprint* obj = Nan::ObjectWrap::Unwrap<SecureCellContextImprint>(args.This());
if(args.Length()<2){
ThrowParameterError("Secure Cell (Context Imprint) failed to encrypt", "not enough arguments, missing message and context");
args.GetReturnValue().SetUndefined();
return;
}
if(!args[0]->IsUint8Array()){
ThrowParameterError("Secure Cell (Context Imprint) failed to encrypt", "message is not a byte buffer, use ByteBuffer or Uint8Array");
args.GetReturnValue().SetUndefined();
return;
}
if(node::Buffer::Length(args[0])==0){
ThrowParameterError("Secure Cell (Context Imprint) failed to encrypt", "message is empty");
args.GetReturnValue().SetUndefined();
return;
}
if(!args[1]->IsUint8Array()){
ThrowParameterError("Secure Cell (Context Imprint) failed to encrypt", "context is not a byte buffer, use ByteBuffer or Uint8Array");
args.GetReturnValue().SetUndefined();
return;
}
if(node::Buffer::Length(args[1])==0){
ThrowParameterError("Secure Cell (Context Imprint) failed to encrypt", "context is empty");
args.GetReturnValue().SetUndefined();
return;
}
size_t length=0;
const uint8_t* context=(const uint8_t*)(node::Buffer::Data(args[1]));
size_t context_length=node::Buffer::Length(args[1]);
if(themis_secure_cell_encrypt_context_imprint(&(obj->key_)[0], obj->key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), context, context_length, NULL, &length)!=THEMIS_BUFFER_TOO_SMALL){
Nan::ThrowError("Secure Cell (Context Imprint) failed encrypting");
status=themis_secure_cell_encrypt_context_imprint(&(obj->key_)[0], obj->key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), context, context_length, NULL, &length);
if(status!=THEMIS_BUFFER_TOO_SMALL){
ThrowError("Secure Cell (Context Imprint) failed to encrypt", status);
args.GetReturnValue().SetUndefined();
return;
}
uint8_t* data=(uint8_t*)(malloc(length));
if(themis_secure_cell_encrypt_context_imprint(&(obj->key_)[0], obj->key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), context, context_length, data, &length)!=THEMIS_SUCCESS){
Nan::ThrowError("Secure Cell (Context Imprint) failed encrypting");
status=themis_secure_cell_encrypt_context_imprint(&(obj->key_)[0], obj->key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), context, context_length, data, &length);
if(status!=THEMIS_SUCCESS){
ThrowError("Secure Cell (Context Imprint) failed to encrypt", status);
free(data);
args.GetReturnValue().SetUndefined();
return;
Expand All @@ -75,18 +119,46 @@ namespace jsthemis {
}

void SecureCellContextImprint::decrypt(const Nan::FunctionCallbackInfo<v8::Value>& args) {
themis_status_t status = THEMIS_FAIL;
SecureCellContextImprint* obj = Nan::ObjectWrap::Unwrap<SecureCellContextImprint>(args.This());
if(args.Length()<2){
ThrowParameterError("Secure Cell (Context Imprint) failed to decrypt", "not enough arguments, expected message and context");
args.GetReturnValue().SetUndefined();
return;
}
if(!args[0]->IsUint8Array()){
ThrowParameterError("Secure Cell (Context Imprint) failed to decrypt", "message is not a byte buffer, use ByteBuffer or Uint8Array");
args.GetReturnValue().SetUndefined();
return;
}
if(node::Buffer::Length(args[0])==0){
ThrowParameterError("Secure Cell (Context Imprint) failed to decrypt", "message is empty");
args.GetReturnValue().SetUndefined();
return;
}
if(!args[1]->IsUint8Array()){
ThrowParameterError("Secure Cell (Context Imprint) failed to decrypt", "context is not a byte buffer, use ByteBuffer or Uint8Array");
args.GetReturnValue().SetUndefined();
return;
}
if(node::Buffer::Length(args[1])==0){
ThrowParameterError("Secure Cell (Context Imprint) failed to decrypt", "context is empty");
args.GetReturnValue().SetUndefined();
return;
}
size_t length=0;
const uint8_t* context=(const uint8_t*)(node::Buffer::Data(args[1]));
size_t context_length=node::Buffer::Length(args[1]);
if(themis_secure_cell_decrypt_context_imprint(&(obj->key_)[0], obj->key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), context, context_length, NULL, &length)!=THEMIS_BUFFER_TOO_SMALL){
Nan::ThrowError("Secure Cell (Context Imprint) failed decrypting");
status=themis_secure_cell_decrypt_context_imprint(&(obj->key_)[0], obj->key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), context, context_length, NULL, &length);
if(status!=THEMIS_BUFFER_TOO_SMALL){
ThrowError("Secure Cell (Context Imprint) failed to decrypt", status);
args.GetReturnValue().SetUndefined();
return;
}
uint8_t* data=(uint8_t*)(malloc(length));
if(themis_secure_cell_decrypt_context_imprint(&(obj->key_)[0], obj->key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), context, context_length, data, &length)!=THEMIS_SUCCESS){
Nan::ThrowError("Secure Cell (Context Imprint) failed decrypting");
status=themis_secure_cell_decrypt_context_imprint(&(obj->key_)[0], obj->key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), context, context_length, data, &length);
if(status!=THEMIS_SUCCESS){
ThrowError("Secure Cell (Context Imprint) failed to decrypt", status);
free(data);
args.GetReturnValue().SetUndefined();
return;
Expand Down
Loading