Procházet zdrojové kódy

Finally added handshake checking

Mike Lewis před 13 roky
rodič
revize
5661a3a28c

+ 2 - 2
SRWebSocketTests/SRTAutobahnTests.m

@@ -71,7 +71,7 @@
     NSURL *prefixURL = [[[NSURL alloc] 
                          initWithScheme:locatorOperation.foundScheme 
                          host:[NSString stringWithFormat:@"%@:%d", 
-                               locatorOperation.foundService.hostName,
+                               @"localhost",
                                locatorOperation.foundService.port] 
                          path:@"/.."] 
                         standardizedURL];
@@ -83,7 +83,7 @@
         return caseGetter.isFinished;
     } timeout:20.0];
     
-    STAssertNil(caseGetter.error, @"CaseGetter should have successfully returned the number of testCases");
+    STAssertNil(caseGetter.error, @"CaseGetter should have successfully returned the number of testCases. Instead got error %@", caseGetter.error);
     
     NSInteger caseCount = caseGetter.caseCount;
     

+ 8 - 0
SocketRocket.xcodeproj/project.pbxproj

@@ -418,6 +418,10 @@
 					"\"$(DEVELOPER_DIR)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/usr/lib/system\"",
 					"\"$(DEVELOPER_DIR)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/usr/lib\"",
 				);
+				OTHER_LDFLAGS = (
+					"-all_load",
+					"-ObjC",
+				);
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				WRAPPER_EXTENSION = octest;
 			};
@@ -439,6 +443,10 @@
 					"\"$(DEVELOPER_DIR)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/usr/lib/system\"",
 					"\"$(DEVELOPER_DIR)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/usr/lib\"",
 				);
+				OTHER_LDFLAGS = (
+					"-all_load",
+					"-ObjC",
+				);
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				WRAPPER_EXTENSION = octest;
 			};

+ 1 - 1
SocketRocket.xcodeproj/xcshareddata/xcschemes/SocketRocket.xcscheme

@@ -31,7 +31,7 @@
             ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
             <ActionContent
                title = "Run Script"
-               scriptText = "PIDFILE=$TMPDIR/srtharness.pid&#10;if [ -r $PIDFILE ]; then&#10;    EXISTING_PID=`cat $PIDFILE`&#10;    echo &quot;Killing Dangling SRTextharneess PID:&quot; $EXISTING_PID&#10;    kill $EXISTING_PID&#10;    rm $PIDFILE&#10;fi&#10;&#10;pushd $PROJECT_DIR&#10;&#10;export MACOSX_DEPLOYMENT_TARGET=&quot;10.7&quot;&#10;&#10;bash TestSupport/ensure_virtualenv.sh $PROJECT_DIR/.env&#10;source .env/bin/activate&#10;&#10;&#10;nohup sr-testharness -k hello_test_harness -i &apos;&apos; -c &apos;[1-8]*&apos; &amp;&#10;&#10;#nohup sr-testharness -k hello_test_harness -i &apos;&apos; -c &apos;*&apos; &amp;&#10;&#10;echo $! &gt; $PIDFILE&#10;&#10;popd"
+               scriptText = "PIDFILE=$TMPDIR/srtharness.pid&#10;if [ -r $PIDFILE ]; then&#10;    EXISTING_PID=`cat $PIDFILE`&#10;    echo &quot;Killing Dangling SRTextharneess PID:&quot; $EXISTING_PID&#10;    kill $EXISTING_PID&#10;    rm $PIDFILE&#10;fi&#10;&#10;pushd $PROJECT_DIR&#10;&#10;export MACOSX_DEPLOYMENT_TARGET=&quot;10.7&quot;&#10;&#10;bash TestSupport/ensure_virtualenv.sh $PROJECT_DIR/.env&#10;source .env/bin/activate&#10;&#10;rm -rf &quot;$PROJECT_DIR/reports/clients/&quot;&#10;nohup sr-testharness -k hello_test_harness -i &apos;&apos; -c &apos;[1-8]*&apos; --debug &amp;&#10;&#10;#nohup sr-testharness -k hello_test_harness -i &apos;&apos; -c &apos;*&apos; &amp;&#10;&#10;echo $! &gt; $PIDFILE&#10;&#10;popd"
                shellToInvoke = "/bin/bash">
                <EnvironmentBuildable>
                   <BuildableReference

+ 56 - 15
SocketRocket/SRWebSocket.m

@@ -20,8 +20,8 @@
 #import <unicode/utf8.h>
 #import <endian.h>
 #import <CommonCrypto/CommonDigest.h>
-
 #import "base64.h"
