Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically verify certificate chain using OpenSSL API

This is very similar to other questions but the ones I've looked at either don't have an answer or don't quite ask the same question. I have a self-signed CA certificate, and two other certificates that are signed with that CA certificate. I'm fairly sure the certificates are correct, because 'openssl verify' works:

$ openssl verify -CAfile ca.pem server.pem server.pem: OK 

(The above is from memory, I don't have them in front of me, so it may be slightly off).

Now I want to verify the certificates programatically. I have a utility function with pseudocode below:

int verify_cert(X509 *cert, X509 *cacert) {      int ret;      X509_STORE *store;      X509_STORE_CTX *ctx;       store = X509_STORE_new();      X590_STORE_add_cert(store, cacert);       ctx = X509_STORE_CTX_new();      X509_STORE_CTX_init(ctx, store, cert, NULL);       ret = X509_verify_cert(ctx);       /* check for errors and clean up */ } 

My problem is that the above code always returns 'failed to find issuer certificate'. What have I done wrong? I believe I am creating a new store, adding the cacert, creating a new context, and adding the child cert to be verified to the context with a pointer to the store which contains the CA. I'm pretty obviously doing something wrong, but I'm unsure what.

Any ideas?

Update: I'm aware I can save these certs to disk and use something like X509_LOOKUP_file or something similar. I'm looking for a solution that doesn't touch the disk unnecessarily.

like image 481
clemej Avatar asked Apr 30 '13 03:04

clemej


People also ask

How do I verify my openssl certificate chain?

Verify Certificate Chain with openssl Note that -untrusted can be used once for a certificate chain bundle of intermediates, or can be used more than once for each intermediate in a separate file. Add the -show_chain flag to output the certificate chain and corresponding depth of each certificate in the chain.

What does openssl x509 do?

The x509 command is a multi purpose certificate utility. It can be used to display certificate information, convert certificates to various forms, sign certificate requests like a "mini CA" or edit certificate trust settings. Since there are a large number of options they will split up into various sections.


1 Answers

You can use the normal validation routines (see How do you verify a public key was issued by your private CA?), like the -verify function in OpenSSL does. You need to create a lookup method (X509_LOOKUP_METHOD) like X509_LOOKUP_file(), but which works with a character string instead of a filename. The code for X509_LOOKUP_buffer() is as follows.

Header file by_buffer.h:

/* File:   by_buffer.h */  #ifndef BY_BUFFER_H #define    BY_BUFFER_H  #include <openssl/x509.h>  #ifdef    __cplusplus extern "C" { #endif #define X509_L_BUF_LOAD    1 #define X509_LOOKUP_load_buf(x,name,type) \         X509_LOOKUP_ctrl((x),X509_L_BUF_LOAD,(name),(long)(type),NULL) X509_LOOKUP_METHOD *X509_LOOKUP_buffer(void);  #ifdef    __cplusplus } #endif  #endif    /* BY_BUFFER_H */ 

The c program by_buffer.c:

/* by_buffer.c - copied and modified from crypto/x509/by_file.c */ /* Copyright (C) - should be the same as for OpenSSL */ #include "by_buffer.h"  #include <stdio.h> #include <time.h> #include <errno.h>  #include "../crypto/cryptlib.h" #include <openssl/lhash.h> #include <openssl/buffer.h> #include <openssl/pem.h> #include <openssl/err.h>  static int by_buffer_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc,     long argl, char **ret); X509_LOOKUP_METHOD x509_buffer_lookup=     {     "Load buffer into cache",     NULL,        /* new */     NULL,        /* free */     NULL,         /* init */     NULL,        /* shutdown */     by_buffer_ctrl,    /* ctrl */     NULL,        /* get_by_subject */     NULL,        /* get_by_issuer_serial */     NULL,        /* get_by_fingerprint */     NULL,        /* get_by_alias */     };  X509_LOOKUP_METHOD *X509_LOOKUP_buffer(void)     {     return(&x509_buffer_lookup);     }  static int by_buffer_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl,          char **ret)     {     int ok=0;     char *certBuf;      switch (cmd)         {     case X509_L_BUF_LOAD:         if (argl == X509_FILETYPE_DEFAULT)             {             X509err(X509_F_BY_FILE_CTRL,X509_R_LOADING_DEFAULTS);             }         else             {             if(argl == X509_FILETYPE_PEM)                 ok = (X509_load_cert_crl_buf(ctx,argp,                     X509_FILETYPE_PEM) != 0);             else                 ok = (X509_load_cert_buf(ctx,argp,(int)argl) != 0);             }         break;         }     return(ok);     }  int X509_load_cert_buf(X509_LOOKUP *ctx, const char *certBuf, int type)     {     int ret=0;     BIO *in=NULL;     int i,count=0;     X509 *x=NULL;      if (certBuf == NULL) return(1);         in=BIO_new(BIO_s_mem());         if(in==NULL) goto err;      if (type == X509_FILETYPE_PEM)         {         for (;;)             {             x=PEM_read_bio_X509_AUX(in,NULL,NULL,NULL);             if (x == NULL)                 {                 if ((ERR_GET_REASON(ERR_peek_last_error()) ==                     PEM_R_NO_START_LINE) && (count > 0))                     {                     ERR_clear_error();                     break;                     }                 else                     {                     X509err(X509_F_X509_LOAD_CERT_FILE,                         ERR_R_PEM_LIB);                     goto err;                     }                 }             i=X509_STORE_add_cert(ctx->store_ctx,x);             if (!i) goto err;             count++;             X509_free(x);             x=NULL;             }         ret=count;         }     else if (type == X509_FILETYPE_ASN1)         {         x=d2i_X509_bio(in,NULL);         if (x == NULL)             {             X509err(X509_F_X509_LOAD_CERT_FILE,ERR_R_ASN1_LIB);             goto err;             }         i=X509_STORE_add_cert(ctx->store_ctx,x);         if (!i) goto err;         ret=i;         }     else         {         X509err(X509_F_X509_LOAD_CERT_FILE,X509_R_BAD_X509_FILETYPE);         goto err;         } err:     if (x != NULL) X509_free(x);     if (in != NULL) BIO_free(in);     return(ret);     }  int X509_load_crl_buf(X509_LOOKUP *ctx, const char *certBuf, int type)     {     int ret=0;     BIO *in=NULL;     int i,count=0;     X509_CRL *x=NULL;      if (certBuf == NULL) return(1);     //in=BIO_new(BIO_s_file_internal());         in=BIO_new(BIO_s_mem());          if(in==NULL) goto err;      if (type == X509_FILETYPE_PEM)         {         for (;;)             {             x=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL);             if (x == NULL)                 {                 if ((ERR_GET_REASON(ERR_peek_last_error()) ==                     PEM_R_NO_START_LINE) && (count > 0))                     {                     ERR_clear_error();                     break;                     }                 else                     {                     X509err(X509_F_X509_LOAD_CRL_FILE,                         ERR_R_PEM_LIB);                     goto err;                     }                 }             i=X509_STORE_add_crl(ctx->store_ctx,x);             if (!i) goto err;             count++;             X509_CRL_free(x);             x=NULL;             }         ret=count;         }     else if (type == X509_FILETYPE_ASN1)         {         x=d2i_X509_CRL_bio(in,NULL);         if (x == NULL)             {             X509err(X509_F_X509_LOAD_CRL_FILE,ERR_R_ASN1_LIB);             goto err;             }         i=X509_STORE_add_crl(ctx->store_ctx,x);         if (!i) goto err;         ret=i;         }     else         {         X509err(X509_F_X509_LOAD_CRL_FILE,X509_R_BAD_X509_FILETYPE);         goto err;         } err:     if (x != NULL) X509_CRL_free(x);     if (in != NULL) BIO_free(in);     return(ret);     }  int X509_load_cert_crl_buf(X509_LOOKUP *ctx, const char *certBuf, int type) {     STACK_OF(X509_INFO) *inf;     X509_INFO *itmp;     BIO *in;     int i, count = 0;     if(type != X509_FILETYPE_PEM)         return X509_load_cert_buf(ctx, certBuf, type);         in = BIO_new(BIO_s_mem());     if(!in) {         X509err(X509_F_X509_LOAD_CERT_CRL_FILE,ERR_R_SYS_LIB);         return 0;     }         BIO_write(in, certBuf, strlen(certBuf));     inf = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL);     BIO_free(in);     if(!inf) {         X509err(X509_F_X509_LOAD_CERT_CRL_FILE,ERR_R_PEM_LIB);         return 0;     }     for(i = 0; i < sk_X509_INFO_num(inf); i++) {         itmp = sk_X509_INFO_value(inf, i);         if(itmp->x509) {             X509_STORE_add_cert(ctx->store_ctx, itmp->x509);             count++;         }         if(itmp->crl) {             X509_STORE_add_crl(ctx->store_ctx, itmp->crl);             count++;         }     }     sk_X509_INFO_pop_free(inf, X509_INFO_free);     return count; } 

Routine in C++ which calls the above routines:

#include "by_buffer.h" static int check(X509_STORE *ctx, const char *certBuf); static X509 *load_cert(const char *certBuf);  int validateKey(const char *rsaKeyCA, const char *rsaCertificate) {     int ret=0;     X509_STORE *cert_ctx=NULL;     X509_LOOKUP *lookup=NULL;      cert_ctx=X509_STORE_new();     if (cert_ctx == NULL) goto end;      OpenSSL_add_all_algorithms();      lookup=X509_STORE_add_lookup(cert_ctx,X509_LOOKUP_buffer());     if (lookup == NULL)         goto end;      if(!X509_LOOKUP_load_buf(lookup,rsaKeyCA,X509_FILETYPE_PEM))         goto end;      lookup=X509_STORE_add_lookup(cert_ctx,X509_LOOKUP_hash_dir());     if (lookup == NULL)         goto end;      X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);      ret = check(cert_ctx, rsaCertificate); end:     if (cert_ctx != NULL) X509_STORE_free(cert_ctx);      return ret; }  static X509 *load_cert(const char *certBuf) {     X509 *x=NULL;     BIO *cert;      if ((cert=BIO_new(BIO_s_mem())) == NULL)         goto end;      BIO_write(cert, certBuf, strlen(certBuf));      x=PEM_read_bio_X509_AUX(cert,NULL, NULL, NULL); end:     if (cert != NULL) BIO_free(cert);     return(x); }  static int check(X509_STORE *ctx, const char *certBuf) {     X509 *x=NULL;     int i=0,ret=0;     X509_STORE_CTX *csc;      x = load_cert(certBuf);     if (x == NULL)         goto end;      csc = X509_STORE_CTX_new();     if (csc == NULL)         goto end;     X509_STORE_set_flags(ctx, 0);     if(!X509_STORE_CTX_init(csc,ctx,x,0))         goto end;     ////// See crypto/asn1/t_x509.c for ideas on how to access and print the values     //printf("X.509 name: %s\n", x->name);     i=X509_verify_cert(csc);     X509_STORE_CTX_free(csc);      ret=0; end:     ret = (i > 0);     if (x != NULL)         X509_free(x);      return(ret); } 
like image 94
Mr Ed Avatar answered Sep 23 '22 11:09

Mr Ed