Ubah soket sederhana menjadi soket SSL

115

Saya menulis program C sederhana, yang menggunakan soket ('klien' dan 'server'). (Penggunaan UNIX / Linux)

Sisi server hanya membuat soket:

sockfd = socket(AF_INET, SOCK_STREAM, 0);

Dan kemudian mengikatnya ke sockaddr:

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

Dan mendengarkan (dan menerima dan membaca):

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

Klien membuat soket, dan kemudian menulis padanya.

Sekarang, saya ingin mengubah koneksi sederhana ini menjadi koneksi SSL, dengan cara yang paling sederhana, paling indah, rapi dan tercepat.

Saya sudah mencoba menambahkan OpenSSL ke proyek saya, tetapi saya tidak dapat menemukan cara mudah untuk menerapkan apa yang saya inginkan.

David Mape
sumber
Jika Anda mencari "koneksi aman" daripada SSL pada khususnya, Anda dapat melihat sesuatu seperti proxychains.sourceforge.net yang berada di luar aplikasi Anda, dan mengaturnya untuk mengirim lalu lintas melalui koneksi SSH. Sejauh SSL dalam aplikasi, OpenSSL cukup mudah jika Anda memahami bagaimana SSL / TLS seharusnya bekerja. Jika Anda menginginkan alternatif, coba yaSSL atau gnuTLS.
Borealid
3
Tentukan 'cara mudah'. OpenSSl adalah standar untuk programmer C. Jika Anda mengalami kesulitan, Anda harus bertanya tentang itu.
Marquis dari Lorne
Periksa yang ini Pengantar Pemrograman OpenSSL (Par t I) . Bagian II terlalu maju dan sulit bagi saya. Tapi part2 layak untuk dilihat.
Rick
Periksa juga Pemrograman aman dengan OpenSSL API . Tapi saya baru saja mendengar pendapat tentang betapa buruknya Openssl dan alternatif lain yang patut dicoba.
Rick
Pilihan lainnya adalah menggunakan alat pembungkus SSL eksternal seperti stunnel, stunnel4paket tersebut ada di distro berbasis Debian dan mudah digunakan. Ada beberapa batasan dibandingkan dengan menambahkan dukungan SSL yang tepat di server Anda, tetapi ini bagus untuk solusi cepat. Saya suka stunnel karena sepertinya cocok dengan pendekatan perangkat lunak UNIX.
Sam Watkins

Jawaban:

150

Ada beberapa langkah saat menggunakan OpenSSL. Anda harus memiliki sertifikat SSL yang dapat berisi sertifikat dengan kunci privat. Pastikan untuk menentukan lokasi yang tepat dari sertifikat (contoh ini memilikinya di root). Ada banyak tutorial bagus di luar sana.

Beberapa termasuk:

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

Anda perlu menginisialisasi 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);
}

Sekarang untuk sebagian besar fungsionalitas. Anda mungkin ingin menambahkan while loop pada koneksi.

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

Anda kemudian dapat membaca atau menulis menggunakan:

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

Perbarui The SSL_CTX_newharus dipanggil dengan metode TLS yang paling sesuai dengan kebutuhan Anda untuk mendukung versi keamanan yang lebih baru, bukan SSLv23_server_method(). Lihat: Deskripsi OpenSSL SSL_CTX_new

TLS_method (), TLS_server_method (), TLS_client_method (). Ini adalah metode SSL / TLS fleksibel versi tujuan umum . Versi protokol aktual yang digunakan akan dinegosiasikan ke versi tertinggi yang didukung oleh klien dan server. Protokol yang didukung adalah SSLv3, TLSv1, TLSv1.1, TLSv1.2, dan TLSv1.3.

CaptainBli
sumber
9
tidak sesederhana yang saya pikirkan, tetapi akhirnya (terima kasih Tuhan!) Saya melihat beberapa kode. Apakah ini lintas platform atau hanya untuk sistem mirip unix / unix?
juliomalegria
3
Saya telah menggunakan kode serupa di berbagai platform: arm, linux, dan windows.
CaptainBli
2
Yang terakhir ifsalah. Seharusnya if (ssl_err <= 0) {hanya itu kesalahan. SSL_accept()kembali 1pada kesuksesan, 0pada "kegagalan terkontrol" dan -1pada "kegagalan fatal". Lihat halaman manual.
Jite
2
Selain itu, cipher DH tidak akan berfungsi jika SSL_CTX_set_tmp_dh[_callback]()tidak dipanggil. Baru saja menemukan cara yang sulit bahwa sandi NULL tidak akan berfungsi tanpanya, menghasilkan nomor peringatan 40.
Roman Dmitrienko
5
@DevNull SSLv23_server_method()Menyatakan bahwa server memahami SSLv2 dan v3 dan sekarang sudah usang. Untuk mendukung TLS 1.1 dan 1.2 ganti metode itu dengan TLS_server_method(). sumber
ezPaint
17

OpenSSL cukup sulit. Sangat mudah untuk secara tidak sengaja membuang semua keamanan Anda dengan tidak melakukan negosiasi dengan tepat. (Heck, saya secara pribadi telah digigit oleh bug di mana curl tidak membaca peringatan OpenSSL dengan tepat, dan tidak dapat berbicara dengan beberapa situs.)

Jika Anda benar-benar ingin cepat dan sederhana, letakkan stud di depan program Anda selama sehari. Memiliki SSL dalam proses yang berbeda tidak akan memperlambat Anda: http://vincent.bernat.im/en/blog/2011-ssl-benchmark.html

BraveNewCurrency
sumber
11
Ini adalah jawaban praktis, tetapi tidak benar-benar menjawab pertanyaannya.
Swiss
4
STUD ditinggalkan pada 2016. Readme
Charles
7

Untuk orang lain seperti saya:

Pernah ada contoh di sumber SSL di direktori demos/ssl/dengan kode contoh di C ++. Sekarang hanya tersedia melalui riwayat: https://github.com/openssl/openssl/tree/691064c47fd6a7d11189df00a0d1b94d8051cbe0/demos/ssl

Anda mungkin harus mencari versi yang berfungsi, saya awalnya memposting jawaban ini pada 6 November 2015. Dan saya harus mengedit sumbernya - tidak banyak.

Sertifikat: .pem di demos/certs/apps/: https://github.com/openssl/openssl/tree/master/demos/certs/apps

18446744073709551615
sumber
-1

Berikut contoh saya utas server soket ssl (banyak koneksi) 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
sumber
Harap sertakan solusi langsung di pos SO Anda.
Maciej Jureczko