kCFStreamPropertySocketSecurityLevel到kCFStreamSocketSecurityLevelNegotiatedSSL导致连接到Java的OSStatus errSSLXCertChainInvalid(-9807)

Hea*_*ers 1 java ssl cocoa cocoa-touch cfnetwork

我有一个简单的Java服务器,它使用自签名证书来标识我用keytool创建的自己:

  System.setProperty("javax.net.ssl.keyStore", "../../pki/z-keystore.jks");
  System.setProperty("javax.net.ssl.keyStorePassword", "ZZZZZZ");
  System.setProperty("javax.net.debug", "all");

  ServerSocketFactory serverSocketFactory = SSLServerSocketFactory
    .getDefault();
  ServerSocket serverSocket = serverSocketFactory
    .createServerSocket(8443);

  System.out.println("Waiting for connections on 8443");
  final AtomicInteger nextSocketId = new AtomicInteger(); 
  while (true) {
   final Socket socket = serverSocket.accept();
   new Thread(new Runnable() {
    @Override
    public void run() {
     final int socketId = nextSocketId.getAndIncrement();

     try {
      System.out.println("Received connection from socketId: " + socketId);
      BufferedReader bufferedReader = new BufferedReader(
        new InputStreamReader(socket.getInputStream()));
      PrintWriter printWriter = new PrintWriter(
        new OutputStreamWriter(socket.getOutputStream()));

      for (String line = bufferedReader.readLine(); line != null; line = bufferedReader
        .readLine()) {
       System.out.println("Read: " + line);
       printWriter.println("Read: " + line);
      }

      bufferedReader.close();
      printWriter.close();
     } catch (SSLHandshakeException e) {
      // don't care
     } catch (Exception e) {
      e.printStackTrace();
     }

     System.out.println("Closed connection from socketId: " + socketId);
    }
   }).start();

  }
Run Code Online (Sandbox Code Playgroud)

我使用在iphone模拟器中运行的简单ios客户端连接到它:

    - (void) connectSecurely {
 CFReadStreamRef readStream;
 CFWriteStreamRef writeStream;
 CFStreamCreatePairWithSocketToHost(NULL, 
            (CFStringRef)@"mcheath.local", 
            8443, 
            &readStream, 
            &writeStream);

 NSDictionary *sslSettings = [NSDictionary dictionaryWithObjectsAndKeys:
         (id)kCFBooleanFalse, (id)kCFStreamSSLValidatesCertificateChain, 
         nil];

 CFReadStreamSetProperty(readStream,
       kCFStreamPropertySSLSettings,
       sslSettings);

 /* Turning on this setting makes the SSL handshake fail with OSStatus -9807 */
 CFReadStreamSetProperty(readStream,
       kCFStreamPropertySocketSecurityLevel, 
       kCFStreamSocketSecurityLevelNegotiatedSSL);

 self.inputStream = (NSInputStream *)readStream;
 self.outputStream = (NSOutputStream *)writeStream;
 [self.inputStream setDelegate:self];
 [self.outputStream setDelegate:self]; 

 [self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] 
        forMode:NSDefaultRunLoopMode];
 [self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] 
         forMode:NSDefaultRunLoopMode];

 CFReadStreamOpen(readStream);
 CFWriteStreamOpen(writeStream);
    }

    #pragma mark -
    #pragma mark NSStreamDelegate

    - (void)stream:(NSStream *)aStream 
       handleEvent:(NSStreamEvent)eventCode {
 switch (eventCode) {
  case NSStreamEventNone:
   NSLog(@"NSStreamEventNone");
   break;
  case NSStreamEventOpenCompleted:
   NSLog(@"NSStreamEventOpenCompleted");
   break;
  case NSStreamEventHasBytesAvailable:
   NSLog(@"NSStreamEventHasBytesAvailable");
   break;
  case NSStreamEventHasSpaceAvailable:
   NSLog(@"NSStreamEventHasSpaceAvailable");
   break;
  case NSStreamEventErrorOccurred:
   NSLog(@"NSStreamEventErrorOccurred: %@", [aStream streamError]);
   NSLog(@"SSL Settings: %@", [aStream propertyForKey:(NSString *) kCFStreamPropertySSLSettings]);
   break;
  case NSStreamEventEndEncountered:
   NSLog(@"NSStreamEventEndEncountered");
   break;
  default:
   break;
 }
    }
Run Code Online (Sandbox Code Playgroud)

为什么将kCFStreamPropertySocketSecurityLevel设置为kCFStreamSocketSecurityLevelNegotiatedSSL导致我的SSL握手失败?

Hea*_*ers 8

答案来自可可未绑定.我需要先设置kCFStreamPropertySocketSecurityLevel,因为设置它会将我的kCFStreamPropertySSLSettings恢复为默认值.当然,文档中没有提到这一点.