From 38f8c733931285221a2b6e2db0ad83f2ce27683b Mon Sep 17 00:00:00 2001 From: Itsnotlupus Date: Sun, 17 Jul 2011 21:31:34 -0500 Subject: [PATCH 1/3] basic support for signing certificates --- dcrypt.coffee | 8 +++- src/dx509.cc | 118 +++++++++++++++++++++++++++++++++++++++++++++----- src/dx509.h | 5 ++- 3 files changed, 116 insertions(+), 15 deletions(-) diff --git a/dcrypt.coffee b/dcrypt.coffee index 265e3cb..6482fae 100644 --- a/dcrypt.coffee +++ b/dcrypt.coffee @@ -120,5 +120,9 @@ dcrypt.x509 = X509 exports.x509 = {} exports.x509.parse = (cert) -> return (new X509).parse(cert) -exports.x509.createCert = (args) -> - return (new X509).createCert(args) +exports.x509.createCert = (country, cname) -> + return (new X509).createCert(country, cname) +exports.x509.signCert = (cert, ca_cert, ca_pkey) -> + x509 = new X509 + x509.parse(cert) + return x509.signCert(ca_cert, ca_pkey) diff --git a/src/dx509.cc b/src/dx509.cc index 4de85ea..fb3cc79 100644 --- a/src/dx509.cc +++ b/src/dx509.cc @@ -10,6 +10,7 @@ void DX509::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor, "parse", parseCert); NODE_SET_PROTOTYPE_METHOD(constructor, "createCert", createCert); + NODE_SET_PROTOTYPE_METHOD(constructor, "signCert", signCert); Local proto = constructor->PrototypeTemplate(); target->Set(String::NewSymbol("X509"), constructor->GetFunction()); @@ -128,8 +129,9 @@ Handle DX509::parseCert(const Arguments &args) { for (int i=0; i DX509::createCert(const Arguments &args) { HandleScope scope; DX509 *dx509 = ObjectWrap::Unwrap(args.This()); + String::Utf8Value country(args[0]->ToString()); + String::Utf8Value cname(args[1]->ToString()); X509 *x = NULL; EVP_PKEY *pkey = NULL; - int ok = dx509->make_cert(&x, 0, 1024, &pkey, 365); + int ok = dx509->make_cert(&x, 0, 1024, &pkey, 365, *country, *cname); + + BUF_MEM *bptr; BIO *bp = BIO_new(BIO_s_mem()); ok =PEM_write_bio_X509(bp, x); Local x509_str = String::New(""); if (ok) { - BUF_MEM *bptr; BIO_get_mem_ptr(bp, &bptr); char *x509_buf = (char *) malloc(bptr->length+1); memcpy(x509_buf, bptr->data, bptr->length-1); @@ -289,12 +311,76 @@ Handle DX509::createCert(const Arguments &args) { free(x509_buf); } if (bp != NULL) BIO_free(bp); + + bp = BIO_new(BIO_s_mem()); + ok = PEM_write_bio_PrivateKey(bp, pkey, NULL, NULL, 0, NULL, NULL); + Local pkey_str = String::New(""); + if (ok) { + BIO_get_mem_ptr(bp, &bptr); + char *pkey_buf = (char *) malloc(bptr->length+1); + memcpy(pkey_buf, bptr->data, bptr->length-1); + pkey_buf[bptr->length-1] = 0; + pkey_str = String::New(pkey_buf); + free(pkey_buf); + } + if (bp != NULL) BIO_free(bp); + dx509->x509_ = x; if (pkey != NULL) EVP_PKEY_free(pkey); + + Local cert_obj = Object::New(); + cert_obj->Set(String::New("x509"), x509_str); + cert_obj->Set(String::New("pkey"), pkey_str); + + return scope.Close(cert_obj); +} + +Handle DX509::signCert(const Arguments &args) { /* ca, ca_pkey */ + HandleScope scope; + DX509 *dx509 = ObjectWrap::Unwrap(args.This()); + + ssize_t ca_cert_len = DecodeBytes(args[0], BINARY); + char* ca_cert_buf = new char[ca_cert_len]; + ssize_t written = DecodeWrite(ca_cert_buf, ca_cert_len, args[0], BINARY); + assert(ca_cert_len = written); + + ssize_t ca_pkey_len = DecodeBytes(args[1], BINARY); + char* ca_pkey_buf = new char[ca_pkey_len]; + written = DecodeWrite(ca_pkey_buf, ca_pkey_len, args[1], BINARY); + assert(ca_pkey_len = written); + + X509 * saved_cert = dx509->x509_; + X509 * ca = NULL; + int ok = dx509->load_cert(ca_cert_buf, ca_cert_len, 1, &ca); + dx509->x509_ = saved_cert; + + EVP_PKEY *ca_pkey = NULL; + ok = dx509->load_private_key(ca_pkey_buf, ca_pkey_len, &ca_pkey); + + ok = dx509->sign_cert(&dx509->x509_, ca, ca_pkey); + + if (ca != NULL) X509_free(ca); + if (ca_pkey != NULL) EVP_PKEY_free(ca_pkey); + + BUF_MEM *bptr; + BIO *bp = BIO_new(BIO_s_mem()); + ok =PEM_write_bio_X509(bp, dx509->x509_); + + Local x509_str = String::New(""); + if (ok) { + BIO_get_mem_ptr(bp, &bptr); + char *x509_buf = (char *) malloc(bptr->length+1); + memcpy(x509_buf, bptr->data, bptr->length-1); + x509_buf[bptr->length-1] = 0; + x509_str = String::New(x509_buf); + free(x509_buf); + } + if (bp != NULL) BIO_free(bp); + return scope.Close(x509_str); } -int DX509::make_cert(X509 **x509p, int type, long bits, EVP_PKEY **pkeyp, int days) { +int DX509::make_cert(X509 **x509p, int type, long bits, EVP_PKEY **pkeyp, int days, const char* country, const char* cname) { X509 *x; EVP_PKEY *pk; RSA *rsa; @@ -329,15 +415,23 @@ int DX509::make_cert(X509 **x509p, int type, long bits, EVP_PKEY **pkeyp, int da X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days); X509_set_pubkey(x, pk); name = X509_get_subject_name(x); - // X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, "AU", -1, -1, 0); - X509_NAME_add_entry_by_txt(name,"C", MBSTRING_ASC, (const unsigned char*)"UK", -1, -1, 0); - - X509_set_issuer_name(x, name); + X509_NAME_add_entry_by_txt(name,"C", MBSTRING_UTF8, (const unsigned char*)country, -1, -1, 0); + X509_NAME_add_entry_by_txt(name,"CN", MBSTRING_UTF8, (const unsigned char*)cname, -1, -1, 0); + + *x509p = x; + *pkeyp = pk; + return 1; +} + +int DX509::sign_cert(X509 **cert, X509 *ca, EVP_PKEY *ca_pkey) { + EVP_PKEY *pk; + X509_NAME *ca_name = NULL; - if (!X509_sign(x, pk, EVP_sha1())) { + ca_name = X509_get_subject_name(ca); + X509_set_issuer_name(*cert, ca_name); + + if (!X509_sign(*cert, ca_pkey, EVP_sha1())) { return -1; } - *x509p = x; - *pkeyp = pk; return 1; } diff --git a/src/dx509.h b/src/dx509.h index 8f7fd13..77ba307 100644 --- a/src/dx509.h +++ b/src/dx509.h @@ -28,17 +28,20 @@ class DX509: node::ObjectWrap { // int add_ext(X509 *cert, int nid, char *value); // int parseCert(); int load_cert(char *cert, int cert_len, int format, X509** x509p); + int load_private_key(char *pkey_buf, int pkey_len, EVP_PKEY** pkey); DX509(); protected: static Handle parseCert(const Arguments &args); static Handle New(const Arguments &args); static Handle createCert(const Arguments &args); + static Handle signCert(const Arguments &args); ~DX509(); private: + int make_cert(X509 **x509p, int type, long bits, EVP_PKEY **pkeyp, int days, const char* country, const char* cname); + int sign_cert(X509 **cert, X509 *ca, EVP_PKEY *ca_pkey); int update_buf_len(const BIGNUM *b, size_t *pbuflen); - int make_cert(X509 **x509p, int type, long bits, EVP_PKEY **pkeyp, int days); X509* x509_; }; #endif From 87d4a41a7af2c36808c8a8151f03b43c16475e8b Mon Sep 17 00:00:00 2001 From: Itsnotlupus Date: Tue, 19 Jul 2011 16:26:43 -0500 Subject: [PATCH 2/3] Fixed runaway strings in x509.parse(), made x509.createCert more customizable --- dcrypt.coffee | 6 ++-- src/dx509.cc | 76 +++++++++++++++++++++++++++++++++++++++++---------- src/dx509.h | 4 ++- 3 files changed, 68 insertions(+), 18 deletions(-) diff --git a/dcrypt.coffee b/dcrypt.coffee index 6482fae..e215048 100644 --- a/dcrypt.coffee +++ b/dcrypt.coffee @@ -120,9 +120,11 @@ dcrypt.x509 = X509 exports.x509 = {} exports.x509.parse = (cert) -> return (new X509).parse(cert) -exports.x509.createCert = (country, cname) -> - return (new X509).createCert(country, cname) +exports.x509.createCert = (bitsize, days, entries, extensions) -> + return (new X509).createCert(bitsize, days, entries, extensions) exports.x509.signCert = (cert, ca_cert, ca_pkey) -> x509 = new X509 x509.parse(cert) return x509.signCert(ca_cert, ca_pkey) +exports.x509.test = (obj) -> + return (new X509).test(obj) diff --git a/src/dx509.cc b/src/dx509.cc index fb3cc79..d7484c2 100644 --- a/src/dx509.cc +++ b/src/dx509.cc @@ -129,7 +129,7 @@ Handle DX509::parseCert(const Arguments &args) { for (int i=0; i DX509::parseCert(const Arguments &args) { ASN1_STRING *sigh = x->signature; unsigned char *s; unsigned int n1 = sigh->length; - s = sigh->data; - for (int i=0; i0) { + s = sigh->data; + for (int i=0; iSet(signature_symbol, String::New(sig_buf)); + } else { + info->Set(signature_symbol, String::New("")); } - char sig_buf [n1*3]; - BIO_read(sig_bio, sig_buf, sizeof(sig_buf)-1); - info->Set(signature_symbol, String::New(sig_buf)); //finger print int j; @@ -290,12 +294,32 @@ int DX509::update_buf_len(const BIGNUM *b, size_t *pbuflen) { Handle DX509::createCert(const Arguments &args) { HandleScope scope; DX509 *dx509 = ObjectWrap::Unwrap(args.This()); - String::Utf8Value country(args[0]->ToString()); - String::Utf8Value cname(args[1]->ToString()); + if (args.Length()<4) { + return ThrowException(Exception::Error(String::New("createCert requires 4 arguments."))); + } + // .createCert(bitSize, days, subject, extensions); + int bitSize = args[0]->Int32Value(); + int days = args[1]->Int32Value(); + Local subject = args[2]->ToObject(); + Local extensions = args[3]->ToObject(); X509 *x = NULL; EVP_PKEY *pkey = NULL; - int ok = dx509->make_cert(&x, 0, 1024, &pkey, 365, *country, *cname); + int ok = dx509->make_cert(&x, 0, bitSize, &pkey, days); + + Local subject_keys = subject->GetPropertyNames(); + for (int i=0,l=subject_keys->Length();iGet(Integer::New(i))); + String::Utf8Value value(subject->Get(String::New(*key))); + dx509->add_entry(x, *key, *value); + } + + Handle ext_keys = extensions->GetPropertyNames(); + for (int i=0,l=ext_keys->Length();iGet(i)); + String::Utf8Value value(extensions->Get(String::New(*key))); + dx509->add_ext(x, *key, *value); + } BUF_MEM *bptr; @@ -380,7 +404,7 @@ Handle DX509::signCert(const Arguments &args) { /* ca, ca_pkey */ return scope.Close(x509_str); } -int DX509::make_cert(X509 **x509p, int type, long bits, EVP_PKEY **pkeyp, int days, const char* country, const char* cname) { +int DX509::make_cert(X509 **x509p, int type, long bits, EVP_PKEY **pkeyp, int days) { X509 *x; EVP_PKEY *pk; RSA *rsa; @@ -410,19 +434,41 @@ int DX509::make_cert(X509 **x509p, int type, long bits, EVP_PKEY **pkeyp, int da } rsa = NULL; X509_set_version(x, 2); - ASN1_INTEGER_set(X509_get_serialNumber(x), 1); + ASN1_INTEGER_set(X509_get_serialNumber(x), 65535); X509_gmtime_adj(X509_get_notBefore(x), 0); X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days); X509_set_pubkey(x, pk); - name = X509_get_subject_name(x); - X509_NAME_add_entry_by_txt(name,"C", MBSTRING_UTF8, (const unsigned char*)country, -1, -1, 0); - X509_NAME_add_entry_by_txt(name,"CN", MBSTRING_UTF8, (const unsigned char*)cname, -1, -1, 0); *x509p = x; *pkeyp = pk; return 1; } +void DX509::add_entry(X509 *x509, const char* key, const char* value) { + X509_NAME *name = X509_get_subject_name(x509); + X509_NAME_add_entry_by_txt(name, key, MBSTRING_UTF8, (const unsigned char*)value, -1, -1, 0); +} + +int DX509::add_ext(X509 *cert, char*key, char *value) { + X509_EXTENSION *ex; + X509V3_CTX ctx; + /* This sets the 'context' of the extensions. */ + /* No configuration database */ + X509V3_set_ctx_nodb(&ctx); + /* Issuer and subject certs: both the target since it is self signed, + * no request and no CRL + */ + X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0); + ex = X509V3_EXT_conf(NULL, &ctx, key, value); // is this UTF8? I hope so. XXX + if (!ex) + return 0; + + X509_add_ext(cert,ex,-1); + X509_EXTENSION_free(ex); + return 1; +} + + int DX509::sign_cert(X509 **cert, X509 *ca, EVP_PKEY *ca_pkey) { EVP_PKEY *pk; X509_NAME *ca_name = NULL; diff --git a/src/dx509.h b/src/dx509.h index 77ba307..36d5b64 100644 --- a/src/dx509.h +++ b/src/dx509.h @@ -39,7 +39,9 @@ class DX509: node::ObjectWrap { ~DX509(); private: - int make_cert(X509 **x509p, int type, long bits, EVP_PKEY **pkeyp, int days, const char* country, const char* cname); + int make_cert(X509 **x509p, int type, long bits, EVP_PKEY **pkeyp, int days); + void add_entry(X509 *x509, const char*key, const char*value); + int add_ext(X509 *x509, char*key, char* value); int sign_cert(X509 **cert, X509 *ca, EVP_PKEY *ca_pkey); int update_buf_len(const BIGNUM *b, size_t *pbuflen); X509* x509_; From ac9b5ad63c4da47af5e7d1a57bbe3946d532938b Mon Sep 17 00:00:00 2001 From: Itsnotlupus Date: Tue, 19 Jul 2011 22:41:11 -0500 Subject: [PATCH 3/3] Added serial as a parameter, since browsers frown on multiple certs from the same CA sharing the same serial#. --- dcrypt.coffee | 4 ++-- src/dx509.cc | 15 ++++++++------- src/dx509.h | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/dcrypt.coffee b/dcrypt.coffee index e215048..02fe6e8 100644 --- a/dcrypt.coffee +++ b/dcrypt.coffee @@ -120,8 +120,8 @@ dcrypt.x509 = X509 exports.x509 = {} exports.x509.parse = (cert) -> return (new X509).parse(cert) -exports.x509.createCert = (bitsize, days, entries, extensions) -> - return (new X509).createCert(bitsize, days, entries, extensions) +exports.x509.createCert = (bitsize, days, serial, entries, extensions) -> + return (new X509).createCert(bitsize, days, serial, entries, extensions) exports.x509.signCert = (cert, ca_cert, ca_pkey) -> x509 = new X509 x509.parse(cert) diff --git a/src/dx509.cc b/src/dx509.cc index d7484c2..3331d8d 100644 --- a/src/dx509.cc +++ b/src/dx509.cc @@ -294,18 +294,19 @@ int DX509::update_buf_len(const BIGNUM *b, size_t *pbuflen) { Handle DX509::createCert(const Arguments &args) { HandleScope scope; DX509 *dx509 = ObjectWrap::Unwrap(args.This()); - if (args.Length()<4) { - return ThrowException(Exception::Error(String::New("createCert requires 4 arguments."))); + if (args.Length()<5) { + return ThrowException(Exception::Error(String::New("createCert requires 5 arguments."))); } // .createCert(bitSize, days, subject, extensions); int bitSize = args[0]->Int32Value(); int days = args[1]->Int32Value(); - Local subject = args[2]->ToObject(); - Local extensions = args[3]->ToObject(); + long serial = args[2]->Int32Value(); + Local subject = args[3]->ToObject(); + Local extensions = args[4]->ToObject(); X509 *x = NULL; EVP_PKEY *pkey = NULL; - int ok = dx509->make_cert(&x, 0, bitSize, &pkey, days); + int ok = dx509->make_cert(&x, 0, bitSize, &pkey, days,serial); Local subject_keys = subject->GetPropertyNames(); for (int i=0,l=subject_keys->Length();i DX509::signCert(const Arguments &args) { /* ca, ca_pkey */ return scope.Close(x509_str); } -int DX509::make_cert(X509 **x509p, int type, long bits, EVP_PKEY **pkeyp, int days) { +int DX509::make_cert(X509 **x509p, int type, long bits, EVP_PKEY **pkeyp, int days, long serial) { X509 *x; EVP_PKEY *pk; RSA *rsa; @@ -434,7 +435,7 @@ int DX509::make_cert(X509 **x509p, int type, long bits, EVP_PKEY **pkeyp, int da } rsa = NULL; X509_set_version(x, 2); - ASN1_INTEGER_set(X509_get_serialNumber(x), 65535); + ASN1_INTEGER_set(X509_get_serialNumber(x), serial); X509_gmtime_adj(X509_get_notBefore(x), 0); X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days); X509_set_pubkey(x, pk); diff --git a/src/dx509.h b/src/dx509.h index 36d5b64..ff90f17 100644 --- a/src/dx509.h +++ b/src/dx509.h @@ -39,7 +39,7 @@ class DX509: node::ObjectWrap { ~DX509(); private: - int make_cert(X509 **x509p, int type, long bits, EVP_PKEY **pkeyp, int days); + int make_cert(X509 **x509p, int type, long bits, EVP_PKEY **pkeyp, int days, long serial); void add_entry(X509 *x509, const char*key, const char*value); int add_ext(X509 *x509, char*key, char* value); int sign_cert(X509 **cert, X509 *ca, EVP_PKEY *ca_pkey);