From f6ccbce1fb4b9fff936f84eb303bef7ac4bd551c Mon Sep 17 00:00:00 2001 From: Bryan Roe Date: Wed, 3 Apr 2019 17:39:22 -0700 Subject: [PATCH] 1. Fixed return value of util_from_cer to be consistent with other util methods 2. Added DER support to tls.loadCertificate 3. Updated sign/verify methods --- microscript/ILibDuktape_Helpers.h | 2 + microscript/ILibDuktape_SHA256.c | 155 ++++++++++++++++++++++++++++-- microscript/ILibDuktape_net.c | 42 ++++++-- microstack/ILibCrypto.c | 2 +- 4 files changed, 186 insertions(+), 15 deletions(-) diff --git a/microscript/ILibDuktape_Helpers.h b/microscript/ILibDuktape_Helpers.h index bc0c1ce..1fba350 100644 --- a/microscript/ILibDuktape_Helpers.h +++ b/microscript/ILibDuktape_Helpers.h @@ -35,6 +35,7 @@ typedef void(*ILibDuktape_HelperEvent)(duk_context *ctx, void *user); #define ILibDuktape_CR2HTTP "\xFF_CR2HTTP" #define ILibDuktape_CR2Options "\xFF_CR2Options" +#define ILibDuktape_TLS_util_cert "\xFF_TLS_util_cert" typedef enum ILibDuktape_LogTypes { @@ -98,6 +99,7 @@ void ILibDuktape_CreateEventWithGetterAndSetterWithMetaData(duk_context *ctx, ch #define ILibDuktape_CreateInstanceMethodWithBooleanProperty(context, propName, propValue, methodName, funcImpl, numArgs) duk_push_c_function(context, funcImpl, numArgs);duk_push_boolean(context, propValue);duk_put_prop_string(ctx, -2, propName);duk_put_prop_string(ctx, -2, methodName); #define ILibDuktape_CreateInstanceMethodWithIntProperty(context, propName, propValue, methodName, funcImpl, numArgs) duk_push_c_function(context, funcImpl, numArgs);duk_push_int(context, propValue);duk_put_prop_string(ctx, -2, propName);duk_put_prop_string(ctx, -2, methodName); #define ILibDuktape_CreateInstanceMethodWithNumberProperty(context, propName, propValue, methodName, funcImpl, numArgs) duk_push_c_function(context, funcImpl, numArgs);duk_push_number(context, (propValue));duk_put_prop_string(ctx, -2, propName);duk_put_prop_string(ctx, -2, methodName); +#define ILibDuktape_CreateInstanceMethodWithPointerProperty(context, propName, propValue, methodName, funcImpl, numArgs) duk_push_pointer(context, propValue);ILibDuktape_CreateInstanceMethodWithPropertyEx(context, propName, -1, methodName, funcImpl, numArgs); void ILibDuktape_CreateInstanceMethodWithProperties(duk_context *ctx, char *funcName, duk_c_function funcImpl, duk_idx_t numArgs, unsigned int propertyCount, ...); duk_idx_t duk_push_int_ex(duk_context *ctx, duk_int_t val); diff --git a/microscript/ILibDuktape_SHA256.c b/microscript/ILibDuktape_SHA256.c index 13686f1..21bdcc5 100644 --- a/microscript/ILibDuktape_SHA256.c +++ b/microscript/ILibDuktape_SHA256.c @@ -30,6 +30,9 @@ limitations under the License. #define ILibDuktape_SHA256_SIGNER_CERT "\xFF_SHA256_SIGNER_CERT" #define ILibDuktape_SHA256_SIGNER_CERT_ALLOC "\xFF_SHA256_SIGNER_CERT_ALLOC" #define ILibDuktape_SHA256_SIGNER_SIGBUFFER "\xFF_SHA256_SIGNER_SIG_BUFFER" +#define ILibDuktape_VERIFIER_PTR "\xFF_VERIFIER_PTR" +#define ILibDuktape_VERIFIER_SIG "\xFF_VERIFIER_SIG" +#define ILibDuktape_VERIFIER_CERT "\xFF_VERIFIER_CERT" typedef struct ILibDuktape_SHA256_Data { @@ -66,6 +69,16 @@ typedef struct ILibDuktape_SHA1_Data }ILibDuktape_SHA1_Data; #ifndef MICROSTACK_NOTLS +typedef struct ILibDuktape_Verifier_Data +{ + duk_context *ctx; + EVP_MD_CTX* mdctx; + ILibDuktape_WritableStream *writableStream; + struct util_cert *cert; + void *promise; + char *sig; + int sigLen; +}ILibDuktape_Verifier_Data; typedef struct ILibDuktape_SHA256_Signer_Data { duk_context *ctx; @@ -256,15 +269,140 @@ void ILibDuktape_SHA256_SIGNER_PUSH(duk_context *ctx, void *chain) data->ctx = ctx; ILibDuktape_CreateInstanceMethod(ctx, "Create", ILibDuktape_SHA256_SIGNER_Create, 1); } + +ILibTransport_DoneState ILibDuktape_VERIFIER_WriteSink(ILibDuktape_WritableStream *stream, char *buffer, int bufferLen, void *user) +{ + if (!ILibMemory_CanaryOK(user)) { return(ILibTransport_DoneState_ERROR); } + ILibDuktape_Verifier_Data *data = (ILibDuktape_Verifier_Data*)user; + EVP_DigestVerifyUpdate(data->mdctx, buffer, bufferLen); + return(ILibTransport_DoneState_COMPLETE); +} +void ILibDuktape_VERIFIER_EndSink(ILibDuktape_WritableStream *stream, void *user) +{ + if (!ILibMemory_CanaryOK(user)) { return; } + ILibDuktape_Verifier_Data *data = (ILibDuktape_Verifier_Data*)user; + + duk_push_heapptr(data->ctx, data->promise); // [promise] + + switch (EVP_DigestVerifyFinal(data->mdctx, (const unsigned char*)data->sig, (unsigned int)data->sigLen)) + { + case 0: + // SigFail + duk_get_prop_string(data->ctx, -1, "_rej"); // [promise][rejector] + duk_swap_top(data->ctx, -2); // [rejector][this] + duk_push_string(data->ctx, "Signature Failed"); // [rejector][this][badsig] + duk_call_method(data->ctx, 1); // [...] + break; + case 1: + // SigSuccess + duk_get_prop_string(data->ctx, -1, "_res"); // [promise][resolved] + duk_swap_top(data->ctx, -2); // [resolved][this] + duk_call_method(data->ctx, 0); // [...] + break; + default: + // Error + duk_get_prop_string(data->ctx, -1, "_rej"); // [promise][rejector] + duk_swap_top(data->ctx, -2); // [rejector][this] + duk_push_sprintf(data->ctx, "EVP_VerifyFinal(): Returned error (%d) ", ERR_get_error()); // [rejector][this][error] + duk_call_method(data->ctx, 1); // [...] + break; + } + duk_pop(data->ctx); // +} + +duk_ret_t ILibDuktape_VERIFIER_Create(duk_context *ctx) +{ + duk_push_current_function(ctx); + const EVP_MD *mdtype = (const EVP_MD*)Duktape_GetPointerProperty(ctx, -1, "mdtype"); + char *sig; + duk_size_t sigLen; + void *promise; + duk_eval_string(ctx, "(function verifyInit(){var p = require('promise'); var ret = new p(function(res, rej){this._res = res; this._rej = rej;}); return(ret);})();"); // [p] + promise = duk_get_heapptr(ctx, -1); + + duk_dup(ctx, 1); + sig = (char*)duk_to_lstring(ctx, -1, &sigLen); + duk_put_prop_string(ctx, -2, ILibDuktape_VERIFIER_SIG); + ILibDuktape_Verifier_Data *data = (ILibDuktape_Verifier_Data*)Duktape_PushBuffer(ctx, sizeof(ILibDuktape_Verifier_Data)); + duk_put_prop_string(ctx, -2, ILibDuktape_VERIFIER_PTR); + data->ctx = ctx; + + data->mdctx = EVP_MD_CTX_create(); + + data->sig = sig; + data->sigLen = (int)sigLen; + data->promise = promise; + + duk_dup(ctx, 0); duk_put_prop_string(ctx, -2, ILibDuktape_VERIFIER_CERT); + data->cert = (struct util_cert*)Duktape_GetBufferProperty(ctx, 0, ILibDuktape_TLS_util_cert); + EVP_PKEY *pkey = X509_get0_pubkey(data->cert->x509); + + + EVP_DigestVerifyInit(data->mdctx, NULL, mdtype, NULL, pkey); + data->writableStream = ILibDuktape_WritableStream_Init(ctx, ILibDuktape_VERIFIER_WriteSink, ILibDuktape_VERIFIER_EndSink, data); + return(1); +} void ILibDuktape_SHA256_VERIFY_PUSH(duk_context *ctx, void *chain) { - ILibDuktape_SHA256_Signer_Data* data; - duk_push_object(ctx); // [signer] - data = (ILibDuktape_SHA256_Signer_Data*)Duktape_PushBuffer(ctx, sizeof(ILibDuktape_SHA256_Signer_Data)); - duk_put_prop_string(ctx, -2, ILibDuktape_SHA256_SIGNER_PTR); // [signer] - data->obj = duk_get_heapptr(ctx, -1); - data->ctx = ctx; - ILibDuktape_CreateInstanceMethod(ctx, "Create", ILibDuktape_SHA256_VERIFIER_Create, 1); + duk_push_object(ctx); + ILibDuktape_CreateInstanceMethodWithPointerProperty(ctx, "mdtype", (void*)EVP_sha256(), "Create", ILibDuktape_VERIFIER_Create, DUK_VARARGS); +} +void ILibDuktape_SHA384_VERIFY_PUSH(duk_context *ctx, void *chain) +{ + duk_push_object(ctx); + ILibDuktape_CreateInstanceMethodWithPointerProperty(ctx, "mdtype", (void*)EVP_sha384(), "Create", ILibDuktape_VERIFIER_Create, DUK_VARARGS); +} +void ILibDuktape_SHA512_VERIFY_PUSH(duk_context *ctx, void *chain) +{ + duk_push_object(ctx); + ILibDuktape_CreateInstanceMethodWithPointerProperty(ctx, "mdtype", (void*)EVP_sha512(), "Create", ILibDuktape_VERIFIER_Create, DUK_VARARGS); +} +duk_ret_t ILibDuktape_RSA_Sign(duk_context *ctx) +{ + struct util_cert *cert = (struct util_cert*)Duktape_GetBufferProperty(ctx, 1, ILibDuktape_TLS_util_cert); + if (cert->pkey == NULL) return(ILibDuktape_Error(ctx, "Private Key Access Denied")); + + duk_size_t bufferLen; + char *buffer = Duktape_GetBuffer(ctx, 2, &bufferLen); + RSA *r = EVP_PKEY_get1_RSA(cert->pkey); + int rsalen = RSA_size(r); + char *sig = duk_push_fixed_buffer(ctx, rsalen); + duk_push_buffer_object(ctx, -1, 0, rsalen, DUK_BUFOBJ_NODEJS_BUFFER); + + if (RSA_sign(duk_require_int(ctx, 0), (unsigned char*)buffer, (unsigned int)bufferLen, (unsigned char*)sig, (unsigned int*)&rsalen, r) != 1) + { + // Failed + unsigned long err = ERR_get_error(); + char *reason = (char*)ERR_reason_error_string(err); + RSA_free(r); + return(ILibDuktape_Error(ctx, "RSA_sign() Error: (%d, %s)", err, reason)); + } + RSA_free(r); + return(1); +} +duk_ret_t ILibDuktape_RSA_Verify(duk_context *ctx) +{ + duk_size_t bufferLen, sigLen; + char *buffer = Duktape_GetBuffer(ctx, 2, &bufferLen); + char *sig = Duktape_GetBuffer(ctx, 3, &sigLen); + + struct util_cert *cert = (struct util_cert*)Duktape_GetBufferProperty(ctx, 1, ILibDuktape_TLS_util_cert); + RSA *r = EVP_PKEY_get1_RSA(X509_get0_pubkey(cert->x509)); + int vstatus = RSA_verify(duk_require_int(ctx, 0), (unsigned char*)buffer, (unsigned int)bufferLen, (unsigned char*)sig, (unsigned int)sigLen, r); + duk_push_boolean(ctx, vstatus == 1); + RSA_free(r); + return(1); +} +void ILibDuktape_RSA_PUSH(duk_context *ctx, void *chain) +{ + duk_push_object(ctx); + ILibDuktape_CreateInstanceMethod(ctx, "sign", ILibDuktape_RSA_Sign, DUK_VARARGS); + ILibDuktape_CreateInstanceMethod(ctx, "verify", ILibDuktape_RSA_Verify, DUK_VARARGS); + duk_push_object(ctx); + duk_push_int(ctx, NID_sha256); duk_put_prop_string(ctx, -2, "SHA256"); + duk_push_int(ctx, NID_sha384); duk_put_prop_string(ctx, -2, "SHA384"); + duk_push_int(ctx, NID_sha512); duk_put_prop_string(ctx, -2, "SHA512"); + duk_put_prop_string(ctx, -2, "TYPES"); } #endif @@ -583,6 +721,9 @@ void ILibDuktape_SHA256_Init(duk_context * ctx) #ifndef MICROSTACK_NOTLS ILibDuktape_ModSearch_AddHandler(ctx, "SHA256Stream_Signer", ILibDuktape_SHA256_SIGNER_PUSH); ILibDuktape_ModSearch_AddHandler(ctx, "SHA256Stream_Verifier", ILibDuktape_SHA256_VERIFY_PUSH); + ILibDuktape_ModSearch_AddHandler(ctx, "SHA384Stream_Verifier", ILibDuktape_SHA384_VERIFY_PUSH); + ILibDuktape_ModSearch_AddHandler(ctx, "SHA512Stream_Verifier", ILibDuktape_SHA512_VERIFY_PUSH); + ILibDuktape_ModSearch_AddHandler(ctx, "RSA", ILibDuktape_RSA_PUSH); #endif ILibDuktape_ModSearch_AddHandler(ctx, "SHA512Stream", ILibDuktape_SHA512_PUSH); ILibDuktape_ModSearch_AddHandler(ctx, "SHA384Stream", ILibDuktape_SHA384_PUSH); diff --git a/microscript/ILibDuktape_net.c b/microscript/ILibDuktape_net.c index e24bb78..4d78c12 100644 --- a/microscript/ILibDuktape_net.c +++ b/microscript/ILibDuktape_net.c @@ -82,7 +82,6 @@ int ILibDuktape_TLS_ctx2server = -1; #define ILibDuktape_SERVER2OPTIONS "\xFF_ServerToOptions" #define ILibDuktape_SERVER2LISTENOPTIONS "\xFF_ServerToListenOptions" #define ILibDuktape_TLSSocket2SecureContext "\xFF_TLSSocket2SecureContext" -#define ILibDuktape_TLS_util_cert "\xFF_TLS_util_cert" extern void ILibAsyncServerSocket_RemoveFromChain(ILibAsyncServerSocket_ServerModule serverModule); @@ -1611,29 +1610,58 @@ duk_ret_t ILibDuktape_TLS_loadCertificate_getKeyHash(duk_context *ctx) util_keyhash(cert[0], hash); return(1); } +duk_ret_t ILibDuktape_TLS_toDER(duk_context *ctx) +{ + duk_push_this(ctx); + struct util_cert *cert = (struct util_cert*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_TLS_util_cert); + int outLen = i2d_X509(cert->x509, NULL); + if (outLen <= 0) + { + return(ILibDuktape_Error(ctx, "Certificate Error")); + } + + char *out = duk_push_fixed_buffer(ctx, outLen); + duk_push_buffer_object(ctx, -1, 0, outLen, DUK_BUFOBJ_NODEJS_BUFFER); + i2d_X509(cert->x509, (unsigned char**)&out); + return(1); +} duk_ret_t ILibDuktape_TLS_loadCertificate(duk_context *ctx) { - duk_size_t pfxLen; + duk_size_t pfxLen, derLen; char *pfx = Duktape_GetBufferPropertyEx(ctx, 0, "pfx", &pfxLen); + char *der = Duktape_GetBufferPropertyEx(ctx, 0, "der", &derLen); + if (der == NULL) { der = Duktape_GetBufferPropertyEx(ctx, 0, "cer", &derLen); } - if (pfx != NULL) + if (pfx != NULL || der != NULL) { duk_push_object(ctx); ILibDuktape_WriteID(ctx, "tls.certificate"); struct util_cert *cert = (struct util_cert*)Duktape_PushBuffer(ctx, sizeof(struct util_cert)); duk_put_prop_string(ctx, -2, ILibDuktape_TLS_util_cert); - if (util_from_p12(pfx, (int)pfxLen, Duktape_GetStringPropertyValue(ctx, 0, "passphrase", NULL), cert) == 0) + if (pfx != NULL) { - // Failed to load certificate - return(ILibDuktape_Error(ctx, "tls.loadCertificate(): Invalid passphrase")); + if (util_from_p12(pfx, (int)pfxLen, Duktape_GetStringPropertyValue(ctx, 0, "passphrase", NULL), cert) == 0) + { + // Failed to load certificate + return(ILibDuktape_Error(ctx, "tls.loadCertificate(): Invalid passphrase")); + } + } + else if (der != NULL) + { + if (util_from_cer(der, (int)derLen, cert) == 0) + { + // Failed to load certificate + return(ILibDuktape_Error(ctx, "tls.loadCertificate(): Failed to parse Certificate (%s)", ERR_reason_error_string(ERR_get_error()))); + } } ILibDuktape_CreateFinalizer(ctx, ILibDuktape_TLS_loadCertificate_finalizer); ILibDuktape_CreateInstanceMethod(ctx, "getKeyHash", ILibDuktape_TLS_loadCertificate_getKeyHash, 0); + ILibDuktape_CreateInstanceMethod(ctx, "toDER", ILibDuktape_TLS_toDER, 0); return(1); } else { - return(ILibDuktape_Error(ctx, "tls.loadCertificate(): pfx not specified")); + return(ILibDuktape_Error(ctx, "tls.loadCertificate(): No certificate format specified")); } } void ILibDuktape_tls_PUSH(duk_context *ctx, void *chain) diff --git a/microstack/ILibCrypto.c b/microstack/ILibCrypto.c index b1610b2..78c7e5c 100644 --- a/microstack/ILibCrypto.c +++ b/microstack/ILibCrypto.c @@ -522,7 +522,7 @@ int __fastcall util_from_cer(char* data, int datalen, struct util_cert* cert) { cert->pkey = NULL; cert->x509 = d2i_X509(NULL, (const unsigned char**)&data, datalen); - return ((cert->x509) == NULL); + return ((cert->x509) != NULL); } int __fastcall util_from_pkcs7b_string(char *data, int datalen, char *out, int outLen)