diff --git a/Makefile.libnx b/Makefile.libnx index f19a1a8..3d49bad 100644 --- a/Makefile.libnx +++ b/Makefile.libnx @@ -39,7 +39,8 @@ include $(DEVKITPRO)/libnx/switch_rules #--------------------------------------------------------------------------------- TARGET := moonlight BUILD := build -SOURCES := libgamestream src/nanogui_resources src src/streaming src/streaming/ffmpeg src/streaming/video src/ui/windows src/ui/buttons src/ui \ +SOURCES := libgamestream src/nanogui_resources src src/streaming src/streaming/ffmpeg \ + src/crypto src/streaming/video src/ui/windows src/ui/buttons src/ui \ third_party/moonlight-common-c/enet third_party/moonlight-common-c/reedsolomon third_party/moonlight-common-c/src \ third_party/nanogui/ext/nanovg/src third_party/nanogui/src DATA := data @@ -52,7 +53,7 @@ INCLUDES := include ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE M_INCLUDES := \ - -I$(TOPDIR)/src -I$(TOPDIR)/src/streaming \ + -I$(TOPDIR)/src -I$(TOPDIR)/src/streaming -I$(TOPDIR)/src/crypto -I$(TOPDIR)/src/crypto/keys \ -I$(TOPDIR)/src/streaming/ffmpeg -I$(TOPDIR)/src/streaming/video -I$(TOPDIR)/src/streaming/audio \ -I$(TOPDIR)/src/nanogui_resources \ -I$(TOPDIR)/src/ui -I$(TOPDIR)/src/ui/buttons -I$(TOPDIR)/src/ui/windows \ @@ -62,10 +63,11 @@ M_INCLUDES := \ -I$(TOPDIR)/third_party/moonlight-common-c/enet/include \ -I$(TOPDIR)/third_party/nanogui/include \ -I$(TOPDIR)/third_party/nanogui/ext/nanovg/src \ - -I$(TOPDIR)/third_party/json/single_include/nlohmann + -I$(TOPDIR)/third_party/json/single_include/nlohmann \ + -I/Users/rock88/Downloads/moonlight-switch-master/dependencies/include DEFINES := -DNANOGUI_USE_OPENGL -DNVG_STB_IMAGE_IMPLEMENTATION -DNANOGUI_NO_GLFW \ - -DHAS_SOCKLEN_T -DHAS_POLL -DHAS_FCNTL -D_GNU_SOURCE + -DHAS_SOCKLEN_T -DHAS_POLL -DHAS_FCNTL -D_GNU_SOURCE -DUSE_MBEDTLS_CRYPTO CFLAGS := -g -Wall -O0 -ffunction-sections \ $(ARCH) $(DEFINES) @@ -81,14 +83,15 @@ LIBS := -lcurl -lmbedtls -lmbedx509 -lmbedcrypto \ -lavcodec -lavutil -lopus -lssl -lcrypto -lbz2 -lz -lexpat -lm \ -lglad -lEGL -lglapi -ldrm_nouveau -lglfw3 \ -lnx -lwebp -lswresample -lavformat -lvpx \ - -L/Users/rock88/Documents/Projects/Switch/moonlight-switch-new/deps/lib + -L/Users/rock88/Downloads/moonlight-switch-master/dependencies/lib -LIBGAMESTREAM_SOURCES = \ - client.c \ - http.c \ - mkcert.c \ +LIBGAMESTREAM_C_SOURCES = \ xml.c +LIBGAMESTREAM_CPP_SOURCES = \ + client.cpp \ + http.cpp + MOONLIGHT_LIBRETRO_C_SOURCES = \ nanogui_resources.c \ moonlight_libnx.c \ @@ -111,7 +114,9 @@ MOONLIGHT_LIBRETRO_CXX_SOURCES = \ InputController.cpp \ MoonlightSession.cpp \ FFmpegVideoDecoder.cpp \ - GLVideoRenderer.cpp + GLVideoRenderer.cpp \ + Data.cpp \ + MbedTLSCryptoManager.cpp MOONLIGHT_COMMON_C_SOURCES = \ callbacks.c \ @@ -202,8 +207,8 @@ export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ export DEPSDIR := $(CURDIR)/$(BUILD) -CFILES := $(LIBGAMESTREAM_SOURCES) $(MOONLIGHT_LIBRETRO_C_SOURCES) $(MOONLIGHT_COMMON_C_SOURCES) $(NANOGUI_C_SOURCES) -CPPFILES := $(MOONLIGHT_LIBRETRO_CXX_SOURCES) $(NANOGUI_CXX_SOURCES) +CFILES := $(LIBGAMESTREAM_C_SOURCES) $(MOONLIGHT_LIBRETRO_C_SOURCES) $(MOONLIGHT_COMMON_C_SOURCES) $(NANOGUI_C_SOURCES) +CPPFILES := $(LIBGAMESTREAM_CPP_SOURCES) $(MOONLIGHT_LIBRETRO_CXX_SOURCES) $(NANOGUI_CXX_SOURCES) SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) diff --git a/libgamestream/client.cpp b/libgamestream/client.cpp index 38abcc6..204ef46 100644 --- a/libgamestream/client.cpp +++ b/libgamestream/client.cpp @@ -18,7 +18,6 @@ */ #include "http.h" -#include "mkcert.h" #include "client.h" #include "errors.h" #include "limits.h" @@ -40,10 +39,6 @@ static char* unique_id = "0123456789ABCDEF"; const char* gs_error; -uid_t getuid() { - return 1; -} - int mkdirtree(const char* directory) { char buffer[PATH_MAX]; char* p = buffer; @@ -207,10 +202,10 @@ static int gs_pair_validate(Data &data, char** result) { return ret; } - if (strcmp(*result, "1") != 0) { - gs_error = "Pairing failed"; - ret = GS_FAILED; - } +// if (strcmp(*result, "1") != 0) { +// gs_error = "Pairing failed"; +// ret = GS_FAILED; +// } if (*result) { free(*result); @@ -252,7 +247,7 @@ int gs_pair(PSERVER_DATA server, char* pin) { Data salted_pin = salt.append(Data(pin, strlen(pin))); LOG_FMT("PIN: %s, salt %s\n", pin, salt.hex().bytes()); - snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&phrase=getservercert&salt=%s&clientcert=%s", server->serverInfo.address, unique_id, salt.hex().bytes(), CryptoManager::read_cert_from_file().hex().bytes()); + snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&phrase=getservercert&salt=%s&clientcert=%s", server->serverInfo.address, unique_id, salt.hex().bytes(), CryptoManager::cert_data().hex().bytes()); if ((ret = http_request(url, &data)) != GS_OK) { return gs_pair_cleanup(ret, server, &result); @@ -308,7 +303,7 @@ int gs_pair(PSERVER_DATA server, char* pin) { Data serverChallenge = decServerChallengeResp.subdata(hashLength, 16); Data clientSecret = Data::random_bytes(16); - Data challengeRespHashInput = serverChallenge.append(CryptoManager::get_signature_from_cert(CryptoManager::read_cert_from_file())).append(clientSecret); + Data challengeRespHashInput = serverChallenge.append(CryptoManager::signature(CryptoManager::cert_data())).append(clientSecret); Data challengeRespHash; @@ -347,7 +342,7 @@ int gs_pair(PSERVER_DATA server, char* pin) { return gs_pair_cleanup(ret, server, &result); } - Data serverChallengeRespHashInput = randomChallenge.append(CryptoManager::get_signature_from_cert(plainCert.hex_to_bytes())).append(serverSecret); + Data serverChallengeRespHashInput = randomChallenge.append(CryptoManager::signature(plainCert.hex_to_bytes())).append(serverSecret); Data serverChallengeRespHash; if (server->serverMajorVersion >= 7) { serverChallengeRespHash = CryptoManager::SHA256_hash_data(serverChallengeRespHashInput); @@ -356,7 +351,7 @@ int gs_pair(PSERVER_DATA server, char* pin) { serverChallengeRespHash = CryptoManager::SHA1_hash_data(serverChallengeRespHashInput); } - Data clientPairingSecret = clientSecret.append(CryptoManager::sign_data(clientSecret, CryptoManager::read_key_from_file())); + Data clientPairingSecret = clientSecret.append(CryptoManager::sign_data(clientSecret, CryptoManager::key_data())); snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&clientpairingsecret=%s", server->serverInfo.address, unique_id, clientPairingSecret.hex().bytes()); if ((ret = http_request(url, &data)) != GS_OK) { @@ -512,16 +507,16 @@ cleanup: } int gs_init(PSERVER_DATA server, char *address, const char *keyDirectory, int log_level, bool unsupported) { - if (!CryptoManager::certs_exists()) { + if (!CryptoManager::load_cert_key_pair()) { LOG("No certs, generate new...\n"); - if (!CryptoManager::generate_certs()) { + if (!CryptoManager::generate_new_cert_key_pair()) { LOG("Failed to generate certs...\n"); return GS_FAILED; } } - http_init(keyDirectory, log_level); + http_init(keyDirectory, 2); LiInitializeServerInformation(&server->serverInfo); server->serverInfo.address = address; diff --git a/libgamestream/http.cpp b/libgamestream/http.cpp index b7d3996..5689870 100644 --- a/libgamestream/http.cpp +++ b/libgamestream/http.cpp @@ -19,6 +19,8 @@ #include "http.h" #include "errors.h" +#include "CryptoManager.hpp" +#include "Log.h" #include #include @@ -47,6 +49,13 @@ static size_t _write_curl(void *contents, size_t size, size_t nmemb, void *userp } int http_init(const char* key_directory, int log_level) { + if (!curl) { + curl_global_init(CURL_GLOBAL_ALL); + LOG_FMT("Curl version: %s\n", curl_version()); + } else { + return GS_OK; + } + curl = curl_easy_init(); debug = log_level >= 2; @@ -59,9 +68,12 @@ int http_init(const char* key_directory, int log_level) { char keyFilePath[4096]; sprintf(&keyFilePath[0], "%s/%s", key_directory, KEY_FILE_NAME); + LOG_FMT("certificateFilePath: %s\n", certificateFilePath); + LOG_FMT("keyFilePath: %s\n", keyFilePath); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L); - curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE,"PEM"); + curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM"); curl_easy_setopt(curl, CURLOPT_SSLCERT, certificateFilePath); curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM"); curl_easy_setopt(curl, CURLOPT_SSLKEY, keyFilePath); @@ -75,7 +87,7 @@ int http_init(const char* key_directory, int log_level) { int http_request(char* url, Data* data) { if (debug) - printf("Request %s\n", url); + LOG_FMT("Request %s\n", url); HTTP_DATA* http_data = (HTTP_DATA*)malloc(sizeof(HTTP_DATA)); http_data->memory = (char*)malloc(1); @@ -88,19 +100,20 @@ int http_request(char* url, Data* data) { if (res != CURLE_OK) { gs_error = curl_easy_strerror(res); + LOG_FMT("Curl error: %s\n", gs_error); return GS_FAILED; } else if (http_data->memory == NULL) { + LOG("Curl error: memory = NULL\n"); return GS_OUT_OF_MEMORY; } *data = Data(http_data->memory, http_data->size); + if (debug) + LOG_FMT("Response:\n%s\n\n", http_data->memory); + free(http_data->memory); free(http_data); - - if (debug) - printf("Response:\n%s\n\n", http_data->memory); - return GS_OK; } diff --git a/libgamestream/http.h b/libgamestream/http.h index 68974ff..d0dfeb6 100644 --- a/libgamestream/http.h +++ b/libgamestream/http.h @@ -21,8 +21,5 @@ #include "Data.hpp" -#define CERTIFICATE_FILE_NAME "client.pem" -#define KEY_FILE_NAME "key.pem" - int http_init(const char* key_directory, int log_level); int http_request(char* url, Data* data); diff --git a/libgamestream/mkcert.c b/libgamestream/mkcert.c deleted file mode 100644 index 0a921eb..0000000 --- a/libgamestream/mkcert.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Moonlight is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Moonlight is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Moonlight; if not, see . - */ - -#include "mkcert.h" - -#include -#include - -#include -#include -#include -#include -#include - -#ifndef OPENSSL_NO_ENGINE -#include -#endif - -static const int NUM_BITS = 2048; -static const int SERIAL = 0; -static const int NUM_YEARS = 10; - -int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years); - -CERT_KEY_PAIR mkcert_generate() { - BIO *bio_err; - X509 *x509 = NULL; - EVP_PKEY *pkey = NULL; - PKCS12 *p12 = NULL; - - CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); - bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); - - mkcert(&x509, &pkey, NUM_BITS, SERIAL, NUM_YEARS); - - p12 = PKCS12_create("limelight", "GameStream", pkey, x509, NULL, 0, 0, 0, 0, 0); - if (p12 == NULL) { - printf("Error generating a valid PKCS12 certificate.\n"); - } - - BIO_free(bio_err); - - return (CERT_KEY_PAIR){x509, pkey, p12}; -} - -void mkcert_free(CERT_KEY_PAIR certKeyPair) { - X509_free(certKeyPair.x509); - EVP_PKEY_free(certKeyPair.pkey); - PKCS12_free(certKeyPair.p12); -} - -void mkcert_save(const char* certFile, const char* p12File, const char* keyPairFile, CERT_KEY_PAIR certKeyPair) { - FILE* certFilePtr = fopen(certFile, "w"); - FILE* keyPairFilePtr = fopen(keyPairFile, "w"); - FILE* p12FilePtr = fopen(p12File, "wb"); - - //TODO: error check - PEM_write_PrivateKey(keyPairFilePtr, certKeyPair.pkey, NULL, NULL, 0, NULL, NULL); - PEM_write_X509(certFilePtr, certKeyPair.x509); - i2d_PKCS12_fp(p12FilePtr, certKeyPair.p12); - - fclose(p12FilePtr); - fclose(certFilePtr); - fclose(keyPairFilePtr); -} - -int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) { - X509* cert = X509_new(); - EVP_PKEY* pk = EVP_PKEY_new(); - BIGNUM* bne = BN_new(); - RSA* rsa = RSA_new(); - - BN_set_word(bne, RSA_F4); - RSA_generate_key_ex(rsa, bits, bne, NULL); - - EVP_PKEY_assign_RSA(pk, rsa); - - X509_set_version(cert, 2); - ASN1_INTEGER_set(X509_get_serialNumber(cert), serial); -#if OPENSSL_VERSION_NUMBER < 0x10100000L - X509_gmtime_adj(X509_get_notBefore(cert), 0); - X509_gmtime_adj(X509_get_notAfter(cert), 60 * 60 * 24 * 365 * years); -#else - ASN1_TIME* before = ASN1_STRING_dup(X509_get0_notBefore(cert)); - ASN1_TIME* after = ASN1_STRING_dup(X509_get0_notAfter(cert)); - - X509_gmtime_adj(before, 0); - X509_gmtime_adj(after, 60 * 60 * 24 * 365 * years); - - X509_set1_notBefore(cert, before); - X509_set1_notAfter(cert, after); - - ASN1_STRING_free(before); - ASN1_STRING_free(after); -#endif - - X509_set_pubkey(cert, pk); - - X509_NAME* name = X509_get_subject_name(cert); - X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, - (const unsigned char*)"NVIDIA GameStream Client", - -1, -1, 0); - X509_set_issuer_name(cert, name); - - X509_sign(cert, pk, EVP_sha256()); - - BN_free(bne); - - *x509p = cert; - *pkeyp = pk; - - return 1; -} diff --git a/libgamestream/mkcert.h b/libgamestream/mkcert.h deleted file mode 100644 index 745aaa6..0000000 --- a/libgamestream/mkcert.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Created by Diego Waxemberg on 10/16/14. - * Copyright (c) 2014 Limelight Stream. All rights reserved. - * - * Moonlight is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Moonlight is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Moonlight; if not, see . - */ - -#pragma once - -#include -#include - -typedef struct _CERT_KEY_PAIR { - X509 *x509; - EVP_PKEY *pkey; - PKCS12 *p12; -} CERT_KEY_PAIR, *PCERT_KEY_PAIR; - -CERT_KEY_PAIR mkcert_generate(); -void mkcert_free(CERT_KEY_PAIR); -void mkcert_save(const char* certFile, const char* p12File, const char* keyPairFile, CERT_KEY_PAIR certKeyPair); diff --git a/moonlight.xcodeproj/project.pbxproj b/moonlight.xcodeproj/project.pbxproj index 6593102..70e32eb 100644 --- a/moonlight.xcodeproj/project.pbxproj +++ b/moonlight.xcodeproj/project.pbxproj @@ -11,6 +11,8 @@ 3602C3BA245DB3C800368900 /* AppListWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3602C3B8245DB3C800368900 /* AppListWindow.cpp */; }; 3602C3BD245DBA9100368900 /* AppButton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3602C3BB245DBA9100368900 /* AppButton.cpp */; }; 3603E93C246316400051287D /* InputController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3603E93A246316400051287D /* InputController.cpp */; }; + 363898332471B7C500F99920 /* OpenSSLCryptoManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 363898302471B7C500F99920 /* OpenSSLCryptoManager.cpp */; }; + 363898342471B7C500F99920 /* MbedTLSCryptoManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 363898312471B7C500F99920 /* MbedTLSCryptoManager.cpp */; }; 3652EFCD245B3B00001FABF3 /* widget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3652EF0F245B3B00001FABF3 /* widget.cpp */; }; 3652EFCE245B3B00001FABF3 /* common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3652EF10245B3B00001FABF3 /* common.cpp */; }; 3652EFCF245B3B00001FABF3 /* checkbox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3652EF11245B3B00001FABF3 /* checkbox.cpp */; }; @@ -50,7 +52,6 @@ 3652F005245C28C6001FABF3 /* GameStreamClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3652F003245C28C6001FABF3 /* GameStreamClient.cpp */; }; 3652F010245C2919001FABF3 /* xml.c in Sources */ = {isa = PBXBuildFile; fileRef = 3652F008245C2918001FABF3 /* xml.c */; }; 3652F011245C2919001FABF3 /* client.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3652F00C245C2918001FABF3 /* client.cpp */; }; - 3652F012245C2919001FABF3 /* mkcert.c in Sources */ = {isa = PBXBuildFile; fileRef = 3652F00D245C2918001FABF3 /* mkcert.c */; }; 3652F013245C2919001FABF3 /* http.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3652F00F245C2918001FABF3 /* http.cpp */; }; 3652F065245C292B001FABF3 /* list.c in Sources */ = {isa = PBXBuildFile; fileRef = 3652F017245C292B001FABF3 /* list.c */; }; 3652F066245C292B001FABF3 /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 3652F01B245C292B001FABF3 /* compress.c */; }; @@ -100,7 +101,6 @@ 36DFE0CE2459FAB100FC51CE /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 36DBDEA22450C2640057C8D3 /* OpenGL.framework */; }; 36DFE217245A278700FC51CE /* glsym_gl.c in Sources */ = {isa = PBXBuildFile; fileRef = 36DFE0DB245A1FEC00FC51CE /* glsym_gl.c */; }; 36DFE218245A278900FC51CE /* rglgen.c in Sources */ = {isa = PBXBuildFile; fileRef = 36DFE0DE245A1FEC00FC51CE /* rglgen.c */; }; - 36E6378C246FFFF30032F5FB /* CryptoManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36E6378A246FFFF30032F5FB /* CryptoManager.cpp */; }; 36E63790247010C70032F5FB /* Data.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36E6378E247010C70032F5FB /* Data.cpp */; }; /* End PBXBuildFile section */ @@ -126,6 +126,10 @@ 3602C3C0245DC7E300368900 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; 3603E93A246316400051287D /* InputController.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InputController.cpp; sourceTree = ""; }; 3603E93B246316400051287D /* InputController.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = InputController.hpp; sourceTree = ""; }; + 3638982F2471B7C500F99920 /* MbedTLSCryptoManager.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MbedTLSCryptoManager.hpp; sourceTree = ""; }; + 363898302471B7C500F99920 /* OpenSSLCryptoManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OpenSSLCryptoManager.cpp; sourceTree = ""; }; + 363898312471B7C500F99920 /* MbedTLSCryptoManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MbedTLSCryptoManager.cpp; sourceTree = ""; }; + 363898322471B7C500F99920 /* OpenSSLCryptoManager.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = OpenSSLCryptoManager.hpp; sourceTree = ""; }; 3652ECE8245B3AFF001FABF3 /* colorpicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = colorpicker.h; sourceTree = ""; }; 3652ECE9245B3AFF001FABF3 /* renderpass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = renderpass.h; sourceTree = ""; }; 3652ECEA245B3AFF001FABF3 /* theme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = theme.h; sourceTree = ""; }; @@ -212,13 +216,11 @@ 3652F001245B6961001FABF3 /* AddHostWindow.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AddHostWindow.hpp; sourceTree = ""; }; 3652F003245C28C6001FABF3 /* GameStreamClient.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GameStreamClient.cpp; sourceTree = ""; }; 3652F004245C28C6001FABF3 /* GameStreamClient.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = GameStreamClient.hpp; sourceTree = ""; }; - 3652F007245C2918001FABF3 /* mkcert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mkcert.h; sourceTree = ""; }; 3652F008245C2918001FABF3 /* xml.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xml.c; sourceTree = ""; }; 3652F009245C2918001FABF3 /* client.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = client.h; sourceTree = ""; }; 3652F00A245C2918001FABF3 /* http.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = http.h; sourceTree = ""; }; 3652F00B245C2918001FABF3 /* errors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = errors.h; sourceTree = ""; }; 3652F00C245C2918001FABF3 /* client.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = client.cpp; sourceTree = ""; }; - 3652F00D245C2918001FABF3 /* mkcert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mkcert.c; sourceTree = ""; }; 3652F00E245C2918001FABF3 /* xml.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xml.h; sourceTree = ""; }; 3652F00F245C2918001FABF3 /* http.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = http.cpp; sourceTree = ""; }; 3652F017245C292B001FABF3 /* list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = list.c; sourceTree = ""; }; @@ -301,6 +303,7 @@ 36D3F8432469B5C400CDEF9B /* MoonlightSession.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MoonlightSession.hpp; sourceTree = ""; }; 36D3F8452469C6BC00CDEF9B /* Log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Log.h; sourceTree = ""; }; 36D3F8492469CC2600CDEF9B /* IAudioRenderer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = IAudioRenderer.hpp; sourceTree = ""; }; + 36D461BE24709B8F00A543B4 /* build.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = build.sh; path = "../../../../Downloads/openssl-1.1.1g/build.sh"; sourceTree = ""; }; 36DBDE8E2450BB7E0057C8D3 /* moonlight */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = moonlight; sourceTree = BUILT_PRODUCTS_DIR; }; 36DBDE992450BCD50057C8D3 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 36DBDE9B2450BCD90057C8D3 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; @@ -320,7 +323,6 @@ 36DFE0DF245A1FEC00FC51CE /* rglgen_headers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rglgen_headers.h; sourceTree = ""; }; 36DFE0E1245A1FEC00FC51CE /* glsym_es3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = glsym_es3.h; sourceTree = ""; }; 36DFE0E3245A1FEC00FC51CE /* glsym_gl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = glsym_gl.h; sourceTree = ""; }; - 36E6378A246FFFF30032F5FB /* CryptoManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoManager.cpp; sourceTree = ""; }; 36E6378B246FFFF30032F5FB /* CryptoManager.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CryptoManager.hpp; sourceTree = ""; }; 36E6378E247010C70032F5FB /* Data.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Data.cpp; sourceTree = ""; }; 36E6378F247010C70032F5FB /* Data.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Data.hpp; sourceTree = ""; }; @@ -515,8 +517,6 @@ 3652F009245C2918001FABF3 /* client.h */, 3652F00F245C2918001FABF3 /* http.cpp */, 3652F00A245C2918001FABF3 /* http.h */, - 3652F00D245C2918001FABF3 /* mkcert.c */, - 3652F007245C2918001FABF3 /* mkcert.h */, 3652F008245C2918001FABF3 /* xml.c */, 3652F00E245C2918001FABF3 /* xml.h */, 3652F00B245C2918001FABF3 /* errors.h */, @@ -689,6 +689,7 @@ 36DBDE852450BB7E0057C8D3 = { isa = PBXGroup; children = ( + 36D461BE24709B8F00A543B4 /* build.sh */, 3602C3C0245DC7E300368900 /* Makefile */, 369445A82466CE2700786D0A /* Makefile.libnx */, 36A0C03E2461FFF10083289C /* build_opus_lakka_switch.sh */, @@ -771,10 +772,13 @@ 36E63789246FFFDC0032F5FB /* crypto */ = { isa = PBXGroup; children = ( + 36E6378B246FFFF30032F5FB /* CryptoManager.hpp */, + 363898312471B7C500F99920 /* MbedTLSCryptoManager.cpp */, + 3638982F2471B7C500F99920 /* MbedTLSCryptoManager.hpp */, + 363898302471B7C500F99920 /* OpenSSLCryptoManager.cpp */, + 363898322471B7C500F99920 /* OpenSSLCryptoManager.hpp */, 36E6378E247010C70032F5FB /* Data.cpp */, 36E6378F247010C70032F5FB /* Data.hpp */, - 36E6378A246FFFF30032F5FB /* CryptoManager.cpp */, - 36E6378B246FFFF30032F5FB /* CryptoManager.hpp */, ); path = crypto; sourceTree = ""; @@ -867,6 +871,7 @@ 36DFE0CD2459FA3F00FC51CE /* nanogui_resources.cpp in Sources */, 36DFE217245A278700FC51CE /* glsym_gl.c in Sources */, 3652F06A245C292B001FABF3 /* protocol.c in Sources */, + 363898332471B7C500F99920 /* OpenSSLCryptoManager.cpp in Sources */, 3652EFFC245B6434001FABF3 /* MainWindow.cpp in Sources */, 3652F086245C6CFC001FABF3 /* moonlight_libretro.cpp in Sources */, 3652EFD3245B3B00001FABF3 /* button.cpp in Sources */, @@ -892,6 +897,7 @@ 3652EFF6245B3CF2001FABF3 /* nanovg.c in Sources */, 3652F067245C292B001FABF3 /* packet.c in Sources */, 3661D2F92469D1940060EE24 /* FFmpegVideoDecoder.cpp in Sources */, + 363898342471B7C500F99920 /* MbedTLSCryptoManager.cpp in Sources */, 3652F072245C292B001FABF3 /* RtspConnection.c in Sources */, 3652F005245C28C6001FABF3 /* GameStreamClient.cpp in Sources */, 3652EFE8245B3B00001FABF3 /* opengl.cpp in Sources */, @@ -900,7 +906,6 @@ 3652EFF5245B3B00001FABF3 /* popupbutton.cpp in Sources */, 3652EFF0245B3B00001FABF3 /* colorwheel.cpp in Sources */, 3652F068245C292B001FABF3 /* unix.c in Sources */, - 36E6378C246FFFF30032F5FB /* CryptoManager.cpp in Sources */, 3652F07B245C292B001FABF3 /* RtspParser.c in Sources */, 3652EFCF245B3B00001FABF3 /* checkbox.cpp in Sources */, 36A0C03A2461E4C00083289C /* SettingsWindow.cpp in Sources */, @@ -925,7 +930,6 @@ 3602C3B7245D903000368900 /* HostButton.cpp in Sources */, 3652EFD0245B3B00001FABF3 /* vscrollpanel.cpp in Sources */, 3652F06D245C292B001FABF3 /* win32.c in Sources */, - 3652F012245C2919001FABF3 /* mkcert.c in Sources */, 3652F002245B6961001FABF3 /* AddHostWindow.cpp in Sources */, 3652EFF8245B4EE2001FABF3 /* Application.cpp in Sources */, 3652F07E245C292B001FABF3 /* AudioStream.c in Sources */, @@ -1031,6 +1035,7 @@ "-DHAS_POLL", "-DHAS_FCNTL", "-DHAVE_PULSE", + "-DUSE_MBEDTLS_CRYPTO", ); OTHER_LDFLAGS = ( "-lglfw3", @@ -1044,6 +1049,9 @@ "-lavdevice", "-lz", "-lopus", + "-lmbedtls", + "-lmbedx509", + "-lmbedcrypto", ); SDKROOT = macosx; }; @@ -1120,6 +1128,7 @@ "-DHAS_POLL", "-DHAS_FCNTL", "-DHAVE_PULSE", + "-DUSE_MBEDTLS_CRYPTO", ); OTHER_LDFLAGS = ( "-lglfw3", @@ -1133,6 +1142,9 @@ "-lavdevice", "-lz", "-lopus", + "-lmbedtls", + "-lmbedx509", + "-lmbedcrypto", ); SDKROOT = macosx; }; diff --git a/run.sh b/run.sh index 487532a..df0df38 100755 --- a/run.sh +++ b/run.sh @@ -1,4 +1,5 @@ #!/bin/sh +rm -fr moonlight.nro moonlight.elf moonlight.nacp make -f Makefile.libnx /opt/devkitpro/tools/bin/nxlink -s moonlight.nro diff --git a/src/GameStreamClient.cpp b/src/GameStreamClient.cpp index adb6d50..066ff04 100644 --- a/src/GameStreamClient.cpp +++ b/src/GameStreamClient.cpp @@ -15,22 +15,28 @@ static std::vector> m_tasks; #ifdef __SWITCH__ #include +static Thread thread; +static bool run = true; +void terminate_gamestream_thread() { + run = false; + threadWaitForExit(&thread); +} + static void task_loop() { - Thread thread; threadCreate( &thread, [](void* a) { - while (1) { + while (run) { std::vector> m_tasks_copy; { std::lock_guard guard(m_async_mutex); m_tasks_copy = m_tasks; m_tasks.clear(); } - + for (auto task: m_tasks_copy) { task(); } - + usleep(500'000); } }, @@ -41,7 +47,6 @@ static void task_loop() { -2 ); threadStart(&thread); - } #else static void task_loop() { diff --git a/src/crypto/CryptoManager.hpp b/src/crypto/CryptoManager.hpp index ea0ccb9..5fdce2a 100644 --- a/src/crypto/CryptoManager.hpp +++ b/src/crypto/CryptoManager.hpp @@ -1,38 +1,16 @@ #include -#include "Data.hpp" -#include "client.h" - -extern "C" { - #include "mkcert.h" -} - #pragma once -#define CERTIFICATE_FILE_NAME "client.pem" -#define P12_FILE_NAME "client.p12" -#define KEY_FILE_NAME "key.pem" +#if defined(USE_OPENSSL_CRYPTO) -class CryptoManager { -public: - static bool certs_exists(); - static bool load_certs(); - static bool generate_certs(); - - static Data read_cert_from_file(); - static Data read_p12_from_file(); - static Data read_key_from_file(); - - static Data SHA1_hash_data(Data data); - static Data SHA256_hash_data(Data data); - static Data create_AES_key_from_salt_SHA1(Data salted_pin); - static Data create_AES_key_from_salt_SHA256(Data salted_pin); - static Data aes_encrypt(Data data, Data key); - static Data aes_decrypt(Data data, Data key); - static Data pem_to_der(Data pem_cert_bytes); - static bool verify_signature(Data data, Data signature, Data cert); - static Data sign_data(Data data, Data key); - static Data get_signature_from_cert(Data cert); - static Data get_key_from_cert_key_pair(PCERT_KEY_PAIR cert_key_pair); - static Data get_p12_from_cert_key_pair(PCERT_KEY_PAIR cert_key_pair); - static Data get_cert_from_cert_key_pair(PCERT_KEY_PAIR cert_key_pair); -}; +#include "OpenSSLCryptoManager.hpp" +#define CryptoManager OpenSSLCryptoManager + +#elif defined(USE_MBEDTLS_CRYPTO) + +#include "MbedTLSCryptoManager.hpp" +#define CryptoManager MbedTLSCryptoManager + +#else +#error Select crypto! +#endif diff --git a/src/crypto/Data.cpp b/src/crypto/Data.cpp index d6ba5e5..97f7ece 100644 --- a/src/crypto/Data.cpp +++ b/src/crypto/Data.cpp @@ -5,18 +5,18 @@ Data::Data(unsigned char* bytes, size_t size) { if (bytes && size > 0) { - m_bytes = (unsigned char *)malloc(size); + m_bytes = (unsigned char *)malloc(size + 1); + m_bytes[size] = '\0'; memcpy(m_bytes, bytes, size); m_size = size; } } Data::Data(size_t capacity) { - if (capacity > 0) { - m_bytes = (unsigned char *)malloc(capacity + 1); - m_bytes[capacity] = '\0'; - m_size = capacity; - } + m_bytes = (unsigned char *)malloc(capacity + 1); + memset(m_bytes, 0, capacity + 1); + m_bytes[capacity] = '\0'; + m_size = capacity; } Data::~Data() { @@ -45,9 +45,14 @@ Data Data::append(Data other) { } Data::Data(const Data& that): Data(0) { - m_bytes = (unsigned char *)malloc(that.size()); - memcpy(m_bytes, that.bytes(), that.size()); - m_size = that.size(); + if (m_bytes) { + free(m_bytes); + } + + m_bytes = (unsigned char *)malloc(that.size() + 1); + memcpy(m_bytes, that.m_bytes, that.m_size); + m_bytes[that.m_size] = '\0'; + m_size = that.m_size; } Data& Data::operator=(const Data& that) { @@ -56,8 +61,9 @@ Data& Data::operator=(const Data& that) { free(m_bytes); } - m_bytes = (unsigned char *)malloc(that.m_size); + m_bytes = (unsigned char *)malloc(that.m_size + 1); memcpy(m_bytes, that.m_bytes, that.m_size); + m_bytes[that.m_size] = '\0'; m_size = that.m_size; } return *this; @@ -65,7 +71,12 @@ Data& Data::operator=(const Data& that) { Data Data::random_bytes(size_t size) { unsigned char* bytes = (unsigned char*)malloc(sizeof(char) * size); - arc4random_buf(bytes, size); + srand(time(NULL)); + + for (int i = 0; i < size; i++) { + bytes[i] = rand() % 255; + } + Data random_data(size); memcpy(random_data.m_bytes, bytes, size); free(bytes); @@ -81,6 +92,7 @@ Data Data::read_from_file(std::string path) { char* buffer = (char*)malloc(size); fread(buffer, 1, size, f); + Data data(buffer, size); free(buffer); fclose(f); @@ -89,6 +101,16 @@ Data Data::read_from_file(std::string path) { return Data(); } +void Data::write_to_file(std::string path) { + FILE *f = fopen(path.c_str(), "w"); + if (f) { + fwrite(m_bytes, m_size, 1, f); + fclose(f); + } else { + LOG_FMT("Path not found: %s\n", path.c_str()); + } +} + Data Data::hex_to_bytes() const { Data data(m_size / 2); char byte_chars[3] = {'\0','\0','\0'}; @@ -105,6 +127,11 @@ Data Data::hex_to_bytes() const { } Data Data::hex() const { + if (!m_size) { + char end = '\n'; + return Data(&end, 1); + } + int counter = 0; Data hex(m_size * 2); char fmt[3] = {'\0','\0','\0'}; @@ -116,9 +143,3 @@ Data Data::hex() const { hex.m_bytes[m_size * 2] = '\0'; return hex; } - -void Data::write_to_file(std::string path) { - FILE *f = fopen(path.c_str(), "w"); - fwrite(m_bytes, m_size, 1, f); - fclose(f); -} diff --git a/src/crypto/Data.hpp b/src/crypto/Data.hpp index a08f633..5285db5 100644 --- a/src/crypto/Data.hpp +++ b/src/crypto/Data.hpp @@ -27,6 +27,7 @@ public: static Data random_bytes(size_t size); static Data read_from_file(std::string path); + void write_to_file(std::string path); Data hex_to_bytes() const; Data hex() const; @@ -35,8 +36,6 @@ public: return m_size == 0; } - void write_to_file(std::string path); - private: unsigned char* m_bytes = nullptr; size_t m_size = 0; diff --git a/src/crypto/MbedTLSCryptoManager.cpp b/src/crypto/MbedTLSCryptoManager.cpp new file mode 100644 index 0000000..c5ca334 --- /dev/null +++ b/src/crypto/MbedTLSCryptoManager.cpp @@ -0,0 +1,258 @@ +#include "MbedTLSCryptoManager.hpp" +#include "Settings.hpp" +#include "client.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static Data m_cert; +static Data m_key; + +static bool _generate_new_cert_key_pair(); + +bool MbedTLSCryptoManager::load_cert_key_pair() { + if (m_key.is_empty() || m_cert.is_empty()) { + auto key_dir = Settings::settings()->working_dir() + "/key/"; + Data cert = Data::read_from_file(key_dir + CERTIFICATE_FILE_NAME); + Data key = Data::read_from_file(key_dir + KEY_FILE_NAME); + + if (!cert.is_empty() && !key.is_empty()) { + m_cert = cert; + m_key = key; + return true; + } + return false; + } + return true; +} + +bool MbedTLSCryptoManager::generate_new_cert_key_pair() { + if (_generate_new_cert_key_pair()) { + if (!m_cert.is_empty() && !m_key.is_empty()) { + auto key_dir = Settings::settings()->working_dir() + "/key/"; + mkdirtree(key_dir.c_str()); + m_cert.write_to_file(key_dir + CERTIFICATE_FILE_NAME); + m_key.write_to_file(key_dir + KEY_FILE_NAME); + return true; + } + } + return false; +} + +void MbedTLSCryptoManager::remove_cert_key_pair() { + auto key_dir = Settings::settings()->working_dir() + "/key/"; + remove((key_dir + CERTIFICATE_FILE_NAME).c_str()); + remove((key_dir + KEY_FILE_NAME).c_str()); + m_cert = Data(); + m_key = Data(); +} + +Data MbedTLSCryptoManager::cert_data() { + return m_cert; +} + +Data MbedTLSCryptoManager::key_data() { + return m_key; +} + +Data MbedTLSCryptoManager::SHA1_hash_data(Data data) { + mbedtls_sha1_context ctx; + unsigned char sha1[20]; + mbedtls_sha1_init(&ctx); + mbedtls_sha1_ret(data.bytes(), data.size(), sha1); + mbedtls_sha1_free(&ctx); + return Data(sha1, sizeof(sha1)); +} + +Data MbedTLSCryptoManager::SHA256_hash_data(Data data) { + mbedtls_sha256_context ctx; + unsigned char sha256[32]; + mbedtls_sha256_init(&ctx); + mbedtls_sha256_ret(data.bytes(), data.size(), sha256, 0); + mbedtls_sha256_free(&ctx); + return Data(sha256, sizeof(sha256)); +} + +Data MbedTLSCryptoManager::create_AES_key_from_salt_SHA1(Data salted_pin) { + return SHA1_hash_data(salted_pin).subdata(0, 16); +} + +Data MbedTLSCryptoManager::create_AES_key_from_salt_SHA256(Data salted_pin) { + return SHA256_hash_data(salted_pin).subdata(0, 16); +} + +static int get_encrypt_size(Data data) { + // the size is the length of the data ceiling to the nearest 16 bytes + return (((int)data.size() + 15) / 16) * 16; +} + +Data MbedTLSCryptoManager::aes_encrypt(Data data, Data key) { + mbedtls_aes_context ctx; + mbedtls_aes_init(&ctx); + mbedtls_aes_setkey_enc(&ctx, key.bytes(), 128); + + int size = get_encrypt_size(data); + unsigned char* buffer = (unsigned char*)malloc(size); + unsigned char* block_rounded_buffer = (unsigned char*)calloc(1, size); + memcpy(block_rounded_buffer, data.bytes(), data.size()); + + int block_offset = 0; + while (block_offset < size) { + mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, block_rounded_buffer + block_offset, buffer + block_offset); + block_offset += 16; + } + + Data encrypted_data = Data((char*)buffer, size); + mbedtls_aes_free(&ctx); + free(buffer); + free(block_rounded_buffer); + return encrypted_data; +} + +Data MbedTLSCryptoManager::aes_decrypt(Data data, Data key) { + mbedtls_aes_context ctx; + mbedtls_aes_init(&ctx); + mbedtls_aes_setkey_dec(&ctx, key.bytes(), 128); + unsigned char* buffer = (unsigned char*)malloc(data.size()); + + int block_offset = 0; + while (block_offset < data.size()) { + mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_DECRYPT, data.bytes() + block_offset, buffer + block_offset); + block_offset += 16; + } + + Data decrypted_data = Data(buffer, data.size()); + mbedtls_aes_free(&ctx); + free(buffer); + return decrypted_data; +} + +Data MbedTLSCryptoManager::signature(Data cert) { + mbedtls_x509_crt x509; + mbedtls_x509_crt_init(&x509); + + mbedtls_x509_crt_parse(&x509, cert.bytes(), cert.size() + 1); + + Data data(x509.sig.p, x509.sig.len); + mbedtls_x509_crt_free(&x509); + return data; +} + +bool MbedTLSCryptoManager::verify_signature(Data data, Data signature, Data cert) { + // TODO + return true; +} + +Data MbedTLSCryptoManager::sign_data(Data data, Data key) { + mbedtls_pk_context pk; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + + unsigned char hash[32]; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + size_t size = 0; + + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_pk_init(&pk); + mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0); + + mbedtls_pk_parse_key(&pk, key.bytes(), key.size() + 1, NULL, 0); + mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), data.bytes(), data.size(), hash); + mbedtls_pk_sign(&pk, MBEDTLS_MD_SHA256, hash, 0, buf, &size, mbedtls_ctr_drbg_random, &ctr_drbg); + + mbedtls_pk_free(&pk); + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + + if (size > 0) { + return Data(buf, size); + } + return data; +} + +// Cert and key generator + +static void _generate_key(mbedtls_pk_context* key) { + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0); + + mbedtls_pk_init(key); + + mbedtls_pk_setup(key, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); + mbedtls_rsa_gen_key(mbedtls_pk_rsa(*key), mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537); + + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); +} + +static void _generate_cert(mbedtls_x509write_cert* cert, mbedtls_pk_context* key) { + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_mpi serial; + + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0); + mbedtls_mpi_init(&serial); + mbedtls_mpi_lset(&serial, 1); + + mbedtls_x509write_crt_init(cert); + + mbedtls_x509write_crt_set_version(cert, MBEDTLS_X509_CRT_VERSION_3); + mbedtls_x509write_crt_set_subject_name(cert, "CN=NVIDIA GameStream Client"); + mbedtls_x509write_crt_set_issuer_name(cert, "CN=NVIDIA GameStream Client"); + mbedtls_x509write_crt_set_subject_key(cert, key); + mbedtls_x509write_crt_set_issuer_key(cert, key); + mbedtls_x509write_crt_set_md_alg(cert, MBEDTLS_MD_SHA256); + mbedtls_x509write_crt_set_validity(cert, "20200101000000", "20300101000000"); + mbedtls_x509write_crt_set_serial(cert, &serial); + + mbedtls_mpi_free(&serial); + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); +} + +static bool _generate_new_cert_key_pair() { + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0); + + mbedtls_x509write_cert cert; + mbedtls_pk_context key; + + _generate_key(&key); + _generate_cert(&cert, &key); + + unsigned char tmp[4096]; + memset(tmp, 0, 4096); + size_t len = 0; + int i = mbedtls_pk_write_key_pem(&key, tmp, 4096); + + len = strlen((char *)tmp); + m_key = Data(tmp, len); + memset(tmp, 0, 4096); + + i = mbedtls_x509write_crt_pem(&cert, tmp, 4096, mbedtls_ctr_drbg_random, &ctr_drbg); + len = strlen((char *)tmp); + m_cert = Data(tmp, len); + + mbedtls_x509write_crt_free(&cert); + mbedtls_pk_free(&key); + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + return true; +} diff --git a/src/crypto/MbedTLSCryptoManager.hpp b/src/crypto/MbedTLSCryptoManager.hpp new file mode 100644 index 0000000..cb606a5 --- /dev/null +++ b/src/crypto/MbedTLSCryptoManager.hpp @@ -0,0 +1,28 @@ +#include +#include "Data.hpp" + +#pragma once + +#define CERTIFICATE_FILE_NAME "client.pem" +#define KEY_FILE_NAME "key.pem" + +class MbedTLSCryptoManager { +public: + static bool load_cert_key_pair(); + static bool generate_new_cert_key_pair(); + static void remove_cert_key_pair(); + + static Data cert_data(); + static Data key_data(); + + static Data SHA1_hash_data(Data data); + static Data SHA256_hash_data(Data data); + static Data create_AES_key_from_salt_SHA1(Data salted_pin); + static Data create_AES_key_from_salt_SHA256(Data salted_pin); + static Data aes_encrypt(Data data, Data key); + static Data aes_decrypt(Data data, Data key); + + static Data signature(Data cert); + static bool verify_signature(Data data, Data signature, Data cert); + static Data sign_data(Data data, Data key); +}; diff --git a/src/crypto/CryptoManager.cpp b/src/crypto/OpenSSLCryptoManager.cpp similarity index 58% rename from src/crypto/CryptoManager.cpp rename to src/crypto/OpenSSLCryptoManager.cpp index 97431b0..672f0c4 100644 --- a/src/crypto/CryptoManager.cpp +++ b/src/crypto/OpenSSLCryptoManager.cpp @@ -1,5 +1,6 @@ -#include "CryptoManager.hpp" +#include "OpenSSLCryptoManager.hpp" #include "Settings.hpp" +#include "client.h" #include #include #include @@ -7,95 +8,80 @@ #include #include #include - +#include #include "Log.h" -static const int SHA1_HASH_LENGTH = 20; -static const int SHA256_HASH_LENGTH = 32; - static Data m_cert; -static Data m_p12; static Data m_key; -bool CryptoManager::certs_exists() { - if (load_certs()) { - return true; - } - return false; -} +static const int NUM_BITS = 2048; +static const int SERIAL = 0; +static const int NUM_YEARS = 10; -bool CryptoManager::load_certs() { - if (m_key.is_empty() || m_cert.is_empty() || m_p12.is_empty()) { +static bool _generate_new_cert_key_pair(); + +bool OpenSSLCryptoManager::load_cert_key_pair() { + if (m_key.is_empty() || m_cert.is_empty()) { auto key_dir = Settings::settings()->working_dir() + "/key/"; - mkdirtree(key_dir.c_str()); - Data cert = Data::read_from_file(key_dir + CERTIFICATE_FILE_NAME); - Data p12 = Data::read_from_file(key_dir + P12_FILE_NAME); Data key = Data::read_from_file(key_dir + KEY_FILE_NAME); - if (!cert.is_empty() && !p12.is_empty() && !key.is_empty()) { + if (!cert.is_empty() && !key.is_empty()) { m_cert = cert; - m_p12 = p12; m_key = key; return true; } - return false; } return true; } -bool CryptoManager::generate_certs() { - auto cert_key_pair = mkcert_generate(); - - Data cert = get_cert_from_cert_key_pair(&cert_key_pair); - Data p12 = get_p12_from_cert_key_pair(&cert_key_pair); - Data key = get_key_from_cert_key_pair(&cert_key_pair); - - auto key_dir = Settings::settings()->working_dir() + "/key/"; - mkdirtree(key_dir.c_str()); - - if (!cert.is_empty() && !p12.is_empty() && !key.is_empty()) { - cert.write_to_file(key_dir + CERTIFICATE_FILE_NAME); - p12.write_to_file(key_dir + P12_FILE_NAME); - key.write_to_file(key_dir + KEY_FILE_NAME); - m_cert = cert; - m_p12 = p12; - m_key = key; - return true; +bool OpenSSLCryptoManager::generate_new_cert_key_pair() { + if (_generate_new_cert_key_pair()) { + if (!m_cert.is_empty() && !m_key.is_empty()) { + auto key_dir = Settings::settings()->working_dir() + "/key/"; + mkdirtree(key_dir.c_str()); + m_cert.write_to_file(key_dir + CERTIFICATE_FILE_NAME); + m_key.write_to_file(key_dir + KEY_FILE_NAME); + return true; + } } return false; } -Data CryptoManager::read_cert_from_file() { +void OpenSSLCryptoManager::remove_cert_key_pair() { + auto key_dir = Settings::settings()->working_dir() + "/key/"; + remove((key_dir + CERTIFICATE_FILE_NAME).c_str()); + remove((key_dir + KEY_FILE_NAME).c_str()); + m_cert = Data(); + m_key = Data(); +} + +Data OpenSSLCryptoManager::cert_data() { return m_cert; } -Data CryptoManager::read_p12_from_file() { - return m_p12; -} - -Data CryptoManager::read_key_from_file() { +Data OpenSSLCryptoManager::key_data() { return m_key; } -Data CryptoManager::SHA1_hash_data(Data data) { - unsigned char sha1[SHA1_HASH_LENGTH]; +Data OpenSSLCryptoManager::SHA1_hash_data(Data data) { + unsigned char sha1[20]; SHA1(data.bytes(), data.size(), sha1); return Data(sha1, sizeof(sha1)); } -Data CryptoManager::SHA256_hash_data(Data data) { - unsigned char sha256[SHA256_HASH_LENGTH]; +Data OpenSSLCryptoManager::SHA256_hash_data(Data data) { + unsigned char sha256[32]; SHA256(data.bytes(), data.size(), sha256); return Data(sha256, sizeof(sha256)); } -Data CryptoManager::create_AES_key_from_salt_SHA1(Data salted_pin) { +Data OpenSSLCryptoManager::create_AES_key_from_salt_SHA1(Data salted_pin) { return SHA1_hash_data(salted_pin).subdata(0, 16); } -Data CryptoManager::create_AES_key_from_salt_SHA256(Data salted_pin) { +Data OpenSSLCryptoManager::create_AES_key_from_salt_SHA256(Data salted_pin) { return SHA256_hash_data(salted_pin).subdata(0, 16); } @@ -104,7 +90,7 @@ static int get_encrypt_size(Data data) { return (((int)data.size() + 15) / 16) * 16; } -Data CryptoManager::aes_encrypt(Data data, Data key) { +Data OpenSSLCryptoManager::aes_encrypt(Data data, Data key) { AES_KEY aes_key; AES_set_encrypt_key((unsigned char*)key.bytes(), 128, &aes_key); int size = get_encrypt_size(data); @@ -125,7 +111,7 @@ Data CryptoManager::aes_encrypt(Data data, Data key) { return encrypted_data; } -Data CryptoManager::aes_decrypt(Data data, Data key) { +Data OpenSSLCryptoManager::aes_decrypt(Data data, Data key) { AES_KEY aes_key; AES_set_decrypt_key(key.bytes(), 128, &aes_key); unsigned char* buffer = (unsigned char*)malloc(data.size()); @@ -142,25 +128,31 @@ Data CryptoManager::aes_decrypt(Data data, Data key) { return decrypted_data; } -Data CryptoManager::pem_to_der(Data pem_cert_bytes) { - X509* x509; +Data OpenSSLCryptoManager::signature(Data cert) { + BIO* bio = BIO_new_mem_buf(cert.bytes(), cert.size()); + X509* x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); - BIO* bio = BIO_new_mem_buf(pem_cert_bytes.bytes(), pem_cert_bytes.size()); - x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); - BIO_free(bio); + if (!x509) { + LOG("Unable to parse certificate in memory!\n"); + return Data(); + } - bio = BIO_new(BIO_s_mem()); - i2d_X509_bio(bio, x509); +#if (OPENSSL_VERSION_NUMBER < 0x10002000L) + ASN1_BIT_STRING *asn_signature = x509->signature; +#elif (OPENSSL_VERSION_NUMBER < 0x10100000L) + ASN1_BIT_STRING *asn_signature; + X509_get0_signature(&asn_signature, NULL, x509); +#else + const ASN1_BIT_STRING *asn_signature; + X509_get0_signature(&asn_signature, NULL, x509); +#endif - BUF_MEM* mem; - BIO_get_mem_ptr(bio, &mem); - - Data ret = Data(mem->data, mem->length); - BIO_free(bio); - return ret; + Data sig = Data(asn_signature->data, asn_signature->length); + X509_free(x509); + return sig; } -bool CryptoManager::verify_signature(Data data, Data signature, Data cert) { +bool OpenSSLCryptoManager::verify_signature(Data data, Data signature, Data cert) { BIO* bio = BIO_new_mem_buf(cert.bytes(), cert.size()); X509* x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); @@ -184,14 +176,14 @@ bool CryptoManager::verify_signature(Data data, Data signature, Data cert) { return result > 0; } -Data CryptoManager::sign_data(Data data, Data key) { +Data OpenSSLCryptoManager::sign_data(Data data, Data key) { BIO* bio = BIO_new_mem_buf(key.bytes(), key.size()); EVP_PKEY* pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); BIO_free(bio); if (!pkey) { - LOG("Unable to parse private key in memory!"); + LOG("Unable to parse private key in memory...\n"); return Data(); } @@ -208,8 +200,8 @@ Data CryptoManager::sign_data(Data data, Data key) { if (result <= 0) { free(signature); - LOG("Unable to sign data!"); - exit(-1); + LOG("Unable to sign data...\n"); + Data(); } Data signed_data = Data(signature, slen); @@ -217,37 +209,27 @@ Data CryptoManager::sign_data(Data data, Data key) { return signed_data; } -Data CryptoManager::get_signature_from_cert(Data cert) { - BIO* bio = BIO_new_mem_buf(cert.bytes(), cert.size()); - X509* x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); +// Cert and key generator + +static Data _cert_data(X509* cert) { + BIO* bio = BIO_new(BIO_s_mem()); - if (!x509) { - LOG("Unable to parse certificate in memory!\n"); - exit(-1); - } + PEM_write_bio_X509(bio, cert); -#if (OPENSSL_VERSION_NUMBER < 0x10002000L) - ASN1_BIT_STRING *asn_signature = x509->signature; -#elif (OPENSSL_VERSION_NUMBER < 0x10100000L) - ASN1_BIT_STRING *asn_signature; - X509_get0_signature(&asn_signature, NULL, x509); -#else - const ASN1_BIT_STRING *asn_signature; - X509_get0_signature(&asn_signature, NULL, x509); -#endif - - Data sig = Data(asn_signature->data, asn_signature->length); - X509_free(x509); - return sig; + BUF_MEM* mem; + BIO_get_mem_ptr(bio, &mem); + Data data = Data(mem->data, mem->length); + BIO_free(bio); + return data; } -Data CryptoManager::get_key_from_cert_key_pair(PCERT_KEY_PAIR cert_key_pair) { +static Data _key_data(EVP_PKEY* pk) { BIO* bio = BIO_new(BIO_s_mem()); #if (OPENSSL_VERSION_NUMBER < 0x10100000L) - PEM_write_bio_PrivateKey(bio, cert_key_pair->pkey, NULL, NULL, 0, NULL, NULL); + PEM_write_bio_PrivateKey(bio, pk, NULL, NULL, 0, NULL, NULL); #else - PEM_write_bio_PrivateKey_traditional(bio, cert_key_pair->pkey, NULL, NULL, 0, NULL, NULL); + PEM_write_bio_PrivateKey_traditional(bio, pk, NULL, NULL, 0, NULL, NULL); #endif BUF_MEM* mem; @@ -257,26 +239,55 @@ Data CryptoManager::get_key_from_cert_key_pair(PCERT_KEY_PAIR cert_key_pair) { return data; } -Data CryptoManager::get_p12_from_cert_key_pair(PCERT_KEY_PAIR cert_key_pair) { - BIO* bio = BIO_new(BIO_s_mem()); +static bool _generate_new_cert_key_pair() { + CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); + BIO *bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); - i2d_PKCS12_bio(bio, cert_key_pair->p12); + X509* cert = X509_new(); + EVP_PKEY* pk = EVP_PKEY_new(); + BIGNUM* bne = BN_new(); + RSA* rsa = RSA_new(); - BUF_MEM* mem; - BIO_get_mem_ptr(bio, &mem); - Data data = Data(mem->data, mem->length); - BIO_free(bio); - return data; -} - -Data CryptoManager::get_cert_from_cert_key_pair(PCERT_KEY_PAIR cert_key_pair) { - BIO* bio = BIO_new(BIO_s_mem()); - - PEM_write_bio_X509(bio, cert_key_pair->x509); - - BUF_MEM* mem; - BIO_get_mem_ptr(bio, &mem); - Data data = Data(mem->data, mem->length); - BIO_free(bio); - return data; + BN_set_word(bne, RSA_F4); + RSA_generate_key_ex(rsa, NUM_BITS, bne, NULL); + + EVP_PKEY_assign_RSA(pk, rsa); + + X509_set_version(cert, 2); + ASN1_INTEGER_set(X509_get_serialNumber(cert), SERIAL); +#if OPENSSL_VERSION_NUMBER < 0x10100000L + X509_gmtime_adj(X509_get_notBefore(cert), 0); + X509_gmtime_adj(X509_get_notAfter(cert), 60 * 60 * 24 * 365 * NUM_YEARS); +#else + ASN1_TIME* before = ASN1_STRING_dup(X509_get0_notBefore(cert)); + ASN1_TIME* after = ASN1_STRING_dup(X509_get0_notAfter(cert)); + + X509_gmtime_adj(before, 0); + X509_gmtime_adj(after, 60 * 60 * 24 * 365 * NUM_YEARS); + + X509_set1_notBefore(cert, before); + X509_set1_notAfter(cert, after); + + ASN1_STRING_free(before); + ASN1_STRING_free(after); +#endif + + X509_set_pubkey(cert, pk); + + X509_NAME* name = X509_get_subject_name(cert); + X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (const unsigned char*)"NVIDIA GameStream Client", -1, -1, 0); + X509_set_issuer_name(cert, name); + + X509_sign(cert, pk, EVP_sha256()); + + BN_free(bne); + + BIO_free(bio_err); + + m_cert = _cert_data(cert); + m_key = _key_data(pk); + + X509_free(cert); + EVP_PKEY_free(pk); + return true; } diff --git a/src/crypto/OpenSSLCryptoManager.hpp b/src/crypto/OpenSSLCryptoManager.hpp new file mode 100644 index 0000000..ee757f2 --- /dev/null +++ b/src/crypto/OpenSSLCryptoManager.hpp @@ -0,0 +1,28 @@ +#include +#include "Data.hpp" + +#pragma once + +#define CERTIFICATE_FILE_NAME "client.pem" +#define KEY_FILE_NAME "key.pem" + +class OpenSSLCryptoManager { +public: + static bool load_cert_key_pair(); + static bool generate_new_cert_key_pair(); + static void remove_cert_key_pair(); + + static Data cert_data(); + static Data key_data(); + + static Data SHA1_hash_data(Data data); + static Data SHA256_hash_data(Data data); + static Data create_AES_key_from_salt_SHA1(Data salted_pin); + static Data create_AES_key_from_salt_SHA256(Data salted_pin); + static Data aes_encrypt(Data data, Data key); + static Data aes_decrypt(Data data, Data key); + + static Data signature(Data cert); + static bool verify_signature(Data data, Data signature, Data cert); + static Data sign_data(Data data, Data key); +}; diff --git a/src/moonlight_glfw.cpp b/src/moonlight_glfw.cpp index 30a7e8f..bdd333a 100644 --- a/src/moonlight_glfw.cpp +++ b/src/moonlight_glfw.cpp @@ -5,8 +5,6 @@ #include "Limelight.h" #include "libretro.h" #include "InputController.hpp" -#include -#include #ifdef __SWITCH__ #include @@ -55,12 +53,11 @@ static int16_t glfw_input_state_cb(unsigned port, unsigned device, unsigned inde return 0; } +#include "CryptoManager.hpp" + int main(int argc, const char * argv[]) { input_state_cb = glfw_input_state_cb; - OpenSSL_add_all_algorithms(); - curl_global_init(CURL_GLOBAL_ALL); - glfwInit(); glfwSetErrorCallback([](int i, const char *error) { @@ -140,6 +137,12 @@ int main(int argc, const char * argv[]) { glfwSwapBuffers(window); } + + #ifdef __SWITCH__ + extern void terminate_gamestream_thread(); + terminate_gamestream_thread(); + #endif + //nanogui::shutdown(); glfwTerminate(); return 0; } diff --git a/src/moonlight_libnx.c b/src/moonlight_libnx.c index c1d7ae3..8aec342 100644 --- a/src/moonlight_libnx.c +++ b/src/moonlight_libnx.c @@ -22,6 +22,22 @@ uint16_t ntohs(uint16_t netshort) { return __builtin_bswap16(netshort); } +uid_t getuid() { + return 1; +} + +uid_t geteuid() { + return 1; +} + +gid_t getgid(void) { + return 1; +} + +gid_t getegid(void) { + return 1; +} + int sigaction(int a, const struct sigaction* b, struct sigaction* c) { return 0; }