// clang++ tlstest.mm -o tlstest -framework Foundation -framework Security -std=c++11 #include #import #include 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:"); ReadBuffer(tlsctx); WriteLine(tlsctx, @"RCPT TO:"); 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]; }