更多 Cpp、Winsock、RSA 和 OpenSSL

Posted

技术标签:

【中文标题】更多 Cpp、Winsock、RSA 和 OpenSSL【英文标题】:More Cpp, Winsock, RSA and OpenSSL 【发布时间】:2012-02-20 12:08:10 【问题描述】:

首先我想警告你这里有很多代码!我希望客户端使用带有 OpenSSL 库的 RSA 连接到服务器。当我启动服务器时,一切都很好,但是当我尝试与客户端连接时,连接失败并出现错误:错误 1408A0C1:SSL 例程:SSL3_GET_CLIENT_HELLO:no shared cipher。感谢您的考虑,但我必须再次警告您这里有很多代码。如果您有兴趣,我正在创建一个到受 RSA 保护的 Java 小程序的 TCP 连接。这不是我的程序,我发现它在网络上乱七八糟。如果您可以为此目的在 cmets 中添加您自己的简单来源,我将不胜感激!

   // THIS IS THE CLIENT FOR THE CONNECTION

#include <openssl/bio.h> // BIO objects for I/O
#include <openssl/ssl.h> // SSL and SSL_CTX for SSL connections
#include <openssl/err.h> // Error reporting

#include <stdio.h> // If you don't know what this is for stop reading now.

void openssltest(void);

int main(int argc, char** argv) 
   CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use
   SSL_library_init(); // Initialize OpenSSL's SSL libraries
   SSL_load_error_strings(); // Load SSL error strings
   ERR_load_BIO_strings(); // Load BIO error strings
   OpenSSL_add_all_algorithms(); // Load all available encryption algorithms

   openssltest(); // We'll define this later.

   return 0;


void openssltest() 
   // Set up a SSL_CTX object, which will tell our BIO object how to do its work
   SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
   // Create a SSL object pointer, which our BIO object will provide.
   SSL* ssl;
   // Create our BIO object for SSL connections.
   BIO* bio = BIO_new_ssl_connect(ctx);
   // Failure?
   if (bio == NULL) 
      printf("Error creating BIO!\n");
           ERR_print_errors_fp(stderr);
      // We need to free up the SSL_CTX before we leave.
           SSL_CTX_free(ctx);
           return;
   
   // Makes ssl point to bio's SSL object.
   BIO_get_ssl(bio, &ssl);
   // Set the SSL to automatically retry on failure.
   SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
   // We're connection to google.com on port 443.
   BIO_set_conn_hostname(bio, "127.0.0.1:6789");

   // Same as before, try to connect.
   if (BIO_do_connect(bio) <= 0) 
      printf("Failed to connect!");
      BIO_free_all(bio);
      SSL_CTX_free(ctx);
      return;
   

   // Now we need to do the SSL handshake, so we can communicate.
   if (BIO_do_handshake(bio) <= 0) 
      printf("Failed to do SSL handshake!");
      BIO_free_all(bio);
      SSL_CTX_free(ctx);
      return;
   
   // Create a buffer for grabbing information from the page.
   char buf[1024];
   memset(buf, 0, sizeof(buf));
   // Create a buffer for the reqest we'll send to the server
   char send[1024];
   memset(send, 0, sizeof(send));
   // Create our GET request.
   strcat(send, "GET / HTTP/1.1\nHost:google.com\nUser Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)\nConnection: Close\n\n");
   // BIO_puts sends a null-terminated string to the server. In this case it's our GET request.
   BIO_puts(bio, send);
   // Loop while there's information to be read.
   while (1) 
      // BIO_read() reads data from the server into a buffer. It returns the number of characters read in.
      int x = BIO_read(bio, buf, sizeof(buf) - 1);
      // If we haven't read in anything, assume there's nothing more to be sent since we used Connection: Close.
      if (x == 0) 
         break;
      
      // If BIO_read() returns a negative number, there was an error
      else if (x < 0) 
         // BIO_should_retry lets us know if we should keep trying to read data or not.
         if (!BIO_should_retry(bio)) 
            printf("\nRead Failed!\n");
            BIO_free_all(bio);
            SSL_CTX_free(ctx);
            return;
         
      
      // We actually got some data, without errors!
      else 
         // Null-terminate our buffer, just in case
         buf[x] = 0;
         // Echo what the server sent to the screen
         printf("%s", buf);
      
   
   // Free up that BIO object we created.
   BIO_free_all(bio);
   // Remember, we also need to free up that SSL_CTX object!
   SSL_CTX_free(ctx);
   // Return.
   return;




    // THIS IS THE SERVER FOR THE CONNECTION


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

#include <iostream>
#include <stdio.h>
#include <winsock2.h>

#define PASSWORD "passme"

void serverThread();

int main(int argc, char** argv) 
   CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use
   SSL_library_init(); // Initialize OpenSSL's SSL libraries
   SSL_load_error_strings(); // Load SSL error strings
   ERR_load_BIO_strings(); // Load BIO error strings
   OpenSSL_add_all_algorithms(); // Load all available encryption algorithms

    serverThread();

   return 0;


