C++Openssl中的服务器密钥交换

Serverkey Exchange in C++ Openssl

本文关键字:密钥交换 服务器 C++Openssl      更新时间:2023-10-16

我在一个c++项目中使用openssl。通过我的代码握手在没有Serverkey Exchange的情况下完成,我需要这样做。如何将握手中的服务器密钥交换添加到代码中?

服务器代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <openssl/rsa.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

/* define HOME to be dir for key and cert files... */
#define HOME "./"
/* Make these what you want for cert & key files */
#define CERTF  "/home/a.seifpour/Desktop/SSL Tutorial/cert.pem"
#define KEYF  "/home/a.seifpour/Desktop/SSL Tutorial/key.pem"

#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); }
int main() {
    int err;
    int listen_sd;
    int sd;
    struct sockaddr_in sa_serv;
    struct sockaddr_in sa_cli;
    unsigned int client_len;
    SSL_CTX* ctx;
    SSL* ssl;
    X509* client_cert;
    char* str;
    char buf [4096];
    const SSL_METHOD *meth;
    /* SSL preliminaries. We keep the certificate and key with the     context. */
    SSL_load_error_strings();
    OpenSSL_add_ssl_algorithms();
    meth = TLSv1_2_server_method();
    ctx = SSL_CTX_new(meth);
    if (!ctx) {
        ERR_print_errors_fp(stderr);
        exit(2);
    }
    if (SSL_CTX_load_verify_locations(ctx, CERTF, KEYF) != 1){
        ERR_print_errors_fp(stderr);
    }
    if (SSL_CTX_set_default_verify_paths(ctx) != 1){
        ERR_print_errors_fp(stderr);
    }
    if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <=     0) {
        ERR_print_errors_fp(stderr);
        exit(3);
    }
    if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0)     {
        ERR_print_errors_fp(stderr);
        exit(4);
    }
    if (!SSL_CTX_check_private_key(ctx)) {
        fprintf(stderr, "Private key does not match the certificate     public keyn");
        exit(5);
    }
//    SSL_CTX_set_verify(ctx,SSL_VERIFY_CLIENT_ONCE, 0);
    /* ----------------------------------------------- */
    /* Prepare TCP socket for receiving connections */
    listen_sd = socket(AF_INET, SOCK_STREAM, 0);
    CHK_ERR(listen_sd, "socket");
    memset(&sa_serv, 0, sizeof (sa_serv));
    sa_serv.sin_family = AF_INET;
    sa_serv.sin_addr.s_addr = INADDR_ANY;
    sa_serv.sin_port = htons(9999); /* Server Port number */
    err = bind(listen_sd, (struct sockaddr*) &sa_serv,
            sizeof (sa_serv));
    CHK_ERR(err, "bind");
    /* Receive a TCP connection. */
    err = listen(listen_sd, 5);
    CHK_ERR(err, "listen");
    client_len = sizeof (sa_cli);
    sd = accept(listen_sd, (struct sockaddr*) &sa_cli, &client_len);
    CHK_ERR(sd, "accept");
    close(listen_sd);
    printf("Connection from %lx, port %xn",
            sa_cli.sin_addr.s_addr, sa_cli.sin_port);
    /* ----------------------------------------------- */
    /* TCP connection is ready. Do server side SSL. */
    ssl = SSL_new(ctx);
    CHK_NULL(ssl);
    SSL_set_fd(ssl, sd);    
    err = SSL_accept(ssl);
    CHK_SSL(err);
    /* Get the cipher - opt */
    printf("SSL connection using %sn", SSL_get_cipher(ssl));
    /* Get client's certificate (note: beware of dynamic allocation) -     opt */
    client_cert = SSL_get_peer_certificate(ssl);
    if (client_cert != NULL) {
        printf("Client certificate:n");
        str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0,     0);
        CHK_NULL(str);
        printf("t subject: %sn", str);
        OPENSSL_free(str);
        str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0,     0);
        CHK_NULL(str);
        printf("t issuer: %sn", str);
        OPENSSL_free(str);
        /* We could do all sorts of certificate verification stuff     here before
           deallocating the certificate. */
        X509_free(client_cert);
    } else
        printf("Client does not have certificate.n");
    /* DATA EXCHANGE - Receive message and send reply. */
    err = SSL_read(ssl, buf, sizeof (buf) - 1);
    CHK_SSL(err);
    buf[err] = '';
    printf("Got %d chars:'%s'n", err, buf);
    err = SSL_write(ssl, "I hear you.", strlen("I hear you."));
    CHK_SSL(err);
    /* Clean up. */
    close(sd);
    SSL_free(ssl);
    SSL_CTX_free(ctx);
}
/* EOF - serv.cpp */

