From 0e574099b029ddfd77ea8f7eba98cd6beed14f05 Mon Sep 17 00:00:00 2001 From: msl Date: Fri, 7 Mar 2014 13:38:30 -0800 Subject: [PATCH 01/52] Add Equifax root cert, an example of a cert with UTCTime formatted dates whose century prefix should be 19. --- test/certs/equifax.crt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 test/certs/equifax.crt diff --git a/test/certs/equifax.crt b/test/certs/equifax.crt new file mode 100644 index 0000000..7a36225 --- /dev/null +++ b/test/certs/equifax.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV +UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy +dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 +MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx +dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f +BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A +cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC +AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm +aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw +ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj +IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF +MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA +A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y +7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh +1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 +-----END CERTIFICATE----- \ No newline at end of file From ea2a28f352f8cf66fe3282e652458bc842d5531b Mon Sep 17 00:00:00 2001 From: msl Date: Fri, 7 Mar 2014 13:40:22 -0800 Subject: [PATCH 02/52] Let OpenSSL handle date parsing. This fixes date parsing for UTCTime dates prior to 2000 and adds support for GeneralizedTime which uses four digit years. --- include/x509.h | 2 +- src/x509.cc | 36 +++++++++++++----------------------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/include/x509.h b/include/x509.h index 7ed1b19..def1a1c 100644 --- a/include/x509.h +++ b/include/x509.h @@ -29,7 +29,7 @@ using namespace v8; #endif Handle try_parse(char *data); -Handle parse_date(char *date); +Handle parse_date(ASN1_TIME *date); Handle parse_serial(ASN1_INTEGER *serial); Handle parse_name(X509_NAME *subject); char* real_name(char *data); diff --git a/src/x509.cc b/src/x509.cc index e582c91..9caaf96 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -163,8 +163,8 @@ Handle try_parse(char *data) { exports->Set(String::NewSymbol("subject"), parse_name(X509_get_subject_name(cert))); exports->Set(String::NewSymbol("issuer"), parse_name(X509_get_issuer_name(cert))); exports->Set(String::NewSymbol("serial"), parse_serial(X509_get_serialNumber(cert))); - exports->Set(String::NewSymbol("notBefore"), parse_date((char*) ASN1_STRING_data(X509_get_notBefore(cert)))); - exports->Set(String::NewSymbol("notAfter"), parse_date((char*) ASN1_STRING_data(X509_get_notAfter(cert)))); + exports->Set(String::NewSymbol("notBefore"), parse_date(X509_get_notBefore(cert))); + exports->Set(String::NewSymbol("notAfter"), parse_date(X509_get_notAfter(cert))); Local altNames(Array::New()); STACK_OF(GENERAL_NAME) *names = NULL; @@ -213,30 +213,20 @@ Handle parse_serial(ASN1_INTEGER *serial) { return scope.Close(serialNumber); } -Handle parse_date(char *date) { +Handle parse_date(ASN1_TIME *date) { HandleScope scope; - char current[3]; - int i; - Local dateArray(Array::New()); - Local output(String::New("")); + BIO *bio; + BUF_MEM *bm; + char formatted[64]; Local args[1]; - for (i = 0; i < (int) strlen(date) - 1; i += 2) { - strncpy(current, &date[i], 2); - current[2] = '\0'; - - dateArray->Set((i / 2), String::New(current)); - } - - output = String::Concat(output, String::Concat(dateArray->Get(1)->ToString(), String::New("/"))); - output = String::Concat(output, String::Concat(dateArray->Get(2)->ToString(), String::New("/"))); - output = String::Concat(output, String::Concat(String::New("20"), dateArray->Get(0)->ToString())); - output = String::Concat(output, String::New(" ")); - output = String::Concat(output, String::Concat(dateArray->Get(3)->ToString(), String::New(":"))); - output = String::Concat(output, String::Concat(dateArray->Get(4)->ToString(), String::New(":"))); - output = String::Concat(output, String::Concat(dateArray->Get(5)->ToString(), String::New(" GMT"))); - - args[0] = output; + formatted[0] = '\0'; + bio = BIO_new(BIO_s_mem()); + ASN1_TIME_print(bio, date); + BIO_get_mem_ptr (bio, &bm); + BUF_strlcpy (formatted, bm->data, bm->length + 1); + BIO_free (bio); + args[0] = String::New(formatted); return scope.Close(Context::GetCurrent()->Global()->Get(String::New("Date"))->ToObject()->CallAsConstructor(1, args)); } From f733c13562885c2eff42a6b96b036c885a4cc6de Mon Sep 17 00:00:00 2001 From: msl Date: Sat, 8 Mar 2014 15:38:39 -0800 Subject: [PATCH 03/52] Fix whitespace. --- src/x509.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/x509.cc b/src/x509.cc index 9caaf96..16acd6f 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -223,9 +223,9 @@ Handle parse_date(ASN1_TIME *date) { formatted[0] = '\0'; bio = BIO_new(BIO_s_mem()); ASN1_TIME_print(bio, date); - BIO_get_mem_ptr (bio, &bm); - BUF_strlcpy (formatted, bm->data, bm->length + 1); - BIO_free (bio); + BIO_get_mem_ptr(bio, &bm); + BUF_strlcpy(formatted, bm->data, bm->length + 1); + BIO_free(bio); args[0] = String::New(formatted); return scope.Close(Context::GetCurrent()->Global()->Get(String::New("Date"))->ToObject()->CallAsConstructor(1, args)); From c48d6044245c72d0cb215d62127c7994c80bb221 Mon Sep 17 00:00:00 2001 From: Yazhong Liu Date: Sun, 14 Sep 2014 20:54:58 +0800 Subject: [PATCH 04/52] fix author error --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 3a2e17a..071b710 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "x.509", - "version": "0.1.1", + "version": "0.1.2", "description": "Simple X509 certificate parser.", - "author": "Yorkie Neil ", + "author": "Colton Baker", "main": "index.js", "repository": { "type": "git", From 6ce9ba8c8e17c431e1fec2741c9911039b1d7b20 Mon Sep 17 00:00:00 2001 From: Yazhong Liu Date: Sun, 14 Sep 2014 21:40:31 +0800 Subject: [PATCH 05/52] fix #11 but without pem stuff --- .gitignore | 3 + binding.gyp | 3 +- include/x509.h | 22 ++--- package.json | 5 +- src/addon.cc | 10 +-- src/x509.cc | 240 +++++++++++++++++++++---------------------------- 6 files changed, 122 insertions(+), 161 deletions(-) diff --git a/.gitignore b/.gitignore index 801e565..6b475b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ + +node_modules build *.log +*.DS_Store diff --git a/binding.gyp b/binding.gyp index 4f9f9db..edd53e0 100644 --- a/binding.gyp +++ b/binding.gyp @@ -16,7 +16,8 @@ 'src/x509.cc' ], 'include_dirs': [ - 'include' + 'include', + " #include +#include +#include // OpenSSL headers #include @@ -17,23 +19,15 @@ using namespace v8; -#if NODE_VERSION_AT_LEAST(0, 11, 3) && defined(__APPLE__) - void get_altnames(const FunctionCallbackInfo &args); - void get_subject(const FunctionCallbackInfo &args); - void get_issuer(const FunctionCallbackInfo &args); - char* parse_args(const FunctionCallbackInfo &args); - void parse_cert(const FunctionCallbackInfo &args); -#else - Handle get_altnames(const Arguments &args); - Handle get_subject(const Arguments &args); - Handle get_issuer(const Arguments &args); - Handle parse_cert(const Arguments &args); -#endif +NAN_METHOD(get_altnames); +NAN_METHOD(get_subject); +NAN_METHOD(get_issuer); +NAN_METHOD(parse_cert); -Handle try_parse(char *data); +Handle try_parse(const std::string& dataString); Handle parse_date(ASN1_TIME *date); Handle parse_serial(ASN1_INTEGER *serial); Handle parse_name(X509_NAME *subject); -char* real_name(char *data); +const char* real_name(char *data); #endif diff --git a/package.json b/package.json index 071b710..764756d 100644 --- a/package.json +++ b/package.json @@ -11,5 +11,8 @@ "scripts": { "test": "node test/test" }, - "license": "MIT" + "license": "MIT", + "dependencies": { + "nan": "^1.3.0" + } } diff --git a/src/addon.cc b/src/addon.cc index 72bae35..832c2db 100644 --- a/src/addon.cc +++ b/src/addon.cc @@ -7,11 +7,11 @@ using namespace v8; void init(Handle exports) { - exports->Set(String::NewSymbol("version"), String::New(VERSION)); - exports->Set(String::NewSymbol("getAltNames"), FunctionTemplate::New(get_altnames)->GetFunction()); - exports->Set(String::NewSymbol("getSubject"), FunctionTemplate::New(get_subject)->GetFunction()); - exports->Set(String::NewSymbol("getIssuer"), FunctionTemplate::New(get_issuer)->GetFunction()); - exports->Set(String::NewSymbol("parseCert"), FunctionTemplate::New(parse_cert)->GetFunction()); + exports->Set(NanNew("version"), NanNew(VERSION)); + exports->Set(NanNew("getAltNames"), NanNew(get_altnames)->GetFunction()); + exports->Set(NanNew("getSubject"), NanNew(get_subject)->GetFunction()); + exports->Set(NanNew("getIssuer"), NanNew(get_issuer)->GetFunction()); + exports->Set(NanNew("parseCert"), NanNew(parse_cert)->GetFunction()); } NODE_MODULE(x509, init) diff --git a/src/x509.cc b/src/x509.cc index 619132c..abaa1aa 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -4,137 +4,106 @@ using namespace v8; // Field names that OpenSSL is missing. -char *MISSING[3][2] = { +static const char *MISSING[3][2] = { { - (char*) "1.3.6.1.4.1.311.60.2.1.1", - (char*) "jurisdictionOfIncorpationLocalityName" + "1.3.6.1.4.1.311.60.2.1.1", + "jurisdictionOfIncorpationLocalityName" }, { - (char*) "1.3.6.1.4.1.311.60.2.1.2", - (char*) "jurisdictionOfIncorporationStateOrProvinceName" + "1.3.6.1.4.1.311.60.2.1.2", + "jurisdictionOfIncorporationStateOrProvinceName" }, { - (char*) "1.3.6.1.4.1.311.60.2.1.3", - (char*) "jurisdictionOfIncorporationCountryName" + "1.3.6.1.4.1.311.60.2.1.3", + "jurisdictionOfIncorporationCountryName" } }; +Handle try_parse(const std::string& dataString); -#if NODE_VERSION_AT_LEAST(0, 11, 3) && defined(__APPLE__) -/* - * Code for 0.11.3 and higher. - */ -void get_altnames(const FunctionCallbackInfo &args) { - Local exports(try_parse(parse_args(args))->ToObject()); - args.GetReturnValue().Set(exports->Get(String::NewSymbol("altNames"))); -} - -void get_subject(const FunctionCallbackInfo &args) { - Local exports(try_parse(parse_args(args))->ToObject()); - args.GetReturnValue().Set(exports->Get(String::NewSymbol("subject"))); -} - -void get_issuer(const FunctionCallbackInfo &args) { - Local exports(try_parse(parse_args(args))->ToObject()); - args.GetReturnValue().Set(exports->Get(String::NewSymbol("issuer"))); -} - -char* parse_args(const FunctionCallbackInfo &args) { +std::string parse_args(_NAN_METHOD_ARGS) { if (args.Length() == 0) { - ThrowException(Exception::Error(String::New("Must provide a certificate file."))); - return NULL; + NanThrowTypeError("Must provide a certificate string."); + return std::string(); } if (!args[0]->IsString()) { - ThrowException(Exception::TypeError(String::New("Certificate must be a string."))); - return NULL; + NanThrowTypeError("Certificate must be a string."); + return std::string(); } if (args[0]->ToString()->Length() == 0) { - ThrowException(Exception::TypeError(String::New("Certificate argument provided, but left blank."))); - return NULL; + NanThrowTypeError("Certificate argument provided, but left blank."); + return std::string(); } - char *value = (char*) malloc(sizeof(char*) * args[0]->ToString()->Length()); - sprintf(value, "%s", *String::Utf8Value(args[0]->ToString())); - return value; -} - -void parse_cert(const FunctionCallbackInfo &args) { - Local exports(try_parse(parse_args(args))->ToObject()); - args.GetReturnValue().Set(exports); -} - -#else -/* - * Code for 0.11.2 and lower. - */ -Handle get_altnames(const Arguments &args) { - HandleScope scope; - Handle exports(Handle::Cast(parse_cert(args))); - - return scope.Close(exports->Get(String::NewSymbol("altNames"))); -} - -Handle get_subject(const Arguments &args) { - HandleScope scope; - Handle exports(Handle::Cast(parse_cert(args))); - - return scope.Close(exports->Get(String::NewSymbol("subject"))); + return *String::Utf8Value(args[0]->ToString()); } -Handle get_issuer(const Arguments &args) { - HandleScope scope; - Handle exports(Handle::Cast(parse_cert(args))); - - return scope.Close(exports->Get(String::NewSymbol("issuer"))); +NAN_METHOD(get_altnames) { + NanScope(); + std::string parsed_arg = parse_args(args); + if(parsed_arg.size() == 0) { + NanReturnUndefined(); + } + Local exports(try_parse(parsed_arg)->ToObject()); + NanReturnValue(exports->Get(NanNew("altNames"))); } -Handle parse_cert(const Arguments &args) { - HandleScope scope; - - if (args.Length() == 0) { - ThrowException(Exception::Error(String::New("Must provide a certificate file."))); - return scope.Close(Undefined()); +NAN_METHOD(get_subject) { + NanScope(); + std::string parsed_arg = parse_args(args); + if(parsed_arg.size() == 0) { + NanReturnUndefined(); } + Local exports(try_parse(parsed_arg)->ToObject()); + NanReturnValue(exports->Get(NanNew("subject"))); +} - if (!args[0]->IsString()) { - ThrowException(Exception::TypeError(String::New("Certificate must be a string."))); - return scope.Close(Undefined()); +NAN_METHOD(get_issuer) { + NanScope(); + std::string parsed_arg = parse_args(args); + if(parsed_arg.size() == 0) { + NanReturnUndefined(); } + Local exports(try_parse(parsed_arg)->ToObject()); + NanReturnValue(exports->Get(NanNew("issuer"))); +} - if (args[0]->ToString()->Length() == 0) { - ThrowException(Exception::TypeError(String::New("Certificate argument provided, but left blank."))); - return scope.Close(Undefined()); +NAN_METHOD(parse_cert) { + NanScope(); + std::string parsed_arg = parse_args(args); + if(parsed_arg.size() == 0) { + NanReturnUndefined(); } - - String::Utf8Value value(args[0]); - return scope.Close(try_parse(*value)); + Local exports(try_parse(parsed_arg)->ToObject()); + NanReturnValue(exports); } -#endif // NODE_VERSION_AT_LEAST - - /* * This is where everything is handled for both -0.11.2 and 0.11.3+. */ -Handle try_parse(char *data) { - HandleScope scope; - Handle exports(Object::New()); +Handle try_parse(const std::string& dataString) { + NanEscapableScope(); + const char* data = dataString.c_str(); + + Handle exports(NanNew()); X509 *cert; BIO *bio = BIO_new(BIO_s_mem()); int result = BIO_puts(bio, data); if (result == -2) { - ThrowException(Exception::Error(String::New("BIO doesn't support BIO_puts."))); - return scope.Close(exports); + NanThrowError("BIO doesn't support BIO_puts."); + BIO_free(bio); + return NanEscapeScope(exports); } else if (result <= 0) { - ThrowException(Exception::Error(String::New("No data was written to BIO."))); - return scope.Close(exports); + NanThrowError("No data was written to BIO."); + BIO_free(bio); + return NanEscapeScope(exports); } // Try raw read @@ -146,35 +115,33 @@ Handle try_parse(char *data) { // If raw read fails, try reading the input as a filename. if (!BIO_read_filename(bio, data)) { - ThrowException(Exception::Error(String::New("File doesn't exist."))); - return scope.Close(exports); + NanThrowError("File doesn't exist."); + return NanEscapeScope(exports); } // Try reading the bio again with the file in it. cert = PEM_read_bio_X509(bio, NULL, 0, NULL); if (cert == NULL) { - ThrowException(Exception::Error(String::New("Unable to parse certificate."))); - return scope.Close(exports); + NanThrowError("Unable to parse certificate."); + return NanEscapeScope(exports); } } - exports->Set(String::NewSymbol("version"), Integer::New((int) X509_get_version(cert))); - exports->Set(String::NewSymbol("subject"), parse_name(X509_get_subject_name(cert))); - exports->Set(String::NewSymbol("issuer"), parse_name(X509_get_issuer_name(cert))); - exports->Set(String::NewSymbol("serial"), parse_serial(X509_get_serialNumber(cert))); - exports->Set(String::NewSymbol("notBefore"), parse_date(X509_get_notBefore(cert))); - exports->Set(String::NewSymbol("notAfter"), parse_date(X509_get_notAfter(cert))); + exports->Set(NanNew("version"), NanNew((int) X509_get_version(cert))); + exports->Set(NanNew("subject"), parse_name(X509_get_subject_name(cert))); + exports->Set(NanNew("issuer"), parse_name(X509_get_issuer_name(cert))); + exports->Set(NanNew("serial"), parse_serial(X509_get_serialNumber(cert))); + exports->Set(NanNew("notBefore"), parse_date(X509_get_notBefore(cert))); + exports->Set(NanNew("notAfter"), parse_date(X509_get_notAfter(cert))); // Signature Algorithm int sig_alg_nid = OBJ_obj2nid(cert->sig_alg->algorithm); if (sig_alg_nid == NID_undef) { - ThrowException(Exception::Error( - String::New("unable to find specified signature algorithm name."))); - return scope.Close(Undefined()); + NanThrowError("unable to find specified signature algorithm name."); + return NanEscapeScope(exports); } - exports->Set(String::NewSymbol("signatureAlgorithm"), - String::New(OBJ_nid2ln(sig_alg_nid))); + exports->Set(NanNew("signatureAlgorithm"), NanNew(OBJ_nid2ln(sig_alg_nid))); // fingerPrint unsigned int md_size, idx; @@ -193,20 +160,18 @@ Handle try_parse(char *data) { } else { fingerprint[0] = '\0'; } - exports->Set(String::NewSymbol("fingerPrint"), String::New(fingerprint)); + exports->Set(NanNew("fingerPrint"), NanNew(fingerprint)); } // public key int pkey_nid = OBJ_obj2nid(cert->cert_info->key->algor->algorithm); if (pkey_nid == NID_undef) { - ThrowException(Exception::Error( - String::New("unable to find specified public key algorithm name."))); - return scope.Close(Undefined()); + NanThrowError("unable to find specified public key algorithm name."); + return NanEscapeScope(exports); } EVP_PKEY *pkey = X509_get_pubkey(cert); - Local publicKey = Object::New(); - publicKey->Set(String::NewSymbol("algorithm"), - String::New(OBJ_nid2ln(pkey_nid))); + Local publicKey = NanNew(); + publicKey->Set(NanNew("algorithm"), NanNew(OBJ_nid2ln(pkey_nid))); if (pkey_nid == NID_rsaEncryption) { char *rsa_e_dec, *rsa_n_hex; @@ -214,14 +179,14 @@ Handle try_parse(char *data) { rsa_key = pkey->pkey.rsa; rsa_e_dec = BN_bn2dec(rsa_key->e); rsa_n_hex = BN_bn2hex(rsa_key->n); - publicKey->Set(String::NewSymbol("e"), String::New(rsa_e_dec)); - publicKey->Set(String::NewSymbol("n"), String::New(rsa_n_hex)); + publicKey->Set(NanNew("e"), NanNew(rsa_e_dec)); + publicKey->Set(NanNew("n"), NanNew(rsa_n_hex)); } - exports->Set(String::NewSymbol("publicKey"), publicKey); + exports->Set(NanNew("publicKey"), publicKey); EVP_PKEY_free(pkey); // alt names - Local altNames(Array::New()); + Local altNames(NanNew()); STACK_OF(GENERAL_NAME) *names = NULL; int i; @@ -236,18 +201,18 @@ Handle try_parse(char *data) { char *name = (char*) ASN1_STRING_data(current->d.dNSName); if (ASN1_STRING_length(current->d.dNSName) != (int) strlen(name)) { - ThrowException(Exception::Error(String::New("Malformed alternative names field."))); - return scope.Close(exports); + NanThrowError("Malformed alternative names field."); + return NanEscapeScope(exports); } - altNames->Set(i, String::New(name)); + altNames->Set(i, NanNew(name)); } } } - exports->Set(String::NewSymbol("altNames"), altNames); + exports->Set(NanNew("altNames"), altNames); // Extensions - Local extensions(Object::New()); + Local extensions(NanNew()); STACK_OF(X509_EXTENSION) *exts = cert->cert_info->extensions; int num_of_exts; int index_of_exts; @@ -289,38 +254,33 @@ Handle try_parse(char *data) { if (nid == NID_undef) { char extname[100]; OBJ_obj2txt(extname, 100, (const ASN1_OBJECT *) obj, 1); - extensions->Set(String::NewSymbol(extname), String::New(bptr->data)); + extensions->Set(NanNew(extname), NanNew(bptr->data)); } else { const char *c_ext_name = OBJ_nid2ln(nid); // IFNULL_FAIL(c_ext_name, "invalid X509v3 extension name"); - extensions->Set(String::NewSymbol(c_ext_name), String::New(bptr->data)); + extensions->Set(NanNew(c_ext_name), NanNew(bptr->data)); } } - exports->Set(String::NewSymbol("extensions"), extensions); + exports->Set(NanNew("extensions"), extensions); X509_free(cert); - -#if NODE_VERSION_AT_LEAST(0, 11, 3) && defined(__APPLE__) - free(data); -#endif - - return scope.Close(exports); + return NanEscapeScope(exports); } Handle parse_serial(ASN1_INTEGER *serial) { - HandleScope scope; + NanEscapableScope(); Local serialNumber; BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL); char *hex = BN_bn2hex(bn); - serialNumber = String::New(hex); + serialNumber = NanNew(hex); BN_free(bn); OPENSSL_free(hex); - return scope.Close(serialNumber); + return NanEscapeScope(serialNumber); } Handle parse_date(ASN1_TIME *date) { - HandleScope scope; + NanEscapableScope(); BIO *bio; BUF_MEM *bm; char formatted[64]; @@ -332,14 +292,14 @@ Handle parse_date(ASN1_TIME *date) { BIO_get_mem_ptr(bio, &bm); BUF_strlcpy(formatted, bm->data, bm->length + 1); BIO_free(bio); - args[0] = String::New(formatted); + args[0] = NanNew(formatted); - return scope.Close(Context::GetCurrent()->Global()->Get(String::New("Date"))->ToObject()->CallAsConstructor(1, args)); + return NanEscapeScope(NanGetCurrentContext()->Global()->Get(NanNew("Date"))->ToObject()->CallAsConstructor(1, args)); } Handle parse_name(X509_NAME *subject) { - HandleScope scope; - Handle cert(Object::New()); + NanEscapableScope(); + Handle cert(NanNew()); int i, length; ASN1_OBJECT *entry; unsigned char *value; @@ -349,13 +309,13 @@ Handle parse_name(X509_NAME *subject) { entry = X509_NAME_ENTRY_get_object(X509_NAME_get_entry(subject, i)); OBJ_obj2txt(buf, 255, entry, 0); value = ASN1_STRING_data(X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject, i))); - cert->Set(String::NewSymbol(real_name(buf)), String::New((const char*) value)); + cert->Set(NanNew(real_name(buf)), NanNew((const char*) value)); } - return scope.Close(cert); + return NanEscapeScope(cert); } // Fix for missing fields in OpenSSL. -char* real_name(char *data) { +const char* real_name(char *data) { int i, length = (int) sizeof(MISSING) / sizeof(MISSING[0]); for (i = 0; i < length; i++) { From 80fdfbb187c5afe958f8f31716a0ca9152d338ab Mon Sep 17 00:00:00 2001 From: Yazhong Liu Date: Sun, 14 Sep 2014 21:44:38 +0800 Subject: [PATCH 06/52] bump version to 0.1.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 764756d..0593995 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "x.509", - "version": "0.1.2", + "version": "0.1.4", "description": "Simple X509 certificate parser.", "author": "Colton Baker", "main": "index.js", From 6894c3497ae15f5bee60ff6141ec1f5c2034be12 Mon Sep 17 00:00:00 2001 From: Yazhong Liu Date: Sun, 14 Sep 2014 21:50:09 +0800 Subject: [PATCH 07/52] fix typo: package name -> x509 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0593995..beec2fe 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "x.509", + "name": "x509", "version": "0.1.4", "description": "Simple X509 certificate parser.", "author": "Colton Baker", From 2fdd62dfb3f90437a685e1e1555433ca3e4d68b6 Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Mon, 15 Sep 2014 15:33:40 -0400 Subject: [PATCH 08/52] Update README.md No need to use `x.509` as the package. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 68c9899..cec340b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Simple X509 certificate parser. ## Installation -From NPM *(recommended)*: `npm install x.509` +From NPM *(recommended)*: `npm install x509` Building and testing from source: ``` @@ -134,4 +134,4 @@ if (cert.notAfter < date) { ## License -MIT \ No newline at end of file +MIT From 8e4e452ba414a190147fea82ca4ce9e7efa2dc1c Mon Sep 17 00:00:00 2001 From: Damian Kaczmarek Date: Mon, 24 Nov 2014 17:36:20 +0100 Subject: [PATCH 09/52] Mention x509.js --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index cec340b..158a2bb 100644 --- a/README.md +++ b/README.md @@ -135,3 +135,6 @@ if (cert.notAfter < date) { ## License MIT + +#### Alternative implementation / build issues +If you are suffering from hard to fix build issues, there is an alternative (pure javascript) implementation using emscripten: https://github.com/encharm/x509.js (based on node-x509, slightly different API) From 96ed4661619320f5237c254b591eb83179fec81f Mon Sep 17 00:00:00 2001 From: yorkie Date: Wed, 9 Sep 2015 23:35:57 +0800 Subject: [PATCH 10/52] use nan@2.x to support nodejs4 --- README.md | 2 + package.json | 4 +- src/addon.cc | 20 ++++-- src/x509.cc | 182 +++++++++++++++++++++++++++++++-------------------- 4 files changed, 129 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index 158a2bb..d36c585 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ node-x509 ========= +*support Node.js 4.0.0* + Simple X509 certificate parser. ## Installation diff --git a/package.json b/package.json index beec2fe..1e8fdf0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "x509", - "version": "0.1.4", + "version": "0.2.0", "description": "Simple X509 certificate parser.", "author": "Colton Baker", "main": "index.js", @@ -13,6 +13,6 @@ }, "license": "MIT", "dependencies": { - "nan": "^1.3.0" + "nan": "2.0.9" } } diff --git a/src/addon.cc b/src/addon.cc index 832c2db..6434e80 100644 --- a/src/addon.cc +++ b/src/addon.cc @@ -7,11 +7,21 @@ using namespace v8; void init(Handle exports) { - exports->Set(NanNew("version"), NanNew(VERSION)); - exports->Set(NanNew("getAltNames"), NanNew(get_altnames)->GetFunction()); - exports->Set(NanNew("getSubject"), NanNew(get_subject)->GetFunction()); - exports->Set(NanNew("getIssuer"), NanNew(get_issuer)->GetFunction()); - exports->Set(NanNew("parseCert"), NanNew(parse_cert)->GetFunction()); + Nan::Set(exports, + Nan::New("version").ToLocalChecked(), + Nan::New(VERSION).ToLocalChecked()); + Nan::Set(exports, + Nan::New("getAltNames").ToLocalChecked(), + Nan::New(get_altnames)->GetFunction()); + Nan::Set(exports, + Nan::New("getSubject").ToLocalChecked(), + Nan::New(get_subject)->GetFunction()); + Nan::Set(exports, + Nan::New("getIssuer").ToLocalChecked(), + Nan::New(get_issuer)->GetFunction()); + Nan::Set(exports, + Nan::New("parseCert").ToLocalChecked(), + Nan::New(parse_cert)->GetFunction()); } NODE_MODULE(x509, init) diff --git a/src/x509.cc b/src/x509.cc index abaa1aa..c6d00bc 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -23,87 +23,93 @@ static const char *MISSING[3][2] = { Handle try_parse(const std::string& dataString); -std::string parse_args(_NAN_METHOD_ARGS) { - if (args.Length() == 0) { - NanThrowTypeError("Must provide a certificate string."); +std::string parse_args(const Nan::FunctionCallbackInfo& info) { + if (info.Length() == 0) { + Nan::ThrowTypeError("Must provide a certificate string."); return std::string(); } - if (!args[0]->IsString()) { - NanThrowTypeError("Certificate must be a string."); + if (!info[0]->IsString()) { + Nan::ThrowTypeError("Certificate must be a string."); return std::string(); } - if (args[0]->ToString()->Length() == 0) { - NanThrowTypeError("Certificate argument provided, but left blank."); + if (info[0]->ToString()->Length() == 0) { + Nan::ThrowTypeError("Certificate argument provided, but left blank."); return std::string(); } - return *String::Utf8Value(args[0]->ToString()); + return *String::Utf8Value(info[0]->ToString()); } NAN_METHOD(get_altnames) { - NanScope(); - std::string parsed_arg = parse_args(args); + Nan::HandleScope scope; + std::string parsed_arg = parse_args(info); if(parsed_arg.size() == 0) { - NanReturnUndefined(); + info.GetReturnValue().SetUndefined(); } Local exports(try_parse(parsed_arg)->ToObject()); - NanReturnValue(exports->Get(NanNew("altNames"))); + Local key = Nan::New("altNames").ToLocalChecked(); + info.GetReturnValue().Set( + Nan::Get(exports, key).ToLocalChecked()); } NAN_METHOD(get_subject) { - NanScope(); - std::string parsed_arg = parse_args(args); + Nan::HandleScope scope; + std::string parsed_arg = parse_args(info); if(parsed_arg.size() == 0) { - NanReturnUndefined(); + info.GetReturnValue().SetUndefined(); } Local exports(try_parse(parsed_arg)->ToObject()); - NanReturnValue(exports->Get(NanNew("subject"))); + Local key = Nan::New("subject").ToLocalChecked(); + info.GetReturnValue().Set( + Nan::Get(exports, key).ToLocalChecked()); } NAN_METHOD(get_issuer) { - NanScope(); - std::string parsed_arg = parse_args(args); + Nan::HandleScope scope; + std::string parsed_arg = parse_args(info); if(parsed_arg.size() == 0) { - NanReturnUndefined(); + info.GetReturnValue().SetUndefined(); } Local exports(try_parse(parsed_arg)->ToObject()); - NanReturnValue(exports->Get(NanNew("issuer"))); + Local key = Nan::New("issuer").ToLocalChecked(); + info.GetReturnValue().Set( + Nan::Get(exports, key).ToLocalChecked()); } NAN_METHOD(parse_cert) { - NanScope(); - std::string parsed_arg = parse_args(args); + Nan::HandleScope scope; + std::string parsed_arg = parse_args(info); if(parsed_arg.size() == 0) { - NanReturnUndefined(); + info.GetReturnValue().SetUndefined(); } Local exports(try_parse(parsed_arg)->ToObject()); - NanReturnValue(exports); + info.GetReturnValue().Set(exports); } /* * This is where everything is handled for both -0.11.2 and 0.11.3+. */ Handle try_parse(const std::string& dataString) { - NanEscapableScope(); + Nan::EscapableHandleScope scope; const char* data = dataString.c_str(); - Handle exports(NanNew()); + Handle exports(Nan::New()); X509 *cert; BIO *bio = BIO_new(BIO_s_mem()); int result = BIO_puts(bio, data); if (result == -2) { - NanThrowError("BIO doesn't support BIO_puts."); + Nan::ThrowError("BIO doesn't support BIO_puts."); BIO_free(bio); - return NanEscapeScope(exports); + return scope.Escape(exports); } else if (result <= 0) { - NanThrowError("No data was written to BIO."); + Nan::ThrowError("No data was written to BIO."); BIO_free(bio); - return NanEscapeScope(exports); + return scope.Escape(exports); } // Try raw read @@ -115,33 +121,47 @@ Handle try_parse(const std::string& dataString) { // If raw read fails, try reading the input as a filename. if (!BIO_read_filename(bio, data)) { - NanThrowError("File doesn't exist."); - return NanEscapeScope(exports); + Nan::ThrowError("File doesn't exist."); + return scope.Escape(exports); } // Try reading the bio again with the file in it. cert = PEM_read_bio_X509(bio, NULL, 0, NULL); if (cert == NULL) { - NanThrowError("Unable to parse certificate."); - return NanEscapeScope(exports); + Nan::ThrowError("Unable to parse certificate."); + return scope.Escape(exports); } } - exports->Set(NanNew("version"), NanNew((int) X509_get_version(cert))); - exports->Set(NanNew("subject"), parse_name(X509_get_subject_name(cert))); - exports->Set(NanNew("issuer"), parse_name(X509_get_issuer_name(cert))); - exports->Set(NanNew("serial"), parse_serial(X509_get_serialNumber(cert))); - exports->Set(NanNew("notBefore"), parse_date(X509_get_notBefore(cert))); - exports->Set(NanNew("notAfter"), parse_date(X509_get_notAfter(cert))); + Nan::Set(exports, + Nan::New("version").ToLocalChecked(), + Nan::New((int) X509_get_version(cert))); + Nan::Set(exports, + Nan::New("subject").ToLocalChecked(), + parse_name(X509_get_subject_name(cert))); + Nan::Set(exports, + Nan::New("issuer").ToLocalChecked(), + parse_name(X509_get_issuer_name(cert))); + Nan::Set(exports, + Nan::New("serial").ToLocalChecked(), + parse_serial(X509_get_serialNumber(cert))); + Nan::Set(exports, + Nan::New("notBefore").ToLocalChecked(), + parse_date(X509_get_notBefore(cert))); + Nan::Set(exports, + Nan::New("notAfter").ToLocalChecked(), + parse_date(X509_get_notAfter(cert))); // Signature Algorithm int sig_alg_nid = OBJ_obj2nid(cert->sig_alg->algorithm); if (sig_alg_nid == NID_undef) { - NanThrowError("unable to find specified signature algorithm name."); - return NanEscapeScope(exports); + Nan::ThrowError("unable to find specified signature algorithm name."); + return scope.Escape(exports); } - exports->Set(NanNew("signatureAlgorithm"), NanNew(OBJ_nid2ln(sig_alg_nid))); + Nan::Set(exports, + Nan::New("signatureAlgorithm").ToLocalChecked(), + Nan::New(OBJ_nid2ln(sig_alg_nid)).ToLocalChecked()); // fingerPrint unsigned int md_size, idx; @@ -160,18 +180,22 @@ Handle try_parse(const std::string& dataString) { } else { fingerprint[0] = '\0'; } - exports->Set(NanNew("fingerPrint"), NanNew(fingerprint)); + Nan::Set(exports, + Nan::New("fingerPrint").ToLocalChecked(), + Nan::New(fingerprint).ToLocalChecked()); } // public key int pkey_nid = OBJ_obj2nid(cert->cert_info->key->algor->algorithm); if (pkey_nid == NID_undef) { - NanThrowError("unable to find specified public key algorithm name."); - return NanEscapeScope(exports); + Nan::ThrowError("unable to find specified public key algorithm name."); + return scope.Escape(exports); } EVP_PKEY *pkey = X509_get_pubkey(cert); - Local publicKey = NanNew(); - publicKey->Set(NanNew("algorithm"), NanNew(OBJ_nid2ln(pkey_nid))); + Local publicKey = Nan::New(); + Nan::Set(publicKey, + Nan::New("algorithm").ToLocalChecked(), + Nan::New(OBJ_nid2ln(pkey_nid)).ToLocalChecked()); if (pkey_nid == NID_rsaEncryption) { char *rsa_e_dec, *rsa_n_hex; @@ -179,14 +203,18 @@ Handle try_parse(const std::string& dataString) { rsa_key = pkey->pkey.rsa; rsa_e_dec = BN_bn2dec(rsa_key->e); rsa_n_hex = BN_bn2hex(rsa_key->n); - publicKey->Set(NanNew("e"), NanNew(rsa_e_dec)); - publicKey->Set(NanNew("n"), NanNew(rsa_n_hex)); + Nan::Set(publicKey, + Nan::New("e").ToLocalChecked(), + Nan::New(rsa_e_dec).ToLocalChecked()); + Nan::Set(publicKey, + Nan::New("n").ToLocalChecked(), + Nan::New(rsa_n_hex).ToLocalChecked()); } - exports->Set(NanNew("publicKey"), publicKey); + Nan::Set(exports, Nan::New("publicKey").ToLocalChecked(), publicKey); EVP_PKEY_free(pkey); // alt names - Local altNames(NanNew()); + Local altNames(Nan::New()); STACK_OF(GENERAL_NAME) *names = NULL; int i; @@ -201,18 +229,17 @@ Handle try_parse(const std::string& dataString) { char *name = (char*) ASN1_STRING_data(current->d.dNSName); if (ASN1_STRING_length(current->d.dNSName) != (int) strlen(name)) { - NanThrowError("Malformed alternative names field."); - return NanEscapeScope(exports); + Nan::ThrowError("Malformed alternative names field."); + return scope.Escape(exports); } - - altNames->Set(i, NanNew(name)); + Nan::Set(altNames, i, Nan::New(name).ToLocalChecked()); } } } - exports->Set(NanNew("altNames"), altNames); + Nan::Set(exports, Nan::New("altNames").ToLocalChecked(), altNames); // Extensions - Local extensions(NanNew()); + Local extensions(Nan::New()); STACK_OF(X509_EXTENSION) *exts = cert->cert_info->extensions; int num_of_exts; int index_of_exts; @@ -254,33 +281,39 @@ Handle try_parse(const std::string& dataString) { if (nid == NID_undef) { char extname[100]; OBJ_obj2txt(extname, 100, (const ASN1_OBJECT *) obj, 1); - extensions->Set(NanNew(extname), NanNew(bptr->data)); + Nan::Set(extensions, + Nan::New(extname).ToLocalChecked(), + Nan::New(bptr->data).ToLocalChecked()); + } else { const char *c_ext_name = OBJ_nid2ln(nid); // IFNULL_FAIL(c_ext_name, "invalid X509v3 extension name"); - extensions->Set(NanNew(c_ext_name), NanNew(bptr->data)); + Nan::Set(extensions, + Nan::New(c_ext_name).ToLocalChecked(), + Nan::New(bptr->data).ToLocalChecked()); } } - exports->Set(NanNew("extensions"), extensions); + Nan::Set(exports, + Nan::New("extensions").ToLocalChecked(), extensions); X509_free(cert); - return NanEscapeScope(exports); + return scope.Escape(exports); } Handle parse_serial(ASN1_INTEGER *serial) { - NanEscapableScope(); + Nan::EscapableHandleScope scope; Local serialNumber; BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL); char *hex = BN_bn2hex(bn); - serialNumber = NanNew(hex); + serialNumber = Nan::New(hex).ToLocalChecked(); BN_free(bn); OPENSSL_free(hex); - return NanEscapeScope(serialNumber); + return scope.Escape(serialNumber); } Handle parse_date(ASN1_TIME *date) { - NanEscapableScope(); + Nan::EscapableHandleScope scope; BIO *bio; BUF_MEM *bm; char formatted[64]; @@ -292,14 +325,17 @@ Handle parse_date(ASN1_TIME *date) { BIO_get_mem_ptr(bio, &bm); BUF_strlcpy(formatted, bm->data, bm->length + 1); BIO_free(bio); - args[0] = NanNew(formatted); + args[0] = Nan::New(formatted).ToLocalChecked(); - return NanEscapeScope(NanGetCurrentContext()->Global()->Get(NanNew("Date"))->ToObject()->CallAsConstructor(1, args)); + Local global = Nan::GetCurrentContext()->Global(); + Local DateObject = Nan::Get(global, + Nan::New("Date").ToLocalChecked()).ToLocalChecked()->ToObject(); + return scope.Escape(DateObject->CallAsConstructor(1, args)); } Handle parse_name(X509_NAME *subject) { - NanEscapableScope(); - Handle cert(NanNew()); + Nan::EscapableHandleScope scope; + Handle cert(Nan::New()); int i, length; ASN1_OBJECT *entry; unsigned char *value; @@ -309,9 +345,11 @@ Handle parse_name(X509_NAME *subject) { entry = X509_NAME_ENTRY_get_object(X509_NAME_get_entry(subject, i)); OBJ_obj2txt(buf, 255, entry, 0); value = ASN1_STRING_data(X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject, i))); - cert->Set(NanNew(real_name(buf)), NanNew((const char*) value)); + Nan::Set(cert, + Nan::New(real_name(buf)).ToLocalChecked(), + Nan::New((const char*) value).ToLocalChecked()); } - return NanEscapeScope(cert); + return scope.Escape(cert); } // Fix for missing fields in OpenSSL. From 68fa0a3f7bec026a74aca9fba5590efbfbde372b Mon Sep 17 00:00:00 2001 From: yorkie Date: Wed, 9 Sep 2015 23:43:39 +0800 Subject: [PATCH 11/52] fix compatible --- src/x509.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/x509.cc b/src/x509.cc index c6d00bc..86f02cf 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -95,7 +95,7 @@ Handle try_parse(const std::string& dataString) { Nan::EscapableHandleScope scope; const char* data = dataString.c_str(); - Handle exports(Nan::New()); + Local exports = Nan::New(); X509 *cert; BIO *bio = BIO_new(BIO_s_mem()); @@ -335,7 +335,7 @@ Handle parse_date(ASN1_TIME *date) { Handle parse_name(X509_NAME *subject) { Nan::EscapableHandleScope scope; - Handle cert(Nan::New()); + Local cert = Nan::New(); int i, length; ASN1_OBJECT *entry; unsigned char *value; From b178ec50cb3fe4f3d5783a0f3ba232bc748d2b1f Mon Sep 17 00:00:00 2001 From: yorkie Date: Wed, 9 Sep 2015 23:44:28 +0800 Subject: [PATCH 12/52] add 4.0 into ci env --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 0b81284..4dc4692 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: node_js node_js: + - "4.0" - "0.11" - "0.10" - "0.8" From 2f53e083b332ded352674e4dd4f9db88132c06e1 Mon Sep 17 00:00:00 2001 From: yorkie Date: Wed, 9 Sep 2015 23:51:03 +0800 Subject: [PATCH 13/52] doesnt support node v0.8 any more --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4dc4692..79b42fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ node_js: - "4.0" - "0.11" - "0.10" - - "0.8" notifications: email: false From cc0e166028eef334dd17a1619632319d811ba5b7 Mon Sep 17 00:00:00 2001 From: yorkie Date: Wed, 9 Sep 2015 23:59:07 +0800 Subject: [PATCH 14/52] update travis config --- .travis.yml | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 79b42fe..580191d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,33 @@ -language: node_js +os: + - linux + +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.8 +language: node_js node_js: - "4.0" - - "0.11" + - "0.12" - "0.10" +install: + - export CXX=g++-4.8 + - $CXX --version + - npm i + +before_install: + - npm install -g node-gyp + - rm -rf ~/.node-gyp/ + notifications: email: false - irc: channels: - "chat.freenode.net#jitsu" on_success: change on_failure: change -before_install: - - npm install -g node-gyp - - rm -rf ~/.node-gyp/ From a51ee749a77eaab4ddea04873376ba1327bfda8f Mon Sep 17 00:00:00 2001 From: yorkie Date: Thu, 10 Sep 2015 00:13:45 +0800 Subject: [PATCH 15/52] update readme --- README.md | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index d36c585..d98d40c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ node-x509 ========= -*support Node.js 4.0.0* +[![Build Status](https://travis-ci.org/Southern/node-x509.svg)](https://travis-ci.org/Southern/node-x509) -Simple X509 certificate parser. +Simple X509 certificate parser. +*support Node.js 4.0.0* ## Installation @@ -19,31 +20,27 @@ npm test ## Usage Reading from a file: ```js -var x509 = require('x509'); - -var issuer = x509.getIssuer(__dirname + '/certs/your.crt'); +const x509 = require('x509'); +const issuer = x509.getIssuer(__dirname + '/certs/your.crt'); ``` Reading from a string: ```js -var fs = require('fs'), - x509 = require('x509'); - -var issuer = x509.getIssuer(fs.readFileSync('./certs/your.crt').toString()); +const fs = require('fs'); +const x509 = require('x509'); +const issuer = x509.getIssuer(fs.readFileSync('./certs/your.crt').toString()); ``` ## Methods **Notes:** - `cert` may be a filename or a raw base64 encoded PEM string in any of these methods. - #### x509.getAltNames(`cert`) Parse certificate with `x509.parseCert` and return the alternate names. ```js -var x509 = require('x509'); - -var altNames = x509.getAltNames(__dirname + '/certs/nodejitsu.com.crt'); +const x509 = require('x509'); +const altNames = x509.getAltNames(__dirname + '/certs/nodejitsu.com.crt'); /* altNames = [ '*.nodejitsu.com', 'nodejitsu.com' ] */ @@ -53,9 +50,8 @@ altNames = [ '*.nodejitsu.com', 'nodejitsu.com' ] Parse certificate with `x509.parseCert` and return the issuer. ```js -var x509 = require('x509'); - -var issuer = x509.getIssuer(__dirname + '/certs/nodejitsu.com.crt'); +const x509 = require('x509'); +const issuer = x509.getIssuer(__dirname + '/certs/nodejitsu.com.crt'); /* issuer = { countryName: 'GB', stateOrProvinceName: 'Greater Manchester', @@ -69,9 +65,8 @@ issuer = { countryName: 'GB', Parse certificate with `x509.parseCert` and return the subject. ```js -var x509 = require('x509'); - -var subject = x509.getSubject(__dirname + '/certs/nodejitsu.com.crt'); +const x509 = require('x509'); +const subject = x509.getSubject(__dirname + '/certs/nodejitsu.com.crt'); /* subject = { countryName: 'US', postalCode: '10010', @@ -88,9 +83,8 @@ subject = { countryName: 'US', Parse subject, issuer, valid before and after date, and alternate names from certificate. ```js -var x509 = require('x509'); - -var cert = x509.parseCert(__dirname + '/certs/nodejitsu.com.crt'); +const x509 = require('x509'); +const cert = x509.parseCert(__dirname + '/certs/nodejitsu.com.crt'); /* cert = { subject: { countryName: 'US', @@ -122,9 +116,9 @@ cert = { subject: ## Examples Checking the date to make sure the certificate is active: ```js -var x509 = require('x509'), - cert = x509.parseCert('yourcert.crt'), - date = new Date(); +const x509 = require('x509'), +const cert = x509.parseCert('yourcert.crt'), +const date = new Date(); if (cert.notBefore > date) { // Certificate isn't active yet. From eaecc39d1b38758372d3e9f9fcaab80c207f8738 Mon Sep 17 00:00:00 2001 From: yorkie Date: Thu, 10 Sep 2015 00:13:59 +0800 Subject: [PATCH 16/52] v0.2.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1e8fdf0..ebc6979 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "x509", - "version": "0.2.0", + "version": "0.2.1", "description": "Simple X509 certificate parser.", "author": "Colton Baker", "main": "index.js", From 488f9e54e5a4c278c5fef904356a9a604e7b466e Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 9 Sep 2015 22:07:24 -0700 Subject: [PATCH 17/52] [fix] git link --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ebc6979..f6dff9f 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "main": "index.js", "repository": { "type": "git", - "url": "http://github.com/yorkie/node-x509" + "url": "git@github.com:Southern/node-x509.git" }, "scripts": { "test": "node test/test" From 682345d1ef8e292699908aa0dbb7d25ea244ddb8 Mon Sep 17 00:00:00 2001 From: yorkie Date: Thu, 10 Sep 2015 15:30:29 +0800 Subject: [PATCH 18/52] v0.2.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f6dff9f..74fc24f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "x509", - "version": "0.2.1", + "version": "0.2.2", "description": "Simple X509 certificate parser.", "author": "Colton Baker", "main": "index.js", From dd30e57c299265bed3a723d9527419195c468277 Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Mon, 2 Nov 2015 21:57:07 -0500 Subject: [PATCH 19/52] Fix README examples. Let's not set everything as a const in the examples. --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index d98d40c..096f1ca 100644 --- a/README.md +++ b/README.md @@ -21,14 +21,14 @@ npm test Reading from a file: ```js const x509 = require('x509'); -const issuer = x509.getIssuer(__dirname + '/certs/your.crt'); +var issuer = x509.getIssuer(__dirname + '/certs/your.crt'); ``` Reading from a string: ```js -const fs = require('fs'); -const x509 = require('x509'); -const issuer = x509.getIssuer(fs.readFileSync('./certs/your.crt').toString()); +const fs = require('fs'), + x509 = require('x509'); +var issuer = x509.getIssuer(fs.readFileSync('./certs/your.crt').toString()); ``` ## Methods @@ -40,7 +40,7 @@ Parse certificate with `x509.parseCert` and return the alternate names. ```js const x509 = require('x509'); -const altNames = x509.getAltNames(__dirname + '/certs/nodejitsu.com.crt'); +var altNames = x509.getAltNames(__dirname + '/certs/nodejitsu.com.crt'); /* altNames = [ '*.nodejitsu.com', 'nodejitsu.com' ] */ @@ -51,7 +51,7 @@ Parse certificate with `x509.parseCert` and return the issuer. ```js const x509 = require('x509'); -const issuer = x509.getIssuer(__dirname + '/certs/nodejitsu.com.crt'); +var issuer = x509.getIssuer(__dirname + '/certs/nodejitsu.com.crt'); /* issuer = { countryName: 'GB', stateOrProvinceName: 'Greater Manchester', @@ -66,7 +66,7 @@ Parse certificate with `x509.parseCert` and return the subject. ```js const x509 = require('x509'); -const subject = x509.getSubject(__dirname + '/certs/nodejitsu.com.crt'); +var subject = x509.getSubject(__dirname + '/certs/nodejitsu.com.crt'); /* subject = { countryName: 'US', postalCode: '10010', @@ -84,7 +84,7 @@ Parse subject, issuer, valid before and after date, and alternate names from cer ```js const x509 = require('x509'); -const cert = x509.parseCert(__dirname + '/certs/nodejitsu.com.crt'); +var cert = x509.parseCert(__dirname + '/certs/nodejitsu.com.crt'); /* cert = { subject: { countryName: 'US', @@ -116,9 +116,9 @@ cert = { subject: ## Examples Checking the date to make sure the certificate is active: ```js -const x509 = require('x509'), -const cert = x509.parseCert('yourcert.crt'), -const date = new Date(); +const x509 = require('x509'); +var cert = x509.parseCert('yourcert.crt'), + date = new Date(); if (cert.notBefore > date) { // Certificate isn't active yet. From b40ad339a7c32b425fa65c40231c98ba66c1b891 Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Mon, 2 Nov 2015 23:38:58 -0500 Subject: [PATCH 20/52] Fix extra characters in the values of extensions Fixes #19 --- include/x509.h | 1 + src/x509.cc | 31 +++++++++++++++++++++---------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/include/x509.h b/include/x509.h index 04fa980..0afed72 100644 --- a/include/x509.h +++ b/include/x509.h @@ -29,5 +29,6 @@ Handle parse_date(ASN1_TIME *date); Handle parse_serial(ASN1_INTEGER *serial); Handle parse_name(X509_NAME *subject); const char* real_name(char *data); +char* trim(char *data, int len); #endif diff --git a/src/x509.cc b/src/x509.cc index 86f02cf..33c92bf 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -267,14 +267,10 @@ Handle try_parse(const std::string& dataString) { BIO_get_mem_ptr(ext_bio, &bptr); BIO_set_close(ext_bio, BIO_NOCLOSE); - // remove newlines - int lastchar = bptr->length; - if (lastchar > 1 && (bptr->data[lastchar-1] == '\n' || bptr->data[lastchar-1] == '\r')) { - bptr->data[lastchar-1] = (char) 0; - } - if (lastchar > 0 && (bptr->data[lastchar] == '\n' || bptr->data[lastchar] == '\r')) { - bptr->data[lastchar] = (char) 0; - } + char *data = (char*) malloc(sizeof(char*) * bptr->length); + BUF_strlcpy(data, bptr->data, bptr->length + 1); + data = trim(data, bptr->length); + BIO_free(ext_bio); unsigned nid = OBJ_obj2nid(obj); @@ -283,14 +279,14 @@ Handle try_parse(const std::string& dataString) { OBJ_obj2txt(extname, 100, (const ASN1_OBJECT *) obj, 1); Nan::Set(extensions, Nan::New(extname).ToLocalChecked(), - Nan::New(bptr->data).ToLocalChecked()); + Nan::New(data).ToLocalChecked()); } else { const char *c_ext_name = OBJ_nid2ln(nid); // IFNULL_FAIL(c_ext_name, "invalid X509v3 extension name"); Nan::Set(extensions, Nan::New(c_ext_name).ToLocalChecked(), - Nan::New(bptr->data).ToLocalChecked()); + Nan::New(data).ToLocalChecked()); } } Nan::Set(exports, @@ -363,3 +359,18 @@ const char* real_name(char *data) { return data; } + +char* trim(char *data, int len) { + if (data[0] == '\n' || data[0] == '\r') { + data = data+1; + } + + if (len > 1 && (data[len-1] == '\n' || data[len-1] == '\r')) { + data[len-1] = (char) 0; + } + if (len > 0 && (data[len] == '\n' || data[len] == '\r')) { + data[len] = (char) 0; + } + + return data; +} From 0bcf0128bc52ab5c60de8de84229eca3cf08bcb2 Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Mon, 2 Nov 2015 23:46:33 -0500 Subject: [PATCH 21/52] Run trim until all \r\n chars are trimmed --- src/x509.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/x509.cc b/src/x509.cc index 33c92bf..3883063 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -364,13 +364,15 @@ char* trim(char *data, int len) { if (data[0] == '\n' || data[0] == '\r') { data = data+1; } - - if (len > 1 && (data[len-1] == '\n' || data[len-1] == '\r')) { + else if (len > 1 && (data[len-1] == '\n' || data[len-1] == '\r')) { data[len-1] = (char) 0; } - if (len > 0 && (data[len] == '\n' || data[len] == '\r')) { + else if (len > 0 && (data[len] == '\n' || data[len] == '\r')) { data[len] = (char) 0; } + else { + return data; + } - return data; + return trim(data, len - 1); } From a036660b3debd45c87c0d7f8441ee4e645376bcc Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Tue, 3 Nov 2015 00:05:23 -0500 Subject: [PATCH 22/52] Call real_name on extension names --- include/x509.h | 2 +- src/x509.cc | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/x509.h b/include/x509.h index 0afed72..bfeca85 100644 --- a/include/x509.h +++ b/include/x509.h @@ -28,7 +28,7 @@ Handle try_parse(const std::string& dataString); Handle parse_date(ASN1_TIME *date); Handle parse_serial(ASN1_INTEGER *serial); Handle parse_name(X509_NAME *subject); -const char* real_name(char *data); +char* real_name(char *data); char* trim(char *data, int len); #endif diff --git a/src/x509.cc b/src/x509.cc index 3883063..90efa82 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -278,14 +278,14 @@ Handle try_parse(const std::string& dataString) { char extname[100]; OBJ_obj2txt(extname, 100, (const ASN1_OBJECT *) obj, 1); Nan::Set(extensions, - Nan::New(extname).ToLocalChecked(), + Nan::New(real_name(extname)).ToLocalChecked(), Nan::New(data).ToLocalChecked()); } else { const char *c_ext_name = OBJ_nid2ln(nid); // IFNULL_FAIL(c_ext_name, "invalid X509v3 extension name"); Nan::Set(extensions, - Nan::New(c_ext_name).ToLocalChecked(), + Nan::New(real_name((char*)c_ext_name)).ToLocalChecked(), Nan::New(data).ToLocalChecked()); } } @@ -349,12 +349,12 @@ Handle parse_name(X509_NAME *subject) { } // Fix for missing fields in OpenSSL. -const char* real_name(char *data) { +char* real_name(char *data) { int i, length = (int) sizeof(MISSING) / sizeof(MISSING[0]); for (i = 0; i < length; i++) { if (strcmp(data, MISSING[i][0]) == 0) - return MISSING[i][1]; + return (char*) MISSING[i][1]; } return data; From 6cad0bd77dad1907dc4bd54d95b857bfa70fe1dd Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Tue, 3 Nov 2015 00:06:10 -0500 Subject: [PATCH 23/52] Add entrustVersionInfo in missing names Just noticed that Equifax had a missing name. --- src/x509.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/x509.cc b/src/x509.cc index 90efa82..25d2a71 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -4,7 +4,12 @@ using namespace v8; // Field names that OpenSSL is missing. -static const char *MISSING[3][2] = { +static const char *MISSING[4][2] = { + { + "1.2.840.113533.7.65.0", + "entrustVersionInfo" + }, + { "1.3.6.1.4.1.311.60.2.1.1", "jurisdictionOfIncorpationLocalityName" From cad2992811fa55626fb2243a925d1f5bb142733a Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Mon, 2 Nov 2015 21:18:00 -0500 Subject: [PATCH 24/52] Free BIO after parsing. Should fix #28 --- src/x509.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/x509.cc b/src/x509.cc index 25d2a71..94a1ed0 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -298,6 +298,8 @@ Handle try_parse(const std::string& dataString) { Nan::New("extensions").ToLocalChecked(), extensions); X509_free(cert); + BIO_free(bio); + return scope.Escape(exports); } From ec713a41bde54a6ed84d032d77bbaee8d5d9eb88 Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Tue, 3 Nov 2015 00:36:28 -0500 Subject: [PATCH 25/52] Remove IRC notifications in .travis.yml [ci skip] --- .travis.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 580191d..81e1cdf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,9 +25,3 @@ before_install: notifications: email: false - irc: - channels: - - "chat.freenode.net#jitsu" - on_success: change - on_failure: change - From 1a9d74214940fdb7ffaaa6fc9558853625562453 Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Tue, 3 Nov 2015 16:50:24 -0500 Subject: [PATCH 26/52] Allocate sizeof(char), not sizeof(char*) --- src/x509.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/x509.cc b/src/x509.cc index 94a1ed0..d48c9da 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -26,8 +26,6 @@ static const char *MISSING[4][2] = { } }; -Handle try_parse(const std::string& dataString); - std::string parse_args(const Nan::FunctionCallbackInfo& info) { if (info.Length() == 0) { Nan::ThrowTypeError("Must provide a certificate string."); @@ -272,7 +270,7 @@ Handle try_parse(const std::string& dataString) { BIO_get_mem_ptr(ext_bio, &bptr); BIO_set_close(ext_bio, BIO_NOCLOSE); - char *data = (char*) malloc(sizeof(char*) * bptr->length); + char *data = (char*) malloc(sizeof(char) * bptr->length); BUF_strlcpy(data, bptr->data, bptr->length + 1); data = trim(data, bptr->length); From 2357b0dddf23ded0b7671b9b94e779fe413d2838 Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Tue, 3 Nov 2015 16:54:08 -0500 Subject: [PATCH 27/52] Fix allocation; maybe 2am coding wasn't the best. - Get rid of the sizeof(char) 1 * n = n I can math now? - Should probably +1 the allocation since the length is +1 --- src/x509.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x509.cc b/src/x509.cc index d48c9da..7e6bfac 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -270,7 +270,7 @@ Handle try_parse(const std::string& dataString) { BIO_get_mem_ptr(ext_bio, &bptr); BIO_set_close(ext_bio, BIO_NOCLOSE); - char *data = (char*) malloc(sizeof(char) * bptr->length); + char *data = (char*) malloc(bptr->length + 1); BUF_strlcpy(data, bptr->data, bptr->length + 1); data = trim(data, bptr->length); From c2db68ccc8583f9f9916b315be8fdb16f88a19c8 Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Tue, 3 Nov 2015 17:13:16 -0500 Subject: [PATCH 28/52] Update .travis.yml Setup the .travis.yml to use the new container-based infrastucture. This should speed up the start time of the builds on Travis. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 81e1cdf..881151f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,3 +25,5 @@ before_install: notifications: email: false + +sudo: false From 7724f79bf76acf399c6821e2b32379757c7fb7d5 Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Fri, 6 Nov 2015 10:08:34 -0500 Subject: [PATCH 29/52] Bump version: v0.2.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 74fc24f..cf22fa4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "x509", - "version": "0.2.2", + "version": "0.2.3", "description": "Simple X509 certificate parser.", "author": "Colton Baker", "main": "index.js", From 8f07dec2d5a851a383723c48697948103138ab23 Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Fri, 6 Nov 2015 10:21:47 -0500 Subject: [PATCH 30/52] BIO_NOCLOSE->BIO_CLOSE in extensions Data is being copied, which means we should be using BIO_CLOSE when setting BIO_set_close. --- src/x509.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x509.cc b/src/x509.cc index 7e6bfac..dee27f5 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -268,7 +268,7 @@ Handle try_parse(const std::string& dataString) { BUF_MEM *bptr; BIO_get_mem_ptr(ext_bio, &bptr); - BIO_set_close(ext_bio, BIO_NOCLOSE); + BIO_set_close(ext_bio, BIO_CLOSE); char *data = (char*) malloc(bptr->length + 1); BUF_strlcpy(data, bptr->data, bptr->length + 1); From c128a788fe704251ab79954564215776bb956496 Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Mon, 22 Feb 2016 10:53:34 -0500 Subject: [PATCH 31/52] v8::Handle -> v8::Local, Handle is no longer a type Fixes #30 --- include/addon.h | 2 +- include/x509.h | 8 ++++---- src/addon.cc | 2 +- src/x509.cc | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/addon.h b/include/addon.h index e8096db..da338b6 100644 --- a/include/addon.h +++ b/include/addon.h @@ -6,6 +6,6 @@ using namespace v8; -void init(Handle exports); +void init(Local exports); #endif diff --git a/include/x509.h b/include/x509.h index bfeca85..055a2b4 100644 --- a/include/x509.h +++ b/include/x509.h @@ -24,10 +24,10 @@ NAN_METHOD(get_subject); NAN_METHOD(get_issuer); NAN_METHOD(parse_cert); -Handle try_parse(const std::string& dataString); -Handle parse_date(ASN1_TIME *date); -Handle parse_serial(ASN1_INTEGER *serial); -Handle parse_name(X509_NAME *subject); +Local try_parse(const std::string& dataString); +Local parse_date(ASN1_TIME *date); +Local parse_serial(ASN1_INTEGER *serial); +Local parse_name(X509_NAME *subject); char* real_name(char *data); char* trim(char *data, int len); diff --git a/src/addon.cc b/src/addon.cc index 6434e80..d641597 100644 --- a/src/addon.cc +++ b/src/addon.cc @@ -6,7 +6,7 @@ using namespace v8; -void init(Handle exports) { +void init(Local exports) { Nan::Set(exports, Nan::New("version").ToLocalChecked(), Nan::New(VERSION).ToLocalChecked()); diff --git a/src/x509.cc b/src/x509.cc index dee27f5..803b9f5 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -94,7 +94,7 @@ NAN_METHOD(parse_cert) { /* * This is where everything is handled for both -0.11.2 and 0.11.3+. */ -Handle try_parse(const std::string& dataString) { +Local try_parse(const std::string& dataString) { Nan::EscapableHandleScope scope; const char* data = dataString.c_str(); @@ -301,7 +301,7 @@ Handle try_parse(const std::string& dataString) { return scope.Escape(exports); } -Handle parse_serial(ASN1_INTEGER *serial) { +Local parse_serial(ASN1_INTEGER *serial) { Nan::EscapableHandleScope scope; Local serialNumber; BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL); @@ -313,7 +313,7 @@ Handle parse_serial(ASN1_INTEGER *serial) { return scope.Escape(serialNumber); } -Handle parse_date(ASN1_TIME *date) { +Local parse_date(ASN1_TIME *date) { Nan::EscapableHandleScope scope; BIO *bio; BUF_MEM *bm; @@ -334,7 +334,7 @@ Handle parse_date(ASN1_TIME *date) { return scope.Escape(DateObject->CallAsConstructor(1, args)); } -Handle parse_name(X509_NAME *subject) { +Local parse_name(X509_NAME *subject) { Nan::EscapableHandleScope scope; Local cert = Nan::New(); int i, length; From 4cea21aba9a5ab3124f528fedca93abdc1f49d67 Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Mon, 22 Feb 2016 10:57:20 -0500 Subject: [PATCH 32/52] Update .travis.yml Include "stable" to use the latest stable version of Node. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 881151f..c45c402 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ addons: language: node_js node_js: + - "stable" - "4.0" - "0.12" - "0.10" From bdc7d416f4c04da0c5605c42e5898a4aa7629ac9 Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Mon, 22 Feb 2016 11:08:00 -0500 Subject: [PATCH 33/52] Bump version: 0.2.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cf22fa4..e206885 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "x509", - "version": "0.2.3", + "version": "0.2.4", "description": "Simple X509 certificate parser.", "author": "Colton Baker", "main": "index.js", From 65b41c39cae9a3e5e375ee9a9ac60400f2aeca4b Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Thu, 3 Mar 2016 08:04:41 -0500 Subject: [PATCH 34/52] Update README [skip ci] --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 096f1ca..17f4e42 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,9 @@ node-x509 ========= -[![Build Status](https://travis-ci.org/Southern/node-x509.svg)](https://travis-ci.org/Southern/node-x509) +[![Build Status](https://travis-ci.org/Southern/node-x509.svg?branch=master)](https://travis-ci.org/Southern/node-x509) -Simple X509 certificate parser. -*support Node.js 4.0.0* +Simple X509 certificate parser. ## Installation From 97fa3388ae3f4dd3143b361ffc27bd37ee88bceb Mon Sep 17 00:00:00 2001 From: tanuck Date: Fri, 13 May 2016 09:26:19 +0100 Subject: [PATCH 35/52] deps: upgrade nan to 2.2.0 (#33) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e206885..8a6ca59 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,6 @@ }, "license": "MIT", "dependencies": { - "nan": "2.0.9" + "nan": "2.2.0" } } From 26b2b518e56b9ff9e94a176189a8deac0e8b2265 Mon Sep 17 00:00:00 2001 From: yorkie Date: Fri, 13 May 2016 16:29:36 +0800 Subject: [PATCH 36/52] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8a6ca59..c791c9c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "x509", - "version": "0.2.4", + "version": "0.2.5", "description": "Simple X509 certificate parser.", "author": "Colton Baker", "main": "index.js", From b6197efe62d5801eb7cc0ac7d23c1665a7a4c513 Mon Sep 17 00:00:00 2001 From: yorkie Date: Thu, 16 Jun 2016 02:56:37 +0800 Subject: [PATCH 37/52] src: fix memory leak when throwing errors in try_parse --- src/x509.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/x509.cc b/src/x509.cc index 803b9f5..acad881 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -125,6 +125,7 @@ Local try_parse(const std::string& dataString) { // If raw read fails, try reading the input as a filename. if (!BIO_read_filename(bio, data)) { Nan::ThrowError("File doesn't exist."); + BIO_free(bio); return scope.Escape(exports); } @@ -133,6 +134,7 @@ Local try_parse(const std::string& dataString) { if (cert == NULL) { Nan::ThrowError("Unable to parse certificate."); + BIO_free(bio); return scope.Escape(exports); } } @@ -160,6 +162,8 @@ Local try_parse(const std::string& dataString) { int sig_alg_nid = OBJ_obj2nid(cert->sig_alg->algorithm); if (sig_alg_nid == NID_undef) { Nan::ThrowError("unable to find specified signature algorithm name."); + X509_free(cert); + BIO_free(bio); return scope.Escape(exports); } Nan::Set(exports, @@ -192,6 +196,8 @@ Local try_parse(const std::string& dataString) { int pkey_nid = OBJ_obj2nid(cert->cert_info->key->algor->algorithm); if (pkey_nid == NID_undef) { Nan::ThrowError("unable to find specified public key algorithm name."); + X509_free(cert); + BIO_free(bio); return scope.Escape(exports); } EVP_PKEY *pkey = X509_get_pubkey(cert); @@ -233,6 +239,8 @@ Local try_parse(const std::string& dataString) { if (ASN1_STRING_length(current->d.dNSName) != (int) strlen(name)) { Nan::ThrowError("Malformed alternative names field."); + X509_free(cert); + BIO_free(bio); return scope.Escape(exports); } Nan::Set(altNames, i, Nan::New(name).ToLocalChecked()); From a4acc34df751a6ad396e67e29e94002e68d64b3c Mon Sep 17 00:00:00 2001 From: yorkie Date: Thu, 16 Jun 2016 05:51:16 +0800 Subject: [PATCH 38/52] v0.2.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c791c9c..212b272 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "x509", - "version": "0.2.5", + "version": "0.2.6", "description": "Simple X509 certificate parser.", "author": "Colton Baker", "main": "index.js", From fced8f846b503a503c601f27579b4046b2ff4b9f Mon Sep 17 00:00:00 2001 From: Giovanni Lela Date: Mon, 3 Oct 2016 03:40:47 +0200 Subject: [PATCH 39/52] verify: basic validation against certificate authority (#38) --- README.md | 29 ++++- binding.gyp | 4 +- include/x509.h | 3 + index.js | 36 ++++++- src/addon.cc | 7 +- src/x509.cc | 130 ++++++++++++++++++----- test/CA_chains/enduser-example.com.chain | 110 +++++++++++++++++++ test/certs/enduser-example.com.crt | 43 ++++++++ test/test.js | 30 +++++- 9 files changed, 358 insertions(+), 34 deletions(-) create mode 100644 test/CA_chains/enduser-example.com.chain create mode 100644 test/certs/enduser-example.com.crt diff --git a/README.md b/README.md index 17f4e42..8576daf 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ Parse subject, issuer, valid before and after date, and alternate names from cer const x509 = require('x509'); var cert = x509.parseCert(__dirname + '/certs/nodejitsu.com.crt'); /* -cert = { subject: +cert = { subject: { countryName: 'US', postalCode: '10010', stateOrProvinceName: 'NY', @@ -94,7 +94,7 @@ cert = { subject: organizationName: 'Nodejitsu', organizationalUnitName: 'PremiumSSL Wildcard', commonName: '*.nodejitsu.com' }, - issuer: + issuer: { countryName: 'GB', stateOrProvinceName: 'Greater Manchester', localityName: 'Salford', @@ -112,6 +112,31 @@ cert = { subject: */ ``` + +#### x509.verify(`cert`, `CABundlePath`, function(err, result){ /*...*/}) + +Performs basic certificate validation against a bundle of ca certificates. + +It accepts an error-first callback as first argument. If the error is null, then +the certificate is valid. + +The error messages are the same returned by openssl: [x509_verify_cert_error_string](https://www.openssl.org/docs/manmaster/crypto/X509_STORE_CTX_get_error.html) + + +**Note:** +As now, this function only accepts absolute paths to existing files as arguments + +```js +const x509 = require('x509'); + +x509.verify( + __dirname + '/certs/user.com.crt', + __dirname + 'enduser-example.com.chain', + function(err, result){ /*...*/} +); + +``` + ## Examples Checking the date to make sure the certificate is active: ```js diff --git a/binding.gyp b/binding.gyp index edd53e0..b01bee3 100644 --- a/binding.gyp +++ b/binding.gyp @@ -36,7 +36,7 @@ 'defines': [ 'uint=unsigned int', ], - 'libraries': [ + 'libraries': [ '-l<(openssl_root)/lib/libeay32.lib', ], 'include_dirs': [ @@ -48,7 +48,7 @@ '<(node_root_dir)/deps/openssl/openssl/include' ], }], - ], + ], } ] } diff --git a/include/x509.h b/include/x509.h index 055a2b4..ce1198b 100644 --- a/include/x509.h +++ b/include/x509.h @@ -23,11 +23,14 @@ NAN_METHOD(get_altnames); NAN_METHOD(get_subject); NAN_METHOD(get_issuer); NAN_METHOD(parse_cert); +NAN_METHOD(verify); Local try_parse(const std::string& dataString); +Local verify(const std::string& dataString); Local parse_date(ASN1_TIME *date); Local parse_serial(ASN1_INTEGER *serial); Local parse_name(X509_NAME *subject); + char* real_name(char *data); char* trim(char *data, int len); diff --git a/index.js b/index.js index df4c476..539a76c 100644 --- a/index.js +++ b/index.js @@ -1,11 +1,43 @@ - var x509 = require('./build/Release/x509'); +var fs = require('fs'); exports.version = x509.version; exports.getAltNames = x509.getAltNames; exports.getSubject = x509.getSubject; exports.getIssuer = x509.getIssuer; +exports.verify = function(certPath, CABundlePath, cb) { + if (!certPath) { + throw new TypeError('Certificate path is required'); + } + if (!CABundlePath) { + throw new TypeError('CA Bundle path is required'); + } + + fs.stat(certPath, function(certPathErr) { + + if (certPathErr) { + return cb(certPathErr); + } + + fs.stat(CABundlePath, function(bundlePathErr) { + + if (bundlePathErr) { + return cb(bundlePathErr); + } + + try { + x509.verify(certPath, CABundlePath); + cb(null); + } + catch (verificationError) { + cb(verificationError); + } + }); + }); +}; + + exports.parseCert = function(path) { var ret = x509.parseCert(path); var exts = {}; @@ -17,4 +49,4 @@ exports.parseCert = function(path) { delete ret.extensions; ret.extensions = exts; return ret; -}; \ No newline at end of file +}; diff --git a/src/addon.cc b/src/addon.cc index d641597..f0aab0c 100644 --- a/src/addon.cc +++ b/src/addon.cc @@ -7,9 +7,14 @@ using namespace v8; void init(Local exports) { - Nan::Set(exports, + Nan::Set(exports, Nan::New("version").ToLocalChecked(), Nan::New(VERSION).ToLocalChecked()); + + Nan::Set(exports, + Nan::New("verify").ToLocalChecked(), + Nan::New(verify)->GetFunction()); + Nan::Set(exports, Nan::New("getAltNames").ToLocalChecked(), Nan::New(get_altnames)->GetFunction()); diff --git a/src/x509.cc b/src/x509.cc index acad881..7606b9f 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -9,7 +9,7 @@ static const char *MISSING[4][2] = { "1.2.840.113533.7.65.0", "entrustVersionInfo" }, - + { "1.3.6.1.4.1.311.60.2.1.1", "jurisdictionOfIncorpationLocalityName" @@ -45,6 +45,84 @@ std::string parse_args(const Nan::FunctionCallbackInfo& info) { return *String::Utf8Value(info[0]->ToString()); } + + +NAN_METHOD(verify) { + Nan::HandleScope scope; + OpenSSL_add_all_algorithms(); + + std::string cert_path = *String::Utf8Value(info[0]->ToString()); + std::string ca_bundlestr = *String::Utf8Value(info[1]->ToString()); + + X509_STORE *store = NULL; + X509_STORE_CTX *verify_ctx = NULL; + X509 *cert = NULL; + BIO *cert_bio = BIO_new(BIO_s_file()); + + // create store + store = X509_STORE_new(); + if (store == NULL) { + X509_STORE_free(store); + BIO_free_all(cert_bio); + Nan::ThrowError("Failed to create X509 certificate store."); + } + + verify_ctx = X509_STORE_CTX_new(); + + if (verify_ctx == NULL) { + X509_STORE_free(store); + BIO_free_all(cert_bio); + Nan::ThrowError("Failed to create X509 verification context."); + } + + // load file in BIO + int ret = BIO_read_filename(cert_bio, cert_path.c_str()); + if (ret != 1) { + X509_STORE_free(store); + X509_free(cert); + BIO_free_all(cert_bio); + X509_STORE_CTX_free(verify_ctx); + Nan::ThrowError("Error reading file"); + } + + // read from BIO + cert = PEM_read_bio_X509(cert_bio, NULL, 0, NULL); + if (cert == NULL) { + X509_STORE_free(store); + X509_free(cert); + X509_STORE_CTX_free(verify_ctx); + BIO_free_all(cert_bio); + Nan::ThrowError("Failed to load cert"); + } + + // load CA bundle + ret = X509_STORE_load_locations(store, ca_bundlestr.c_str(), NULL); + if (ret != 1) { + X509_STORE_free(store); + X509_free(cert); + BIO_free_all(cert_bio); + X509_STORE_CTX_free(verify_ctx); + Nan::ThrowError("Error loading CA chain file"); + } + + // verify + X509_STORE_CTX_init(verify_ctx, store, cert, NULL); + ret = X509_verify_cert(verify_ctx); + + if (ret <= 0) { + Nan::ThrowError(X509_verify_cert_error_string(verify_ctx->error)); + } + + X509_STORE_free(store); + X509_free(cert); + X509_STORE_CTX_free(verify_ctx); + BIO_free_all(cert_bio); + + info.GetReturnValue().Set(Nan::New(true)); +} + + + NAN_METHOD(get_altnames) { Nan::HandleScope scope; std::string parsed_arg = parse_args(info); @@ -139,23 +217,23 @@ Local try_parse(const std::string& dataString) { } } - Nan::Set(exports, - Nan::New("version").ToLocalChecked(), + Nan::Set(exports, + Nan::New("version").ToLocalChecked(), Nan::New((int) X509_get_version(cert))); - Nan::Set(exports, - Nan::New("subject").ToLocalChecked(), + Nan::Set(exports, + Nan::New("subject").ToLocalChecked(), parse_name(X509_get_subject_name(cert))); - Nan::Set(exports, - Nan::New("issuer").ToLocalChecked(), + Nan::Set(exports, + Nan::New("issuer").ToLocalChecked(), parse_name(X509_get_issuer_name(cert))); - Nan::Set(exports, - Nan::New("serial").ToLocalChecked(), + Nan::Set(exports, + Nan::New("serial").ToLocalChecked(), parse_serial(X509_get_serialNumber(cert))); - Nan::Set(exports, - Nan::New("notBefore").ToLocalChecked(), + Nan::Set(exports, + Nan::New("notBefore").ToLocalChecked(), parse_date(X509_get_notBefore(cert))); - Nan::Set(exports, - Nan::New("notAfter").ToLocalChecked(), + Nan::Set(exports, + Nan::New("notAfter").ToLocalChecked(), parse_date(X509_get_notAfter(cert))); // Signature Algorithm @@ -187,8 +265,8 @@ Local try_parse(const std::string& dataString) { } else { fingerprint[0] = '\0'; } - Nan::Set(exports, - Nan::New("fingerPrint").ToLocalChecked(), + Nan::Set(exports, + Nan::New("fingerPrint").ToLocalChecked(), Nan::New(fingerprint).ToLocalChecked()); } @@ -202,8 +280,8 @@ Local try_parse(const std::string& dataString) { } EVP_PKEY *pkey = X509_get_pubkey(cert); Local publicKey = Nan::New(); - Nan::Set(publicKey, - Nan::New("algorithm").ToLocalChecked(), + Nan::Set(publicKey, + Nan::New("algorithm").ToLocalChecked(), Nan::New(OBJ_nid2ln(pkey_nid)).ToLocalChecked()); if (pkey_nid == NID_rsaEncryption) { @@ -212,11 +290,11 @@ Local try_parse(const std::string& dataString) { rsa_key = pkey->pkey.rsa; rsa_e_dec = BN_bn2dec(rsa_key->e); rsa_n_hex = BN_bn2hex(rsa_key->n); - Nan::Set(publicKey, - Nan::New("e").ToLocalChecked(), + Nan::Set(publicKey, + Nan::New("e").ToLocalChecked(), Nan::New(rsa_e_dec).ToLocalChecked()); - Nan::Set(publicKey, - Nan::New("n").ToLocalChecked(), + Nan::Set(publicKey, + Nan::New("n").ToLocalChecked(), Nan::New(rsa_n_hex).ToLocalChecked()); } Nan::Set(exports, Nan::New("publicKey").ToLocalChecked(), publicKey); @@ -288,15 +366,15 @@ Local try_parse(const std::string& dataString) { if (nid == NID_undef) { char extname[100]; OBJ_obj2txt(extname, 100, (const ASN1_OBJECT *) obj, 1); - Nan::Set(extensions, - Nan::New(real_name(extname)).ToLocalChecked(), + Nan::Set(extensions, + Nan::New(real_name(extname)).ToLocalChecked(), Nan::New(data).ToLocalChecked()); } else { const char *c_ext_name = OBJ_nid2ln(nid); // IFNULL_FAIL(c_ext_name, "invalid X509v3 extension name"); Nan::Set(extensions, - Nan::New(real_name((char*)c_ext_name)).ToLocalChecked(), + Nan::New(real_name((char*)c_ext_name)).ToLocalChecked(), Nan::New(data).ToLocalChecked()); } } @@ -305,7 +383,7 @@ Local try_parse(const std::string& dataString) { X509_free(cert); BIO_free(bio); - + return scope.Escape(exports); } @@ -337,7 +415,7 @@ Local parse_date(ASN1_TIME *date) { args[0] = Nan::New(formatted).ToLocalChecked(); Local global = Nan::GetCurrentContext()->Global(); - Local DateObject = Nan::Get(global, + Local DateObject = Nan::Get(global, Nan::New("Date").ToLocalChecked()).ToLocalChecked()->ToObject(); return scope.Escape(DateObject->CallAsConstructor(1, args)); } diff --git a/test/CA_chains/enduser-example.com.chain b/test/CA_chains/enduser-example.com.chain new file mode 100644 index 0000000..ae6d3ac --- /dev/null +++ b/test/CA_chains/enduser-example.com.chain @@ -0,0 +1,110 @@ +-----BEGIN CERTIFICATE----- +MIIKCzCCBfOgAwIBAgIJAKknEXQ8dpNQMA0GCSqGSIb3DQEBCwUAMIGbMQswCQYD +VQQGEwJJVDEPMA0GA1UECAwGTWlsYW5vMREwDwYDVQQHDAhMYW1icmF0ZTEPMA0G +A1UECgwGUHJvdmEgMRswGQYDVQQLDBJEaXBhcnRpbWVudG8gUHJvdmUxETAPBgNV +BAMMCEdpb3Zhbm5pMScwJQYJKoZIhvcNAQkBFhhnaW92YW5uaS5sZWxhQGxpbmst +bWUuaXQwHhcNMTYwODA0MTA0MzMxWhcNMjEwODA0MTA0MzMxWjCBmzELMAkGA1UE +BhMCSVQxDzANBgNVBAgMBk1pbGFubzERMA8GA1UEBwwITGFtYnJhdGUxDzANBgNV +BAoMBlByb3ZhIDEbMBkGA1UECwwSRGlwYXJ0aW1lbnRvIFByb3ZlMREwDwYDVQQD +DAhHaW92YW5uaTEnMCUGCSqGSIb3DQEJARYYZ2lvdmFubmkubGVsYUBsaW5rLW1l +Lml0MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEAqgGFE4wyBW5i9rDR +HH79yRRzBx9AmwwVc1rw/0SzrG066jNW4XdxzmIZVcBsnmUC6ZH3GUA1vN2nyWm6 +IURVC2dv6X3zJE1tsogwCD30eyh9a97BLiqWUdgBnwEfIzyS37/E2Vv6y9s5HI80 +83H2NbM+zZdxzwLEOhSrnHcfN7mg1z/0/AecXnPTISvOZRb162ZL779OPOw987Xr +nYbaPmyH8n5NLl7SaG8493PDfKQRE4+/1q6SXzmbHkPtRgtBP3yiuAxt+ZcHCBzp +l8MV9qADKFVHdbW+pekLGlx5FfY7SkB1z9dnXpZXW8ot+CLtThm/0+c5nocFAO41 +e3f4oEr5IzhLJw5QXJj6icIjV+vOpSCTlenlexKyA9VRNbPN8sUg3Qz6P4ZEe58b +w3yaoxqpcI+PNmFNOWWc88xhFPHIO0rk3Yd91SXcSd74fwnSW2SXy06IrMxiVeVP +SS3Qtp086imC1VDE3gRhgSA7YdN636u5hmLJyqvvb/gl2ARAy7l65VMKOZ4uyo6Q +ptCU7AdR+NhGwJiEIWSpH8ZlNHYDWEbtRKzDMsoFGMxj3tQDTtKXmWXzQ/8RXK86 +1sFTWSZxCMC6US0iWJpb/PWCTLxXlQhLBDiHSXjFHijHoI/CJKRQbOJ3XSxZydGU +ZJf+bAy1JLoTab8RGarnsDaeXJisDfglezRXj4/1kvDwZRDsO47Sqp6DubbbmVym +i7BAarv8aEkkiDf7LITACCcdDpHjJwo8nClsKSsf3DHphghpVsvooi8GNIMAlFcO +kEkS41+IaiRfwSkwQfnKK680KP/WDCYPBJTGR1sEFj7+7gThmH/kNKjExtqNBliR +BH8R3gLK/K7T68mloNCVoYH6XTiLuvmhRzsbnre0gKe9Tu0A/I7d2IsSPFZa0BYo +Y1Vlpcze9Qy6ti8lz6NYgPdkVDvYDUvle2Z5EPKofb5I/ICsPDHJbEcvOwzhBVXn +A34bR68Lrv+Lgtud9uYclHh2lZ8K6fbD0y0U1UZFT35RE8nJkTT0YWNIDL6Yf60l +rut4WQ9kOW474HSMjbAY3gWRGED6xb6tQLr8LyXdk9MxqO49fT9ynD7huI1MFgP0 +M7ks+H+Cb+FQaEhFNnziSB3NtdCmkT6spn9RQVtrBZxLLLdC2gHzwjI9e75MaujM +Y5A5/cAunNSqhsqMmMFomBeIOR9rBkyyIA60Zp3MZeH60JSZdy16Z7e7OMrRCfm3 +s15XMfZUJxoyMuwcr5PL6jNTQXu6wjE9k+kQcepApkYzbeZNKYqp231KrNEGu0Qu +6O8+kNRq2OwA9eGNopbPcqxbEXU76Z04/4HgQXKvqf+L2ulPOrKR7WbKL6q8yHYU +++OAaQIDAQABo1AwTjAdBgNVHQ4EFgQUI4fY0hlppvcOkfKPqwZD+LVrV4cwHwYD +VR0jBBgwFoAUI4fY0hlppvcOkfKPqwZD+LVrV4cwDAYDVR0TBAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCBAEAi5uS7afoN/cLruOv8D0IIoqj48o+vw3HxumcaFBtF8b/ +Tx/dJ3Aml6kqXEERL4a9dS75V2R1AmPQ34p7GFDTlnF+i/QlbmL9p3z8r5ohxhUj +IYm4eaQk8BEPrBXfCz2j9T7GSP7wqqnbfW2Ha72X9tviBpIItM2ufyfbE1Sqzmcu +NlLG3I4h6ZZjnZVYaPvMtGF1wEouxxr9+9jL9pt1kKMBwADRYtNeiT/aNF1M8tcV +f8inMXk0ytZd2H/3l3mnt/3dEPN0r7W4LFJ0QWUUanVcIygNU+BXFJuPn3W3J9Yt +wq4RK0avF02pSr8r3OtwxJs0IkIvq2i2qq4DkHKwOnxj5ng81l+J4eEbehkei3Yu +Fs5ogGLr386wTFsj7zi1Ta0sMgeF6M0ZcV0dnGWeC1ko13Z5y/y0S285Ok8WfHAV +Tba6NYUdSkwfWdfiRRAJbJN7zuygbPwJU2Du+j45c8cZrWTY0JfHLyKf43xsqJpZ +lZLgHKVDzL1eCsq/un41EksVOOrLG75o8VeMtPB9hLtJU3VWQ9KyZ0Nx6QIl0iFK +fvXknCgWAMy01xcO5xiAD7hX0IVJv/sXX9pPQsSSDyiSQ+kBWkwWVImWh5sig9hs +vNaWGoYVtgI+IUnH1wjsYgpntTnvR0mB9PB0xMRMFi6xQ2SL6ayAY8T/+R2fRlAy +gohn7mu+c3yIUDCFy9W5zuzsu/yOVTcgzoDYDCM5G+zba+FpISH0uIrUviyXLDAv +k+I3IpK2LPYYk0LSS+tWsxC0T+GrW6Wd6bV7bO8Go4geGfyou4tMV1r4UxMLNP5Y +KlH3XKx0Y9DnzsLge5+VsZd3q1jnwUU3s5tJYzz+zYPUEP5Fru6wfY6lzFrsb/TK +xG+nbh9NgjLL0WdLyjWrujkx1G1j6+ppDdiR5LybWq/IgPIvD9XIdPbc5wfoNSEX +7KiOapGPZ6Hmyb35SEJ82hAStf1xrNuIRK+Js+u2NI8jLc5fLW0Ng33ax58jK14K +WCKJK65olFBumq0I9dUtp/f+Za03qsM/L/s01Y5hYpkt4GxnPRkmS9kCnCyW7tiu +1T2i/gr3rDkETz5K7LG9R+mVjHtgblxEkPBlYiPVdCmkAplG4sZfkFw2/4OKVJLU +SP2TreiyE3cPnbIAvqnySGzjaFVCCP3cLEftHqFybuAJZVmRRX2no5JsGAWMl0h9 +LwYoEt86mIKTXqevpGRIINB0T+C/J8nnJ72emt5wSEFpk1TenRisGFtKZG2AqA8J +2Au6TUwMroJYpFNH2WUrN+WTbbVThAwDBy6gexSG4ogWGZ6xn4+fB3X7rzzPW+6A +yqpAdvmBvsx/2qjnUCB8TOTD2vw96Fy+dLx6itb97Q== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIJljCCBX6gAwIBAgICEAAwDQYJKoZIhvcNAQEFBQAwgZsxCzAJBgNVBAYTAklU +MQ8wDQYDVQQIDAZNaWxhbm8xETAPBgNVBAcMCExhbWJyYXRlMQ8wDQYDVQQKDAZQ +cm92YSAxGzAZBgNVBAsMEkRpcGFydGltZW50byBQcm92ZTERMA8GA1UEAwwIR2lv +dmFubmkxJzAlBgkqhkiG9w0BCQEWGGdpb3Zhbm5pLmxlbGFAbGluay1tZS5pdDAe +Fw0xNjA4MDQxMDU2MzFaFw0xODA4MDQxMDU2MzFaMHkxEjAQBgNVBAMMCWdpb3Zh +bm5pMjEOMAwGA1UECAwFTW9uemExCzAJBgNVBAYTAklUMSQwIgYJKoZIhvcNAQkB +FhVnaW92YW5uaTJAZXhhbXBsZS5jb20xDDAKBgNVBAoMA0FBQTESMBAGA1UECwwJ +bm9uIGxvIHNvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2jXjqPqc ++tmoCobO97WWn0uYdZgpPxDU9nzHBLa9QX1wFY8lnUdQ3y91FdraiEx5ChuJD9Qu ++UZuAPkdIQInhffSu5tiy5B0DTe3xoPnMlbyOyWpf3Ok6op0Jawn0s6a4ggvi5Vc +91UmpHLtl1bsVfulkha1RdcMdC4eP8qUax0w0nSCJ+Cpr/Db096IRWRSPu81eCcr ++LUx7EVGxd80jbOX5/1ZXdnBU7/Im7Du/dbUr039uaccpJ22AX1GkujbBsoJwsLb +FELtDRb9Nvjsb1YycPLBGWRSY6PIqCTQU8rY/U9HlvSXWtcMFgV97DCm7YsYgmuU +UsmkBbZUyIUmEUaLF+yDqVl7dlIS7RjTrd9w5NADfs1aoU2oATmZ8hERehbjuc4i +OGx2uK24ewRN8r+JoSujgaX1RNw+z7CGOudG+1LIQY3VBnGO1dgtnR+ILYRHZGPk +1mkdPoqO0KYcTTIHymn/46z7izK3jbx5Gb8Kk2gjQxdh0clFX51Tr8smG35GAHHd +zvS52R4yIrKHyoAEj5qwKiJv0BjgyAZ2QgmmtX5Of1jnq8zXl/Vz2kU5oGzfdIn6 +ykJXw7f0lmnKpaHb85rPUR12hjKuyTAgCVJcYryf5Qd1VUbWdFrymv/g9HV7zXHw +wr6G11JfpMuLbT8M7rNyroBdJgGxWshbxk0CAwEAAaOCAgMwggH/MA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFBFQFe3W9thg26oQqGwsSn4uQxc+MB8GA1UdIwQY +MBaAFCOH2NIZaab3DpHyj6sGQ/i1a1eHMAsGA1UdDwQEAwIBpjATBgNVHSUEDDAK +BggrBgEFBQcDATBsBgNVHR8EZTBjMDKgMKAuhixodHRwOi8vcGtpLnNwYXJrbGlu +Z2NhLmNvbS9TcGFya2xpbmdSb290LmNybDAtoCugKYYnaHR0cDovL3BraS5iYWNr +dXAuY29tL1NwYXJrbGluZ1Jvb3QuY3JsMEMGA1UdEQQ8MDqCG1NwYXJrbGluZyBJ +bnRlcm1pZGlhdGUgQ0EgMYIbU3BhcmtsaW5nIENBIEludGVybWlkaWF0ZSAxMIHW +BggrBgEFBQcBAQSByTCBxjA4BggrBgEFBQcwAoYsaHR0cDovL3BraS5zcGFya2xp +bmdjYS5jb20vU3BhcmtsaW5nUm9vdC5jcnQwMwYIKwYBBQUHMAKGJ2h0dHA6Ly9w +a2kuYmFja3VwLmNvbS9TcGFya2xpbmdSb290LmNydDAsBggrBgEFBQcwAYYgaHR0 +cDovL3BraS5zcGFya2xpbmdjYS5jb20vb2NzcC8wJwYIKwYBBQUHMAGGG2h0dHA6 +Ly9wa2kuYmFja3VwLmNvbS9vY3NwLzANBgkqhkiG9w0BAQUFAAOCBAEAo5wUZnHM +3X0rQJAWF+V1d4WSXlEF2D3TBHiY772NIRjyfuoGGFkbzJakW0msVZ0OW7y5JGbT +i8aRzkZPxjxi/4BGMhqG2tGkEiglFL4qXw0bcULNVr7EJyQ3eMy36vGKQiJUYEZ/ +uidsoOUD2mlwJ+54Dufr7g4bo66QIrM5vZi7DWtikq5+WOWl+Z4c4aI+2eVeTc95 +LmsVrr9pUdjn4FFc4L7B1Qn8kI33Ob+Bwq6U60NEPdDXG4Pn0cXz7nsmSb3gr9Zi +4vnoqPPDp0m8LuyhasALO3As7jq8GGajHAsrCPuf4jz9gZ/HSk6upVeMlnCxl0d/ +k0CTOGeTfjKquxgOotQ11seMInxw1yhb2exDWAU6PPn42WnB3oTzRNbqlcB+5ZL4 +k5wFtNDLJ0tGL4AFSiCTrLR9DZp9dvp/N3B5XpjYlDIaitIc3qWfKbBGapnTPgto +3W3eV6Ex7lpZMmWPboVasbcuovpUwSqac363PmagzVZ+dBVmmqsxUKt1SjSBhzJH +MUbOYZ+gAu25AedSdAkLYDnTUGQXheu+sbHiVRKPebhp9gr+dN5m0skREhK1pFYF ++DlqoC7Du8SBl06Khv/YiBGQj9RGqv+Buw2HHC9fpYNw5asSFso6w7d/5JmYXmLZ +7sbl8G9A+x2WpZQ8w6rkssMqoV+CWmpLLlJT7wQucypgaK37Ez81NwQc83iNlIyR +ZnlNKgUxgfueStM/3TY5F7e873CvGtQ1kd9z+CwTtxo5QdEr/cZc3lToVKWPwJwv +fXIxvN4LN6KK1scnI/17iSrUBjWRnfhp0/rIUZAl7PZ2646bmdRZkxNwRXmjRVOd +fqDU+wERwjv3hb248U360mctkhbkM0Wp8l/zh6rRHc5zq0koq752/asuZHG8tX4h +Z88BsbGGEyd4wrQ7ZB4uidB3LneQwZPBQPV45RPAxAS3l0RQBXiGaAukzmtHb/of +XM5cWHCGdBfTG3wgUQzyd7E5PnstlhkKkZoif1IfYK702s+mSCu1MHTe17+TS9Hq +qoSrEW+Stb46ThMuz/w74rOmokayPBMd3aEdvk/JrrBG4kBUNXprcTz5DJRpsfLr +T77ewrWab7CBkT28FQjg7s9yfsZhzyTPbwIPA2aauSMXX+eV9tgScBH9uKxzCSfM +OT+nvDQmnHd4mqrhha2smzJOZcQqN1P7/8tl26ZnWEhi08sXIJjSLu+f/G0U1F5E +PfaCXF1M/vNQy/kX2Kq4M8Z+Rc/qDMEy1AIuSTpmk39CnLE/tzuOCDy3NIQJNhqw +UpmoF2//OGGfg8DCCGtiza4G0cIKG/svBhvu7G9StYhHvIfcAtf3jLnpQVvPyHL8 +oxvvzR0LzlWlXA== +-----END CERTIFICATE----- diff --git a/test/certs/enduser-example.com.crt b/test/certs/enduser-example.com.crt new file mode 100644 index 0000000..53d86d4 --- /dev/null +++ b/test/certs/enduser-example.com.crt @@ -0,0 +1,43 @@ +-----BEGIN CERTIFICATE----- +MIIHqjCCBZKgAwIBAgICEAEwDQYJKoZIhvcNAQEFBQAweTESMBAGA1UEAwwJZ2lv +dmFubmkyMQ4wDAYDVQQIDAVNb256YTELMAkGA1UEBhMCSVQxJDAiBgkqhkiG9w0B +CQEWFWdpb3Zhbm5pMkBleGFtcGxlLmNvbTEMMAoGA1UECgwDQUFBMRIwEAYDVQQL +DAlub24gbG8gc28wHhcNMTYwODA0MTUxMDE3WhcNMTcwODA0MTUxMDE3WjCBrjFF +MEMGA1UEAww8VmFsaWRTaWduIFs2NTIzOGJiODBmZjVjMTQ1LDY1MjM4YmI4MGZm +NWMxNDZdIFVzZXJzKDUwKSBERU1PMREwDwYDVQQIDAhMb21iYXJkeTELMAkGA1UE +BhMCSVQxIzAhBgkqhkiG9w0BCQEWFHZhbGlkc2lnbkBsaW5rLW1lLml0MQ8wDQYD +VQQKDAZMaW5rbWUxDzANBgNVBAsMBkxpbmttZTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBANh2LEbkUX4ojZacXr6I9YL1BdChcoWfFqGNXk2qX8LVv0AA +dHjt57L9bfGAeQ49U16WsR9ud4aoOw9D+OMf4BXn1egKIFkNQw4EAL8FUqVHC9zB +Q2EybjV15gjkgsvPf/UMBA/Ag2Gj8JT2piULirpI6O7LN/dq68ElGCxpWwr2+zv7 +BlSQ3j8ctDqZbnXdQjtlm/xDfr1ND7cGo7TtwgPbxFpQwuPEJiuTwKA6Qu+C4Do/ +GJgK81rV8Q04XwY0fX4hniP2M5Zhq3idgekJZR9qZ+lPnu3dAJ/2yrEw+bbL0uwf +1bvJG2I+wqthIlfZXc4kgDTBi1Wi4VKxyAl9RE1vhwKvzDYPCUdwW5X+4jVmKJsd +GjzY59kMOO3LejxaY43E8gYwRfjbClhz1pWxlkxcEbqrXU8hzdKjk7qHsgSZ2UWG +9ybmYA2VvP+lA+hzqjaQS1Cypu2xS37QWdK0E/z0WLMoZrzaCV/mTSA/1+rqdCDG +GA37C4W1otbnwCbaEnGdjVrE1oHhseNRNVegKTUvwA91dHN+3DtMVtcCAzRCc3Y+ +UmVzWCJbJrKJezYrUr8JbeR9csB2niyd//80vdeZ/1gDVDSCeargCIIEXvksRWVY +P81ZUxI1Gc4olmUw4KLhfQjdtdtOs3chPy9WPtemL6r9G51Vu5G6/rKqBV2LAgMB +AAGjggIEMIICADAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTS8qwcImqEYUd4NJ6Z +qxUvq0UvfjAfBgNVHSMEGDAWgBQRUBXt1vbYYNuqEKhsLEp+LkMXPjALBgNVHQ8E +BAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwfgYDVR0fBHcwdTA7oDmgN4Y1aHR0 +cDovL3BraS5zcGFya2xpbmdjYS5jb20vU3BhcmtsaW5nSW50ZXJtaWRpYXRlMS5j +cmwwNqA0oDKGMGh0dHA6Ly9wa2kuYmFja3VwLmNvbS9TcGFya2xpbmdJbnRlcm1p +ZGlhdGUxLmNybDAjBgNVHREEHDAaggtleGFtcGxlLmNvbYILZXhhbXBsZS5vcmcw +gegGCCsGAQUFBwEBBIHbMIHYMEEGCCsGAQUFBzAChjVodHRwOi8vcGtpLnNwYXJr +bGluZ2NhLmNvbS9TcGFya2xpbmdJbnRlcm1lZGlhdGUxLmNydDA8BggrBgEFBQcw +AoYwaHR0cDovL3BraS5iYWNrdXAuY29tL1NwYXJrbGluZ0ludGVybWVkaWF0ZTEu +Y3J0MCwGCCsGAQUFBzABhiBodHRwOi8vcGtpLnNwYXJrbGluZ2NhLmNvbS9vY3Nw +LzAnBggrBgEFBQcwAYYbaHR0cDovL3BraS5iYWNrdXAuY29tL29jc3AvMA0GCSqG +SIb3DQEBBQUAA4ICAQBZV0tenQyAWW5O2DLCXxbGUIEgOhikulAOA0jWdwhvMpVu +GLHH1Uf9p37FNm08tmjVoub0oyQ/QexvParxiE4HyvJepMdtBMtVJhV9ej2YX/fu +YpAQHzLiRqFOvC3DHnOmkapkgV4he/qFnysfwc9KUNN6/vq4kp9ChjXv8Wy25Jfr +50unv+b5FTSARkhc3vX64eXbe4w4xcxyqJexZa0rgH2+ezRwRuhSBofp8Oa7vS11 +nBBoGPeTYBQi/FfE1QDKR+Ji2aRcdFNj0CYXIMVEqTt9dXSobFwAxXa9eG2TL5nY +KKBht2aOr1XVc7eXK+EgErAMIuopFz78cnHs4QnTQgTMf/HBPSdVmjUPlSSNwyW2 +qrgAodwZksfoHTKj2Ka8FOYuUSb8kJFD+3FRCbwLiFZUjsXp+0hAdrHHhLGAzEsX +UkRV36aswQS4CQ7uDm8uZzbPi/H5lUmBZOtHy2abrW3C18QiCMNqMjErUh2ZJEpk +I8n4vFBctOyN7tO0v4sliv8h1Q1Kokts3GdrhTxCoUZfuu/zPDnwp25thX9eOT1E +GW8HUE06ULRd2CFOAqGqtkLeb2sxtTjXZ1H7IMTMIBwav1CCvFUtaYzy5VO8Mdq8 +S8PVNIfcn2GwopOkpYUAqKkREyq3dXPTciB0cj7JiEjpAZWfsSUoTC6rtRcosQ== +-----END CERTIFICATE----- diff --git a/test/test.js b/test/test.js index 6096f3f..c364fdc 100644 --- a/test/test.js +++ b/test/test.js @@ -1,6 +1,7 @@ var x509 = require('../index'), fs = require('fs'), - path = require('path'); + path = require('path'), + assert = require('assert'); // All cert files should read without throwing an error. // Simple enough test, no? @@ -10,3 +11,30 @@ fs.readdirSync(path.join(__dirname, 'certs')).forEach(function (file) { // x509.parseCert(path.join(__dirname, 'certs', file)); console.log(); }); + + +x509.verify( + path.join(__dirname, 'certs/enduser-example.com.crt'), + path.join(__dirname, 'CA_chains/enduser-example.com.chain'), + function (err) { + assert.strictEqual(err, null); + } +); + + + +x509.verify( + path.join(__dirname, 'certs/acaline.com.crt'), + path.join(__dirname, 'CA_chains/enduser-example.com.chain'), + function (err, result) { + assert.throws(assert.ifError.bind(null, err), /unable to get local issuer/) + } +); + +x509.verify( + path.join(__dirname, 'certs/notexisting.com.crt'), + path.join(__dirname, 'CA_chains/enduser-example.com.chain'), + function (err, result) { + assert.throws(assert.ifError.bind(null, err), /ENOENT/) + } +); From a87d702e2f832c6c4423e158b9347b0c9b010e4c Mon Sep 17 00:00:00 2001 From: yorkie Date: Mon, 3 Oct 2016 09:41:45 +0800 Subject: [PATCH 40/52] v0.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 212b272..0e93242 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "x509", - "version": "0.2.6", + "version": "0.3.0", "description": "Simple X509 certificate parser.", "author": "Colton Baker", "main": "index.js", From 034349def584663ef73db90775c2f6e5ef2c8efe Mon Sep 17 00:00:00 2001 From: Jakob Krigovsky Date: Thu, 15 Dec 2016 21:01:49 +0100 Subject: [PATCH 41/52] Fix link to OpenSSL documentation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8576daf..6a49152 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ Performs basic certificate validation against a bundle of ca certificates. It accepts an error-first callback as first argument. If the error is null, then the certificate is valid. -The error messages are the same returned by openssl: [x509_verify_cert_error_string](https://www.openssl.org/docs/manmaster/crypto/X509_STORE_CTX_get_error.html) +The error messages are the same returned by openssl: [x509_verify_cert_error_string](https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_get_error.html) **Note:** From 50a0162690b7a794ab95678d2a0f9c7595c81074 Mon Sep 17 00:00:00 2001 From: Paul Spicer Date: Thu, 22 Dec 2016 12:30:18 -0500 Subject: [PATCH 42/52] Added bitSize to public key field --- src/x509.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/x509.cc b/src/x509.cc index 7606b9f..80b40e2 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -286,16 +286,21 @@ Local try_parse(const std::string& dataString) { if (pkey_nid == NID_rsaEncryption) { char *rsa_e_dec, *rsa_n_hex; + uint32_t rsa_key_length_int; RSA *rsa_key; rsa_key = pkey->pkey.rsa; rsa_e_dec = BN_bn2dec(rsa_key->e); rsa_n_hex = BN_bn2hex(rsa_key->n); + rsa_key_length_int = RSA_size(rsa_key) * 8; Nan::Set(publicKey, Nan::New("e").ToLocalChecked(), Nan::New(rsa_e_dec).ToLocalChecked()); Nan::Set(publicKey, Nan::New("n").ToLocalChecked(), Nan::New(rsa_n_hex).ToLocalChecked()); + Nan::Set(publicKey, + Nan::New("bitSize").ToLocalChecked(), + Nan::New(rsa_key_length_int)); } Nan::Set(exports, Nan::New("publicKey").ToLocalChecked(), publicKey); EVP_PKEY_free(pkey); From 6b8e27f693b1a131a6d771e6caaa677c45ffeb72 Mon Sep 17 00:00:00 2001 From: Jan Kryl Date: Mon, 30 Jan 2017 09:46:02 +0100 Subject: [PATCH 43/52] Support for subject hash property of a certificate --- src/x509.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/x509.cc b/src/x509.cc index 7606b9f..c82e98f 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -1,4 +1,5 @@ #include +#include #include using namespace v8; @@ -236,6 +237,13 @@ Local try_parse(const std::string& dataString) { Nan::New("notAfter").ToLocalChecked(), parse_date(X509_get_notAfter(cert))); + // Subject hash + std::stringstream stream; + stream << std::hex << X509_subject_name_hash(cert); + Nan::Set(exports, + Nan::New("subjectHash").ToLocalChecked(), + Nan::New(stream.str()).ToLocalChecked()); + // Signature Algorithm int sig_alg_nid = OBJ_obj2nid(cert->sig_alg->algorithm); if (sig_alg_nid == NID_undef) { From b53d6abb48e6ba3ea99ede97a59bbd5acfbafd99 Mon Sep 17 00:00:00 2001 From: Jan Kryl Date: Tue, 31 Jan 2017 16:24:28 +0100 Subject: [PATCH 44/52] Fix memory leak in bindings --- src/x509.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/x509.cc b/src/x509.cc index 7606b9f..487747a 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -356,9 +356,9 @@ Local try_parse(const std::string& dataString) { BIO_get_mem_ptr(ext_bio, &bptr); BIO_set_close(ext_bio, BIO_CLOSE); - char *data = (char*) malloc(bptr->length + 1); + char *data = new char[bptr->length + 1]; BUF_strlcpy(data, bptr->data, bptr->length + 1); - data = trim(data, bptr->length); + char *trimmed_data = trim(data, bptr->length); BIO_free(ext_bio); @@ -368,15 +368,16 @@ Local try_parse(const std::string& dataString) { OBJ_obj2txt(extname, 100, (const ASN1_OBJECT *) obj, 1); Nan::Set(extensions, Nan::New(real_name(extname)).ToLocalChecked(), - Nan::New(data).ToLocalChecked()); + Nan::New(trimmed_data).ToLocalChecked()); } else { const char *c_ext_name = OBJ_nid2ln(nid); // IFNULL_FAIL(c_ext_name, "invalid X509v3 extension name"); Nan::Set(extensions, Nan::New(real_name((char*)c_ext_name)).ToLocalChecked(), - Nan::New(data).ToLocalChecked()); + Nan::New(trimmed_data).ToLocalChecked()); } + delete[] data; } Nan::Set(exports, Nan::New("extensions").ToLocalChecked(), extensions); From 9584ed4966e7c67b50c15a81ea49721177ba0272 Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Mon, 6 Feb 2017 14:17:09 -0500 Subject: [PATCH 45/52] v0.3.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0e93242..9009c5e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "x509", - "version": "0.3.0", + "version": "0.3.1", "description": "Simple X509 certificate parser.", "author": "Colton Baker", "main": "index.js", From 8b34a620f8a7d8dac8dbad16b8c6c86b9debd86f Mon Sep 17 00:00:00 2001 From: Andrew Stitt Date: Thu, 16 Feb 2017 20:20:42 -0800 Subject: [PATCH 46/52] fixes for memory and error status leaks in parse cert --- src/x509.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/x509.cc b/src/x509.cc index 0e04958..f2c8167 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -134,6 +134,7 @@ NAN_METHOD(get_altnames) { Local key = Nan::New("altNames").ToLocalChecked(); info.GetReturnValue().Set( Nan::Get(exports, key).ToLocalChecked()); + ERR_clear_error(); } NAN_METHOD(get_subject) { @@ -146,6 +147,7 @@ NAN_METHOD(get_subject) { Local key = Nan::New("subject").ToLocalChecked(); info.GetReturnValue().Set( Nan::Get(exports, key).ToLocalChecked()); + ERR_clear_error(); } NAN_METHOD(get_issuer) { @@ -158,6 +160,7 @@ NAN_METHOD(get_issuer) { Local key = Nan::New("issuer").ToLocalChecked(); info.GetReturnValue().Set( Nan::Get(exports, key).ToLocalChecked()); + ERR_clear_error(); } NAN_METHOD(parse_cert) { @@ -168,6 +171,7 @@ NAN_METHOD(parse_cert) { } Local exports(try_parse(parsed_arg)->ToObject()); info.GetReturnValue().Set(exports); + ERR_clear_error(); } /* @@ -198,11 +202,13 @@ Local try_parse(const std::string& dataString) { cert = PEM_read_bio_X509(bio, NULL, 0, NULL); if (cert == NULL) { + BIO_free_all(bio); // Switch to file BIO bio = BIO_new(BIO_s_file()); // If raw read fails, try reading the input as a filename. if (!BIO_read_filename(bio, data)) { + ERR_clear_error(); Nan::ThrowError("File doesn't exist."); BIO_free(bio); return scope.Escape(exports); @@ -212,6 +218,7 @@ Local try_parse(const std::string& dataString) { cert = PEM_read_bio_X509(bio, NULL, 0, NULL); if (cert == NULL) { + ERR_clear_error(); Nan::ThrowError("Unable to parse certificate."); BIO_free(bio); return scope.Escape(exports); @@ -247,6 +254,7 @@ Local try_parse(const std::string& dataString) { // Signature Algorithm int sig_alg_nid = OBJ_obj2nid(cert->sig_alg->algorithm); if (sig_alg_nid == NID_undef) { + ERR_clear_error(); Nan::ThrowError("unable to find specified signature algorithm name."); X509_free(cert); BIO_free(bio); @@ -281,6 +289,7 @@ Local try_parse(const std::string& dataString) { // public key int pkey_nid = OBJ_obj2nid(cert->cert_info->key->algor->algorithm); if (pkey_nid == NID_undef) { + ERR_clear_error(); Nan::ThrowError("unable to find specified public key algorithm name."); X509_free(cert); BIO_free(bio); @@ -303,9 +312,11 @@ Local try_parse(const std::string& dataString) { Nan::Set(publicKey, Nan::New("e").ToLocalChecked(), Nan::New(rsa_e_dec).ToLocalChecked()); + OPENSSL_free(rsa_e_dec); Nan::Set(publicKey, Nan::New("n").ToLocalChecked(), Nan::New(rsa_n_hex).ToLocalChecked()); + OPENSSL_free(rsa_n_hex); Nan::Set(publicKey, Nan::New("bitSize").ToLocalChecked(), Nan::New(rsa_key_length_int)); @@ -329,6 +340,7 @@ Local try_parse(const std::string& dataString) { char *name = (char*) ASN1_STRING_data(current->d.dNSName); if (ASN1_STRING_length(current->d.dNSName) != (int) strlen(name)) { + ERR_clear_error(); Nan::ThrowError("Malformed alternative names field."); X509_free(cert); BIO_free(bio); @@ -337,6 +349,7 @@ Local try_parse(const std::string& dataString) { Nan::Set(altNames, i, Nan::New(name).ToLocalChecked()); } } + sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); } Nan::Set(exports, Nan::New("altNames").ToLocalChecked(), altNames); @@ -395,6 +408,7 @@ Local try_parse(const std::string& dataString) { Nan::Set(exports, Nan::New("extensions").ToLocalChecked(), extensions); + ERR_clear_error(); X509_free(cert); BIO_free(bio); From 380d771c7e1a8cf93ad0ed03c6b6b2e722337197 Mon Sep 17 00:00:00 2001 From: Colton Baker Date: Tue, 21 Mar 2017 19:52:40 -0400 Subject: [PATCH 47/52] Bump version: v0.3.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9009c5e..ed22dc3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "x509", - "version": "0.3.1", + "version": "0.3.2", "description": "Simple X509 certificate parser.", "author": "Colton Baker", "main": "index.js", From 0d702544618ec95e77cde3d0dc3b5043cb416026 Mon Sep 17 00:00:00 2001 From: Yazhong Liu Date: Tue, 28 Nov 2017 16:59:55 +0800 Subject: [PATCH 48/52] test: update cert & chain for verify (#62) generated by https://certificatechain.io/ --- test/CA_chains/enduser-example.com.chain | 124 +++-------------------- test/certs/enduser-example.com.crt | 57 +++-------- 2 files changed, 32 insertions(+), 149 deletions(-) diff --git a/test/CA_chains/enduser-example.com.chain b/test/CA_chains/enduser-example.com.chain index ae6d3ac..15c7840 100644 --- a/test/CA_chains/enduser-example.com.chain +++ b/test/CA_chains/enduser-example.com.chain @@ -1,110 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIKCzCCBfOgAwIBAgIJAKknEXQ8dpNQMA0GCSqGSIb3DQEBCwUAMIGbMQswCQYD -VQQGEwJJVDEPMA0GA1UECAwGTWlsYW5vMREwDwYDVQQHDAhMYW1icmF0ZTEPMA0G -A1UECgwGUHJvdmEgMRswGQYDVQQLDBJEaXBhcnRpbWVudG8gUHJvdmUxETAPBgNV -BAMMCEdpb3Zhbm5pMScwJQYJKoZIhvcNAQkBFhhnaW92YW5uaS5sZWxhQGxpbmst -bWUuaXQwHhcNMTYwODA0MTA0MzMxWhcNMjEwODA0MTA0MzMxWjCBmzELMAkGA1UE -BhMCSVQxDzANBgNVBAgMBk1pbGFubzERMA8GA1UEBwwITGFtYnJhdGUxDzANBgNV -BAoMBlByb3ZhIDEbMBkGA1UECwwSRGlwYXJ0aW1lbnRvIFByb3ZlMREwDwYDVQQD -DAhHaW92YW5uaTEnMCUGCSqGSIb3DQEJARYYZ2lvdmFubmkubGVsYUBsaW5rLW1l -Lml0MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEAqgGFE4wyBW5i9rDR -HH79yRRzBx9AmwwVc1rw/0SzrG066jNW4XdxzmIZVcBsnmUC6ZH3GUA1vN2nyWm6 -IURVC2dv6X3zJE1tsogwCD30eyh9a97BLiqWUdgBnwEfIzyS37/E2Vv6y9s5HI80 -83H2NbM+zZdxzwLEOhSrnHcfN7mg1z/0/AecXnPTISvOZRb162ZL779OPOw987Xr -nYbaPmyH8n5NLl7SaG8493PDfKQRE4+/1q6SXzmbHkPtRgtBP3yiuAxt+ZcHCBzp -l8MV9qADKFVHdbW+pekLGlx5FfY7SkB1z9dnXpZXW8ot+CLtThm/0+c5nocFAO41 -e3f4oEr5IzhLJw5QXJj6icIjV+vOpSCTlenlexKyA9VRNbPN8sUg3Qz6P4ZEe58b -w3yaoxqpcI+PNmFNOWWc88xhFPHIO0rk3Yd91SXcSd74fwnSW2SXy06IrMxiVeVP -SS3Qtp086imC1VDE3gRhgSA7YdN636u5hmLJyqvvb/gl2ARAy7l65VMKOZ4uyo6Q -ptCU7AdR+NhGwJiEIWSpH8ZlNHYDWEbtRKzDMsoFGMxj3tQDTtKXmWXzQ/8RXK86 -1sFTWSZxCMC6US0iWJpb/PWCTLxXlQhLBDiHSXjFHijHoI/CJKRQbOJ3XSxZydGU -ZJf+bAy1JLoTab8RGarnsDaeXJisDfglezRXj4/1kvDwZRDsO47Sqp6DubbbmVym -i7BAarv8aEkkiDf7LITACCcdDpHjJwo8nClsKSsf3DHphghpVsvooi8GNIMAlFcO -kEkS41+IaiRfwSkwQfnKK680KP/WDCYPBJTGR1sEFj7+7gThmH/kNKjExtqNBliR -BH8R3gLK/K7T68mloNCVoYH6XTiLuvmhRzsbnre0gKe9Tu0A/I7d2IsSPFZa0BYo -Y1Vlpcze9Qy6ti8lz6NYgPdkVDvYDUvle2Z5EPKofb5I/ICsPDHJbEcvOwzhBVXn -A34bR68Lrv+Lgtud9uYclHh2lZ8K6fbD0y0U1UZFT35RE8nJkTT0YWNIDL6Yf60l -rut4WQ9kOW474HSMjbAY3gWRGED6xb6tQLr8LyXdk9MxqO49fT9ynD7huI1MFgP0 -M7ks+H+Cb+FQaEhFNnziSB3NtdCmkT6spn9RQVtrBZxLLLdC2gHzwjI9e75MaujM -Y5A5/cAunNSqhsqMmMFomBeIOR9rBkyyIA60Zp3MZeH60JSZdy16Z7e7OMrRCfm3 -s15XMfZUJxoyMuwcr5PL6jNTQXu6wjE9k+kQcepApkYzbeZNKYqp231KrNEGu0Qu -6O8+kNRq2OwA9eGNopbPcqxbEXU76Z04/4HgQXKvqf+L2ulPOrKR7WbKL6q8yHYU -++OAaQIDAQABo1AwTjAdBgNVHQ4EFgQUI4fY0hlppvcOkfKPqwZD+LVrV4cwHwYD -VR0jBBgwFoAUI4fY0hlppvcOkfKPqwZD+LVrV4cwDAYDVR0TBAUwAwEB/zANBgkq -hkiG9w0BAQsFAAOCBAEAi5uS7afoN/cLruOv8D0IIoqj48o+vw3HxumcaFBtF8b/ -Tx/dJ3Aml6kqXEERL4a9dS75V2R1AmPQ34p7GFDTlnF+i/QlbmL9p3z8r5ohxhUj -IYm4eaQk8BEPrBXfCz2j9T7GSP7wqqnbfW2Ha72X9tviBpIItM2ufyfbE1Sqzmcu -NlLG3I4h6ZZjnZVYaPvMtGF1wEouxxr9+9jL9pt1kKMBwADRYtNeiT/aNF1M8tcV -f8inMXk0ytZd2H/3l3mnt/3dEPN0r7W4LFJ0QWUUanVcIygNU+BXFJuPn3W3J9Yt -wq4RK0avF02pSr8r3OtwxJs0IkIvq2i2qq4DkHKwOnxj5ng81l+J4eEbehkei3Yu -Fs5ogGLr386wTFsj7zi1Ta0sMgeF6M0ZcV0dnGWeC1ko13Z5y/y0S285Ok8WfHAV -Tba6NYUdSkwfWdfiRRAJbJN7zuygbPwJU2Du+j45c8cZrWTY0JfHLyKf43xsqJpZ -lZLgHKVDzL1eCsq/un41EksVOOrLG75o8VeMtPB9hLtJU3VWQ9KyZ0Nx6QIl0iFK -fvXknCgWAMy01xcO5xiAD7hX0IVJv/sXX9pPQsSSDyiSQ+kBWkwWVImWh5sig9hs -vNaWGoYVtgI+IUnH1wjsYgpntTnvR0mB9PB0xMRMFi6xQ2SL6ayAY8T/+R2fRlAy -gohn7mu+c3yIUDCFy9W5zuzsu/yOVTcgzoDYDCM5G+zba+FpISH0uIrUviyXLDAv -k+I3IpK2LPYYk0LSS+tWsxC0T+GrW6Wd6bV7bO8Go4geGfyou4tMV1r4UxMLNP5Y -KlH3XKx0Y9DnzsLge5+VsZd3q1jnwUU3s5tJYzz+zYPUEP5Fru6wfY6lzFrsb/TK -xG+nbh9NgjLL0WdLyjWrujkx1G1j6+ppDdiR5LybWq/IgPIvD9XIdPbc5wfoNSEX -7KiOapGPZ6Hmyb35SEJ82hAStf1xrNuIRK+Js+u2NI8jLc5fLW0Ng33ax58jK14K -WCKJK65olFBumq0I9dUtp/f+Za03qsM/L/s01Y5hYpkt4GxnPRkmS9kCnCyW7tiu -1T2i/gr3rDkETz5K7LG9R+mVjHtgblxEkPBlYiPVdCmkAplG4sZfkFw2/4OKVJLU -SP2TreiyE3cPnbIAvqnySGzjaFVCCP3cLEftHqFybuAJZVmRRX2no5JsGAWMl0h9 -LwYoEt86mIKTXqevpGRIINB0T+C/J8nnJ72emt5wSEFpk1TenRisGFtKZG2AqA8J -2Au6TUwMroJYpFNH2WUrN+WTbbVThAwDBy6gexSG4ogWGZ6xn4+fB3X7rzzPW+6A -yqpAdvmBvsx/2qjnUCB8TOTD2vw96Fy+dLx6itb97Q== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIJljCCBX6gAwIBAgICEAAwDQYJKoZIhvcNAQEFBQAwgZsxCzAJBgNVBAYTAklU -MQ8wDQYDVQQIDAZNaWxhbm8xETAPBgNVBAcMCExhbWJyYXRlMQ8wDQYDVQQKDAZQ -cm92YSAxGzAZBgNVBAsMEkRpcGFydGltZW50byBQcm92ZTERMA8GA1UEAwwIR2lv -dmFubmkxJzAlBgkqhkiG9w0BCQEWGGdpb3Zhbm5pLmxlbGFAbGluay1tZS5pdDAe -Fw0xNjA4MDQxMDU2MzFaFw0xODA4MDQxMDU2MzFaMHkxEjAQBgNVBAMMCWdpb3Zh -bm5pMjEOMAwGA1UECAwFTW9uemExCzAJBgNVBAYTAklUMSQwIgYJKoZIhvcNAQkB -FhVnaW92YW5uaTJAZXhhbXBsZS5jb20xDDAKBgNVBAoMA0FBQTESMBAGA1UECwwJ -bm9uIGxvIHNvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2jXjqPqc -+tmoCobO97WWn0uYdZgpPxDU9nzHBLa9QX1wFY8lnUdQ3y91FdraiEx5ChuJD9Qu -+UZuAPkdIQInhffSu5tiy5B0DTe3xoPnMlbyOyWpf3Ok6op0Jawn0s6a4ggvi5Vc -91UmpHLtl1bsVfulkha1RdcMdC4eP8qUax0w0nSCJ+Cpr/Db096IRWRSPu81eCcr -+LUx7EVGxd80jbOX5/1ZXdnBU7/Im7Du/dbUr039uaccpJ22AX1GkujbBsoJwsLb -FELtDRb9Nvjsb1YycPLBGWRSY6PIqCTQU8rY/U9HlvSXWtcMFgV97DCm7YsYgmuU -UsmkBbZUyIUmEUaLF+yDqVl7dlIS7RjTrd9w5NADfs1aoU2oATmZ8hERehbjuc4i -OGx2uK24ewRN8r+JoSujgaX1RNw+z7CGOudG+1LIQY3VBnGO1dgtnR+ILYRHZGPk -1mkdPoqO0KYcTTIHymn/46z7izK3jbx5Gb8Kk2gjQxdh0clFX51Tr8smG35GAHHd -zvS52R4yIrKHyoAEj5qwKiJv0BjgyAZ2QgmmtX5Of1jnq8zXl/Vz2kU5oGzfdIn6 -ykJXw7f0lmnKpaHb85rPUR12hjKuyTAgCVJcYryf5Qd1VUbWdFrymv/g9HV7zXHw -wr6G11JfpMuLbT8M7rNyroBdJgGxWshbxk0CAwEAAaOCAgMwggH/MA8GA1UdEwEB -/wQFMAMBAf8wHQYDVR0OBBYEFBFQFe3W9thg26oQqGwsSn4uQxc+MB8GA1UdIwQY -MBaAFCOH2NIZaab3DpHyj6sGQ/i1a1eHMAsGA1UdDwQEAwIBpjATBgNVHSUEDDAK -BggrBgEFBQcDATBsBgNVHR8EZTBjMDKgMKAuhixodHRwOi8vcGtpLnNwYXJrbGlu -Z2NhLmNvbS9TcGFya2xpbmdSb290LmNybDAtoCugKYYnaHR0cDovL3BraS5iYWNr -dXAuY29tL1NwYXJrbGluZ1Jvb3QuY3JsMEMGA1UdEQQ8MDqCG1NwYXJrbGluZyBJ -bnRlcm1pZGlhdGUgQ0EgMYIbU3BhcmtsaW5nIENBIEludGVybWlkaWF0ZSAxMIHW -BggrBgEFBQcBAQSByTCBxjA4BggrBgEFBQcwAoYsaHR0cDovL3BraS5zcGFya2xp -bmdjYS5jb20vU3BhcmtsaW5nUm9vdC5jcnQwMwYIKwYBBQUHMAKGJ2h0dHA6Ly9w -a2kuYmFja3VwLmNvbS9TcGFya2xpbmdSb290LmNydDAsBggrBgEFBQcwAYYgaHR0 -cDovL3BraS5zcGFya2xpbmdjYS5jb20vb2NzcC8wJwYIKwYBBQUHMAGGG2h0dHA6 -Ly9wa2kuYmFja3VwLmNvbS9vY3NwLzANBgkqhkiG9w0BAQUFAAOCBAEAo5wUZnHM -3X0rQJAWF+V1d4WSXlEF2D3TBHiY772NIRjyfuoGGFkbzJakW0msVZ0OW7y5JGbT -i8aRzkZPxjxi/4BGMhqG2tGkEiglFL4qXw0bcULNVr7EJyQ3eMy36vGKQiJUYEZ/ -uidsoOUD2mlwJ+54Dufr7g4bo66QIrM5vZi7DWtikq5+WOWl+Z4c4aI+2eVeTc95 -LmsVrr9pUdjn4FFc4L7B1Qn8kI33Ob+Bwq6U60NEPdDXG4Pn0cXz7nsmSb3gr9Zi -4vnoqPPDp0m8LuyhasALO3As7jq8GGajHAsrCPuf4jz9gZ/HSk6upVeMlnCxl0d/ -k0CTOGeTfjKquxgOotQ11seMInxw1yhb2exDWAU6PPn42WnB3oTzRNbqlcB+5ZL4 -k5wFtNDLJ0tGL4AFSiCTrLR9DZp9dvp/N3B5XpjYlDIaitIc3qWfKbBGapnTPgto -3W3eV6Ex7lpZMmWPboVasbcuovpUwSqac363PmagzVZ+dBVmmqsxUKt1SjSBhzJH -MUbOYZ+gAu25AedSdAkLYDnTUGQXheu+sbHiVRKPebhp9gr+dN5m0skREhK1pFYF -+DlqoC7Du8SBl06Khv/YiBGQj9RGqv+Buw2HHC9fpYNw5asSFso6w7d/5JmYXmLZ -7sbl8G9A+x2WpZQ8w6rkssMqoV+CWmpLLlJT7wQucypgaK37Ez81NwQc83iNlIyR -ZnlNKgUxgfueStM/3TY5F7e873CvGtQ1kd9z+CwTtxo5QdEr/cZc3lToVKWPwJwv -fXIxvN4LN6KK1scnI/17iSrUBjWRnfhp0/rIUZAl7PZ2646bmdRZkxNwRXmjRVOd -fqDU+wERwjv3hb248U360mctkhbkM0Wp8l/zh6rRHc5zq0koq752/asuZHG8tX4h -Z88BsbGGEyd4wrQ7ZB4uidB3LneQwZPBQPV45RPAxAS3l0RQBXiGaAukzmtHb/of -XM5cWHCGdBfTG3wgUQzyd7E5PnstlhkKkZoif1IfYK702s+mSCu1MHTe17+TS9Hq -qoSrEW+Stb46ThMuz/w74rOmokayPBMd3aEdvk/JrrBG4kBUNXprcTz5DJRpsfLr -T77ewrWab7CBkT28FQjg7s9yfsZhzyTPbwIPA2aauSMXX+eV9tgScBH9uKxzCSfM -OT+nvDQmnHd4mqrhha2smzJOZcQqN1P7/8tl26ZnWEhi08sXIJjSLu+f/G0U1F5E -PfaCXF1M/vNQy/kX2Kq4M8Z+Rc/qDMEy1AIuSTpmk39CnLE/tzuOCDy3NIQJNhqw -UpmoF2//OGGfg8DCCGtiza4G0cIKG/svBhvu7G9StYhHvIfcAtf3jLnpQVvPyHL8 -oxvvzR0LzlWlXA== +MIIC+zCCAeOgAwIBAgIJAI6zVCRN44FlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV +BAMMCXg1MDktdGVzdDAeFw0xNzExMjgwODQ2NDdaFw0yNzExMjYwODQ2NDdaMBQx +EjAQBgNVBAMMCXg1MDktdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMmi9qSlfyxP9Btj1WlPcfymRQg3qHi0cpM8hxlevWf87cP5SQA1QEPq17xQ +EoLUt6nEf9a8BjoE/GCPXifYD6cPb3fqxGi/IiMjuNwznlfGWNhOnqKbhJo0FZna +/wdCEP8upRmmWqx1pHgr7QQgPYHZIMiCbtG66+VV4KNgD5YjIOMABEJfalh3GOFh +STWbFEUXqLjqttFF4xfve88Xk6+xpCFCCzC5SraVCR1OL2UiUyOMMKkyWlLL2Jd3 +TsVbRTTuxLBPohajwGPxuusqaoMLvQ73WzArnfDADRHqm67rlx6EFe1BjCyzKiT7 +f354LnsZZhj6jnPOQxs6rrsqH9kCAwEAAaNQME4wHQYDVR0OBBYEFGimY7g6t0Uh +lrr3ZpBqPXpvW/T+MB8GA1UdIwQYMBaAFGimY7g6t0Uhlrr3ZpBqPXpvW/T+MAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKjz0ylupkmE/FtiDLz1x3uL +UsLo/a82HoAwUi/GPICQdp5wjI5E02GoM04HdRvRZXVXiTdPlZrSEvHHLuBo/BdK +XkEpwFFYhBNg3n+KmU7M4NNL8Uwb2BLX7432I1blQKe756T4A1O8OxKIhD7JyxGn +SAaz5PZNQIm9hw2Elt/P9/7n86aHrsFYOl4K2rUlCfuh+9KzBkjpykU50idbd+FI +V4mmvN9s8XXcYpCzQB5mfVgTSSRpvYxmrkHUODOnxQJ4jn0LNNEhq6HsB5tUhu0b +RZASyTfbHfAfflGbkONnTiEHfux3CCYM2BuJ0Mdk5gZPcCY3yRgZP1i8PGTIaOc= -----END CERTIFICATE----- diff --git a/test/certs/enduser-example.com.crt b/test/certs/enduser-example.com.crt index 53d86d4..15c7840 100644 --- a/test/certs/enduser-example.com.crt +++ b/test/certs/enduser-example.com.crt @@ -1,43 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIHqjCCBZKgAwIBAgICEAEwDQYJKoZIhvcNAQEFBQAweTESMBAGA1UEAwwJZ2lv -dmFubmkyMQ4wDAYDVQQIDAVNb256YTELMAkGA1UEBhMCSVQxJDAiBgkqhkiG9w0B -CQEWFWdpb3Zhbm5pMkBleGFtcGxlLmNvbTEMMAoGA1UECgwDQUFBMRIwEAYDVQQL -DAlub24gbG8gc28wHhcNMTYwODA0MTUxMDE3WhcNMTcwODA0MTUxMDE3WjCBrjFF -MEMGA1UEAww8VmFsaWRTaWduIFs2NTIzOGJiODBmZjVjMTQ1LDY1MjM4YmI4MGZm -NWMxNDZdIFVzZXJzKDUwKSBERU1PMREwDwYDVQQIDAhMb21iYXJkeTELMAkGA1UE -BhMCSVQxIzAhBgkqhkiG9w0BCQEWFHZhbGlkc2lnbkBsaW5rLW1lLml0MQ8wDQYD -VQQKDAZMaW5rbWUxDzANBgNVBAsMBkxpbmttZTCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBANh2LEbkUX4ojZacXr6I9YL1BdChcoWfFqGNXk2qX8LVv0AA -dHjt57L9bfGAeQ49U16WsR9ud4aoOw9D+OMf4BXn1egKIFkNQw4EAL8FUqVHC9zB -Q2EybjV15gjkgsvPf/UMBA/Ag2Gj8JT2piULirpI6O7LN/dq68ElGCxpWwr2+zv7 -BlSQ3j8ctDqZbnXdQjtlm/xDfr1ND7cGo7TtwgPbxFpQwuPEJiuTwKA6Qu+C4Do/ -GJgK81rV8Q04XwY0fX4hniP2M5Zhq3idgekJZR9qZ+lPnu3dAJ/2yrEw+bbL0uwf -1bvJG2I+wqthIlfZXc4kgDTBi1Wi4VKxyAl9RE1vhwKvzDYPCUdwW5X+4jVmKJsd -GjzY59kMOO3LejxaY43E8gYwRfjbClhz1pWxlkxcEbqrXU8hzdKjk7qHsgSZ2UWG -9ybmYA2VvP+lA+hzqjaQS1Cypu2xS37QWdK0E/z0WLMoZrzaCV/mTSA/1+rqdCDG -GA37C4W1otbnwCbaEnGdjVrE1oHhseNRNVegKTUvwA91dHN+3DtMVtcCAzRCc3Y+ -UmVzWCJbJrKJezYrUr8JbeR9csB2niyd//80vdeZ/1gDVDSCeargCIIEXvksRWVY -P81ZUxI1Gc4olmUw4KLhfQjdtdtOs3chPy9WPtemL6r9G51Vu5G6/rKqBV2LAgMB -AAGjggIEMIICADAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTS8qwcImqEYUd4NJ6Z -qxUvq0UvfjAfBgNVHSMEGDAWgBQRUBXt1vbYYNuqEKhsLEp+LkMXPjALBgNVHQ8E -BAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwfgYDVR0fBHcwdTA7oDmgN4Y1aHR0 -cDovL3BraS5zcGFya2xpbmdjYS5jb20vU3BhcmtsaW5nSW50ZXJtaWRpYXRlMS5j -cmwwNqA0oDKGMGh0dHA6Ly9wa2kuYmFja3VwLmNvbS9TcGFya2xpbmdJbnRlcm1p -ZGlhdGUxLmNybDAjBgNVHREEHDAaggtleGFtcGxlLmNvbYILZXhhbXBsZS5vcmcw -gegGCCsGAQUFBwEBBIHbMIHYMEEGCCsGAQUFBzAChjVodHRwOi8vcGtpLnNwYXJr -bGluZ2NhLmNvbS9TcGFya2xpbmdJbnRlcm1lZGlhdGUxLmNydDA8BggrBgEFBQcw -AoYwaHR0cDovL3BraS5iYWNrdXAuY29tL1NwYXJrbGluZ0ludGVybWVkaWF0ZTEu -Y3J0MCwGCCsGAQUFBzABhiBodHRwOi8vcGtpLnNwYXJrbGluZ2NhLmNvbS9vY3Nw -LzAnBggrBgEFBQcwAYYbaHR0cDovL3BraS5iYWNrdXAuY29tL29jc3AvMA0GCSqG -SIb3DQEBBQUAA4ICAQBZV0tenQyAWW5O2DLCXxbGUIEgOhikulAOA0jWdwhvMpVu -GLHH1Uf9p37FNm08tmjVoub0oyQ/QexvParxiE4HyvJepMdtBMtVJhV9ej2YX/fu -YpAQHzLiRqFOvC3DHnOmkapkgV4he/qFnysfwc9KUNN6/vq4kp9ChjXv8Wy25Jfr -50unv+b5FTSARkhc3vX64eXbe4w4xcxyqJexZa0rgH2+ezRwRuhSBofp8Oa7vS11 -nBBoGPeTYBQi/FfE1QDKR+Ji2aRcdFNj0CYXIMVEqTt9dXSobFwAxXa9eG2TL5nY -KKBht2aOr1XVc7eXK+EgErAMIuopFz78cnHs4QnTQgTMf/HBPSdVmjUPlSSNwyW2 -qrgAodwZksfoHTKj2Ka8FOYuUSb8kJFD+3FRCbwLiFZUjsXp+0hAdrHHhLGAzEsX -UkRV36aswQS4CQ7uDm8uZzbPi/H5lUmBZOtHy2abrW3C18QiCMNqMjErUh2ZJEpk -I8n4vFBctOyN7tO0v4sliv8h1Q1Kokts3GdrhTxCoUZfuu/zPDnwp25thX9eOT1E -GW8HUE06ULRd2CFOAqGqtkLeb2sxtTjXZ1H7IMTMIBwav1CCvFUtaYzy5VO8Mdq8 -S8PVNIfcn2GwopOkpYUAqKkREyq3dXPTciB0cj7JiEjpAZWfsSUoTC6rtRcosQ== +MIIC+zCCAeOgAwIBAgIJAI6zVCRN44FlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV +BAMMCXg1MDktdGVzdDAeFw0xNzExMjgwODQ2NDdaFw0yNzExMjYwODQ2NDdaMBQx +EjAQBgNVBAMMCXg1MDktdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMmi9qSlfyxP9Btj1WlPcfymRQg3qHi0cpM8hxlevWf87cP5SQA1QEPq17xQ +EoLUt6nEf9a8BjoE/GCPXifYD6cPb3fqxGi/IiMjuNwznlfGWNhOnqKbhJo0FZna +/wdCEP8upRmmWqx1pHgr7QQgPYHZIMiCbtG66+VV4KNgD5YjIOMABEJfalh3GOFh +STWbFEUXqLjqttFF4xfve88Xk6+xpCFCCzC5SraVCR1OL2UiUyOMMKkyWlLL2Jd3 +TsVbRTTuxLBPohajwGPxuusqaoMLvQ73WzArnfDADRHqm67rlx6EFe1BjCyzKiT7 +f354LnsZZhj6jnPOQxs6rrsqH9kCAwEAAaNQME4wHQYDVR0OBBYEFGimY7g6t0Uh +lrr3ZpBqPXpvW/T+MB8GA1UdIwQYMBaAFGimY7g6t0Uhlrr3ZpBqPXpvW/T+MAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKjz0ylupkmE/FtiDLz1x3uL +UsLo/a82HoAwUi/GPICQdp5wjI5E02GoM04HdRvRZXVXiTdPlZrSEvHHLuBo/BdK +XkEpwFFYhBNg3n+KmU7M4NNL8Uwb2BLX7432I1blQKe756T4A1O8OxKIhD7JyxGn +SAaz5PZNQIm9hw2Elt/P9/7n86aHrsFYOl4K2rUlCfuh+9KzBkjpykU50idbd+FI +V4mmvN9s8XXcYpCzQB5mfVgTSSRpvYxmrkHUODOnxQJ4jn0LNNEhq6HsB5tUhu0b +RZASyTfbHfAfflGbkONnTiEHfux3CCYM2BuJ0Mdk5gZPcCY3yRgZP1i8PGTIaOc= -----END CERTIFICATE----- From 75a6a3dff6ee27a77ff6f7c718ef0cc19c5104a1 Mon Sep 17 00:00:00 2001 From: qile222 Date: Tue, 28 Nov 2017 22:47:08 +0800 Subject: [PATCH 49/52] src: fix verify crash caused by invalid cert format (#60) --- src/x509.cc | 101 ++++++++++++++++++++++----------------------------- test/test.js | 16 ++++++++ 2 files changed, 59 insertions(+), 58 deletions(-) diff --git a/src/x509.cc b/src/x509.cc index f2c8167..a836301 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -58,68 +58,53 @@ NAN_METHOD(verify) { X509_STORE *store = NULL; X509_STORE_CTX *verify_ctx = NULL; X509 *cert = NULL; - BIO *cert_bio = BIO_new(BIO_s_file()); - - // create store - store = X509_STORE_new(); - if (store == NULL) { - X509_STORE_free(store); - BIO_free_all(cert_bio); - Nan::ThrowError("Failed to create X509 certificate store."); - } - - verify_ctx = X509_STORE_CTX_new(); - - if (verify_ctx == NULL) { - X509_STORE_free(store); - BIO_free_all(cert_bio); - Nan::ThrowError("Failed to create X509 verification context."); - } - - // load file in BIO - int ret = BIO_read_filename(cert_bio, cert_path.c_str()); - if (ret != 1) { - X509_STORE_free(store); - X509_free(cert); - BIO_free_all(cert_bio); - X509_STORE_CTX_free(verify_ctx); - Nan::ThrowError("Error reading file"); - } - - // read from BIO - cert = PEM_read_bio_X509(cert_bio, NULL, 0, NULL); - if (cert == NULL) { - X509_STORE_free(store); - X509_free(cert); - X509_STORE_CTX_free(verify_ctx); - BIO_free_all(cert_bio); - Nan::ThrowError("Failed to load cert"); - } - - // load CA bundle - ret = X509_STORE_load_locations(store, ca_bundlestr.c_str(), NULL); - if (ret != 1) { - X509_STORE_free(store); - X509_free(cert); - BIO_free_all(cert_bio); - X509_STORE_CTX_free(verify_ctx); - Nan::ThrowError("Error loading CA chain file"); - } - - // verify - X509_STORE_CTX_init(verify_ctx, store, cert, NULL); - ret = X509_verify_cert(verify_ctx); - - if (ret <= 0) { - Nan::ThrowError(X509_verify_cert_error_string(verify_ctx->error)); - } - + 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_file()); + int ret = BIO_read_filename(cert_bio, cert_path.c_str()); + if (ret != 1) { + error = "Error reading file"; + break; + } + cert = PEM_read_bio_X509(cert_bio, NULL, 0, NULL); + if (cert == NULL) { + error = "Failed to load cert"; + break; + } + ret = X509_STORE_load_locations(store, ca_bundlestr.c_str(), NULL); + if (ret != 1) { + error = "Error loading CA chain file"; + break; + } + X509_STORE_CTX_init(verify_ctx, store, cert, NULL); + ret = X509_verify_cert(verify_ctx); + if (ret <= 0) { + error = X509_verify_cert_error_string(verify_ctx->error); + break; + } + } while(0); + X509_STORE_free(store); X509_free(cert); X509_STORE_CTX_free(verify_ctx); BIO_free_all(cert_bio); - - info.GetReturnValue().Set(Nan::New(true)); + if (error != NULL) { + Nan::ThrowError(error); + } else { + info.GetReturnValue().Set(Nan::New(true)); + } } diff --git a/test/test.js b/test/test.js index c364fdc..c98818d 100644 --- a/test/test.js +++ b/test/test.js @@ -38,3 +38,19 @@ x509.verify( assert.throws(assert.ifError.bind(null, err), /ENOENT/) } ); + +x509.verify( + path.join(__dirname, 'certs/equifax.crt'), + path.join(__dirname, '/test.js'), + function(err, result) { + assert.throws(assert.ifError.bind(null, err), /Error loading CA chain file/) + } +); + +x509.verify( + path.join(__dirname, '/test.js'), + path.join(__dirname, 'CA_chains/enduser-example.com.chain'), + function(err, result) { + assert.throws(assert.ifError.bind(null, err), /Failed to load cert/) + } +); \ No newline at end of file From d7e6c43f890cdeec3e82f0751e66858553f7124a Mon Sep 17 00:00:00 2001 From: Yorkie Liu Date: Tue, 28 Nov 2017 22:48:00 +0800 Subject: [PATCH 50/52] v0.3.3: bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ed22dc3..904298c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "x509", - "version": "0.3.2", + "version": "0.3.3", "description": "Simple X509 certificate parser.", "author": "Colton Baker", "main": "index.js", From 6033d4b8721d08ecd2ab9463a5ca6a08270796ce Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Wed, 19 Dec 2018 14:20:44 +0000 Subject: [PATCH 51/52] Updated version #71 with formatting corrected (#74) This is the #71 but with corrected formatting as per the discussion in #71 Thank you to those who worked on fix; aim here is to get the fix merged as it is needed by many projects Signed-off-by: Matthew B. White --- package.json | 2 +- src/x509.cc | 50 +++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 904298c..30b72e3 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,6 @@ }, "license": "MIT", "dependencies": { - "nan": "2.2.0" + "nan": "2.12.0" } } diff --git a/src/x509.cc b/src/x509.cc index a836301..00e02ae 100644 --- a/src/x509.cc +++ b/src/x509.cc @@ -43,7 +43,7 @@ std::string parse_args(const Nan::FunctionCallbackInfo& info) { return std::string(); } - return *String::Utf8Value(info[0]->ToString()); + return *Nan::Utf8String(info[0]->ToString()); } @@ -91,7 +91,7 @@ NAN_METHOD(verify) { X509_STORE_CTX_init(verify_ctx, store, cert, NULL); ret = X509_verify_cert(verify_ctx); if (ret <= 0) { - error = X509_verify_cert_error_string(verify_ctx->error); + error = X509_verify_cert_error_string(X509_STORE_CTX_get_error(verify_ctx)); break; } } while(0); @@ -237,7 +237,11 @@ Local try_parse(const std::string& dataString) { Nan::New(stream.str()).ToLocalChecked()); // Signature Algorithm +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + int sig_alg_nid = X509_get_signature_nid(cert); +#else int sig_alg_nid = OBJ_obj2nid(cert->sig_alg->algorithm); +#endif if (sig_alg_nid == NID_undef) { ERR_clear_error(); Nan::ThrowError("unable to find specified signature algorithm name."); @@ -272,7 +276,11 @@ Local try_parse(const std::string& dataString) { } // public key +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + int pkey_nid = X509_get_signature_nid(cert); +#else int pkey_nid = OBJ_obj2nid(cert->cert_info->key->algor->algorithm); +#endif if (pkey_nid == NID_undef) { ERR_clear_error(); Nan::ThrowError("unable to find specified public key algorithm name."); @@ -290,9 +298,18 @@ Local try_parse(const std::string& dataString) { char *rsa_e_dec, *rsa_n_hex; uint32_t rsa_key_length_int; RSA *rsa_key; +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + rsa_key = EVP_PKEY_get1_RSA(pkey); + const BIGNUM *n; + const BIGNUM *e; + RSA_get0_key(rsa_key, &n, &e, NULL); + rsa_e_dec = BN_bn2dec(e); + rsa_n_hex = BN_bn2hex(n); +#else rsa_key = pkey->pkey.rsa; rsa_e_dec = BN_bn2dec(rsa_key->e); rsa_n_hex = BN_bn2hex(rsa_key->n); +#endif rsa_key_length_int = RSA_size(rsa_key) * 8; Nan::Set(publicKey, Nan::New("e").ToLocalChecked(), @@ -322,7 +339,12 @@ Local try_parse(const std::string& dataString) { GENERAL_NAME *current = sk_GENERAL_NAME_value(names, i); if (current->type == GEN_DNS) { - char *name = (char*) ASN1_STRING_data(current->d.dNSName); + char *name = NULL; +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + name = (char *)ASN1_STRING_get0_data(current->d.dNSName); +#else + name = (char *)ASN1_STRING_data(current->d.dNSName); +#endif if (ASN1_STRING_length(current->d.dNSName) != (int) strlen(name)) { ERR_clear_error(); @@ -340,7 +362,11 @@ Local try_parse(const std::string& dataString) { // Extensions Local extensions(Nan::New()); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + const STACK_OF(X509_EXTENSION) *exts = X509_get0_extensions(cert); +#else STACK_OF(X509_EXTENSION) *exts = cert->cert_info->extensions; +#endif int num_of_exts; int index_of_exts; if (exts) { @@ -360,7 +386,11 @@ Local try_parse(const std::string& dataString) { BIO *ext_bio = BIO_new(BIO_s_mem()); // IFNULL_FAIL(ext_bio, "unable to allocate memory for extension value BIO"); if (!X509V3_EXT_print(ext_bio, ext, 0, 0)) { - M_ASN1_OCTET_STRING_print(ext_bio, ext->value); + unsigned char *buf = NULL; + int len = i2d_ASN1_OCTET_STRING(X509_EXTENSION_get_data(ext), &buf); + if (len >= 0) { + BIO_write(ext_bio, static_cast(buf), len); + } } BUF_MEM *bptr; @@ -430,7 +460,7 @@ Local parse_date(ASN1_TIME *date) { Local global = Nan::GetCurrentContext()->Global(); Local DateObject = Nan::Get(global, Nan::New("Date").ToLocalChecked()).ToLocalChecked()->ToObject(); - return scope.Escape(DateObject->CallAsConstructor(1, args)); + return scope.Escape(Nan::CallAsConstructor(DateObject, 1, args).ToLocalChecked()); } Local parse_name(X509_NAME *subject) { @@ -438,13 +468,19 @@ Local parse_name(X509_NAME *subject) { Local cert = Nan::New(); int i, length; ASN1_OBJECT *entry; - unsigned char *value; + const unsigned char *value; char buf[255]; length = X509_NAME_entry_count(subject); for (i = 0; i < length; i++) { entry = X509_NAME_ENTRY_get_object(X509_NAME_get_entry(subject, i)); OBJ_obj2txt(buf, 255, entry, 0); - value = ASN1_STRING_data(X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject, i))); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + value = ASN1_STRING_get0_data( + X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject, i))); +#else + value = ASN1_STRING_data( + X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject, i))); +#endif Nan::Set(cert, Nan::New(real_name(buf)).ToLocalChecked(), Nan::New((const char*) value).ToLocalChecked()); From 17b2b7a97c16619065671a231f2d7ae78f5f3181 Mon Sep 17 00:00:00 2001 From: Yorkie Liu Date: Wed, 19 Dec 2018 22:20:02 +0800 Subject: [PATCH 52/52] v0.3.4: bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 30b72e3..cc6ee44 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "x509", - "version": "0.3.3", + "version": "0.3.4", "description": "Simple X509 certificate parser.", "author": "Colton Baker", "main": "index.js",