Transforme um soquete simples em um soquete SSL

115

Eu escrevi programas C simples, que usam soquetes ('cliente' e 'servidor'). (Uso UNIX / Linux)

O lado do servidor simplesmente cria um soquete:

sockfd = socket(AF_INET, SOCK_STREAM, 0);

E então o vincula ao sockaddr:

bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

E ouve (e aceita e lê):

listen(sockfd,5);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
read(newsockfd,buffer,255);

O cliente cria o soquete e grava nele.

Agora, eu quero converter essa conexão simples em uma conexão SSL, da maneira mais simples, idílica, organizada e rápida.

Tentei adicionar OpenSSL ao meu projeto, mas não consigo encontrar uma maneira fácil de implementar o que desejo.

David Mape
fonte
Se você estiver procurando por "uma conexão segura" ao invés de SSL em particular, você pode olhar algo como proxychains.sourceforge.net que reside fora de seu aplicativo e configurá-lo para enviar tráfego por uma conexão SSH. No que diz respeito ao SSL no aplicativo, OpenSSL é muito fácil se você entender como o SSL / TLS deve funcionar. Se você quiser uma alternativa, tente yaSSL ou gnuTLS.
Borealid,
3
Defina 'maneira fácil'. OpenSSl é o padrão para programadores C. Se você está tendo dificuldade com isso, pergunte sobre isso.
Marquês de Lorne,
Verifique este aqui Uma Introdução à Programação OpenSSL (Parte I) . A Parte II é muito avançada e difícil para mim. Mas vale a pena dar uma olhada na part2.
Rick
Verifique também a programação segura com a API OpenSSL . Mas acabei de ouvir opiniões sobre o quão ruim o Openssl é e outras alternativas que vale a pena tentar.
Rick
Outra opção é usar uma ferramenta de wrapper SSL externa, como stunnelo stunnel4pacote está em distros baseadas em Debian e é fácil de usar. Existem algumas limitações em comparação com a adição de suporte SSL adequado em seu servidor, mas pode ser bom para uma solução rápida. Gosto do stunnel porque parece se adequar à abordagem de ferramentas de software UNIX.
Sam Watkins

Respostas:

150

Existem várias etapas ao usar o OpenSSL. Você deve ter feito um certificado SSL que pode conter o certificado com a chave privada, certifique-se de especificar a localização exata do certificado (este exemplo tem na raiz). Existem muitos bons tutoriais por aí.

Alguns incluem:

#include <openssl/applink.c>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

Você precisará inicializar o OpenSSL:

void InitializeSSL()
{
    SSL_load_error_strings();
    SSL_library_init();
    OpenSSL_add_all_algorithms();
}

void DestroySSL()
{
    ERR_free_strings();
    EVP_cleanup();
}

void ShutdownSSL()
{
    SSL_shutdown(cSSL);
    SSL_free(cSSL);
}

Agora, para a maior parte da funcionalidade. Você pode querer adicionar um loop while nas conexões.

int sockfd, newsockfd;
SSL_CTX *sslctx;
SSL *cSSL;

InitializeSSL();
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd< 0)
{
    //Log and Error
    return;
}
struct sockaddr_in saiServerAddress;
bzero((char *) &saiServerAddress, sizeof(saiServerAddress));
saiServerAddress.sin_family = AF_INET;
saiServerAddress.sin_addr.s_addr = serv_addr;
saiServerAddress.sin_port = htons(aPortNumber);

bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

listen(sockfd,5);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

sslctx = SSL_CTX_new( SSLv23_server_method());
SSL_CTX_set_options(sslctx, SSL_OP_SINGLE_DH_USE);
int use_cert = SSL_CTX_use_certificate_file(sslctx, "/serverCertificate.pem" , SSL_FILETYPE_PEM);

int use_prv = SSL_CTX_use_PrivateKey_file(sslctx, "/serverCertificate.pem", SSL_FILETYPE_PEM);