客户端代码:

#include <stdio.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
/* define HOME to be dir for key and cert files... */
#define HOME "./"
/* Make these what you want for cert & key files */
#define CERTF  "/home/a.seifpour/Desktop/SSL Tutorial/cert.pem"
#define KEYF  "/home/a.seifpour/Desktop/SSL Tutorial/key.pem"
#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); }
int main() {
    int err;
    int sd;
    struct sockaddr_in sa;
    SSL_CTX* ctx;
    SSL* ssl;
    X509* server_cert;
    char* str;
    char buf [4096];
    const SSL_METHOD *meth;
    OpenSSL_add_ssl_algorithms();
    meth = TLSv1_2_client_method();
    SSL_load_error_strings();
    ctx = SSL_CTX_new(meth);
    CHK_NULL(ctx);
//    if (SSL_CTX_set_cipher_list(ctx, "ECDHE-ECDSA-AES256-GCM-    SHA384") != 1)
//        ERR_print_errors_fp(stderr);
    /* ----------------------------------------------- */
    /* Create a socket and connect to server using normal socket     calls. */
    sd = socket(AF_INET, SOCK_STREAM, 0);
    CHK_ERR(sd, "socket");
    memset(&sa, 0, sizeof (sa));
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = inet_addr("127.0.0.1"); /* Server IP */
    sa.sin_port = htons(9999); /* Server Port number */
    err = connect(sd, (struct sockaddr*) &sa, sizeof (sa));
    CHK_ERR(err, "connect");
    /* ----------------------------------------------- */
    /* Now we have TCP conncetion. 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. */
    /* Get the cipher - opt */
    printf("SSL connection using %sn", SSL_get_cipher(ssl));
    /* Get server's certificate (note: beware of dynamic allocation) -     opt */

    server_cert = SSL_get_peer_certificate(ssl);
    CHK_NULL(server_cert);
    printf("Server certificate:n");
    str = X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0);
    CHK_NULL(str);
    printf("t subject: %sn", str);
    OPENSSL_free(str);
    str = X509_NAME_oneline(X509_get_issuer_name(server_cert), 0, 0);
    CHK_NULL(str);
    printf("t issuer: %sn", str);
    OPENSSL_free(str);
    /* We could do all sorts of certificate verification stuff here     before
       deallocating the certificate. */
    X509_free(server_cert);
    /* --------------------------------------------------- */
    /* DATA EXCHANGE - Send a message and receive a reply. */
    err = SSL_write(ssl, "Hello World!", strlen("Hello World!"));
    CHK_SSL(err);
    err = SSL_read(ssl, buf, sizeof (buf) - 1);
    //    err = recv(sd, buf, sizeof(buf), 0);
    CHK_SSL(err);
    buf[err] = '';
    printf("Got %d chars:'%s'n", err, buf);
    SSL_shutdown(ssl); /* send SSL/TLS close_notify */
    /* Clean up. */
    //    close(sd);
    SSL_free(ssl);
    SSL_CTX_free(ctx);
}
/* EOF - cli.cpp */

ServerKeyExchange是为短暂Diffie-Hellman协议发送的消息。您不需要为此更改代码,只需要启用(仅?)DHE和ECDHE密码套件即可。您的密码套件选择似乎超出了您提供的代码范围。

在打开这些密码套件之前,请确保您了解对这些协议的攻击,例如Logjam,并且至少只允许安全密钥大小。