diff --git a/meshcore/agentcore.c b/meshcore/agentcore.c index 44def79..26ceb18 100644 --- a/meshcore/agentcore.c +++ b/meshcore/agentcore.c @@ -1670,6 +1670,92 @@ duk_ret_t ILibDuktape_MeshAgent_ServerInfo(duk_context *ctx) return(1); } +duk_ret_t ILibDuktape_MeshAgent_GenerateCertsForDiagnosticAgent(duk_context *ctx) +{ + char *rootSubject = (char*)duk_require_string(ctx, 0); + char tmp[UTIL_SHA384_HASHSIZE]; + struct util_cert tmpCert; + + duk_push_this(ctx); + MeshAgentHostContainer *agent = (MeshAgentHostContainer*)Duktape_GetPointerProperty(ctx, -1, MESH_AGENT_PTR); + duk_push_object(ctx); + +#ifdef WIN32 + PCCERT_CONTEXT certCtx = NULL; + char *certCtx_data = NULL; + if (wincrypto_open_ex(TRUE, rootSubject, &certCtx) == 0) // Force certificate re-generation + { + int l; + do { + // Finish off work with our own certificate + l = wincrypto_getcert_ex(&certCtx_data, certCtx); + if (l > 0) + { + util_from_cer(certCtx_data, l, &tmpCert); + util_keyhash(tmpCert, tmp); + if (((int*)tmp)[0] == 0) { wincrypto_close_ex(certCtx); wincrypto_open_ex(1, rootSubject, &certCtx); } + } + } while (l != 0 && ((int*)tmp)[0] == 0); // This removes any chance that the self_id starts with 32 bits of zeros. + + if (l > 0) + { + // Save the root cert in CER format + duk_push_object(ctx); // [object][root] + char *rootBuffer = duk_push_fixed_buffer(ctx, l); // [object][root][buffer] + duk_push_buffer_object(ctx, -1, 0, l, DUK_BUFOBJ_NODEJS_BUFFER); // [object][root][buffer][nodeBuffer] + duk_put_prop_string(ctx, -3, "der"); // [object][root][buffer] + duk_pop(ctx); // [object][root] + duk_put_prop_string(ctx, -2, "root"); // [object] + memcpy_s(rootBuffer, l, certCtx_data, l); + + // Generate a new TLS certificate & save it. + l = wincrypto_mkCert(rootSubject, L"CN=localhost", CERTIFICATE_TLS_SERVER, L"hidden", &certCtx_data); + + duk_push_object(ctx); // [object][tls] + char *buffer = duk_push_fixed_buffer(ctx, l); // [object][tls][buffer] + duk_push_buffer_object(ctx, -1, 0, l, DUK_BUFOBJ_NODEJS_BUFFER); // [object][tls][buffer][nodeBuffer] + duk_put_prop_string(ctx, -3, "pfx"); // [object][tls][buffer] + duk_pop(ctx); // [object][tls] + duk_push_string(ctx, "hidden"); duk_put_prop_string(ctx, -2, "passphrase"); + duk_put_prop_string(ctx, -2, "tls"); // [object] + memcpy_s(buffer, l, certCtx_data, l); + util_free(certCtx_data); + return(1); + } + + // wincrypto error + return(ILibDuktape_Error(ctx, "Error Generating Certificates using WinCrypto")); + } + else + { +#endif + // Generate a new self-signed root certificate for this node using OpenSSL + do + { + if (util_mkCert(NULL, &(tmpCert), 3072, 10000, "MeshNodeCertificate", CERTIFICATE_ROOT, NULL) == 0) + { + return(ILibDuktape_Error(ctx, "Error Generating Certificates using OpenSSL")); + } + util_keyhash(tmpCert, tmp); + } while (((int*)tmp)[0] == 0); // This removes any chance that the self_id starts with 32 bits of zeros. + + duk_push_object(ctx); // [object][root] + char *pfx = NULL; + int pfxLen = util_to_p12(tmpCert, "hidden", &pfx); + char *jspfx = duk_push_fixed_buffer(ctx, pfxLen); // [object][root][buffer] + duk_push_buffer_object(ctx, -1, 0, pfxLen, DUK_BUFOBJ_NODEJS_BUFFER); // [object][root][buffer][nodeBuffer] + duk_put_prop_string(ctx, -3, "pfx"); // [object][root][buffer] + duk_pop(ctx); // [object][root] + duk_push_string(ctx, "hidden"); duk_put_prop_string(ctx, -2, "passphrase"); + duk_put_prop_string(ctx, -2, "root"); // [object] + + memcpy_s(jspfx, pfxLen, pfx, pfxLen); + util_free(pfx); + util_freecert(&tmpCert); + return(1); + } +} + void ILibDuktape_MeshAgent_PUSH(duk_context *ctx, void *chain) { MeshAgentHostContainer *agent; @@ -1715,6 +1801,7 @@ void ILibDuktape_MeshAgent_PUSH(duk_context *ctx, void *chain) // Always use the root cert for agent authentication duk_push_pointer(ctx, &agent->selfcert); duk_put_prop_string(ctx, -2, ILibDuktape_MeshAgent_Cert_NonLeaf); + ILibDuktape_CreateInstanceMethod(ctx, "GenerateAgentCertificate", ILibDuktape_MeshAgent_GenerateCertsForDiagnosticAgent, 1); #endif ILibDuktape_EventEmitter_CreateEventEx(emitter, "Ready"); diff --git a/meshcore/wincrypto.cpp b/meshcore/wincrypto.cpp index d31e51f..1d91a3d 100644 --- a/meshcore/wincrypto.cpp +++ b/meshcore/wincrypto.cpp @@ -125,14 +125,21 @@ int __fastcall wincrypto_isopen() return (wincrypto_hProv != NULL && wincrypto_hCertStore != NULL && wincrypto_certCtx != NULL); } -void __fastcall wincrypto_close() +void __fastcall wincrypto_close_ex(PCCERT_CONTEXT certCtx) { - if (wincrypto_certCtx != NULL) { CertFreeCertificateContext(wincrypto_certCtx); wincrypto_certCtx = NULL; } - if (wincrypto_hProv != NULL) { NCryptFreeObject(wincrypto_hProv); wincrypto_hProv = NULL; } - if (wincrypto_hCertStore != NULL) { CertCloseStore(wincrypto_hCertStore, 0); wincrypto_hCertStore = NULL; } + if (certCtx != NULL) + { + CertFreeCertificateContext(certCtx); + } + else + { + if (wincrypto_certCtx != NULL) { CertFreeCertificateContext(wincrypto_certCtx); wincrypto_certCtx = NULL; } + if (wincrypto_hProv != NULL) { NCryptFreeObject(wincrypto_hProv); wincrypto_hProv = NULL; } + if (wincrypto_hCertStore != NULL) { CertCloseStore(wincrypto_hCertStore, 0); wincrypto_hCertStore = NULL; } + } } -int __fastcall wincrypto_open(int newcert, char *rootSubject) +int __fastcall wincrypto_open_ex(int newcert, char *rootSubject, PCCERT_CONTEXT *certCtx) { DWORD KeyLength = 3072; NCRYPT_KEY_HANDLE hKeyNode = NULL; @@ -172,9 +179,10 @@ int __fastcall wincrypto_open(int newcert, char *rootSubject) akeyLen = sprintf_s(akeycontainer, sizeof(akeycontainer), "%s_privatekey", rootSubject); if (mbstowcs_s(&wkeyLen, (wchar_t*)wkeycontainer, sizeof(wkeycontainer) / 2, (char*)akeycontainer, 64) != 0) { return(1); } // Error creating privatekey container name + if (certCtx == NULL) { certCtx = &wincrypto_certCtx; } ZeroMemory(&exts, sizeof(exts)); - wincrypto_close(); + wincrypto_close_ex(*certCtx); // Open the best CNG possible while (providerName == NULL && wincrypto_CngProviders[r] != NULL) { @@ -299,7 +307,7 @@ int __fastcall wincrypto_open(int newcert, char *rootSubject) error: // Clean up if (hKeyNode != NULL) NCryptFreeObject(hKeyNode); - wincrypto_close(); + wincrypto_close_ex(*certCtx); return 1; end: @@ -479,11 +487,19 @@ end: } // Get the X509 certificate including the public key (Direct reference, no need to free this). -int __fastcall wincrypto_getcert(char** data) +int __fastcall wincrypto_getcert_ex(char** data, PCCERT_CONTEXT certCtx) { - if (wincrypto_certCtx == NULL) { *data = NULL; return 0; } - *data = (char*)wincrypto_certCtx->pbCertEncoded; - return (int)wincrypto_certCtx->cbCertEncoded; + if (certCtx != NULL) + { + *data = (char*)certCtx->pbCertEncoded; + return (int)certCtx->cbCertEncoded; + } + else + { + if (wincrypto_certCtx == NULL) { *data = NULL; return 0; } + *data = (char*)wincrypto_certCtx->pbCertEncoded; + return (int)wincrypto_certCtx->cbCertEncoded; + } } // Create an X509, RSA 3027bit certificate with the MeshAgent certificate as signing root. diff --git a/meshcore/wincrypto.h b/meshcore/wincrypto.h index 8cb2811..2b3f865 100644 --- a/meshcore/wincrypto.h +++ b/meshcore/wincrypto.h @@ -23,15 +23,18 @@ void __fastcall wincrypto_setregistryA(char* name, char* value); int __fastcall wincrypto_getregistry(LPCWSTR name, char** value); int __fastcall wincrypto_getregistryA(char* name, char** value); int __fastcall wincrypto_isopen(); -void __fastcall wincrypto_close(); -int __fastcall wincrypto_open(int newcert, char *rootSubject); +void __fastcall wincrypto_close_ex(PCCERT_CONTEXT certCtx); +#define wincrypto_close() wincrypto_close_ex(NULL) +#define wincrypto_open(newCert, rootSubject) wincrypto_open_ex(newCert, rootSubject, NULL) +int __fastcall wincrypto_open_ex(int newcert, char *rootSubject, PCCERT_CONTEXT *certCtx); void __fastcall wincrypto_random(int length, char* result); int __fastcall wincrypto_md5(char* data, int datalen, char* result); int __fastcall wincrypto_sha256(char* data, int datalen, char* result); int __fastcall wincrypto_sha384(char* data, int datalen, char* result); int __fastcall wincrypto_sign(char* data, int len, char** signature); int __fastcall wincrypto_decrypt(char* encdata, int encdatalen, char** data); -int __fastcall wincrypto_getcert(char** data); +#define wincrypto_getcert(data) wincrypto_getcert_ex(data, NULL) +int __fastcall wincrypto_getcert_ex(char** data, PCCERT_CONTEXT certCtx); int __fastcall wincrypto_mkCert(char* rootSubject, wchar_t* subject, int certtype, wchar_t* password, char** data); // certtype: 1=Root, 2=Server, 3=Client #endif