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

implement verifyFromStr #63

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
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
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,21 @@ x509.verify(

```

#### x509.verifyFromStr(`certStr`, `CABundleStr`, function(err, result){ /*...*/})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As @Southern said at #63 (comment), please update the CABundleStr to caBundleStr.


It is the same with verify.

```js
const x509 = require('x509');

x509.verify(
path.readFileSync(__dirname + '/certs/user.com.crt'),
path.readFileSync(__dirname + 'enduser-example.com.chain'),
function(err, result){ /*...*/}
);

```

## Examples
Checking the date to make sure the certificate is active:
```js
Expand Down
2 changes: 2 additions & 0 deletions include/x509.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ NAN_METHOD(get_subject);
NAN_METHOD(get_issuer);
NAN_METHOD(parse_cert);
NAN_METHOD(verify);
NAN_METHOD(verify_from_str);

Local<Value> try_parse(const std::string& dataString);
Local<Value> verify(const std::string& dataString);
Local<Value> verify_from_str(const std::string& dataString);
Local<Value> parse_date(ASN1_TIME *date);
Local<Value> parse_serial(ASN1_INTEGER *serial);
Local<Object> parse_name(X509_NAME *subject);
Expand Down
29 changes: 27 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,32 @@ exports.getAltNames = x509.getAltNames;
exports.getSubject = x509.getSubject;
exports.getIssuer = x509.getIssuer;

exports.verifyFromStr = function(certStr, CABundleStr, cb) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid if certStr and CABundleStr is a Buffer or String.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CABundleStr should be caBundleStr. It is not a constant, therefore it should not start with a capital.

if (typeof cb !== 'function') {
throw new Error('cb should be function')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Miss semi-colons in this file.

}
if (certStr instanceof Buffer) {
certStr = certStr.toString()
} else if (typeof certStr !== 'string') {
cb(new Error('certStr should be string or buffer'))
return
}
if (CABundleStr instanceof Buffer) {
CABundleStr = CABundleStr.toString()
} else if (typeof CABundleStr !== 'string') {
cb(new Error('CABundleStr should be string or buffer'))
return
}
var caughtErr = null;
try {
x509.verify_from_str(certStr, CABundleStr);
} catch (verificationError) {
caughtErr = verificationError;
} finally {
cb(caughtErr);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid the callback is a function, too.

}
};

