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

我有一个简单的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(); } 

我使用在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; } } 

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

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

OSStatus -9807是 :

 errSSLXCertChainInvalid = -9807, /* Invalid certificate chain */ 

您的客户无法validation自签名证书的有效性。

Interesting Posts