2010-07-16 64 views
3

我有一個簡單的SMTP客戶端,我試圖添加TLS支持。我不確定在客戶發出「STARTTLS」命令後會發生什麼。大多數消息來源(包括RFC本身)都將其描述爲TLS會話的協商,但這並不是特別清楚。通過套接字與ESMTP協商TLS

怎麼去做這件事?我的客戶端用Objective C編寫,並使用Cocoa的流對象(套接字的包裝器)。可可流有能力將TLS指定爲具有NSStream的setProperty函數的套接字安全級別系統。

但是它似乎,在打開連接在此之前必須完成。如果是這種情況,那麼客戶希望在從服務器接收到代碼220(爲了響應STARTTLS)之後斷開連接,然後在指定TLS時重新連接?

或者更確切地說,這只是NSStream的限制?普通套接字是否在不關閉的情況下重新協商TLS或SSL?

此外,一旦STARTTLS已發出和隨後的談判完成,預計在客戶端的一部分的任何其他編碼/解碼?

道歉,如果這些都是簡單的問題。我很難找到合適的例子。

乾杯!

回答

1

客戶端發送STARTTLS命令和服務器與一個成功代碼回覆後,客戶端則有當時的同一個插座上,以啓動其SSL/TLS握手。在啓動SSL/TLS握手之前不要斷開插座。這將啓動一個新的SMTP會話,您將不得不再次發出STARTTLS命令。

一旦SSL/TLS握手成功地完成,無需額外的工作是必要的,只是把你剩餘的SMTP命令通常,它們將被加密來回。某些客戶端在建立TLS後發出新的HELO/EHLO命令,以防服務器的功能在加密模式下不同。

不幸的是,我所看到的,NSStream不支持啓動SSL /流後TLS是開放的。這是NSStream的限制,並且是documented by Apple

對於SSL安全性,NSStream限定 各種安全級別屬性( 例如, NSStreamSocketSecurityLevelSSLv2)。 forKey:使用密鑰 NSStreamSocketSecurityLevelKey流 對象,如在此 示例消息:您 通過發送 的setProperty設置這些屬性

[IStream的 的setProperty:NSStreamSocketSecurityLevelTLSv1 forKey:NSStreamSocketSecurityLevelKey];

您必須在 打開流之前設置屬性。

我不知道Objective C/Cocoa中是否可以這樣做,但是您可能需要編寫自己的流類來連接到主SMTP流。然後,您可以在準備好時啓動SSL/TLS,並將其委託給主流進行輸入/輸出。或者找到爲您處理這些細節的第三方SMTP類。

+0

感謝您的答覆非常有用。 在發佈最初的問題後,我做了一些調查並最終得出了相同的結論。 解決方案是爲OpenSSL套接字編寫一個簡單的Objective-C包裝器,並使用它替代NSStream。 – Gareth 2010-07-19 16:44:28

5

我剛剛發現,NSStream允許您通過設置kCFStreamSSLLevel屬性並重新打開流,將已激活的非TLS連接升級爲TLS。我剛剛通過smtp.gmail.com:25進行了SMTP連接測試,結果令人驚訝!我所描述的情況下,任何人NSStream/SMTP序列感興趣:

NSHost* host = [NSHost hostWithName:address]; 
[NSStream getStreamsToHost:host port:port inputStream:&is outputStream:&os]; 
[is setDelegate:self]; 
[os setDelegate:self]; 
[is scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
[os scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
[is open]; 
[os open]; 

SMTP對話,直到我們發送STARTTLS和服務器說OK:

-> 220 mx.google.com ESMTP gb6sm4472052wbb.0 
<- EHLO example.address.com 
-> 250-mx.google.com at your service, [84.227.165.204] 
-> 250-SIZE 35882577 
-> 250-8BITMIME 
-> 250-STARTTLS 
-> 250 ENHANCEDSTATUSCODES 
<- STARTTLS 
-> 220 2.0.0 Ready to start TLS 

在這一點上我們執行以下的升級插座到SSL:

NSMutableDictionary* settings = [NSMutableDictionary dictionary]; 
[settings setObject:NSStreamSocketSecurityLevelNegotiatedSSL forKey:(NSString*)kCFStreamSSLLevel]; 
[settings setObject:address forKey:(NSString*)kCFStreamSSLPeerName]; 
[is setProperty:settings forKey:(NSString*)kCFStreamPropertySSLSettings]; 
[os setProperty:settings forKey:(NSString*)kCFStreamPropertySSLSettings]; 
[is open]; 
[os open]; 

我們現在可以像以前一樣使用is和os。 AUTH選項現在可用證明服務器認爲連接是安全的。

<- EHLO example.address.com 
-> 250-mx.google.com at your service, [84.227.165.204] 
-> 250-SIZE 35882577 
-> 250-8BITMIME 
-> 250-AUTH LOGIN PLAIN XOAUTH 
-> 250 ENHANCEDSTATUSCODES 
<- AUTH PLAIN hIdDeNbAsE64dAtA 
-> 235 2.7.0 Accepted 
<- MAIL FROM: <[email protected]> 
-> 250 2.1.0 OK gb6sm4472052wbb.0 
<- RCPT TO: <[email protected]> 
-> 250 2.1.5 OK gb6sm4472052wbb.0 
<- DATA 
<- From: =?UTF-8?B?QWxlc3NhbmRybyBWb2x6?= <[email protected]> 
<- To: =?UTF-8?B?QWxl?= <[email protected]> 
<- Subject: =?UTF-8?B?VGVzdA==?= 
<- Mime-Version: 1.0; 
<- Content-Type: text/html; charset="UTF-8"; 
<- Content-Transfer-Encoding: 7bit; 
<- 
<- Ciao! 
<- . 
-> 354 Go ahead gb6sm4472052wbb.0 
-> 250 2.0.0 OK 1307994916 gb6sm4472052wbb.0 
<- QUIT 
-> 221 2.0.0 closing connection gb6sm4472052wbb.0 

我希望這是別人... 乾杯,

+0

Alessandro Volz - 感謝您的詳細回覆。我前一段時間解決了這個問題,但我相信你的答案對未來的某個人很有用。 – Gareth 2011-06-14 12:09:00