добрый день. по работе необходимо реализовать ссл-сервер и ссл-клиента на с++ под линукс. пошарив по инету и начитавшись документации набросал тестовые клиент и сервер. сгенерировал серитфикаты, как сказано тут
http://codeghar.wordpress.com/2008/03/17/create-a-certificate-authority-and-certificates-with-openssl/ . при подключении клиент выдает ошибку:
error SSL_ERROR_SYSCALL
error: error:00000000:lib(0):func(0):reason(0)
The peer does not have certificate
sending request...
5914:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:188:
-1 bytes sent
текст клиента:
int main() {
int err;
SSL_CTX * ctx = init_ctx("client-cert.pem", "client-private.pem", "certs/cacert.pem", "clientpass");
if (!ctx) {
fprintf(stderr, "couldn't init ctx\n");
exit(1);
}
int sock = tcp_connect("localhost", 4443);
/* Connect the SSL socket */
SSL * ssl = SSL_new(ctx);
BIO * sbio = BIO_new_socket(sock,BIO_NOCLOSE);
SSL_set_bio(ssl,sbio,sbio);
if((err = SSL_connect(ssl)) != 1) {
switch(SSL_get_error(ssl, err)) {
case SSL_ERROR_NONE:
fprintf(stderr, "error SSL_ERROR_NONE\n");
break;
case SSL_ERROR_ZERO_RETURN:
fprintf(stderr, "errorSSL_ERROR_ZERO_RETURN \n");
break;
case SSL_ERROR_WANT_READ:
fprintf(stderr, "error SSL_ERROR_WANT_READ\n");
break;
case SSL_ERROR_WANT_WRITE:
fprintf(stderr, "error SSL_ERROR_WANT_WRITE\n");
break;
case SSL_ERROR_WANT_CONNECT:
fprintf(stderr, "error SSL_ERROR_WANT_CONNECT\n");
break;
case SSL_ERROR_WANT_X509_LOOKUP:
fprintf(stderr, "error SSL_ERROR_WANT_X509_LOOKUP\n");
break;
case SSL_ERROR_SYSCALL:
fprintf(stderr, "error SSL_ERROR_SYSCALL\n");
break;
case SSL_ERROR_SSL:
fprintf(stderr, "error SSL_ERROR_SSL\n");
break;
default:
fprintf(stderr, "error f****** s***!!!\n");
break;
}
fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
ERR_print_errors_fp(stderr);
//exit(1);
}
check_cert(ssl, "host.com");
fprintf(stderr, "%d bytes sent\n", send_request(ssl, "come with me, we'll go dreaming"));
/* shutdown ssl connection */
err = SSL_shutdown(ssl);
if (err < 0) {
ERR_print_errors_fp(stderr);
exit(1);
}
close(sock);
SSL_free(ssl);
SSL_CTX_free(ctx);
return 0;
}
ssize_t send_request(SSL * ssl, const char * req) {
fprintf(stderr, "sending request...\n");
ssize_t size = SSL_write(ssl, req, strlen(req));
if (size < 0) {
ERR_print_errors_fp(stderr);
}
return size;
}
int pem_passwd_cb(char *buf, int size, int rwflag, void *password) {
strncpy(buf, (char *)(password), size);
buf[size - 1] = '\0';
return(strlen(buf));
}
typedef int (*pem_passwd_func) (char *, int , int , void *);
SSL_CTX * init_ctx(const char * cert, const char * key, const char * ca_cert, char * password) {
SSL_library_init();
SSL_load_error_strings();
pem_passwd_func passwd_func = &pem_passwd_cb;
SSL_CTX * ctx = SSL_CTX_new(SSLv23_method());
if (!ctx) {
ERR_print_errors_fp(stderr);
return NULL;
}
/* Load the server certificate into the SSL_CTX structure */
if (SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
return NULL;
}
SSL_CTX_set_default_passwd_cb(ctx, passwd_func);
SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *)password);
/* Load the private-key corresponding to the server certificate */
if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
return NULL;
}
/* Check if the server certificate and private-key matches */
if (!SSL_CTX_check_private_key(ctx)) {
fprintf(stderr,"Private key does not match the certificate public key\n");
return NULL;
}
/* verify client */
/* Load the RSA CA certificate into the SSL_CTX structure */
if (!SSL_CTX_load_verify_locations(ctx, ca_cert, NULL)) {
ERR_print_errors_fp(stderr);
return NULL;
}
return ctx;
}
Функция tcp_connect() отрабатывает верно, т.к. сервер сообщает по поступившем соединении. Приватный ключ защищен паролем. тут проблема либо в коде (не очень вероятно), либо в сертификатов (мне нужна двусторонняя авторизация — как сервера, так и клиента). Пробовал тестировать при помощи s_client:
milo@milonote:~/src/tests/ssl$ openssl s_client -connect localhost:4443 -cert client-cert.pem -key client-private.pem -verify 1 -CAfile cacert.pem -prexit -msg -pass password
verify depth is 1
Invalid password argument "password"
Error getting password
говорит, пароль неверный, хотя он точно верный, потому как уже пару раз перегенеривал сертификат и ключ. И да, может быть это неправильно, но я генерировал сертификат и ключ для клиента от серверного CA сертификата.
Прошу помочь, потому как уже сутки пытаюсь выяснить причину. Спасибо.
Здравствуйте, milo, Вы писали:
M>Здравствуйте, MTimur, Вы писали:
MT>>Здравствуйте, milo, Вы писали:
M>>>Invalid password argument "password"
M>>>Error getting password
MT>>http://www.mail-archive.com/openssl-users@openssl.org/msg48820.html
M>ошибка та же
вобщем openssl s_client и openssl s_server начали работать ошибка была в том, что надо пароль писать "pass:пароль", а не "пароль:пароль", как по ссылке указано. остается проблема с моими клиентам. че делать?
Здравствуйте, milo, Вы писали:
M>вобщем openssl s_client и openssl s_server начали работать ошибка была в том, что надо пароль писать "pass:пароль", а не "пароль:пароль", как по ссылке указано. остается проблема с моими клиентам. че делать?
Apache? Что в логах ssl на сервере?
server ~ # cat /var/log/apache2/ssl_access_log
server ~ # cat /var/log/apache2/ssl_error_log
На сервере сертификат самоподписанный? — возможно в этом причина.
Здравствуйте, MTimur, Вы писали:
MT>Здравствуйте, milo, Вы писали:
M>>вобщем openssl s_client и openssl s_server начали работать ошибка была в том, что надо пароль писать "pass:пароль", а не "пароль:пароль", как по ссылке указано. остается проблема с моими клиентам. че делать?
MT>Apache? Что в логах ssl на сервере?
MT>server ~ # cat /var/log/apache2/ssl_access_log
MT>server ~ # cat /var/log/apache2/ssl_error_log
MT>На сервере сертификат самоподписанный? — возможно в этом причина.
Спасибо, проблему решил. Апач не использовал — надо было своего демона писать. Проблема была не в клиенте, а в сервере, в SSL_set_fd передавал по ошибки серверный сокет вместо клиентского.