--- /dev/null
+// 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];
+}