exports.verify = function(certPath, CABundlePath, cb) {
if (!certPath) {
throw new TypeError('Certificate path is required');
Expand All @@ -29,8 +55,7 @@ exports.verify = function(certPath, CABundlePath, cb) {
try {
x509.verify(certPath, CABundlePath);
cb(null);
}
catch (verificationError) {
} catch (verificationError) {
cb(verificationError);
}
});
Expand Down
4 changes: 4 additions & 0 deletions src/addon.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ void init(Local<Object> exports) {
Nan::Set(exports,
Nan::New<String>("version").ToLocalChecked(),
Nan::New<String>(VERSION).ToLocalChecked());

Nan::Set(exports,
Nan::New<String>("verify_from_str").ToLocalChecked(),
Nan::New<FunctionTemplate>(verify_from_str)->GetFunction());

Nan::Set(exports,
Nan::New<String>("verify").ToLocalChecked(),
Expand Down
67 changes: 66 additions & 1 deletion src/x509.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,72 @@ std::string parse_args(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return *String::Utf8Value(info[0]->ToString());
}


NAN_METHOD(verify_from_str) {
Nan::HandleScope scope;
OpenSSL_add_all_algorithms();
std::string cert_str = *String::Utf8Value(info[0]->ToString());
std::string ca_str = *String::Utf8Value(info[1]->ToString());

X509_STORE *store = NULL;
X509_STORE_CTX *verify_ctx = NULL;
X509 *ca_cert = NULL;
BIO *ca_bio = NULL;
X509 *cert = NULL;
BIO *cert_bio = NULL;
const char *error = NULL;
do {
store = X509_STORE_new();
if (store == NULL) {
error = "Failed to create X509 certificate store.";
break;
}
verify_ctx = X509_STORE_CTX_new();
if (verify_ctx == NULL) {
error = "Failed to create X509 verification context.";
break;
}
cert_bio = BIO_new(BIO_s_mem());
size_t ret = BIO_puts(cert_bio, cert_str.c_str());
if (ret != cert_str.length()) {
error = "Error reading cert content";
break;
}
cert = PEM_read_bio_X509(cert_bio, NULL, 0, NULL);
if (cert == NULL) {
error = "Failed to load cert";
break;
}
ca_bio = BIO_new(BIO_s_mem());
ret = BIO_puts(ca_bio, ca_str.c_str());
if (ret != ca_str.length()) {
error = "Error reading ca content";
break;
}
ca_cert = PEM_read_bio_X509(ca_bio, NULL, 0, NULL);
if (ca_cert == NULL) {
error = "Failed to load ca";
break;
}
X509_STORE_CTX_init(verify_ctx, store, ca_cert, NULL);
X509_STORE_add_cert(store, cert);
ret = X509_verify_cert(verify_ctx);
if (ret < 1) {
error = X509_verify_cert_error_string(verify_ctx->error);
break;
}
} while(0);
X509_STORE_free(store);
X509_STORE_CTX_free(verify_ctx);
X509_free(ca_cert);
BIO_free_all(ca_bio);
X509_free(cert);
BIO_free_all(cert_bio);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check store, verify_ctx and others is a NULL, free a NULL might cause segfault.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these functions have checked NULL, the free function also does nothing when ptr is NULL , so we don't need to check again

if (error != NULL) {
Nan::ThrowError(error);
} else {
info.GetReturnValue().Set(Nan::New(true));
}
}

NAN_METHOD(verify) {
Nan::HandleScope scope;
Expand Down
51 changes: 50 additions & 1 deletion test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,53 @@ x509.verify(
function(err, result) {
assert.throws(assert.ifError.bind(null, err), /Failed to load cert/)
}
);
);

x509.verifyFromStr(
fs.readFileSync(path.join(__dirname, 'certs/enduser-example.com.crt')),
fs.readFileSync(path.join(__dirname, 'CA_chains/enduser-example.com.chain')),
function(err, result) {
assert.strictEqual(err, null)
}
);

x509.verifyFromStr(
fs.readFileSync(path.join(__dirname, 'certs/acaline.com.crt')),
fs.readFileSync(path.join(__dirname, 'CA_chains/enduser-example.com.chain')),
function(err, result) {
assert.throws(assert.ifError.bind(null, err), /self signed certificate/)
}
);

x509.verifyFromStr(
fs.readFileSync(path.join(__dirname, 'test.js')),
fs.readFileSync(path.join(__dirname, 'CA_chains/enduser-example.com.chain')),
function(err, result) {
assert.throws(assert.ifError.bind(null, err), /Failed to load cert/)
}
);

x509.verifyFromStr(
fs.readFileSync(path.join(__dirname, 'certs/acaline.com.crt')),
fs.readFileSync(path.join(__dirname, 'test.js')),
function(err, result) {
assert.throws(assert.ifError.bind(null, err), /Failed to load ca/)
}
);

x509.verifyFromStr(
123456,
fs.readFileSync(path.join(__dirname, 'CA_chains/enduser-example.com.chain')),
function(err, result) {
assert.throws(assert.ifError.bind(null, err), /certStr should be string or buffer/)
}
)

try {
x509.verifyFromStr(
fs.readFileSync(path.join(__dirname, 'certs/acaline.com.crt')),
fs.readFileSync(path.join(__dirname, 'CA_chains/enduser-example.com.chain'))
)
} catch (err) {
assert.throws(assert.ifError.bind(null, err), /cb should be function/)
}