1

我有一个简单的 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 握手失败?

4

2 回答 2

8

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

于 2011-01-25T02:02:00.670 回答
0

OSStatus -9807 是

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

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

于 2011-01-21T05:07:53.367 回答