From fbae7f88b51cc63b973282a84e34d346259006e5 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 22 Dec 2018 00:05:48 -0800 Subject: [PATCH] Add server cert pinning after pairing --- Limelight/Crypto/CryptoManager.h | 2 +- Limelight/Crypto/CryptoManager.m | 36 +++++++----- Limelight/Database/TemporaryHost.h | 12 ++-- Limelight/Database/TemporaryHost.m | 4 ++ .../Limelight.xcdatamodeld/.xccurrentversion | 2 +- .../Moonlight v1.3.xcdatamodel/contents | 40 +++++++++++++ Limelight/Network/AppAssetRetriever.m | 2 +- Limelight/Network/ConnectionHelper.h | 2 +- Limelight/Network/ConnectionHelper.m | 4 +- Limelight/Network/DiscoveryManager.m | 4 +- Limelight/Network/DiscoveryWorker.h | 2 +- Limelight/Network/DiscoveryWorker.m | 11 ++-- Limelight/Network/HttpManager.h | 4 +- Limelight/Network/HttpManager.m | 56 ++++++++++++++----- Limelight/Network/PairManager.h | 4 +- Limelight/Network/PairManager.m | 13 +++-- Limelight/Stream/StreamConfiguration.h | 1 + Limelight/Stream/StreamConfiguration.m | 2 +- Limelight/Stream/StreamManager.m | 4 +- .../ViewControllers/MainFrameViewController.m | 20 ++++--- Moonlight.xcodeproj/project.pbxproj | 4 +- 21 files changed, 157 insertions(+), 72 deletions(-) create mode 100644 Limelight/Limelight.xcdatamodeld/Moonlight v1.3.xcdatamodel/contents diff --git a/Limelight/Crypto/CryptoManager.h b/Limelight/Crypto/CryptoManager.h index 6e84804..b1fc76d 100644 --- a/Limelight/Crypto/CryptoManager.h +++ b/Limelight/Crypto/CryptoManager.h @@ -13,7 +13,7 @@ + (NSData*) readKeyFromFile; + (NSData*) readP12FromFile; + (NSData*) getSignatureFromCert:(NSData*)cert; -+ (NSData*) nullTerminateString:(NSData*)data; ++ (NSData*) pemToDer:(NSData*)pemCertBytes; - (NSData*) createAESKeyFromSaltSHA1:(NSData*)saltedPIN; - (NSData*) createAESKeyFromSaltSHA256:(NSData*)saltedPIN; diff --git a/Limelight/Crypto/CryptoManager.m b/Limelight/Crypto/CryptoManager.m index 5e5367e..9f7c5db 100644 --- a/Limelight/Crypto/CryptoManager.m +++ b/Limelight/Crypto/CryptoManager.m @@ -87,17 +87,28 @@ static NSData* p12 = nil; return (((int)[data length] + 15) / 16) * 16; } -+ (NSData*) nullTerminateString:(NSData*)data { - NSMutableData* mutData = [NSMutableData dataWithData:data]; - [mutData appendBytes:"" length:1]; - return mutData; ++ (NSData*) pemToDer:(NSData*)pemCertBytes { + X509* x509; + + BIO* bio = BIO_new_mem_buf([pemCertBytes bytes], (int)[pemCertBytes length]); + x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); + BIO_free(bio); + + bio = BIO_new(BIO_s_mem()); + i2d_X509_bio(bio, x509); + + BUF_MEM* mem; + BIO_get_mem_ptr(bio, &mem); + + NSData* ret = [[NSData alloc] initWithBytes:mem->data length:mem->length]; + BIO_free(bio); + + return ret; } - (bool) verifySignature:(NSData *)data withSignature:(NSData*)signature andCert:(NSData*)cert { - const char* buffer = [[CryptoManager nullTerminateString:cert] bytes]; X509* x509; - BIO* bio = BIO_new(BIO_s_mem()); - BIO_puts(bio, buffer); + BIO* bio = BIO_new_mem_buf([cert bytes], (int)[cert length]); x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); BIO_free(bio); @@ -122,9 +133,7 @@ static NSData* p12 = nil; } - (NSData *)signData:(NSData *)data withKey:(NSData *)key { - const char* buffer = [[CryptoManager nullTerminateString:key] bytes]; - BIO* bio = BIO_new(BIO_s_mem()); - BIO_puts(bio, buffer); + BIO* bio = BIO_new_mem_buf([key bytes], (int)[key length]); EVP_PKEY* pkey; pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); @@ -211,11 +220,8 @@ static NSData* p12 = nil; } + (NSData *)getSignatureFromCert:(NSData *)cert { - const char* buffer = [[CryptoManager nullTerminateString:cert] bytes]; - X509* x509; - BIO* bio = BIO_new(BIO_s_mem()); - BIO_puts(bio, buffer); - x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); + BIO* bio = BIO_new_mem_buf([cert bytes], (int)[cert length]); + X509* x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); if (!x509) { Log(LOG_E, @"Unable to parse certificate in memory!"); diff --git a/Limelight/Database/TemporaryHost.h b/Limelight/Database/TemporaryHost.h index 6062cda..f029427 100644 --- a/Limelight/Database/TemporaryHost.h +++ b/Limelight/Database/TemporaryHost.h @@ -16,15 +16,17 @@ @property (nonatomic, nullable) NSString * activeAddress; @property (nonatomic, nullable) NSString * currentGame; +@property (nonatomic, nullable, retain) NSData *serverCert; +@property (nonatomic, nullable, retain) NSString *address; +@property (nonatomic, nullable, retain) NSString *externalAddress; +@property (nonatomic, nullable, retain) NSString *localAddress; +@property (nonatomic, nullable, retain) NSString *mac; +@property (nonatomic) int serverCodecModeSupport; + NS_ASSUME_NONNULL_BEGIN -@property (nonatomic, retain) NSString *address; -@property (nonatomic, retain) NSString *externalAddress; -@property (nonatomic, retain) NSString *localAddress; -@property (nonatomic, retain) NSString *mac; @property (nonatomic, retain) NSString *name; @property (nonatomic, retain) NSString *uuid; -@property (nonatomic) int serverCodecModeSupport; @property (nonatomic, retain) NSMutableSet *appList; - (id) initFromHost:(Host*)host; diff --git a/Limelight/Database/TemporaryHost.m b/Limelight/Database/TemporaryHost.m index c8d6ccb..4b9988f 100644 --- a/Limelight/Database/TemporaryHost.m +++ b/Limelight/Database/TemporaryHost.m @@ -31,6 +31,7 @@ self.uuid = host.uuid; self.pairState = [host.pairState intValue]; self.serverCodecModeSupport = host.serverCodecModeSupport; + self.serverCert = host.serverCert; NSMutableSet *appList = [[NSMutableSet alloc] init]; @@ -60,6 +61,9 @@ if (self.mac != nil) { parentHost.mac = self.mac; } + if (self.serverCert != nil) { + parentHost.serverCert = self.serverCert; + } parentHost.name = self.name; parentHost.uuid = self.uuid; parentHost.serverCodecModeSupport = self.serverCodecModeSupport; diff --git a/Limelight/Limelight.xcdatamodeld/.xccurrentversion b/Limelight/Limelight.xcdatamodeld/.xccurrentversion index 3bc8a00..fe08733 100644 --- a/Limelight/Limelight.xcdatamodeld/.xccurrentversion +++ b/Limelight/Limelight.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - Moonlight v1.2.xcdatamodel + Moonlight v1.3.xcdatamodel diff --git a/Limelight/Limelight.xcdatamodeld/Moonlight v1.3.xcdatamodel/contents b/Limelight/Limelight.xcdatamodeld/Moonlight v1.3.xcdatamodel/contents new file mode 100644 index 0000000..9eee4f1 --- /dev/null +++ b/Limelight/Limelight.xcdatamodeld/Moonlight v1.3.xcdatamodel/contents @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Limelight/Network/AppAssetRetriever.m b/Limelight/Network/AppAssetRetriever.m index 30dce85..6888383 100644 --- a/Limelight/Network/AppAssetRetriever.m +++ b/Limelight/Network/AppAssetRetriever.m @@ -20,7 +20,7 @@ static const int MAX_ATTEMPTS = 5; - (void) main { int attempts = 0; while (![self isCancelled] && attempts++ < MAX_ATTEMPTS) { - HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.activeAddress uniqueId:[IdManager getUniqueId] deviceName:deviceName cert:[CryptoManager readCertFromFile]]; + HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.activeAddress uniqueId:[IdManager getUniqueId] serverCert:_host.serverCert]; AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init]; [hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.id]]]; diff --git a/Limelight/Network/ConnectionHelper.h b/Limelight/Network/ConnectionHelper.h index 65cc0d3..52fa67b 100644 --- a/Limelight/Network/ConnectionHelper.h +++ b/Limelight/Network/ConnectionHelper.h @@ -14,7 +14,7 @@ @interface ConnectionHelper : NSObject -+(AppListResponse*) getAppListForHostWithHostIP:(NSString*) hostIP deviceName:(NSString*)deviceName cert:(NSData*) cert uniqueID:(NSString*) uniqueId; ++(AppListResponse*) getAppListForHostWithHostIP:(NSString*) hostIP serverCert:(NSData*) serverCert uniqueID:(NSString*) uniqueId; @end diff --git a/Limelight/Network/ConnectionHelper.m b/Limelight/Network/ConnectionHelper.m index 83cc3bf..bb41539 100644 --- a/Limelight/Network/ConnectionHelper.m +++ b/Limelight/Network/ConnectionHelper.m @@ -14,8 +14,8 @@ @implementation ConnectionHelper -+(AppListResponse*) getAppListForHostWithHostIP:(NSString*) hostIP deviceName:(NSString*)deviceName cert:(NSData*) cert uniqueID:(NSString*) uniqueId { - HttpManager* hMan = [[HttpManager alloc] initWithHost:hostIP uniqueId:uniqueId deviceName:deviceName cert:cert]; ++(AppListResponse*) getAppListForHostWithHostIP:(NSString*) hostIP serverCert:(NSData*) cert uniqueID:(NSString*) uniqueId { + HttpManager* hMan = [[HttpManager alloc] initWithHost:hostIP uniqueId:uniqueId serverCert:cert]; // Try up to 5 times to get the app list AppListResponse* appListResp; diff --git a/Limelight/Network/DiscoveryManager.m b/Limelight/Network/DiscoveryManager.m index bc1cf41..ad19273 100644 --- a/Limelight/Network/DiscoveryManager.m +++ b/Limelight/Network/DiscoveryManager.m @@ -48,7 +48,7 @@ } - (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(TemporaryHost *, NSString*))callback { - HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert]; + HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddress uniqueId:_uniqueId serverCert:nil]; ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init]; [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest:false] fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]]; @@ -183,7 +183,7 @@ } - (NSOperation*) createWorkerForHost:(TemporaryHost*)host { - DiscoveryWorker* worker = [[DiscoveryWorker alloc] initWithHost:host uniqueId:_uniqueId cert:_cert]; + DiscoveryWorker* worker = [[DiscoveryWorker alloc] initWithHost:host uniqueId:_uniqueId]; return worker; } diff --git a/Limelight/Network/DiscoveryWorker.h b/Limelight/Network/DiscoveryWorker.h index 40c4711..da6491d 100644 --- a/Limelight/Network/DiscoveryWorker.h +++ b/Limelight/Network/DiscoveryWorker.h @@ -10,7 +10,7 @@ @interface DiscoveryWorker : NSOperation -- (id) initWithHost:(TemporaryHost*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert; +- (id) initWithHost:(TemporaryHost*)host uniqueId:(NSString*)uniqueId; - (void) discoverHost; - (TemporaryHost*) getHost; diff --git a/Limelight/Network/DiscoveryWorker.m b/Limelight/Network/DiscoveryWorker.m index 1a2e00f..9095146 100644 --- a/Limelight/Network/DiscoveryWorker.m +++ b/Limelight/Network/DiscoveryWorker.m @@ -16,16 +16,14 @@ @implementation DiscoveryWorker { TemporaryHost* _host; NSString* _uniqueId; - NSData* _cert; } static const float POLL_RATE = 2.0f; // Poll every 2 seconds -- (id) initWithHost:(TemporaryHost*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert { +- (id) initWithHost:(TemporaryHost*)host uniqueId:(NSString*)uniqueId { self = [super init]; _host = host; _uniqueId = uniqueId; - _cert = cert; return self; } @@ -98,7 +96,7 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds return; } - ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:address]; + ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:address cert:_host.serverCert]; receivedResponse = [self checkResponse:serverInfoResp]; if (receivedResponse) { [serverInfoResp populateHost:_host]; @@ -123,11 +121,10 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds } } -- (ServerInfoResponse*) requestInfoAtAddress:(NSString*)address { +- (ServerInfoResponse*) requestInfoAtAddress:(NSString*)address cert:(NSData*)cert { HttpManager* hMan = [[HttpManager alloc] initWithHost:address uniqueId:_uniqueId - deviceName:deviceName - cert:_cert]; + serverCert:cert]; ServerInfoResponse* response = [[ServerInfoResponse alloc] init]; [hMan executeRequestSynchronously:[HttpRequest requestForResponse:response withUrlRequest:[hMan newServerInfoRequest:true] diff --git a/Limelight/Network/HttpManager.h b/Limelight/Network/HttpManager.h index 3299c38..8328ded 100644 --- a/Limelight/Network/HttpManager.h +++ b/Limelight/Network/HttpManager.h @@ -12,8 +12,8 @@ @interface HttpManager : NSObject -- (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert; -- (NSURLRequest*) newPairRequest:(NSData*)salt; +- (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId serverCert:(NSData*) serverCert; +- (NSURLRequest*) newPairRequest:(NSData*)salt clientCert:(NSData*)clientCert; - (NSURLRequest*) newUnpairRequest; - (NSURLRequest*) newChallengeRequest:(NSData*)challenge; - (NSURLRequest*) newChallengeRespRequest:(NSData*)challengeResp; diff --git a/Limelight/Network/HttpManager.m b/Limelight/Network/HttpManager.m index eca8387..6f679cc 100644 --- a/Limelight/Network/HttpManager.m +++ b/Limelight/Network/HttpManager.m @@ -25,12 +25,12 @@ NSString* _baseHTTPSURL; NSString* _uniqueId; NSString* _deviceName; - NSData* _cert; + NSData* _serverCert; NSMutableData* _respData; NSData* _requestResp; dispatch_semaphore_t _requestLock; - BOOL _errorOccurred; + NSError* _error; } static const NSString* HTTP_PORT = @"47989"; @@ -43,11 +43,11 @@ static const NSString* HTTPS_PORT = @"47984"; return [xmlString dataUsingEncoding:NSUTF8StringEncoding]; } -- (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert { +- (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId serverCert:(NSData*) serverCert { self = [super init]; _uniqueId = uniqueId; _deviceName = deviceName; - _cert = cert; + _serverCert = serverCert; _requestLock = dispatch_semaphore_create(0); _respData = [[NSMutableData alloc] init]; NSURLSessionConfiguration* config = [NSURLSessionConfiguration ephemeralSessionConfiguration]; @@ -68,13 +68,15 @@ static const NSString* HTTPS_PORT = @"47984"; } - (void) executeRequestSynchronously:(HttpRequest*)request { - Log(LOG_D, @"Making Request: %@", request); [_respData setLength:0]; + _error = nil; + + Log(LOG_D, @"Making Request: %@", request); [[_urlSession dataTaskWithRequest:request.request completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error) { if (error != NULL) { Log(LOG_D, @"Connection error: %@", error); - self->_errorOccurred = true; + self->_error = error; } else { Log(LOG_D, @"Received response: %@", response); @@ -94,7 +96,7 @@ static const NSString* HTTPS_PORT = @"47984"; }] resume]; dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER); - if (!_errorOccurred && request.response) { + if (!_error && request.response) { [request.response populateWithData:_requestResp]; // If the fallback error code was detected, issue the fallback request @@ -106,7 +108,15 @@ static const NSString* HTTPS_PORT = @"47984"; [self executeRequestSynchronously:request]; } } - _errorOccurred = false; + else if (_error && [_error code] == NSURLErrorServerCertificateUntrusted && request.fallbackRequest) { + // This will fall back to HTTP on serverinfo queries to allow us to pair again + // and get the server cert updated. + Log(LOG_D, @"Attempting fallback request after certificate trust failure"); + request.request = request.fallbackRequest; + request.fallbackError = 0; + request.fallbackRequest = NULL; + [self executeRequestSynchronously:request]; + } } - (NSURLRequest*) createRequestFromString:(NSString*) urlString timeout:(int)timeout { @@ -116,9 +126,9 @@ static const NSString* HTTPS_PORT = @"47984"; return request; } -- (NSURLRequest*) newPairRequest:(NSData*)salt { +- (NSURLRequest*) newPairRequest:(NSData*)salt clientCert:(NSData*)clientCert { NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=getservercert&salt=%@&clientcert=%@", - _baseHTTPSURL, _uniqueId, _deviceName, [self bytesToHex:salt], [self bytesToHex:_cert]]; + _baseHTTPURL, _uniqueId, _deviceName, [self bytesToHex:salt], [self bytesToHex:clientCert]]; // This call blocks while waiting for the user to input the PIN on the PC return [self createRequestFromString:urlString timeout:EXTRA_LONG_TIMEOUT_SEC]; } @@ -130,18 +140,18 @@ static const NSString* HTTPS_PORT = @"47984"; - (NSURLRequest*) newChallengeRequest:(NSData*)challenge { NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientchallenge=%@", - _baseHTTPSURL, _uniqueId, _deviceName, [self bytesToHex:challenge]]; + _baseHTTPURL, _uniqueId, _deviceName, [self bytesToHex:challenge]]; return [self createRequestFromString:urlString timeout:NORMAL_TIMEOUT_SEC]; } - (NSURLRequest*) newChallengeRespRequest:(NSData*)challengeResp { NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&serverchallengeresp=%@", - _baseHTTPSURL, _uniqueId, _deviceName, [self bytesToHex:challengeResp]]; + _baseHTTPURL, _uniqueId, _deviceName, [self bytesToHex:challengeResp]]; return [self createRequestFromString:urlString timeout:NORMAL_TIMEOUT_SEC]; } - (NSURLRequest*) newClientSecretRespRequest:(NSString*)clientPairSecret { - NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientpairingsecret=%@", _baseHTTPSURL, _uniqueId, _deviceName, clientPairSecret]; + NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientpairingsecret=%@", _baseHTTPURL, _uniqueId, _deviceName, clientPairSecret]; return [self createRequestFromString:urlString timeout:NORMAL_TIMEOUT_SEC]; } @@ -249,6 +259,26 @@ static const NSString* HTTPS_PORT = @"47984"; // Allow untrusted server certificates if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + if (_serverCert) { + SecCertificateRef actualCert = SecTrustGetCertificateAtIndex(challenge.protectionSpace.serverTrust, 0); + + CFDataRef actualCertData; + + actualCertData = SecCertificateCopyData(actualCert); + + if (!CFEqual(actualCertData, (__bridge CFDataRef)_serverCert)) { + Log(LOG_E, @"Server certificate mismatch"); + CFRelease(actualCertData); + completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, NULL); + return; + } + + CFRelease(actualCertData); + + // Fall-through to TLS success + } + + // Allow TLS handshake to proceed completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust]); } diff --git a/Limelight/Network/PairManager.h b/Limelight/Network/PairManager.h index bf1e84f..c137ff4 100644 --- a/Limelight/Network/PairManager.h +++ b/Limelight/Network/PairManager.h @@ -11,14 +11,14 @@ @protocol PairCallback - (void) showPIN:(NSString*)PIN; -- (void) pairSuccessful; +- (void) pairSuccessful:(NSData*)serverCert; - (void) pairFailed:(NSString*)message; - (void) alreadyPaired; @end @interface PairManager : NSOperation -- (id) initWithManager:(HttpManager*)httpManager andCert:(NSData*)cert callback:(id)callback; +- (id) initWithManager:(HttpManager*)httpManager clientCert:(NSData*)clientCert callback:(id)callback; - (NSString*) generatePIN; - (NSData*) saltPIN:(NSString*)PIN; - (void) initiatePair:(int)serverMajorVersion; diff --git a/Limelight/Network/PairManager.m b/Limelight/Network/PairManager.m index 6a55a26..cae5081 100644 --- a/Limelight/Network/PairManager.m +++ b/Limelight/Network/PairManager.m @@ -17,14 +17,14 @@ @implementation PairManager { HttpManager* _httpManager; - NSData* _cert; + NSData* _clientCert; id _callback; } -- (id) initWithManager:(HttpManager*)httpManager andCert:(NSData*)cert callback:(id)callback { +- (id) initWithManager:(HttpManager*)httpManager clientCert:(NSData*)clientCert callback:(id)callback { self = [super init]; _httpManager = httpManager; - _cert = cert; + _clientCert = clientCert; _callback = callback; return self; } @@ -62,7 +62,7 @@ [_callback showPIN:PIN]; HttpResponse* pairResp = [[HttpResponse alloc] init]; - [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:pairResp withUrlRequest:[_httpManager newPairRequest:salt]]]; + [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:pairResp withUrlRequest:[_httpManager newPairRequest:salt clientCert:_clientCert]]]; if (![self verifyResponseStatus:pairResp]) { return; } @@ -113,7 +113,7 @@ NSData* serverChallenge = [decServerChallengeResp subdataWithRange:NSMakeRange(hashLength, 16)]; NSData* clientSecret = [Utils randomBytes:16]; - NSData* challengeRespHashInput = [self concatData:[self concatData:serverChallenge with:[CryptoManager getSignatureFromCert:_cert]] with:clientSecret]; + NSData* challengeRespHashInput = [self concatData:[self concatData:serverChallenge with:[CryptoManager getSignatureFromCert:_clientCert]] with:clientSecret]; NSData* challengeRespHash; if (serverMajorVersion >= 7) { challengeRespHash = [cryptoMan SHA256HashData: challengeRespHashInput]; @@ -180,7 +180,8 @@ [_callback pairFailed:@"Pairing stage #5 failed"]; return; } - [_callback pairSuccessful]; + + [_callback pairSuccessful: [CryptoManager pemToDer:[Utils hexToBytes:plainCert]]]; } - (BOOL) verifyResponseStatus:(HttpResponse*)resp { diff --git a/Limelight/Stream/StreamConfiguration.h b/Limelight/Stream/StreamConfiguration.h index 8bf8ee8..7c8ec33 100644 --- a/Limelight/Stream/StreamConfiguration.h +++ b/Limelight/Stream/StreamConfiguration.h @@ -28,5 +28,6 @@ @property BOOL enableHdr; @property BOOL multiController; @property BOOL allowHevc; +@property NSData* serverCert; @end diff --git a/Limelight/Stream/StreamConfiguration.m b/Limelight/Stream/StreamConfiguration.m index 3efa33a..45ab688 100644 --- a/Limelight/Stream/StreamConfiguration.m +++ b/Limelight/Stream/StreamConfiguration.m @@ -9,5 +9,5 @@ #import "StreamConfiguration.h" @implementation StreamConfiguration -@synthesize host, appID, width, height, frameRate, bitRate, riKeyId, riKey, gamepadMask, streamingRemotely, appName, optimizeGameSettings, playAudioOnPC, audioChannelMask, audioChannelCount, enableHdr, multiController, allowHevc; +@synthesize host, appID, width, height, frameRate, bitRate, riKeyId, riKey, gamepadMask, streamingRemotely, appName, optimizeGameSettings, playAudioOnPC, audioChannelMask, audioChannelCount, enableHdr, multiController, allowHevc, serverCert; @end diff --git a/Limelight/Stream/StreamManager.m b/Limelight/Stream/StreamManager.m index 48f14ac..223abbc 100644 --- a/Limelight/Stream/StreamManager.m +++ b/Limelight/Stream/StreamManager.m @@ -38,12 +38,10 @@ - (void)main { [CryptoManager generateKeyPairUsingSSL]; NSString* uniqueId = [IdManager getUniqueId]; - NSData* cert = [CryptoManager readCertFromFile]; HttpManager* hMan = [[HttpManager alloc] initWithHost:_config.host uniqueId:uniqueId - deviceName:deviceName - cert:cert]; + serverCert:_config.serverCert]; ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init]; [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest:false] diff --git a/Limelight/ViewControllers/MainFrameViewController.m b/Limelight/ViewControllers/MainFrameViewController.m index 75a4ff8..5fac30d 100644 --- a/Limelight/ViewControllers/MainFrameViewController.m +++ b/Limelight/ViewControllers/MainFrameViewController.m @@ -37,7 +37,7 @@ NSOperationQueue* _opQueue; TemporaryHost* _selectedHost; NSString* _uniqueId; - NSData* _cert; + NSData* _clientCert; DiscoveryManager* _discMan; AppAssetManager* _appManager; StreamConfiguration* _streamConfig; @@ -98,11 +98,14 @@ static NSMutableSet* hostList; }); } -- (void)pairSuccessful { +- (void)pairSuccessful:(NSData*)serverCert { dispatch_async(dispatch_get_main_queue(), ^{ + // Store the cert from pairing with the host + self->_selectedHost.serverCert = serverCert; + [self->_pairAlert dismissViewControllerAnimated:YES completion:nil]; self->_pairAlert = nil; - + [self->_discMan startDiscovery]; [self alreadyPaired]; }); @@ -139,7 +142,7 @@ static NSMutableSet* hostList; // Exempt this host from discovery while handling the applist query [self->_discMan removeHostFromDiscovery:host]; - AppListResponse* appListResp = [ConnectionHelper getAppListForHostWithHostIP:host.activeAddress deviceName:deviceName cert:self->_cert uniqueID:self->_uniqueId]; + AppListResponse* appListResp = [ConnectionHelper getAppListForHostWithHostIP:host.activeAddress serverCert:host.serverCert uniqueID:self->_uniqueId]; [self->_discMan addHostToDiscovery:host]; @@ -307,7 +310,7 @@ static NSMutableSet* hostList; [self showLoadingFrame: ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - HttpManager* hMan = [[HttpManager alloc] initWithHost:host.activeAddress uniqueId:self->_uniqueId deviceName:deviceName cert:self->_cert]; + HttpManager* hMan = [[HttpManager alloc] initWithHost:host.activeAddress uniqueId:self->_uniqueId serverCert:host.serverCert]; ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init]; // Exempt this host from discovery while handling the serverinfo request @@ -352,7 +355,7 @@ static NSMutableSet* hostList; Log(LOG_I, @"Trying to pair"); // Polling the server while pairing causes the server to screw up [self->_discMan stopDiscoveryBlocking]; - PairManager* pMan = [[PairManager alloc] initWithManager:hMan andCert:self->_cert callback:self]; + PairManager* pMan = [[PairManager alloc] initWithManager:hMan clientCert:self->_clientCert callback:self]; [self->_opQueue addOperation:pMan]; } else { @@ -457,6 +460,7 @@ static NSMutableSet* hostList; _streamConfig.host = app.host.activeAddress; _streamConfig.appID = app.id; _streamConfig.appName = app.name; + _streamConfig.serverCert = app.host.serverCert; DataManager* dataMan = [[DataManager alloc] init]; TemporarySettings* streamSettings = [dataMan getSettings]; @@ -524,7 +528,7 @@ static NSMutableSet* hostList; Log(LOG_I, @"Quitting application: %@", currentApp.name); [self showLoadingFrame: ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - HttpManager* hMan = [[HttpManager alloc] initWithHost:app.host.activeAddress uniqueId:self->_uniqueId deviceName:deviceName cert:self->_cert]; + HttpManager* hMan = [[HttpManager alloc] initWithHost:app.host.activeAddress uniqueId:self->_uniqueId serverCert:app.host.serverCert]; HttpResponse* quitResponse = [[HttpResponse alloc] init]; HttpRequest* quitRequest = [HttpRequest requestForResponse: quitResponse withUrlRequest:[hMan newQuitAppRequest]]; @@ -700,7 +704,7 @@ static NSMutableSet* hostList; // Set up crypto [CryptoManager generateKeyPairUsingSSL]; _uniqueId = [IdManager getUniqueId]; - _cert = [CryptoManager readCertFromFile]; + _clientCert = [CryptoManager readCertFromFile]; _appManager = [[AppAssetManager alloc] initWithCallback:self]; _opQueue = [[NSOperationQueue alloc] init]; diff --git a/Moonlight.xcodeproj/project.pbxproj b/Moonlight.xcodeproj/project.pbxproj index eba09b5..a8c34f4 100644 --- a/Moonlight.xcodeproj/project.pbxproj +++ b/Moonlight.xcodeproj/project.pbxproj @@ -165,6 +165,7 @@ 98132E8C20BC9A62007A053F /* Moonlight v1.1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Moonlight v1.1.xcdatamodel"; sourceTree = ""; }; 9832D1341BBCD5C50036EF48 /* TemporaryApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemporaryApp.h; path = Database/TemporaryApp.h; sourceTree = ""; }; 9832D1351BBCD5C50036EF48 /* TemporaryApp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TemporaryApp.m; path = Database/TemporaryApp.m; sourceTree = ""; }; + 98517B1B21CE0A9000481377 /* Moonlight v1.3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Moonlight v1.3.xcdatamodel"; sourceTree = ""; }; 9865DC3B2132922E0005B9B9 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS11.4.sdk/System/Library/Frameworks/GameController.framework; sourceTree = DEVELOPER_DIR; }; 986CCE6C2133E45300168291 /* Moonlight v1.2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Moonlight v1.2.xcdatamodel"; sourceTree = ""; }; 98878AE0206A226D00586E90 /* OSPortabilityDefs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OSPortabilityDefs.h; sourceTree = ""; }; @@ -1504,6 +1505,7 @@ FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + 98517B1B21CE0A9000481377 /* Moonlight v1.3.xcdatamodel */, 986CCE6C2133E45300168291 /* Moonlight v1.2.xcdatamodel */, 98132E8C20BC9A62007A053F /* Moonlight v1.1.xcdatamodel */, FB53E1441BE5DCBC00CD6ECE /* Moonlight v1.0-2.xcdatamodel */, @@ -1512,7 +1514,7 @@ FB4678F21A51BDCB00377732 /* Limelight 0.3.0.xcdatamodel */, FB290D0619B2C406004C83CF /* Limelight.xcdatamodel */, ); - currentVersion = 986CCE6C2133E45300168291 /* Moonlight v1.2.xcdatamodel */; + currentVersion = 98517B1B21CE0A9000481377 /* Moonlight v1.3.xcdatamodel */; path = Limelight.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel;