7

SSLで動作するWebSocketセキュリティサーバーがあります。サーバーと通信する際のセキュリティを確保するために、iOS クライアントにクライアント SSL 証明書を入れたいと考えています。

iOS クライアントでは WebSocket を使用しているため、SocketRocket (Objective-C WebSocket クライアント ライブラリ) を使用して WebSocket 通信を実装します。

問題は、クライアント SSL 証明書をサーバーに送信する方法がわからないことです。

のように、CFStream のプロパティを設定できますkCFStreamPropertySocketSecurityLevel。しかし、私はそれがどのように機能するのかわかりません。また、CFStream で証明書に関するドキュメントが見つかりません。

didReceiveAuthenticationChallengeHTTPS サーバーに接続する必要がある場合は、NSURLConnection で使用できることを知っています。しかし、私が知っているように、CFStream には対応するものはありませんでした。

誰かにアイデアはありますか?

4

1 に答える 1

14

多くの研究と試行錯誤を経て、今では自分自身で答えることができます。また、お役に立てれば幸いです。

実際、私が必要としているのは、CFStream を使用してクライアント SSL 認証を実装することです。だから私はこれらを行う必要があります:

  1. PKCS #12 ファイルをアプリ バンドルに入れる
  2. このファイルを次のように読んNSDataでくださいpkcsData
  3. メソッドSecPKCS12Importを使用してインポートするpkcsData
  4. 上記でインポートしたデータから ID と証明書を取得し、証明書配列を生成します
  5. 配列をキー入力するように設定kCFStreamSSLCertificateskCFStreamPropertySSLSettingsますCFWriteStreamRef

以下のサンプルコード:

  // Read .p12 file
  NSString *path = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"];
  NSData *pkcs12data = [[NSData alloc] initWithContentsOfFile:path];

  // Import .p12 data
  CFArrayRef keyref = NULL;
  OSStatus sanityChesk = SecPKCS12Import((__bridge CFDataRef)pkcs12data,
                                         (__bridge CFDictionaryRef)[NSDictionary
                                                                    dictionaryWithObject:@"123456"
                                                                    forKey:(__bridge id)kSecImportExportPassphrase],
                                         &keyref);
  if (sanityChesk != noErr) {
    NSLog(@"Error while importing pkcs12 [%ld]", sanityChesk);
  } else
    NSLog(@"Success opening p12 certificate.");

  // Identity
  CFDictionaryRef identityDict = CFArrayGetValueAtIndex(keyref, 0);
  SecIdentityRef identityRef = (SecIdentityRef)CFDictionaryGetValue(identityDict,
                                                                    kSecImportItemIdentity);

  // Cert
  SecCertificateRef cert = NULL;
  OSStatus status = SecIdentityCopyCertificate(identityRef, &cert);
  if (status)
    NSLog(@"SecIdentityCopyCertificate failed.");

  // the certificates array, containing the identity then the root certificate
  NSArray *myCerts = [[NSArray alloc] initWithObjects:(__bridge id)identityRef, (__bridge id)cert, nil];

  //
  [SSLOptions setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsExpiredRoots];
  [SSLOptions setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsExpiredCertificates];
  [SSLOptions setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];
  [SSLOptions setObject:[NSNumber numberWithBool:NO] forKey:(NSString *)kCFStreamSSLValidatesCertificateChain];
  [SSLOptions setObject:@"test.domain.com:443" forKey:(NSString *)kCFStreamSSLPeerName];
  [SSLOptions setObject:(NSString *)kCFStreamSocketSecurityLevelNegotiatedSSL forKey:(NSString*)kCFStreamSSLLevel];
  [SSLOptions setObject:(NSString *)kCFStreamSocketSecurityLevelNegotiatedSSL forKey:(NSString*)kCFStreamPropertySocketSecurityLevel];
  [SSLOptions setObject:myCerts forKey:(NSString *)kCFStreamSSLCertificates];
  [SSLOptions setObject:[NSNumber numberWithBool:NO] forKey:(NSString *)kCFStreamSSLIsServer];

  [_outputStream setProperty:SSLOptions
                        forKey:(__bridge id)kCFStreamPropertySSLSettings];

私は SocketRocket を使用しているため、次のコードを自分のフォークに追加しました: https://github.com/nickcheng/SocketRocket

于 2013-06-14T10:26:18.000 に答える