I am trying to verify the revoked certificates of server using OCSP, but unable to find the proper implementation of OCSP API's. Can anyone help me in suggesting the changes i can do in my existing mtls code to check the server's revoked certificates using OCSP?
Below is the Client Code:
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "client.h"
#define BUFSIZE 128
static SSL_CTX *get_client_context(const char *ca_pem,
const char *cert_pem,
const char *key_pem) {
SSL_CTX *ctx;
/* Create a generic context */
if (!(ctx = SSL_CTX_new(SSLv23_client_method()))) {
fprintf(stderr, "Cannot create a client context\n");
return NULL;
}
/* Load the client's CA file location */
if (SSL_CTX_load_verify_locations(ctx, ca_pem, NULL) != 1) {
fprintf(stderr, "Cannot load client's CA file\n");
goto fail;
}
/* Load the client's certificate */
if (SSL_CTX_use_certificate_file(ctx, cert_pem, SSL_FILETYPE_PEM) != 1) {
fprintf(stderr, "Cannot load client's certificate file\n");
goto fail;
}
/* Load the client's key */
if (SSL_CTX_use_PrivateKey_file(ctx, key_pem, SSL_FILETYPE_PEM) != 1) {
fprintf(stderr, "Cannot load client's key file\n");
goto fail;
}
/* Verify that the client's certificate and the key match */
if (SSL_CTX_check_private_key(ctx) != 1) {
fprintf(stderr, "Client's certificate and key don't match\n");
goto fail;
}
/* We won't handle incomplete read/writes due to renegotiation */
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
/* Specify that we need to verify the server's certificate */
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
/* We accept only certificates signed only by the CA himself */
SSL_CTX_set_verify_depth(ctx, 1);
/* Done, return the context */
return ctx;
fail:
SSL_CTX_free(ctx);
return NULL;
}
int client(const char *conn_str, const char *ca_pem,
const char *cert_pem, const char *key_pem) {
static char buffer[BUFSIZE];
SSL_CTX *ctx;
BIO *sbio;
SSL *ssl;
size_t len;
/* Failure till we know it's a success */
int rc = -1;
/* Initialize OpenSSL */
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
/* Get a context */
if (!(ctx = get_client_context(ca_pem, cert_pem, key_pem))) {
return rc;
}
/* Get a BIO */
if (!(sbio = BIO_new_ssl_connect(ctx))) {
fprintf(stderr, "Could not get a BIO object from context\n");
goto fail1;
}
/* Get the SSL handle from the BIO */
BIO_get_ssl(sbio, &ssl);
/* Connect to the server */
if (BIO_set_conn_hostname(sbio, conn_str) != 1) {
fprintf(stderr, "Could not connecto to the server\n");
goto fail2;
}
/* Perform SSL handshake with the server */
if (SSL_do_handshake(ssl) != 1) {
fprintf(stderr, "SSL Handshake failed\n");
goto fail2;
}
/* Verify that SSL handshake completed successfully */
if (SSL_get_verify_result(ssl) != X509_V_OK) {
fprintf(stderr, "Verification of handshake failed\n");
goto fail2;
}
/* Inform the user that we've successfully connected */
printf("SSL handshake successful with %s\n", conn_str);
/* Read a line from the user */
if (!fgets(buffer, BUFSIZE, stdin)) {
fprintf(stderr, "Could not read input from the user\n");
goto fail3;
}
/* Get the length of the buffer */
len = strlen(buffer);
/* Write the input onto the SSL socket */
if ((rc = SSL_write(ssl, buffer, (int) len)) != len) {
fprintf(stderr, "Cannot write to the server\n");
goto fail3;
}
/* Read from the server */
if ((rc = SSL_read(ssl, buffer, BUFSIZE)) < 0) {
fprintf(stderr, "Cannot read from the server\n");
goto fail3;
}
/* Check if we've got back what we sent? (Not perfect, but OK for us) */
if (len == rc) {
/* Print it on the screen again */
printf("%s", buffer);
}
rc = 0;
/* Cleanup and exit */
fail3:
BIO_ssl_shutdown(sbio);
fail2:
BIO_free_all(sbio);
fail1:
SSL_CTX_free(ctx);
return rc;
}
Here is the Server Code:
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "server.h"
/* Global variable that indicates work is present */
static int do_work = 1;
/* Buffer size to be used for transfers */
#define BUFSIZE 128
/*
* Prepare a SSL context for use by the server
*/
static SSL_CTX *get_server_context(const char *ca_pem,
const char *cert_pem,
const char *key_pem) {
SSL_CTX *ctx;
/* Get a default context */
if (!(ctx = SSL_CTX_new(SSLv23_server_method()))) {
fprintf(stderr, "SSL_CTX_new failed\n");
return NULL;
}
/* Set the CA file location for the server */
if (SSL_CTX_load_verify_locations(ctx, ca_pem, NULL) != 1) {
fprintf(stderr, "Could not set the CA file location\n");
goto fail;
}
/* Load the client's CA file location as well */
SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(ca_pem));
/* Set the server's certificate signed by the CA */
if (SSL_CTX_use_certificate_file(ctx, cert_pem, SSL_FILETYPE_PEM) != 1) {
fprintf(stderr, "Could not set the server's certificate\n");
goto fail;
}
/* Set the server's key for the above certificate */
if (SSL_CTX_use_PrivateKey_file(ctx, key_pem, SSL_FILETYPE_PEM) != 1) {
fprintf(stderr, "Could not set the server's key\n");
goto fail;
}
/* We've loaded both certificate and the key, check if they match */
if (SSL_CTX_check_private_key(ctx) != 1) {
fprintf(stderr, "Server's certificate and the key don't match\n");
goto fail;
}
/* We won't handle incomplete read/writes due to renegotiation */
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
/* Specify that we need to verify the client as well */
SSL_CTX_set_verify(ctx,
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
NULL);
/* We accept only certificates signed only by the CA himself */
SSL_CTX_set_verify_depth(ctx, 1);
/* Done, return the context */
return ctx;
fail:
SSL_CTX_free(ctx);
return NULL;
}
static int get_socket(int port_num) {
struct sockaddr_in sin;
int sock, val;
/* Create a socket */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "Cannot create a socket\n");
return -1;
}
/* We don't want bind() to fail with EBUSY */
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
fprintf(stderr, "Could not set SO_REUSEADDR on the socket\n");
goto fail;
}
/* Fill up the server's socket structure */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port_num);
/* Bind the socket to the specified port number */
if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
fprintf(stderr, "Could not bind the socket\n");
goto fail;
}
/* Specify that this is a listener socket */
if (listen(sock, SOMAXCONN) < 0) {
fprintf(stderr, "Failed to listen on this socket\n");
goto fail;
}
/* Done, return the socket */
return sock;
fail:
close(sock);
return -1;
}
int server(const char *port_str, const char *ca_pem,
const char *cert_pem, const char *key_pem) {
static char buffer[BUFSIZE];
struct sockaddr_in sin;
socklen_t sin_len;
SSL_CTX *ctx;
SSL *ssl;
int port_num, listen_fd, net_fd, rc, len;
/* Parse the port number, and then validate it's range */
port_num = atoi(port_str);
if (port_num < 1 || port_num > 65535) {
fprintf(stderr, "Invalid port number: %s\n", port_str);
return -1;
}
/* Initialize OpenSSL */
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
/* Get a server context for our use */
if (!(ctx = get_server_context(ca_pem, cert_pem, key_pem))) {
return -1;
}
/* Get a socket which is ready to listen on the server's port number */
if ((listen_fd = get_socket(port_num)) < 0) {
goto fail;
}
/* Get to work */
while (do_work != 0) {
/* Hold on till we can an incoming connection */
sin_len = sizeof(sin);
if ((net_fd = accept(listen_fd,
(struct sockaddr *) &sin,
&sin_len)) < 0) {
fprintf(stderr, "Failed to accept connection\n");
continue;
}
/* Get an SSL handle from the context */
if (!(ssl = SSL_new(ctx))) {
fprintf(stderr, "Could not get an SSL handle from the context\n");
close(net_fd);
continue;
}
/* Associate the newly accepted connection with this handle */
SSL_set_fd(ssl, net_fd);
/* Now perform handshake */
if ((rc = SSL_accept(ssl)) != 1) {
fprintf(stderr, "Could not perform SSL handshake\n");
if (rc != 0) {
SSL_shutdown(ssl);
}
SSL_free(ssl);
continue;
}
/* Print success connection message on the server */
printf("SSL handshake successful with %s:%d\n",
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
/* Echo server... */
while ((len = SSL_read(ssl, buffer, BUFSIZE)) != 0) {
if (len < 0) {
fprintf(stderr, "SSL read on socket failed\n");
break;
} else if ((rc = SSL_write(ssl, buffer, len)) != len) {
break;
}
}
/* Successfully echoed, print on our screen as well */
printf("%s", buffer);
/* Cleanup the SSL handle */
SSL_shutdown(ssl);
SSL_free(ssl);
}
/* Close the listening socket */
close(listen_fd);
fail:
SSL_CTX_free(ctx);
return 0;
}
For more information on the code, i am using the "https://github.com/zapstar/two-way-ssl-c/blob/master/server.c" for reference.