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.
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.
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.
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); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With