Reimplemet CryptoManager for use mbedtls, other fixes...

This commit is contained in:
rock88 2020-05-18 21:19:46 +03:00
parent 246f4abd4d
commit d12e1090f8
18 changed files with 594 additions and 381 deletions

View file

@ -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)/*.*)))

View file

@ -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;

View file

@ -19,6 +19,8 @@
#include "http.h"
#include "errors.h"
#include "CryptoManager.hpp"
#include "Log.h"
#include <stdbool.h>
#include <string.h>
@ -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;
}

View file

@ -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);

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "mkcert.h"
#include <stdio.h>
#include <stdlib.h>
#include <openssl/crypto.h>
#include <openssl/pem.h>
#include <openssl/conf.h>
#include <openssl/pkcs12.h>
#include <openssl/bio.h>
#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
#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;
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <openssl/x509v3.h>
#include <openssl/pkcs12.h>
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);

View file

@ -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 = "<group>"; };
3603E93A246316400051287D /* InputController.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InputController.cpp; sourceTree = "<group>"; };
3603E93B246316400051287D /* InputController.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = InputController.hpp; sourceTree = "<group>"; };
3638982F2471B7C500F99920 /* MbedTLSCryptoManager.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MbedTLSCryptoManager.hpp; sourceTree = "<group>"; };
363898302471B7C500F99920 /* OpenSSLCryptoManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OpenSSLCryptoManager.cpp; sourceTree = "<group>"; };
363898312471B7C500F99920 /* MbedTLSCryptoManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MbedTLSCryptoManager.cpp; sourceTree = "<group>"; };
363898322471B7C500F99920 /* OpenSSLCryptoManager.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = OpenSSLCryptoManager.hpp; sourceTree = "<group>"; };
3652ECE8245B3AFF001FABF3 /* colorpicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = colorpicker.h; sourceTree = "<group>"; };
3652ECE9245B3AFF001FABF3 /* renderpass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = renderpass.h; sourceTree = "<group>"; };
3652ECEA245B3AFF001FABF3 /* theme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = theme.h; sourceTree = "<group>"; };
@ -212,13 +216,11 @@
3652F001245B6961001FABF3 /* AddHostWindow.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AddHostWindow.hpp; sourceTree = "<group>"; };
3652F003245C28C6001FABF3 /* GameStreamClient.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GameStreamClient.cpp; sourceTree = "<group>"; };
3652F004245C28C6001FABF3 /* GameStreamClient.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = GameStreamClient.hpp; sourceTree = "<group>"; };
3652F007245C2918001FABF3 /* mkcert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mkcert.h; sourceTree = "<group>"; };
3652F008245C2918001FABF3 /* xml.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xml.c; sourceTree = "<group>"; };
3652F009245C2918001FABF3 /* client.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = client.h; sourceTree = "<group>"; };
3652F00A245C2918001FABF3 /* http.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = http.h; sourceTree = "<group>"; };
3652F00B245C2918001FABF3 /* errors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = errors.h; sourceTree = "<group>"; };
3652F00C245C2918001FABF3 /* client.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = client.cpp; sourceTree = "<group>"; };
3652F00D245C2918001FABF3 /* mkcert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mkcert.c; sourceTree = "<group>"; };
3652F00E245C2918001FABF3 /* xml.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xml.h; sourceTree = "<group>"; };
3652F00F245C2918001FABF3 /* http.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = http.cpp; sourceTree = "<group>"; };
3652F017245C292B001FABF3 /* list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = list.c; sourceTree = "<group>"; };
@ -301,6 +303,7 @@
36D3F8432469B5C400CDEF9B /* MoonlightSession.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MoonlightSession.hpp; sourceTree = "<group>"; };
36D3F8452469C6BC00CDEF9B /* Log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Log.h; sourceTree = "<group>"; };
36D3F8492469CC2600CDEF9B /* IAudioRenderer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = IAudioRenderer.hpp; sourceTree = "<group>"; };
36D461BE24709B8F00A543B4 /* build.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = build.sh; path = "../../../../Downloads/openssl-1.1.1g/build.sh"; sourceTree = "<group>"; };
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 = "<group>"; };
36DFE0E1245A1FEC00FC51CE /* glsym_es3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = glsym_es3.h; sourceTree = "<group>"; };
36DFE0E3245A1FEC00FC51CE /* glsym_gl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = glsym_gl.h; sourceTree = "<group>"; };
36E6378A246FFFF30032F5FB /* CryptoManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoManager.cpp; sourceTree = "<group>"; };
36E6378B246FFFF30032F5FB /* CryptoManager.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CryptoManager.hpp; sourceTree = "<group>"; };
36E6378E247010C70032F5FB /* Data.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Data.cpp; sourceTree = "<group>"; };
36E6378F247010C70032F5FB /* Data.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Data.hpp; sourceTree = "<group>"; };
@ -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 = "<group>";
@ -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;
};

1
run.sh
View file

@ -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

View file

@ -15,12 +15,18 @@ static std::vector<std::function<void()>> m_tasks;
#ifdef __SWITCH__
#include <switch.h>
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<std::function<void()>> m_tasks_copy; {
std::lock_guard<std::mutex> guard(m_async_mutex);
m_tasks_copy = m_tasks;
@ -41,7 +47,6 @@ static void task_loop() {
-2
);
threadStart(&thread);
}
#else
static void task_loop() {

View file

@ -1,38 +1,16 @@
#include <stdio.h>
#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();
#include "OpenSSLCryptoManager.hpp"
#define CryptoManager OpenSSLCryptoManager
static Data read_cert_from_file();
static Data read_p12_from_file();
static Data read_key_from_file();
#elif defined(USE_MBEDTLS_CRYPTO)
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 "MbedTLSCryptoManager.hpp"
#define CryptoManager MbedTLSCryptoManager
#else
#error Select crypto!
#endif

View file

@ -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);
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);
}

View file

@ -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;

View file

@ -0,0 +1,258 @@
#include "MbedTLSCryptoManager.hpp"
#include "Settings.hpp"
#include "client.h"
#include <string.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#include <mbedtls/aes.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/x509.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/error.h>
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;
}

View file

@ -0,0 +1,28 @@
#include <stdio.h>
#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);
};

View file

@ -1,5 +1,6 @@
#include "CryptoManager.hpp"
#include "OpenSSLCryptoManager.hpp"
#include "Settings.hpp"
#include "client.h"
#include <string.h>
#include <cstdlib>
#include <openssl/aes.h>
@ -7,95 +8,80 @@
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/pkcs12.h>
#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);
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());
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;
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
if (!x509) {
LOG("Unable to parse certificate in memory!\n");
exit(-1);
}
static Data _cert_data(X509* cert) {
BIO* bio = BIO_new(BIO_s_mem());
#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
PEM_write_bio_X509(bio, cert);
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;
}

View file

@ -0,0 +1,28 @@
#include <stdio.h>
#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);
};

View file

@ -5,8 +5,6 @@
#include "Limelight.h"
#include "libretro.h"
#include "InputController.hpp"
#include <curl/curl.h>
#include <openssl/ssl.h>
#ifdef __SWITCH__
#include <glad/glad.h>
@ -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;
}

View file

@ -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;
}