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.


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.


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


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


-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;
}

Inclua a solução diretamente em sua postagem do SO.
Maciej Jureczko
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.