Согласование TLS с ESMTP через сокеты - PullRequest
4 голосов
/ 16 июля 2010

У меня есть простой SMTP-клиент, к которому я пытаюсь добавить поддержку TLS.Я не уверен относительно того, что происходит после того, как клиент выполнит команду «STARTTLS».Большинство источников (включая сам RFC) описывают это как согласование сеанса TLS, но это не совсем ясно.

Как можно поступить так?Мой клиент написан на Objective C и использует объекты потока Какао (обертка для сокетов).Потоки какао имеют возможность назначать TLS в качестве системы уровня безопасности сокетов с помощью функции setProperty NSStream.

Кажется, однако, что это должно быть сделано до открытия соединения.Если это так, то ожидается ли, что клиент отключится после получения кода 220 от сервера (в ответ на STARTTLS), а затем переподключится, указав TLS?

Или, скорее, это просто ограничение NSStream?Разве простые сокеты повторно согласовывают TLS или SSL, не закрываясь?

Кроме того, после выдачи STARTTLS и завершения последующих согласований ожидается ли какое-либо другое кодирование / декодирование со стороны клиента?

Извините, если это простые вопросы.Мне было трудно найти подходящие примеры.

Приветствия!

Ответы [ 2 ]

7 голосов
/ 14 июня 2011

Я только что обнаружил, что NSStream позволяет вам обновить уже активное не-TLS-соединение до TLS, установив свойство kCFStreamSSLLevel и снова открыв потоки. Я только что проверил это на SMTP-соединении с smtp.gmail.com:25, и на удивление это работает! Я описываю последовательность 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 и сервер не скажет ОК:

-> 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: <example.address@gmail.com>
-> 250 2.1.0 OK gb6sm4472052wbb.0
<- RCPT TO: <another.address@gmail.com>
-> 250 2.1.5 OK gb6sm4472052wbb.0
<- DATA
<- From: =?UTF-8?B?QWxlc3NhbmRybyBWb2x6?= <example.address@gmail.com>
<- To: =?UTF-8?B?QWxl?= <another.address@gmail.com>
<- 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

Надеюсь, это кому-нибудь пригодится ... Cheers,

1 голос
/ 17 июля 2010

После того, как клиент отправит команду STARTTLS и сервер ответит кодом успеха, клиент должен будет инициировать свое рукопожатие SSL / TLS в то же время в том же сокете. НЕ отсоединяйте сокет до начала рукопожатия SSL / TLS. Это запустит новый сеанс SMTP, и вам придется снова вводить команду STARTTLS.

После успешного завершения рукопожатия SSL / TLS дополнительная работа не требуется, просто отправьте оставшиеся SMTP-команды в обычном режиме, и они будут зашифрованы взад и вперед. Некоторые клиенты выдают новую команду HELO / EHLO после установления TLS, если возможности сервера в зашифрованном режиме отличаются один раз.

К сожалению, из того, что я вижу, NSStream не поддерживает инициирование SSL / TLS после открытия потока. Это ограничение NSStream, и оно задокументировано Apple :

Для безопасности SSL NSStream определяет различные свойства уровня безопасности (для пример, NSStreamSocketSecurityLevelSSLv2). Вы установить эти свойства, отправив setProperty: forKey: в поток объект с помощью ключа NSStreamSocketSecurityLevelKey, как в этот пример сообщения:

[IStream SetProperty: NSStreamSocketSecurityLevelTLSv1 forKey: NSStreamSocketSecurityLevelKey];

Вы должны установить свойство перед вами откройте поток.

Я не знаю, возможно ли это в Objective C / Cocoa, но вам, возможно, придется написать свой собственный класс потока, который вы присоединяете к своему основному потоку SMTP. Затем вы можете инициировать SSL / TLS, когда будете готовы, и передать его вашему основному потоку для ввода / вывода. Или же найдите сторонний класс SMTP, который обрабатывает эти детали для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...