Add small program to help debug TLS issues using a non-Go stack.
authorRobert Sesek <rsesek@bluestatic.org>
Sun, 1 Jan 2017 06:37:40 +0000 (01:37 -0500)
committerRobert Sesek <rsesek@bluestatic.org>
Sun, 1 Jan 2017 21:25:10 +0000 (16:25 -0500)
deployment/tlstest.mm [new file with mode: 0644]

diff --git a/deployment/tlstest.mm b/deployment/tlstest.mm
new file mode 100644 (file)
index 0000000..59805ba
--- /dev/null
@@ -0,0 +1,151 @@
+// clang++ tlstest.mm -o tlstest -framework Foundation -framework Security -std=c++11
+
+#include <CoreFoundation/CoreFoundation.h>
+#import <Foundation/Foundation.h>
+#include <Security/SecureTransport.h>
+
+struct StreamPair {
+  NSInputStream* in;
+  NSOutputStream* out;
+};
+
+const size_t kBufferSize = 1024;
+
+NSString* ReadBuffer(NSInputStream* stream) {
+  uint8_t buf[kBufferSize];
+  NSInteger bytes_read = [stream read:buf maxLength:sizeof(buf)];
+  NSString* line  = [[[NSString alloc] initWithBytes:buf
+                                              length:bytes_read
+                                            encoding:NSASCIIStringEncoding] autorelease];
+  NSLog(@">>> %@", line);
+  return line;
+}
+
+void WriteLine(NSOutputStream* stream, NSString* line) {
+  NSLog(@"<<< %@", line);
+  [stream write:(const uint8_t*)[line UTF8String] maxLength:[line length]];
+  const uint8_t nl = '\n';
+  [stream write:&nl maxLength:1];
+}
+
+OSStatus MySSLRead(SSLConnectionRef conn, void* data, size_t* data_len) {
+  NSInputStream* stream = ((StreamPair*)conn)->in;
+  *data_len = [stream read:(uint8_t*)data maxLength:*data_len];
+  return noErr;
+}
+
+OSStatus MySSLWrite(SSLConnectionRef conn, const void* data, size_t* data_len) {
+  NSOutputStream* stream = ((StreamPair*)conn)->out;
+  *data_len = [stream write:(uint8_t*)data maxLength:*data_len];
+  return noErr;
+}
+
+NSString* ReadBuffer(SSLContextRef tlsctx) {
+  uint8_t buf[kBufferSize];
+  size_t data_len;
+  OSStatus status = SSLRead(tlsctx, buf, sizeof(buf), &data_len);
+  if (status != noErr) {
+    NSLog(@"SSLRead error: %d", status);
+    return nil;
+  }
+
+  NSString* line  = [[[NSString alloc] initWithBytes:buf
+                                              length:data_len
+                                            encoding:NSASCIIStringEncoding] autorelease];
+  NSLog(@">+> %@", line);
+  return line;
+}
+
+void WriteLine(SSLContextRef tlsctx, NSString* line) {
+  NSLog(@"<+< %@", line);
+  size_t processed;
+  OSStatus status = SSLWrite(tlsctx, [line UTF8String], [line length], &processed);
+  if (status != noErr) {
+    NSLog(@"SSLWrite error: %d", status);
+    return;
+  }
+
+  const char nl = '\n';
+  status = SSLWrite(tlsctx, &nl, 1, &processed);
+  if (status != noErr) {
+    NSLog(@"SSLWrite error: %d", status);
+    return;
+  }
+}
+
+int main() {
+  CFReadStreamRef read_cf;
+  CFWriteStreamRef write_cf;
+  CFStreamCreatePairWithSocketToHost(NULL, CFSTR("localhost"), 9925, &read_cf, &write_cf);
+
+  NSInputStream* is = (NSInputStream*)read_cf;
+  NSOutputStream* os = (NSOutputStream*)write_cf;
+
+  [is open];
+  [os open];
+
+  ReadBuffer(is);
+  WriteLine(os, @"EHLO tlstest");
+  ReadBuffer(is);
+
+  StreamPair pair = { is, os };
+
+  SSLContextRef tlsctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
+  SSLSetIOFuncs(tlsctx, MySSLRead, MySSLWrite);
+  SSLSetConnection(tlsctx, &pair);
+  SSLSetSessionOption(tlsctx, kSSLSessionOptionBreakOnServerAuth, true);
+
+  WriteLine(os, @"STARTTLS");
+  ReadBuffer(is);
+
+  // Skip trust verification.
+  OSStatus handshake = SSLHandshake(tlsctx);
+  NSLog(@"SSL Handshake = %d", handshake);
+  if (handshake == errSSLServerAuthCompleted) {
+    handshake = SSLHandshake(tlsctx);
+    NSLog(@"SSL Handshake = %d", handshake);
+  }
+
+  ReadBuffer(tlsctx);
+  WriteLine(tlsctx, @"EHLO tlstest-tls");
+
+  ReadBuffer(tlsctx);
+  ReadBuffer(tlsctx);
+
+  WriteLine(tlsctx, @"MAIL FROM:<test@tlstest>");
+  ReadBuffer(tlsctx);
+
+  WriteLine(tlsctx, @"RCPT TO:<test@localhost>");
+  ReadBuffer(tlsctx);
+
+  WriteLine(tlsctx, @"DATA");
+  sleep(10);
+  ReadBuffer(tlsctx);
+
+  WriteLine(tlsctx, @"More data");
+  WriteLine(tlsctx, @"and some more");
+  WriteLine(tlsctx, @"more more more");
+  WriteLine(tlsctx, @"adfasdf;lan io;aweofani ef;awe");
+  WriteLine(tlsctx, @"adfasdf;lan io;aweofani ef;awe");
+  WriteLine(tlsctx, @"adfasdf;lan io;aweofani ef;awe");
+  WriteLine(tlsctx, @"adfasdf;lan io;aweofani ef;awe");
+  WriteLine(tlsctx, @"adfasdf;lan io;aweofani ef;awe");
+  WriteLine(tlsctx, @"adfasdf;lan io;aweofani ef;awe");
+  WriteLine(tlsctx, @"adfasdf;lan io;aweofani ef;awe");
+  WriteLine(tlsctx, @"adfasdf;lan io;aweofani ef;awe");
+  WriteLine(tlsctx, @"adfasdf;lan io;aweofani ef;awe");
+  WriteLine(tlsctx, @"adfasdf;lan io;aweofani ef;awe");
+  WriteLine(tlsctx, @"adfasdf;lan io;aweofani ef;awe");
+  WriteLine(tlsctx, @"adfasdf;lan io;aweofani ef;awe");
+  WriteLine(tlsctx, @".");
+
+  ReadBuffer(tlsctx);
+
+  WriteLine(tlsctx, @"QUIT");
+  ReadBuffer(tlsctx);
+
+  SSLClose(tlsctx);
+
+  [is close];
+  [os close];
+}