+#import "NSData+SRB64Additions.h"
 
 typedef enum  {
     SROpCodeTextFrame = 0x1,
@@ -70,7 +70,7 @@ static inline dispatch_queue_t log_queue() {
 
 static inline void SRFastLog(NSString *format, ...)  {
     
-#if 1
+#if 0
     __block va_list arg_list;
     va_start (arg_list, format);
     
@@ -82,7 +82,7 @@ static inline void SRFastLog(NSString *format, ...)  {
 #endif
 }
 
-static NSString *const strAppendForAuth = @"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+static NSString *const SRWebSocketAppendToSecKeyString = @"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
 
 static inline int32_t validate_dispatch_data_partial_string(NSData *data) {
     
@@ -130,22 +130,25 @@ static inline int32_t validate_dispatch_data_partial_string(NSData *data) {
 }
 
 
-@interface NSString (DispatchDataAdditions)
+@interface NSData (SRWebSocket)
 
 - (NSString *)stringBySHA1ThenBase64Encoding;
 
 @end
 
-#define CONSERVATIVE_COPY
 
-@implementation NSString (DispatchDataAdditions)
+@interface NSString (SRWebSocket)
 
 - (NSString *)stringBySHA1ThenBase64Encoding;
-{
+
+@end
+
+
+static NSString *newSHA1String(const char *bytes, size_t length) {
     uint8_t md[CC_SHA1_DIGEST_LENGTH];
     
-    CC_SHA1([self UTF8String], [self lengthOfBytesUsingEncoding:NSUTF8StringEncoding], md);
-
+    CC_SHA1(bytes, length, md);
+    
     size_t buffer_size = ((sizeof(md) * 3 + 2) / 2);
     
     char *buffer =  (char *)malloc(buffer_size);
@@ -159,6 +162,23 @@ static inline int32_t validate_dispatch_data_partial_string(NSData *data) {
     }
 }
 
+@implementation NSData (SRWebSocket)
+
+- (NSString *)stringBySHA1ThenBase64Encoding;
+{
+    return newSHA1String(self.bytes, self.length);
+}
+
+@end
+
+
+@implementation NSString (SRWebSocket)
+
+- (NSString *)stringBySHA1ThenBase64Encoding;
+{
+    return newSHA1String(self.UTF8String, self.length);
+}
+
 @end
 
 NSString *const SRWebSocketErrorDomain = @"SRWebSocketErrorDomain";
@@ -211,7 +231,7 @@ typedef void (^data_callback)(SRWebSocket *webSocket,  NSData *data);
 
 - (void)_sendFrameWithOpcode:(SROpCode)opcode data:(id)data;
 
-- (void)_checkHandshake:(NSDictionary *)headers;
+- (BOOL)_checkHandshake:(NSDictionary *)headers;
 - (void)_SR_commonInit;
 
 + (dispatch_queue_t)globalReadQueue;
@@ -244,6 +264,8 @@ typedef void (^data_callback)(SRWebSocket *webSocket,  NSData *data);
     
     NSString *_closeReason;
     
+    NSString *_secKey;
+    
     uint8_t _currentReadMaskKey[4];
     size_t _currentReadMaskOffset;
 
@@ -367,16 +389,24 @@ static __strong NSData *CRLFCRLF;
 
 
 
-- (void)_checkHandshake:(NSDictionary *)headers;
+- (BOOL)_checkHandshake:(NSDictionary *)headers;
 {
-    SRFastLog(@"TODO: Add handshake checking");
+    NSString *acceptHeader = [headers objectForKey:@"Sec-WebSocket-Accept"];
+    
+    if (acceptHeader == nil) {
+        return NO;
+    }
+    
+    NSString *concattedString = [_secKey stringByAppendingString:SRWebSocketAppendToSecKeyString];
+    NSString *expectedAccept = [concattedString stringBySHA1ThenBase64Encoding];
+    
+    return [acceptHeader isEqualToString:expectedAccept];
 }
 
 - (void)_HTTPHeadersDidFinish;
 {
     NSDictionary *dict = CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(_receivedHTTPHeaders));
-
-    [self _checkHandshake:dict];
+    
     NSInteger responseCode = CFHTTPMessageGetResponseStatusCode(_receivedHTTPHeaders);
     
     if (responseCode >= 400) {
@@ -386,6 +416,11 @@ static __strong NSData *CRLFCRLF;
 
     }
     
+    if(![self _checkHandshake:dict]) {
+        [self failWithError:[NSError errorWithDomain:SRWebSocketErrorDomain code:2133 userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Invalid Sec-WebSocket-Accept response"] forKey:NSLocalizedDescriptionKey]]];
+        return;
+    }
+    
     self.readyState = SR_OPEN;
     
     if (!_didFail) {
@@ -430,9 +465,15 @@ static __strong NSData *CRLFCRLF;
         CFHTTPMessageSetHeaderFieldValue(request, (__bridge CFStringRef)key, (__bridge CFStringRef)obj);
     }];
     
+    
+    NSMutableData *keyBytes = [[NSMutableData alloc] initWithLength:16];
+    SecRandomCopyBytes(kSecRandomDefault, keyBytes.length, keyBytes.mutableBytes);
+    _secKey = [keyBytes SR_stringByBase64Encoding];
+    assert([_secKey length] == 24);
+    
     CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Upgrade"), CFSTR("websocket"));
     CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Connection"), CFSTR("Upgrade"));
-    CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Key"), CFSTR("/PiDVHFKG9+oB7rLAudvxw=="));
+    CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Key"), (__bridge CFStringRef)_secKey);
     CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Version"), (__bridge CFStringRef)[NSString stringWithFormat:@"%d", _webSocketVersion]);
     CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Origin"), (__bridge CFStringRef)_url.absoluteString);