Мое приложение подключается к серверу электронной почты IMAP. Один клиент настроил свой сервер для отклонения сертификатов SSLv2, и теперь мое приложение не может подключиться к серверу. Все остальные почтовые клиенты успешно подключаются к этому серверу. Мое приложение использует openssl.
Я отладил, создав минимальный клиент openssl и попытавшись подключиться к серверу. Ниже приведен код подключения к почтовому серверу (с использованием Windows-сокетов, но та же проблема с Unix-сокетами).
Сервер отправляет свое начальное приветствие IMAP, но после того, как клиент отправляет первую команду, сервер закрывает соединение. В Wireshark я вижу, что после отправки команды на сервер он возвращает сообщение об ошибке TLSv1 21 (зашифрованное предупреждение) и соединение отсутствует.
Я ищу правильную настройку OpenSSL для успешного подключения.
Спасибо
#include <stdio.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <winsock2.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define CHK_NULL(x) if((x)==NULL) exit(1)
#define CHK_ERR(err,s) if((err)==-1) { perror(s); exit(1); }
#define CHK_SSL(err) if((err)==-1) { ERR_print_errors_fp(stderr); exit(2); }
SSL *ssl;
char buf[4096];
void write(const char *s){
int err = SSL_write(ssl, s, strlen(s));
printf("> %s\n", s);
CHK_SSL(err);
}
void read(){
int n = SSL_read(ssl, buf, sizeof(buf) - 1);
CHK_SSL(n);
if(n==0){
int e = SSL_get_error(ssl, 0);
printf("Read error %i\n", e);
exit(1);
}
buf[n] = 0;
printf("%s\n", buf);
}
void main(){
int err=0;
SSLeay_add_ssl_algorithms();
SSL_METHOD *meth = SSLv23_client_method();
SSL_load_error_strings();
SSL_CTX *ctx = SSL_CTX_new(meth);
CHK_NULL(ctx);
WSADATA data;
WSAStartup(0x202, &data);
int sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
CHK_ERR(sd, "socket");
struct sockaddr_in sa;
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr("195.137.27.14");
sa.sin_port = htons(993);
err = connect(sd,(struct sockaddr*) &sa, sizeof(sa));
CHK_ERR(err, "connect");
/* ----------------------------------------------- */
/* Now we have TCP connection. Start SSL negotiation. */
ssl = SSL_new(ctx); CHK_NULL(ssl);
SSL_set_fd(ssl, sd);
err = SSL_connect(ssl); CHK_SSL(err);
// Following two steps are optional and not required for data exchange to be successful.
/*
printf("SSL connection using %s\n", SSL_get_cipher(ssl));
X509 *server_cert = SSL_get_peer_certificate(ssl); CHK_NULL(server_cert);
printf("Server certificate:\n");
char *str = X509_NAME_oneline(X509_get_subject_name(server_cert),0,0);
CHK_NULL(str);
printf(" subject: %s\n", str);
OPENSSL_free(str);
str = X509_NAME_oneline(X509_get_issuer_name (server_cert),0,0);
CHK_NULL(str);
printf(" issuer: %s\n", str);
OPENSSL_free(str);
// We could do all sorts of certificate verification stuff here before deallocating the certificate.
X509_free(server_cert);
*/
printf("\n\n");
read(); // get initial IMAP greeting
write("1 CAPABILITY\r\n"); // send 1st command
read(); // get reply to cmd; server closes connection here
write("2 LOGIN a b\r\n");
read();
SSL_shutdown(ssl);
closesocket(sd);
SSL_free(ssl);
SSL_CTX_free(ctx);
}