title: How to do mutual tls authentication in C code using openssl?
body: <p>I'm going to try TLS with mutual authentication using openssl.</p>
  
  <p>However, as shown in the output results below, the client can receive a server certificate and output it, but the server has not received the client certificate.</p>
  
  <p>The details of my work are as follows.</p>
  
  <ol>
  <li>Server and client certificate generation (without certificate signing through CA, just self-signing)</li>
  </ol>
  
  <p>(1) Generating the server key and certificate.</p>
  
  <p>$ openssl genrsa -des3 -out server.key 2048</p>
  
  <p>$ openssl req -new -key server.key -out server.csr</p>
  
  <p>$ cp server.key server.key.origin</p>
  
  <p>$ openssl rsa -in server.key.origin -out server.key</p>
  
  <p>$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt</p>
  
  <p>(2) Generating the client key and certificate.
  $ openssl genrsa -des3 -out client.key 2048</p>
  
  <p>$ openssl req -new -key client.key -out client.csr</p>
  
  <p>$ cp client.key client.key.origin</p>
  
  <p>$ openssl rsa -in client.key.origin -out client.key</p>
  
  <p>$ openssl x509 -req -days 365 -in client.csr -signkey client.key -out client.crt</p>
  
  <p>// Server.c</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;memory.h&gt;
  #include &lt;errno.h&gt;
  #include &lt;sys/types.h&gt;
  #include &lt;sys/socket.h&gt;
  #include &lt;netinet/in.h&gt;
  #include &lt;arpa/inet.h&gt;
  #include &lt;netdb.h&gt;
  #include &lt;openssl/rsa.h&gt;
  #include &lt;openssl/crypto.h&gt;
  #include &lt;openssl/x509.h&gt;
  #include &lt;openssl/pem.h&gt;
  #include &lt;openssl/ssl.h&gt;
  #include &lt;openssl/err.h&gt;
  
  #define HOME "./"
  #define CERTF HOME "server.crt"
  #define KEYF HOME "server.key"
  
  #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(void) {
  int err;
      int listen_sd;
      int sd;
      struct sockaddr_in sa_serv;
      struct sockaddr_in sa_cli;
      size_t client_len;
  
      SSL_CTX  *ctx;
      SSL    *ssl;
      X509                *client_cert;
      char                *str;
      char                buf[4096];
      SSL_METHOD  *meth;
  
      SSL_load_error_strings();
      SSLeay_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_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) &lt;= 0) {
          ERR_print_errors_fp(stderr);
          exit(3);
      }
  
      if(SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) &lt;= 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);
      }
  
      listen_sd = socket(AF_INET, SOCK_STREAM, 0);
      CHK_ERR(listen_sd, "socket");
  
      memset(&amp;sa_serv, 0x00, sizeof(sa_serv));
      sa_serv.sin_family = AF_INET;
      sa_serv.sin_addr.s_addr = INADDR_ANY;
      sa_serv.sin_port = htons(1111);
  
      err = bind(listen_sd, (struct sockaddr*)&amp;sa_serv, sizeof(sa_serv));
      CHK_ERR(err, "bind");
  
      err = listen(listen_sd, 5);
      CHK_ERR(err, "listen");
  
      client_len = sizeof(sa_cli);
      sd = accept(listen_sd, (struct sockaddr*)&amp;sa_cli, &amp;client_len);
      CHK_ERR(sd, "accept");
      close(listen_sd);
  
      ssl = SSL_new(ctx);
      CHK_NULL(ssl);
      SSL_set_fd(ssl, sd);
  
  // to request client's certificate
  SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
  
      err = SSL_accept(ssl);
      CHK_SSL(err);
  
      printf("SSL connection using %s \n", SSL_get_cipher(ssl));
  
      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: %s\n", str);
          OPENSSL_free(str);
  
          str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
          CHK_NULL(str);
          printf("\t issuer: %s\n", str);
          OPENSSL_free(str);
  
          X509_free(client_cert);
      } else {
          printf("Client does not have certificate. \n");
      }
  
      err = SSL_read(ssl, buf, sizeof(buf)-1);
      CHK_SSL(err);
      buf[err] = 0x00;
      printf("Got %d chars: %s \n", err, buf);
  
      err = SSL_write(ssl, "I hear you/", strlen("I hear you."));
      CHK_SSL(err);
  
      close(sd);
      SSL_free(ssl);
      SSL_CTX_free(ctx);
  
      return(0);
  }
  </code></pre>
  
  <p>// client.c</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;memory.h&gt;
  #include &lt;errno.h&gt;
  #include &lt;sys/types.h&gt;
  #include &lt;sys/socket.h&gt;
  #include &lt;netinet/in.h&gt;
  #include &lt;arpa/inet.h&gt;
  #include &lt;netdb.h&gt;
  
  #include &lt;openssl/crypto.h&gt;
  #include &lt;openssl/x509.h&gt;
  #include &lt;openssl/pem.h&gt;
  #include &lt;openssl/ssl.h&gt;
  #include &lt;openssl/err.h&gt;
  
  #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(void) {
      int err;
      int sd;
      struct sockaddr_in sa;
  
      SSL_CTX   *ctx;
      SSL     *ssl;
      X509                    *server_cert;
      char                    *str;
      char                    buf[4096];
      SSL_METHOD    *meth;
  
      SSL_load_error_strings();
      SSLeay_add_ssl_algorithms();
      meth = TLSv1_2_client_method();
      ctx = SSL_CTX_new(meth);
      CHK_NULL(ctx);
  
      if(SSL_CTX_use_certificate_file(ctx, "./client.crt", SSL_FILETYPE_PEM) &lt;= 0) {
          ERR_print_errors_fp(stderr);
          exit(3);
      }
  
      if(SSL_CTX_use_PrivateKey_file(ctx, "./client.key", SSL_FILETYPE_PEM) &lt;= 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);
      }
  
      CHK_SSL(err);
  
      sd = socket(AF_INET, SOCK_STREAM, 0);
      CHK_ERR(sd, "socket");
  
      memset(&amp;sa, 0x00, sizeof(sa));
      sa.sin_family = AF_INET;
      sa.sin_addr.s_addr = inet_addr("127.0.0.1");
      sa.sin_port = htons(1111);
  
      err = connect(sd, (struct sockaddr*)&amp;sa, sizeof(sa));
      CHK_ERR(err, "connect");
  
      ssl = SSL_new(ctx);
      CHK_NULL(ssl);
  
      SSL_set_fd(ssl, sd);
      err = SSL_connect(ssl);
      CHK_NULL(err);
  
      printf("SSL connection using %s \n", SSL_get_cipher(ssl));
  
      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: %s \n", str);
      OPENSSL_free(str);
  
      str = X509_NAME_oneline(X509_get_issuer_name(server_cert), 0, 0);
      CHK_NULL(str);
      printf("\t issuer: %s \n", str);
      OPENSSL_free(str);
  
      X509_free(server_cert);
  
      err = SSL_write(ssl, "Hello World!", strlen("Hello World!"));
      CHK_SSL(err);
  
      err = SSL_read(ssl, buf, sizeof(buf)-1);
      CHK_SSL(err);
      buf[err] = 0x0;
      printf("Got %d chars: %s \n", err, buf);
      SSL_shutdown(ssl);
  
      close(sd);
      SSL_free(ssl);
      SSL_CTX_free(ctx);
  
      return 0;
  }
  </code></pre>
  
  <p>below is output results.</p>
  
  <p>(1) server</p>
  
  <p>$ ./server</p>
  
  <p>SSL connection using ECDHE-RSA-AES256-GCM-SHA384</p>
  
  <p>Client does not have certificate.</p>
  
  <p>Got 12 chars: Hello World!</p>
  
  <p>(2) client</p>
  
  <p>$ ./client</p>
  
  <p>SSL connection using ECDHE-RSA-AES256-GCM-SHA384</p>
  
  <p>Server certificate:</p>
  
  <p>subject: /C=IN/ST=WB/L=Kolkata/O=TEST-INFO-CLIENTA/OU=IT/CN=clienta.com/emailAddress=aaa@aaa.com</p>
  
  <p>issuer: /C=IN/ST=WB/L=Kolkata/O=TEST-INFO-CLIENTA/OU=IT/CN=clienta.com/emailAddress=aaa@aaa.com</p>
  
  <p>Got 11 chars: I hear you/</p>
  
  <p>=======================================================      </p>
  
  <p>I don't know why the server's output says, "Client does not have certificate."</p>
  
  <p>Although I added "SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL)" in server.c, the server does not receive the client's certificate.</p>
  
  <p>If anyone knows about this, please reply.</p>