cSSL = SSL_new(sslctx);
SSL_set_fd(cSSL, newsockfd );
//Here is the SSL Accept portion.  Now all reads and writes must use SSL
ssl_err = SSL_accept(cSSL);
if(ssl_err <= 0)
{
    //Error occurred, log and close down ssl
    ShutdownSSL();
}

Você pode ler ou escrever usando:

SSL_read(cSSL, (char *)charBuffer, nBytesToRead);
SSL_write(cSSL, "Hi :3\n", 6);

Atualizar O SSL_CTX_newdeve ser chamado com o método TLS que melhor se adapta às suas necessidades para oferecer suporte às versões mais recentes de segurança, em vez de SSLv23_server_method(). Veja: OpenSSL SSL_CTX_new descrição

TLS_method (), TLS_server_method (), TLS_client_method (). Esses são os métodos SSL / TLS de versão flexível de uso geral . A versão do protocolo real usada será negociada para a versão mais alta mutuamente suportada pelo cliente e pelo servidor. Os protocolos suportados são SSLv3, TLSv1, TLSv1.1, TLSv1.2 e TLSv1.3.

CaptainBli
fonte
9
não tão "simples" como pensei, mas finalmente (graças a Deus!) vejo algum código. Isso é multiplataforma ou apenas para sistemas tipo unix / unix?
juliomalegria
3
Usei código semelhante em várias plataformas: arm, linux e windows.
CaptainBli de
2
O último ifestá errado. Deve ser if (ssl_err <= 0) {só então é um erro. SSL_accept()retorna 1em caso de sucesso, 0em "falha controlada" e -1em "falha fatal". Veja a página do manual.
Jite
2
Além disso, as cifras DH não funcionarão se SSL_CTX_set_tmp_dh[_callback]()não forem chamadas. Acabei de descobrir da maneira mais difícil que as cifras NULL não funcionam sem ele, produzindo o alerta número 40.
Roman Dmitrienko
5
@DevNull Os SSLv23_server_method()estados que o servidor entende SSLv2 e v3 e agora está obsoleto. Para oferecer suporte a TLS 1.1 e 1.2, substitua esse método por TLS_server_method(). fonte
ezPaint
17

OpenSSL é bastante difícil. É fácil desperdiçar acidentalmente toda a sua segurança ao não fazer a negociação exatamente da maneira certa. (Caramba, fui pessoalmente mordido por um bug em que curl não estava lendo os alertas do OpenSSL exatamente da maneira certa e não conseguia falar com alguns sites.)

Se você realmente quer algo rápido e simples, coloque o stud antes do seu programa e ligue-o um dia. Ter SSL em um processo diferente não deixará você lento: http://vincent.bernat.im/en/blog/2011-ssl-benchmark.html

BraveNewCurrency
fonte
11
Esta é uma resposta prática, mas não responde realmente à pergunta.
Suíça
4
STUD foi abandonado em 2016. O leia-me recomenda: github.com/varnish/hitch
Charles
7

Para outros como eu:

Era uma vez um exemplo na fonte SSL no diretório demos/ssl/com código de exemplo em C ++. Agora está disponível apenas por meio do histórico: https://github.com/openssl/openssl/tree/691064c47fd6a7d11189df00a0d1b94d8051cbe0/demos/ssl

Você provavelmente terá que encontrar uma versão funcional. Originalmente, postei esta resposta em 6 de novembro de 2015. E tive que editar a fonte - não muito.

Certificados: .pem em demos/certs/apps/: https://github.com/openssl/openssl/tree/master/demos/certs/apps

18446744073709551615
fonte
-1

Aqui, meu exemplo de encadeamentos de servidor de soquete ssl (conexão múltipla) https://github.com/breakermind/CppLinux/blob/master/QtSslServerThreads/breakermindsslserver.cpp

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <iostream>

#include <breakermindsslserver.h>

using namespace std;

int main(int argc, char *argv[])
{
    BreakermindSslServer boom;
    boom.Start(123,"/home/user/c++/qt/BreakermindServer/certificate.crt", "/home/user/c++/qt/BreakermindServer/private.key");
    return 0;
}
Fanex
fonte
Inclua a solução diretamente em sua postagem do SO.
Maciej Jureczko