Skip to content
Open
Show file tree
Hide file tree
Changes from all 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){ /*...*/})

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) {
if (typeof cb !== 'function') {
throw new Error('cb should be function');
}
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/)
}