3
\$\begingroup\$

I have recently begun to dabble with OpenSSL to provide TLS encryption to TCP socket communication. Through documentation and heavy reference on example code I have come up with the following code (most of the code that is not related to OpenSSL has been gutted).

Client

#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/x509v3.h>

int create_socket(int port) {
  /* returns a valid socket fd */
}

int main(int argc, char **argv) {
  int sock;
  SSL *ssl;
  SSL_CTX *ctx;
  const SSL_METHOD *method;
  X509_VERIFY_PARAM *param;

  /* init */
  SSL_load_error_strings();
  OpenSSL_add_ssl_algorithms();

  /* create context */
  method = TLSv1_2_client_method();

  if (!(ctx = SSL_CTX_new(method))) {
    exit(1);
  }

  /* configure context */
  SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
  SSL_CTX_set_verify_depth(ctx, 4);
  SSL_CTX_load_verify_locations(ctx, "/path/to/cert.pem", NULL);
  SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_COMPRESSION);

  /* open a socket */
  sock = create_socket(1337);

  /* create ssl instance from context */
  ssl = SSL_new(ctx);

  param = SSL_get0_param(ssl);

  X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
  X509_VERIFY_PARAM_set1_host(param, "localhost", 0);

  /* assign socket to ssl intance */
  SSL_set_fd(ssl, sock);

  /* perform ssl handshake & connection */
  SSL_connect(ssl);

  /* perform ssl reads / writes */

  // SSL_read(ssl, buff, 255);

  /* cleanup */
  close(sock);
  SSL_free(ssl);
  SSL_CTX_free(ctx);
  EVP_cleanup();
}

Server

#include <stdio.h>                                                                                                                       
#include <unistd.h>                                                                                                                      
#include <sys/socket.h>                                                                                                                  
#include <arpa/inet.h>                                                                                                                   
#include <openssl/ssl.h>                                                                                                                 
#include <openssl/err.h>   
#include <openssl/x509v3.h>                                                                                                              

int create_socket(int port) {                                                                                                            
  /* returns a valid socket fd */                                                                                                        
}                                                                                                                                        

int main(int argc, char **argv) {                                                                                                        
  int sock;                                                                                                                              
  SSL_CTX *ctx;                                                                                                                          

  /* init */                                                                                                                             
  SSL_load_error_strings();                                                                                                              
  OpenSSL_add_ssl_algorithms();                                                                                                          

  /* create context */                                                                                                                   
  method = TLSv1_2_server_method();                                                                                                       

  if (!(ctx = SSL_CTX_new(method))) {                                                                                                    
    exit(1);                                                                                                                             
  }

  /* configure context */                                                                                                                
  SSL_CTX_set_ecdh_auto(ctx, 1);

  /* Set the key and cert */                                                                                                             
  if (SSL_CTX_use_certificate_file(ctx, "cert.pem", SSL_FILETYPE_PEM) <= 0) {                                                            
    exit(1);
  }

  if (SSL_CTX_use_PrivateKey_file(ctx, "key.pem", SSL_FILETYPE_PEM) <= 0) {                                                              
    exit(1);
  }                                                                                                                                      

  /* open a socket */
  sock = create_socket(5555);                                                                                                            

  /* Handle connections */                                                                                                               
  while(1) {                                                                                                                             
    int nsock;
    SSL *ssl;

    /* accept client connections
       if there are any */                                                                                                               
    nsock = accept_connection(sock);                                                                                                     

    /* create ssl instance from context */                                                                                               
    ssl = SSL_new(ctx);

    /* assign socket to ssl intance */                                                                                                   
    SSL_set_fd(ssl, client);                                                                                                             

    /* perform ssl handshake & connection */                                                                                             
    SSL_accept(ssl);                                                                                                                     

    /* perform ssl reads / writes */
    SSL_write(ssl, buff, sizeof(buff));

    /* free ssl instance */
    SSL_free(ssl);

    /* close client connection */
    close(client);
  }
}

I would love feedback on the OpenSSL code. I would like to verify that this code is using modern OpenSSL programming techniques and function calls as it will serve as a reference foundation for further socket programming I would like to do. Like I said before, there is some code that has been removed for the sake of keeping the scope to OpenSSL (error output and formatting, the entire create_socket function, etc). Please let me know if I can clarify anything!

\$\endgroup\$
  • 2
    \$\begingroup\$ You don't document what the code actually should do outside of documenting each statement. So it is hard to tell if it is a correct implementation of what you aim for. But, what is obvious for me is that you don't check that the target you access actually is the one you expect, i.e. that the hostname you want matches the subject of the certificate. This makes your code open to man in the middle attacks where the attacker just need to present an arbitrary certificate signed by the CA you trust. This might not be a problem if the CA is a single self-signed certificate only you have access to. \$\endgroup\$ – Steffen Ullrich Oct 5 '17 at 4:36
  • \$\begingroup\$ The goal of this code is to set up a secure connection between the client and the server. This functionality is all that I am aiming for with this implementation. As far as preventing man in the middle attacks, the function call SSL_CTX_load_verify_locations on the client specifies a directory and/or file to verify the certificate with. I have not been able to test with a certificate from a CA, but I have been able to test with a self-signed certificate by pointing that function to the actually certificate client side and it is approved. When pointed at a different file, it fails. \$\endgroup\$ – chadduffin Oct 5 '17 at 4:49
  • \$\begingroup\$ If you validate against a CA you also need to check the subject so that you only accept the specific certificate matching the expected target and not an arbitrary certificate issued by the CA. See wiki.openssl.org/index.php/Hostname_validation. \$\endgroup\$ – Steffen Ullrich Oct 5 '17 at 4:53
  • \$\begingroup\$ The hard part of SSL is not to get an SSL connection working at all but to make sure that it is secure against man in the middle attacks. This means proper certificate validation and strong ciphers. You fail with the first since you don't check the subject of the certificate (and also don't check for revocation) and it is not clear if you succeed with the last. This probably depends on the version of OpenSSL and the ciphers declared as default. Also, you still allow TLS 1.0 and TLS 1.1 - it is recommended to use TLS 1.2 only if you control both client and server. \$\endgroup\$ – Steffen Ullrich Oct 5 '17 at 4:57
  • \$\begingroup\$ Which version of OpenSSL are you targetting? There are some differences between OpenSSL 1.0.2 and 1.1.0. If you are actually using 1.1.0 then you might do certain things differently. \$\endgroup\$ – Matt Caswell Oct 5 '17 at 7:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.