diff --git a/meshcore/agentcore.c b/meshcore/agentcore.c index 5bbd071..44def79 100644 --- a/meshcore/agentcore.c +++ b/meshcore/agentcore.c @@ -67,6 +67,7 @@ limitations under the License. #include #endif + #define HEX_IDENTIFIER (unsigned short)12408 #define EXE_IDENTIFIER (unsigned int)778401893 #define MSH_IDENTIFIER (unsigned int)778924904 @@ -1851,7 +1852,8 @@ int agent_GenerateCertificates(MeshAgentHostContainer *agent, char* certfile) if (certfile == NULL) { #if defined(WIN32) - if (wincrypto_open(TRUE) == 0) // Force certificate re-generation + char *rootSubject = (agent->capabilities & MeshCommand_AuthInfo_CapabilitiesMask_RECOVERY) == MeshCommand_AuthInfo_CapabilitiesMask_RECOVERY ? "CN=MeshNodeDiagnosticCertificate" : "CN=MeshNodeCertificate"; + if (wincrypto_open(TRUE, rootSubject) == 0) // Force certificate re-generation { int l; do { @@ -1861,14 +1863,14 @@ int agent_GenerateCertificates(MeshAgentHostContainer *agent, char* certfile) { util_from_cer(str, l, &(agent->selfcert)); util_keyhash(agent->selfcert, agent->g_selfid); - if (((int*)agent->g_selfid)[0] == 0) { wincrypto_close(); wincrypto_open(1); } + if (((int*)agent->g_selfid)[0] == 0) { wincrypto_close(); wincrypto_open(1, rootSubject); } } } while (l != 0 && ((int*)agent->g_selfid)[0] == 0); // This removes any chance that the self_id starts with 32 bits of zeros. if (l > 0) { // Generate a new TLS certificate & save it. - l = wincrypto_mkCert(L"CN=localhost", CERTIFICATE_TLS_SERVER, L"hidden", &str); + l = wincrypto_mkCert(rootSubject, L"CN=localhost", CERTIFICATE_TLS_SERVER, L"hidden", &str); util_from_p12(str, l, "hidden", &(agent->selftlscert)); ILibSimpleDataStore_PutEx(agent->masterDb, "SelfNodeTlsCert", 15, str, l); util_free(str); @@ -1958,9 +1960,11 @@ int agent_LoadCertificates(MeshAgentHostContainer *agent) if (len == 0 || util_from_p12(ILibScratchPad2, len, "hidden", &(agent->selfcert)) == 0) { #if defined(WIN32) + char *rootSubject = (agent->capabilities & MeshCommand_AuthInfo_CapabilitiesMask_RECOVERY) == MeshCommand_AuthInfo_CapabilitiesMask_RECOVERY ? "CN=MeshNodeDiagnosticCertificate" : "CN=MeshNodeCertificate"; + // No cert in this .db file. Try to load or generate a root certificate from a Windows crypto provider. This can be TPM backed which is great. // However, if we don't have the second cert created, we need to regen the root... - if (wincrypto_open(FALSE) == 0 && ILibSimpleDataStore_Get(agent->masterDb, "SelfNodeTlsCert", NULL, 0) != 0) + if (wincrypto_open(FALSE, rootSubject) == 0 && ILibSimpleDataStore_Get(agent->masterDb, "SelfNodeTlsCert", NULL, 0) != 0) { char* str = NULL; int l; @@ -1972,7 +1976,7 @@ int agent_LoadCertificates(MeshAgentHostContainer *agent) { util_from_cer(str, l, &(agent->selfcert)); util_keyhash(agent->selfcert, agent->g_selfid); - if (((int*)agent->g_selfid)[0] == 0) { wincrypto_open(TRUE); } // Force generation of a new certificate. + if (((int*)agent->g_selfid)[0] == 0) { wincrypto_open(TRUE, rootSubject); } // Force generation of a new certificate. } } while (l != 0 && ((int*)agent->g_selfid)[0] == 0); // This removes any chance that the self_id starts with 32 bits of zeros. @@ -1985,7 +1989,7 @@ int agent_LoadCertificates(MeshAgentHostContainer *agent) if (len == 0) { // Generate a new TLS certificate & save it. util_freecert(&(agent->selftlscert)); - l = wincrypto_mkCert(L"CN=localhost", CERTIFICATE_TLS_SERVER, L"hidden", &str); + l = wincrypto_mkCert(rootSubject, L"CN=localhost", CERTIFICATE_TLS_SERVER, L"hidden", &str); if (l > 0) { util_from_p12(str, l, "hidden", &(agent->selftlscert)); ILibSimpleDataStore_PutEx(agent->masterDb, "SelfNodeTlsCert", 15, str, l); @@ -2419,7 +2423,8 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge // Create a PKCS7 signature using Windows crypto & send it char* signature = NULL; signLen = wincrypto_sign((unsigned char*)ILibScratchPad, sizeof(AuthRequest->serverHash) + UTIL_SHA384_HASHSIZE + UTIL_SHA384_HASHSIZE, &signature); - if (signLen > 0) { + if (signLen > 0) + { // Signature succesful, send the result to the server memcpy_s((unsigned char*)(rav->data + certLen), sizeof(ILibScratchPad2) - sizeof(MeshCommand_BinaryPacket_AuthVerify_Header) - certLen, signature, signLen); ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, (char*)rav, sizeof(MeshCommand_BinaryPacket_AuthVerify_Header) + certLen + signLen, ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete); @@ -3619,7 +3624,10 @@ int MeshAgent_AgentMode(MeshAgentHostContainer *agentHost, int paramLen, char ** int ri; for (ri = 0; ri < paramLen; ++ri) { - if (strcmp(param[ri], "-recovery") == 0) { agentHost->capabilities |= MeshCommand_AuthInfo_CapabilitiesMask_RECOVERY; parseCommands = 0; } + if (strcmp(param[ri], "-recovery") == 0) + { + agentHost->capabilities |= MeshCommand_AuthInfo_CapabilitiesMask_RECOVERY; parseCommands = 0; + } } @@ -3745,8 +3753,18 @@ int MeshAgent_AgentMode(MeshAgentHostContainer *agentHost, int paramLen, char ** { char* str = NULL; int len = (int)util_readfile(MeshAgent_MakeAbsolutePath(agentHost->exePath, ".proxy"), &str, 1024); - if (str != NULL) { ILibSimpleDataStore_PutEx(agentHost->masterDb, "WebProxy", 8, str, len); free(str); } - else { ILibSimpleDataStore_DeleteEx(agentHost->masterDb, "WebProxy", 8); } + if (str != NULL) + { + if (len > 0) + { + ILibSimpleDataStore_PutEx(agentHost->masterDb, "WebProxy", 8, str, len); + } + else + { + ILibSimpleDataStore_DeleteEx(agentHost->masterDb, "WebProxy", 8); + } + free(str); + } } } diff --git a/meshcore/wincrypto.cpp b/meshcore/wincrypto.cpp index 1b884f2..d31e51f 100644 --- a/meshcore/wincrypto.cpp +++ b/meshcore/wincrypto.cpp @@ -32,8 +32,6 @@ HCRYPTPROV wincrypto_hProv = NULL; #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) #define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) LPWSTR wincrypto_CngProviders[3] = { L"Microsoft Platform Crypto Provider", MS_KEY_STORAGE_PROVIDER, NULL }; -LPWSTR wincrypto_containername = L"MeshAgentContainer"; -LPCTSTR wincrypto_subject = "CN=MeshNodeCertificate"; HANDLE wincrypto_hCertStore = NULL; PCCERT_CONTEXT wincrypto_certCtx = NULL; #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) @@ -134,7 +132,7 @@ void __fastcall wincrypto_close() if (wincrypto_hCertStore != NULL) { CertCloseStore(wincrypto_hCertStore, 0); wincrypto_hCertStore = NULL; } } -int __fastcall wincrypto_open(int newcert) +int __fastcall wincrypto_open(int newcert, char *rootSubject) { DWORD KeyLength = 3072; NCRYPT_KEY_HANDLE hKeyNode = NULL; @@ -166,6 +164,15 @@ int __fastcall wincrypto_open(int newcert) CRYPT_BIT_BLOB keyusage2; DWORD pkSize = 0; + char wkeycontainer[255]; // MAX Length of X509 distinguished name is 64 characters, so this should be OK + char akeycontainer[255]; // MAX Length of X509 distinguished name is 64 characters, so this should be OK + int akeyLen; + size_t wkeyLen; + if (rootSubject == NULL || strnlen_s(rootSubject, 255) > 64) { return(1); } // X509 distinguished name must be specifified and limited to 64 characters. + + 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 + ZeroMemory(&exts, sizeof(exts)); wincrypto_close(); @@ -179,9 +186,9 @@ int __fastcall wincrypto_open(int newcert) if (wincrypto_hProv == NULL) goto error; // Create cert subject string in format csp understands - if (!CertStrToName(X509_ASN_ENCODING, wincrypto_subject, CERT_X500_NAME_STR, NULL, NULL, &subjectEncodedSize, NULL)) goto error; + if (!CertStrToName(X509_ASN_ENCODING, (LPCTSTR)rootSubject, CERT_X500_NAME_STR, NULL, NULL, &subjectEncodedSize, NULL)) goto error; if ((subjectEncoded = (PBYTE)malloc(subjectEncodedSize)) == NULL) ILIBCRITICALEXIT(254); - if (!CertStrToName(X509_ASN_ENCODING, wincrypto_subject, CERT_X500_NAME_STR, NULL, subjectEncoded, &subjectEncodedSize, NULL)) goto error; + if (!CertStrToName(X509_ASN_ENCODING, (LPCTSTR)rootSubject, CERT_X500_NAME_STR, NULL, subjectEncoded, &subjectEncodedSize, NULL)) goto error; sib.cbData = subjectEncodedSize; sib.pbData = subjectEncoded; @@ -210,9 +217,9 @@ int __fastcall wincrypto_open(int newcert) // Generate node RSA key-pair #ifdef _CONSOLE - if (FAILED(status = NCryptCreatePersistedKey(wincrypto_hProv, &hKeyNode, BCRYPT_RSA_ALGORITHM, wincrypto_containername, 0, NCRYPT_OVERWRITE_KEY_FLAG))) goto error; + if (FAILED(status = NCryptCreatePersistedKey(wincrypto_hProv, &hKeyNode, BCRYPT_RSA_ALGORITHM, (LPCWSTR)wkeycontainer, 0, NCRYPT_OVERWRITE_KEY_FLAG))) goto error; #else - if (FAILED(status = NCryptCreatePersistedKey(wincrypto_hProv, &hKeyNode, BCRYPT_RSA_ALGORITHM, wincrypto_containername, 0, NCRYPT_MACHINE_KEY_FLAG | NCRYPT_OVERWRITE_KEY_FLAG))) goto error; + if (FAILED(status = NCryptCreatePersistedKey(wincrypto_hProv, &hKeyNode, BCRYPT_RSA_ALGORITHM, (LPCWSTR)wkeycontainer, 0, NCRYPT_MACHINE_KEY_FLAG | NCRYPT_OVERWRITE_KEY_FLAG))) goto error; #endif if (FAILED(status = NCryptSetProperty(hKeyNode, NCRYPT_LENGTH_PROPERTY, (PBYTE)&KeyLength, 4, NCRYPT_PERSIST_FLAG | NCRYPT_SILENT_FLAG))) { KeyLength = 2048; // If 3072 is not supported, go down to 2048. @@ -222,7 +229,7 @@ int __fastcall wincrypto_open(int newcert) // Create self signed cert ZeroMemory(&kpi, sizeof(kpi)); - kpi.pwszContainerName = wincrypto_containername; + kpi.pwszContainerName = (LPWSTR)wkeycontainer; kpi.pwszProvName = providerName; kpi.dwProvType = 0; kpi.dwFlags = 0; @@ -480,7 +487,7 @@ int __fastcall wincrypto_getcert(char** data) } // Create an X509, RSA 3027bit certificate with the MeshAgent certificate as signing root. -int __fastcall wincrypto_mkCert(wchar_t* subject, int certtype, wchar_t* password, char** data) +int __fastcall wincrypto_mkCert(char* rootSubject, wchar_t* subject, int certtype, wchar_t* password, char** data) { NCRYPT_KEY_HANDLE hKeyNode = NULL; DWORD hKeyNodeSpec = 0; @@ -553,9 +560,9 @@ int __fastcall wincrypto_mkCert(wchar_t* subject, int certtype, wchar_t* passwor if (!CryptExportPublicKeyInfo(hNewKey, AT_KEYEXCHANGE, X509_ASN_ENCODING, pkInfo, &pkSize)) goto end; // Create cert issuer string in format the CSP understands - if (!CertStrToName(X509_ASN_ENCODING, wincrypto_subject, CERT_X500_NAME_STR, NULL, NULL, &subject1EncodedSize, NULL)) goto end; + if (!CertStrToName(X509_ASN_ENCODING, (LPCTSTR)rootSubject, CERT_X500_NAME_STR, NULL, NULL, &subject1EncodedSize, NULL)) goto end; if ((subject1Encoded = (PBYTE)malloc(subject1EncodedSize)) == NULL) ILIBCRITICALEXIT(254); - if (!CertStrToName(X509_ASN_ENCODING, wincrypto_subject, CERT_X500_NAME_STR, NULL, subject1Encoded, &subject1EncodedSize, NULL)) goto end; + if (!CertStrToName(X509_ASN_ENCODING, (LPCTSTR)rootSubject, CERT_X500_NAME_STR, NULL, subject1Encoded, &subject1EncodedSize, NULL)) goto end; sib1.cbData = subject1EncodedSize; sib1.pbData = subject1Encoded; diff --git a/meshcore/wincrypto.h b/meshcore/wincrypto.h index d8ee344..8cb2811 100644 --- a/meshcore/wincrypto.h +++ b/meshcore/wincrypto.h @@ -24,7 +24,7 @@ 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); +int __fastcall wincrypto_open(int newcert, char *rootSubject); 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); @@ -32,6 +32,6 @@ 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); -int __fastcall wincrypto_mkCert(wchar_t* subject, int certtype, wchar_t* password, char** data); // certtype: 1=Root, 2=Server, 3=Client +int __fastcall wincrypto_mkCert(char* rootSubject, wchar_t* subject, int certtype, wchar_t* password, char** data); // certtype: 1=Root, 2=Server, 3=Client #endif