void serverThread() 
    // First, we need to initialize Winsock.
    WSADATA wsadata;
    int ret = WSAStartup(0x101, &wsadata);
    if (ret != 0) 
  printf("WSAStartup() failed with: %d!\n", GetLastError());
  return;
    

    // Next we need to create a server socket.
    SOCKET server = socket(AF_INET, SOCK_STREAM, 0);
    sockaddr_in sockaddrin;
    // Internet socket
    sockaddrin.sin_family = AF_INET;
    // Accept any IP
    sockaddrin.sin_addr.s_addr = INADDR_ANY;
    // Use port 6789
    sockaddrin.sin_port = htons(6789);

    // Valid socket?
    if (server == INVALID_SOCKET) 
  printf("Error creating server socket!");
  return;
    

    // Now bind to the port
    ret = bind(server, (sockaddr*) &(sockaddrin), sizeof(sockaddrin));
    if (ret != 0) 
  printf("Error binding to port!\n");
  return;
    

    // Start listening for connections
    // Second param is max number of connections
    ret = listen(server, 50);
    if (ret != 0) 
  printf("Error listening for connections!\n");
  return;
    

    // Set up to accept connections
    SOCKET client;
    sockaddr_in clientsockaddrin;
    int len = sizeof(clientsockaddrin);
    printf("Server ready to accept connections!\n");

    while (1) 
  // Block until a connection is ready
  client = accept(server, (sockaddr*) &clientsockaddrin, &len);
  printf("Connection recieved from %s!\n", inet_ntoa(clientsockaddrin.sin_addr));

  // Notice that we use server_method instead of client_method
  SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method());
  BIO* bio = BIO_new_file("dh1024.pem", "r");
  // Did we get a handle to the file?
  if (bio == NULL) 
    printf("Couldn't open DH param file!\n");
    break;
  

  // Read in the DH params.
  DH* ret = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
  // Free up the BIO object.
  BIO_free(bio);
  // Set up our SSL_CTX to use the DH parameters.
  if (SSL_CTX_set_tmp_dh(ctx, ret) < 0) 
    printf("Couldn't set DH parameters!\n");
    break;
  

  // Now we need to generate a RSA key for use.
  // 1024-bit key. If you want to use something stronger, go ahead but it must be a power of 2. Upper limit should be 4096.
  RSA* rsa = RSA_generate_key(1024, RSA_F4, NULL, NULL);

  // Set up our SSL_CTX to use the generated RSA key.
  if (!SSL_CTX_set_tmp_rsa(ctx, rsa)) 
    printf("Couldn't set RSA key!\n");
    // We don't break out here because it's not a requirement for the RSA key to be set. It does help to have it.
  
  // Free up the RSA structure.
  RSA_free(rsa);

  SSL_CTX_set_cipher_list(ctx, "ALL");
  // Set up our SSL object as before
  SSL* ssl = SSL_new(ctx);
  // Set up our BIO object to use the client socket
  BIO* sslclient = BIO_new_socket(client, BIO_NOCLOSE);
  // Set up our SSL object to use the BIO.
  SSL_set_bio(ssl, sslclient, sslclient);

  // Do SSL handshaking.
  int r = SSL_accept(ssl);
  // Something failed. Print out all the error information, since all of it may be relevant to the problem.
  if (r != 1) 
    printf("SSL_accept() returned %d\n", r);
    printf("Error in SSL_accept(): %d\n", SSL_get_error(ssl, r));
    char error[65535];
    ERR_error_string_n(ERR_get_error(), error, 65535);
    printf("Error: %s\n\n", error);
    ERR_print_errors(sslclient);
    int err = WSAGetLastError();
    printf("WSA: %d\n", err);
    break;
  

  


int password_callback(char* buffer, int num, int rwflag, void* userdata) 
    if (num < (strlen(PASSWORD) + 1)) 
  return(0);
    
    strcpy(buffer, PASSWORD);
    return strlen(PASSWORD);


int verify_callback(int ok, X509_STORE_CTX* store) 
    char data[255];

    if (!ok) 
  X509* cert = X509_STORE_CTX_get_current_cert(store);
  int depth = X509_STORE_CTX_get_error_depth(store);
  int err = X509_STORE_CTX_get_error(store);

  printf("Error with certificate at depth: %d!\n", depth);
  X509_NAME_oneline(X509_get_issuer_name(cert), data, 255);
  printf("\tIssuer: %s\n", data);
  X509_NAME_oneline(X509_get_subject_name(cert), data, 255);
  printf("\tSubject: %s\n", data);
  printf("\tError %d: %s\n", err, X509_verify_cert_error_string(err));
    

    return ok;

【问题讨论】:

大多数时候人们发布的代码太少,所以即使你的问题不容易理解,至少还有机会。 :-) 【参考方案1】:

通常该错误表明您尚未在服务器中配置 RSA 密钥。为了使用 RSA 密码套件,您的服务器必须具有正确配置 RSA 密钥的证书。

【讨论】:

你能把我引到 'net 上的一个页面,在那里我可以了解更多关于 RSA 密钥的信息吗? 这很有效,我收到一个错误:1408A0C1:SSL 例程:SSL3_GET_CLIENT_HELLO:no shared cipher error now 您应该首先使用浏览器连接到您的 SSL 服务器。这样,您一次只需要调试一个应用程序,首先是您的服务器,然后是您的客户端。 我发现设置的问题出在服务器端。我在网上找不到这方面的帮助。我认为问题出在证书上。如果你能告诉我如何生成一个好的,我将不胜感激!

以上是关于更多 Cpp、Winsock、RSA 和 OpenSSL的主要内容,如果未能解决你的问题,请参考以下文章

EF 基础提供程序在 Open 上失败

Winsock重复包含

winsock 缺少数据 c++ win32

C ++ Winsock发送文件[关闭]

更多细节的理解RSA算法

实验一:基于Winsock完成简单的网络程序开发