How to get key usage values from X509 cert? - c

I need to retrieve information from x509 cert to verify Key usage. For example I need to make sure certificate can be used for digital signing (80).
It can be printed out by the following code piece, but i actually want to verify if certificate has a specific property. What i need is a method like boolean certHasAbility(X509 * cert, int purpose );, where purpose can be DigitalSignature(80) or Key Encipherment(20).
STACK_OF(X509_EXTENSION) *ext_list;
ext_list = cert->cert_info->extensions;
outbio = BIO_new_fp(stdout, BIO_NOCLOSE);
if(sk_X509_EXTENSION_num(ext_list) <= 0)
return 1;
for (int i=0; i<sk_X509_EXTENSION_num(ext_list); i++) {
ASN1_OBJECT *obj;
X509_EXTENSION *ext;
ext = sk_X509_EXTENSION_value(ext_list, i);
obj = X509_EXTENSION_get_object(ext);
BIO_printf(outbio, "\n");
BIO_printf(outbio, "Object %.2d: ", i);
i2a_ASN1_OBJECT(outbio, obj);
BIO_printf(outbio, "\n");
X509V3_EXT_print(outbio, ext, NULL, NULL);
BIO_printf(outbio, "\n");
}

I would use X509_get_ext_d2i function:
static void print_my_key_usage(X509 *cert)
{
ASN1_BIT_STRING *usage = X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL);
if (usage && (usage->length > 0))
{
if (usage->data[0] & 0x80)
printf("digitalSignature\n");
....
if (usage->data[0] & 0x08)
printf("keyAgreement\n");
if (usage->data[0] & 0x04)
printf("keyCertSign\n");
if (usage->data[0] & 0x02)
printf("cRLSign\n");
}
}
You can find details of bits from RFC5280.
Because there can be more than 1 byte in the bit string,
you need to handle it someway in your function:
boolean certHasAbility(X509 *cert, int purpose)
{
ASN1_BIT_STRING *usage = X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL);
if (usage)
{
if (usage->length == 1)
{
return (usage->data[0] & purpose) == purpose;
}
else
{
// TODO: handle different lengths.
}
}
}

Related

How to implement Triple DES crypto in C using OpenSSL library

I'm trying to implement Triple DES encryption in C using OpenSSL library but I am not such professional in cryptography. I've found a useful sample code here for DES ECB crypto but I could not find an example code on how to implement 3DES and most of web resources just describe how to use OpenSSL as a tool.
I've implemented DES ECB for a specific purpose as follows
typedef struct
{
size_t size;
unsigned char* data;
} byte_array, *byte_array_ptr;
for encryption
byte_array_ptr des_encrypt_to_pin_block(byte_array_ptr key_bytes, byte_array_ptr xor_bytes)
{
if ((key_bytes->size != 8) || (xor_bytes->size != 8))
return NULL;
DES_key_schedule schedule;
const_DES_cblock key_data;
const_DES_cblock xor_data;
DES_cblock buffer;
memcpy(&key_data, key_bytes->data, key_bytes->size);
memcpy(&xor_data, xor_bytes->data, xor_bytes->size);
if (DES_set_key(&key_data, &schedule) < 0)
{
printf("ERROR: %s", "DES Set Key Error!");
return NULL;
}
DES_ecb_encrypt(&xor_data, &buffer, &schedule, DES_ENCRYPT);
byte_array_ptr pin_block;
pin_block = (byte_array_ptr)malloc(sizeof(size_t) + 8);
pin_block->size = 8;
pin_block->data = (unsigned char *)malloc(pin_block->size);
memcpy(pin_block->data, &buffer, pin_block->size);
return pin_block;
}
and the decryption
byte_array_ptr des_decrypt_to_xor_bytes(byte_array_ptr key_bytes, byte_array_ptr pin_block)
{
if ((key_bytes->size != 8) || (pin_block->size != 8))
return NULL;
DES_key_schedule schedule;
const_DES_cblock key_data;
const_DES_cblock pin_data;
DES_cblock buffer;
memcpy(&key_data, key_bytes->data, key_bytes->size);
memcpy(&pin_data, pin_block->data, pin_block->size);
if (DES_set_key(&key_data, &schedule) < 0)
{
printf("ERROR: %s", "DES Set Key Error!");
return NULL;
}
DES_ecb_encrypt(&pin_data, &buffer, &schedule, DES_DECRYPT);
byte_array_ptr xor_bytes;
xor_bytes = (byte_array_ptr)malloc(sizeof(size_t) + 8);
xor_bytes->size = 8;
xor_bytes->data = (unsigned char *)malloc(xor_bytes->size);
memcpy(xor_bytes->data, &buffer, xor_bytes->size);
return xor_bytes;
}
but I have no idea how to do it for 3DES.
Any idea?
OpenSSL provides a set of functions for Triple DES in EDE mode(Encrypt using key #1, Decrypt using key #2, Encrypt using key #3) for all encryption schemes. Also its common situation when key #1 equals key #3, there are functions for this case either.
So if you have all three keys the functions are:
DES_ecb3_encrypt()
DES_ede3_cbc_encrypt()
DES_ede3_ofb_encrypt()
DES_ede3_cfb_encrypt()
If you have only two keys the functions are:
DES_ecb2_encrypt()
DES_ede2_cbc_encrypt()
DES_ede2_ofb_encrypt()
DES_ede2_cfb_encrypt()

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.
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);
}
I think, you can use "X509_STORE_set_verify_cb" to add a callback to identify the actual error:
static int verify_cb(int ok, X509_STORE_CTX *ctx)
{
if (!ok)
{
/* check the error code and current cert*/
X509 *currentCert = X509_STORE_CTX_get_current_cert(ctx);
int certError = X509_STORE_CTX_get_error(ctx);
int depth = X509_STORE_CTX_get_error_depth(ctx);
printCert(currentCert);
printf("Error depth %d, certError %d", depth, certError)
}
return(ok);
}
int verify_cert(X509 *cert, X509 *cacert)
{
int ret;
X509_STORE *store;
X509_STORE_CTX *ctx;
store = X509_STORE_new();
X509_STORE_set_verify_cb(store, verify_cb);
X590_STORE_add_cert(store, cacert);
ctx = X509_STORE_CTX_new();
X509_STORE_CTX_init(ctx, store, cert, NULL);
ret = X590_verify_cert(ctx);
/* check for errors and clean up */
}
Unless we know the error code it is difficult to guess the actual problem. The code otherwise looks OK.
I encountered this problem myself and started off with code very close to the OP. My certificate chain included 3 certificates:
Certificate 1 (root-ca) Issuer: root-ca Subject: root-ca
Certificate 2 (signing-ca) Issuer: root-ca Subject: signing-ca
Certificate 3 (device) Issuer: signing-ca Subject: device
I wanted to verify the device certificate. My ca.pem equivalent (wrt OP) contained the root-ca and signing-ca.
The X509_verify_cert function needs the entire certificate chain all the way to the root (root-ca & signing-ca) in the X509_store.
Below is my code that works for me. Checks on return values were omitted to lean the code down.
int getIssuerCert(X509_STORE *x509_store){
STACK_OF(X509_INFO) *inf;
X509_INFO *itmp;
BIO *in;
int i, count = 0;
in = BIO_new(BIO_s_mem());
BIO_write(in, issuerCertStr, strlen(issuerCertStr)); //string containing root-ca & signing-ca
inf = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL);
if(in != NULL) BIO_free(in);
for(i = 0; i < sk_X509_INFO_num(inf); i++) {
itmp = sk_X509_INFO_value(inf, i);
if(itmp->x509) {
X509_STORE_add_cert(x509_store, itmp->x509);
count++;
}
if(itmp->crl) {
X509_STORE_add_crl(x509_store, itmp->crl);
count++;
}
}
sk_X509_INFO_pop_free(inf, X509_INFO_free);
return 0;
}
int verify_cert(){
int ret = 0;
X509 *devCert = NULL;
X509_STORE *x509_store = NULL;
X509_STORE_CTX *x509_store_ctx = NULL;
OpenSSL_add_all_algorithms();
devCert = getDeviceCert(); // Returns X509 pointer
x509_store = X509_STORE_new();
X509_STORE_set_verify_cb(x509_store, verify_cb);
X509_STORE_set_flags(x509_store, 0);
x509_store_ctx = X509_STORE_CTX_new();
X509_STORE_CTX_init(x509_store_ctx, x509_store, devCert, NULL)
X509_STORE_CTX_set_purpose(x509_store_ctx, X509_PURPOSE_ANY);
ret = X509_verify_cert(x509_store_ctx);
if(x509_store_ctx != NULL) X509_STORE_CTX_free(x509_store_ctx);
if(x509_store != NULL) X509_STORE_free(x509_store);
if(devCert != NULL) X509_free(devCert);
EVP_cleanup();
return ret;
}
I didn't need to create any lookup methods. The key for me was looping through my certificates from my string in memory so I had all the certificates I need to complete the chain. The string is equivalent to what I would have fed into openssl verify for the option -CAfile.
Also, make sure your X509 pointers are not null when the are used.
A possible answer (don't have the rep points to add a comment, sorry): the manpage for SSL_CTX_load_verify_locations(3) says,
When building its own certificate chain, an OpenSSL client/server will try to fill in
missing certificates from CAfile/CApath, if the certificate chain was not explicitly
specified (see SSL_CTX_add_extra_chain_cert(3), SSL_CTX_use_certificate(3).
(Failure to match parens theirs, not mine.)
Which seems to mean that, as an alternative to SSL_CTX_load_verify_locations(3), it should be possible to use SSL_CTX_add_extra_chain_cert(3) or SSL_CTX_use_certificate(3) -- both of which take a X509 * arg. Thus obviating the need for Mr Ed's solution as seen above.
Please take a look at SSL_CTX_load_verify_locations () function: http://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html
SSL_CTX_load_verify_locations() specifies the locations for ctx, at
which CA certificates for verification purposes are located. The
certificates available via CAfile and CApath are trusted.
You can generate a CA certificate file containing both ca.pem server.pem:
#!/bin/sh
rm CAfile.pem
for i in ca.pem server.pem ; do
openssl x509 -in $i -text >> CAfile.pem
done
And then set CAfile variable to point to CAfile.pem file.
Hope it helps !
See the official source code:
apps/verify.c
static int check(X509_STORE *ctx, const char *file,
STACK_OF(X509) *uchain, STACK_OF(X509) *tchain,
STACK_OF(X509_CRL) *crls, int show_chain);
You can see how to output 'OK' here:
if (i > 0 && X509_STORE_CTX_get_error(csc) == X509_V_OK) {
printf("%s: OK\n", (file == NULL) ? "stdin" : file);
The function dependence can be found in apps/apps.c

SQLite in C and supporting REGEXP

I'm using sqlite3 in C and I'd like to add support for the REGEXP operator. By default, a user defined function regexp() is not present and calling REGEXP will usually result in an error (according to the SQLite pages).
How do I add a regexp function to support REGEXP? Presumably I will do this via the sqlite3_create_function call, but I don't know what the application-defined regexp() will look like.
Can I use a function from regex.h with sqlite3_create_function and how? Any function I pass to SQLite has to take three arguments of type sqlite3_context*, int, sqlite3_value**. However, the SQLite documents don't seem to explain the meaning of these parameters.
Is there sample code for a C regexp() function?
I've not been able to find much on this using Google or the SQLite pages.
You can also try this:
#include <regex.h>
...
void sqlite_regexp(sqlite3_context* context, int argc, sqlite3_value** values) {
int ret;
regex_t regex;
char* reg = (char*)sqlite3_value_text(values[0]);
char* text = (char*)sqlite3_value_text(values[1]);
if ( argc != 2 || reg == 0 || text == 0) {
sqlite3_result_error(context, "SQL function regexp() called with invalid arguments.\n", -1);
return;
}
ret = regcomp(&regex, reg, REG_EXTENDED | REG_NOSUB);
if ( ret != 0 ) {
sqlite3_result_error(context, "error compiling regular expression", -1);
return;
}
ret = regexec(&regex, text , 0, NULL, 0);
regfree(&regex);
sqlite3_result_int(context, (ret != REG_NOMATCH));
}
...
sqlite3_create_function(*db, "regexp", 2, SQLITE_ANY,0, &sqlite_regexp,0,0)
It would look something like this:
static void user_regexp(sqlite3_context *context, int argc, sqlite3_value **argv)
{
struct re_pattern_buffer buffer;
const char *out;
char *pattern;
char *input_string;
char *result;
struct re_registers regs;
if ((sqlite3_value_type(argv[0]) != SQLITE_TEXT )
|| ((sqlite3_value_type(argv[1]) != SQLITE_TEXT ))
{
sqlite3_result_err("Improper argument types");
return;
}
re_set_syntax(RE_SYNTAX_POSIX_EGREP);
memset(&buffer, 0, sizeof (buffer));
if (!(pattern = strdupa(sqlite3_value_text(argv[0])))
|| !(input_string = strdupa(sqlite3_value_text(argv[1]))))
{
sqlite3_result_err_nomem("Could not allocate memory for strings");
return;
}
if ((out = re_compile_pattern(pattern, strlen(pattern), &buffer))
{
sqlite3_result_err("Could not compile pattern!");
return;
}
if (re_match(&buffer, input_string, strlen(input_string), 0, &regs) < 0)
sqlite3_result_int64(context, 0);
else
{
result = strndupa(input_string + regs.start[0], regs.end[0] - regs.start[0]);
sqlite3_result_text(context, result, NULL, SQLITE_TRANSIENT);
}
}
Okay, a bit too late for this but I'm tempted to post this for all people who are using a C++ Wrapper for the C SQLITE API like the [ SQLiteCpp ] which I am using. This answer assumes that you use SQLiteCpp.
Install Regex for windows binaries from [ here ]. This gives you just enough files ie the regex.h include file and regex2.dll. Do remember to add the path regex.h in your project and have a copy of the dll in the folder containing client executables.
Before building the [ SQLiteCpp ], we need to make some changes to add the regex capabilities to SELECT queries. For this open the Database.cpp file from the [ SQLiteCpp ] project and
Include the regex.h header from the Regex for windows
After all the includes, add below ( of course you can customize to custom fit your needs!) piece of code just below it.
extern "C" {
void sqlite_regexp(sqlite3_context* context, int argc, sqlite3_value** values) {
int ret;
regex_t regex;
char regtext[100];
char* reg = (char*)sqlite3_value_text(values[0]);
sprintf(regtext, ".*%s.*", reg);
//printf("Regtext : %s", regtext);
char* text = (char*)sqlite3_value_text(values[1]);
/* printf("Text : %s\n", text);
printf("Reg : %s\n", reg); */
if (argc != 2 || reg == 0 || text == 0) {
sqlite3_result_error(context, "SQL function regexp() called with invalid arguments.\n", -1);
return;
}
ret = regcomp(&regex, regtext, REG_EXTENDED | REG_NOSUB | REG_ICASE);
if (ret != 0) {
sqlite3_result_error(context, "error compiling regular expression", -1);
return;
}
ret = regexec(&regex, text, 0, NULL, 0);
/* if (ret == 0) {
printf("Found a match. Press any key to continue");
getc(stdin);
}*/
regfree(&regex);
sqlite3_result_int(context, (ret != REG_NOMATCH));
}
}
Now it is time to change the constructors defined in the file. Change those like shown below.
// Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
Database::Database(const char* apFilename,
const int aFlags /*= SQLite::OPEN_READONLY*/,
const int aBusyTimeoutMs/* = 0 */,
const char* apVfs/*= NULL*/) :
mpSQLite(NULL),
mFilename(apFilename)
{
const int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs);
//std::cout << "Reached here";
//sqlite3_create_function_v2(mpSQLite, "REGEXP", 2, SQLITE_ANY,&sqlite_regexp, NULL, NULL, NULL,NULL);
sqlite3_create_function(mpSQLite, "regexp", 2, SQLITE_ANY, 0, &sqlite_regexp, 0, 0);
if (SQLITE_OK != ret)
{
const SQLite::Exception exception(mpSQLite, ret); // must create before closing
sqlite3_close(mpSQLite); // close is required even in case of error on opening
throw exception;
}
else {
}
if (aBusyTimeoutMs > 0)
{
setBusyTimeout(aBusyTimeoutMs);
}
}
// Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
Database::Database(const std::string& aFilename,
const int aFlags /* = SQLite::OPEN_READONLY*/,
const int aBusyTimeoutMs/* = 0*/,
const std::string& aVfs/* = "" */) :
mpSQLite(NULL),
mFilename(aFilename)
{
const int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? NULL : aVfs.c_str());
sqlite3_create_function(mpSQLite, "regexp", 2, SQLITE_ANY, 0, &sqlite_regexp, 0, 0);
if (SQLITE_OK != ret)
{
const SQLite::Exception exception(mpSQLite, ret); // must create before closing
sqlite3_close(mpSQLite); // close is required even in case of error on opening
throw exception;
}
if (aBusyTimeoutMs > 0)
{
setBusyTimeout(aBusyTimeoutMs);
}
}
By now, you've some serious regex capabilities with your sqlite. Just build the project.
Write a client program to test the functionality. It can be something like below ( borrowed without shame from SQLiteCpp Example ).
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <SQLiteCpp/SQLiteCpp.h>
#include <SQLiteCpp/VariadicBind.h>
// Notice no sqlite3.h huh?
// Well, this is a C++ wrapper for the SQLITE CAPI afterall.
#ifdef SQLITECPP_ENABLE_ASSERT_HANDLER
namespace SQLite
{
/// definition of the assertion handler enabled when SQLITECPP_ENABLE_ASSERT_HANDLER is defined in the project (CMakeList.txt)
void assertion_failed(const char* apFile, const long apLine, const char* apFunc, const char* apExpr, const char* apMsg)
{
// Print a message to the standard error output stream, and abort the program.
std::cerr << apFile << ":" << apLine << ":" << " error: assertion failed (" << apExpr << ") in " << apFunc << "() with message \"" << apMsg << "\"\n";
std::abort();
}
}
#endif
/// Get example path
static inline std::string getExamplePath()
{
std::string filePath(__FILE__);
return filePath.substr(0, filePath.length() - std::string("Client.cpp").length());
}
/// Example Database
static const std::string filename_example_db3 = getExamplePath() + "/example.db3";
/// Image
static const std::string filename_logo_png = getExamplePath() + "/logo.png";
/// Object Oriented Basic example
class Example
{
public:
//Constructor
Example() :
mDb(filename_example_db3),
// User change the db and tables accordingly
mQuery(mDb, "SELECT id,name FROM lookup WHERE name REGEXP :keyword")
// Open a database file in readonly mode
{
}
virtual ~Example()
{
}
/// List the rows where the "weight" column is greater than the provided aParamValue
void namehaskeyword(const std::string searchfor)
{
std::cout << "Matching results for " << searchfor << "\n";
// Bind the integer value provided to the first parameter of the SQL query
mQuery.bind(1,searchfor); // same as mQuery.bind(1, aParamValue);
// Loop to execute the query step by step, to get one a row of results at a time
while (mQuery.executeStep())
{
std::cout<<mQuery.getColumn(0) << "\t" << mQuery.getColumn(1) << "\n";
}
// Reset the query to be able to use it again later
mQuery.reset();
}
private:
SQLite::Database mDb; ///< Database connection
SQLite::Statement mQuery; ///< Database prepared SQL query
};
int main()
{
// Using SQLITE_VERSION would require #include <sqlite3.h> which we want to avoid: use SQLite::VERSION if possible.
// std::cout << "SQlite3 version " << SQLITE_VERSION << std::endl;
std::cout << "SQlite3 version " << SQLite::VERSION << " (" << SQLite::getLibVersion() << ")" << std::endl;
std::cout << "SQliteC++ version " << SQLITECPP_VERSION << std::endl;
try
{
// Doing a regex query.
Example example;
char wannaquit = 'n';
std::string keyword;
// Deliberate unlimited loop. You implement something sensible here.
while (wannaquit != 'y') {
// Demonstrates the way to use the same query with different parameter values
std::cout << "Enter the keyword to search for : ";
std::getline(std::cin, keyword);
example.namehaskeyword(keyword);
}
}
catch (std::exception& e)
{
std::cout << "SQLite exception : " << e.what() << std::endl;
return EXIT_FAILURE; // unexpected error : exit the example program
}
return EXIT_SUCCESS;
}
Note : This assumes that the database is in the same folder as your cpp

Read certificate files from memory instead of a file using OpenSSL

I have a server which would listen on HTTPS using OpenSSL. For this, I have to provide the certificate to use. However, the current implementation uses a filename to be provided to the OpenSSL API.
I want the certificate information to be read from memory, so that I don't have to ship the certificate file opening. I tried to google, but I didn't come up with any options.
Is is possible? If so, how do I read certificate files from memory instead of a file using OpenSSL?
EDIT: The following was moved from the comments to the question.
// CURRENT
void start_server()
{
const char *fileName = "cert_and_key.pem";
set_server_ssl_file(fileName);
}
set_server_ssl_file(const char *fileName)
{
//initialize context
SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM);
}
//REQUIRED
void start_server()
{
const char *cert = "--BEGIN CERTIFICATE--............";
const char *key = "--BEGIN RSA PRIVATE KEY--.......";
set_server_ssl_options(cert, key);
}
set_server_ssl_options(const char *cert, const char *key)
{
//IMPLEMENTATION REQUIRED
}
The following code did the job for me:
SSL_CTX *CTX;
X509 *cert = NULL;
RSA *rsa = NULL;
BIO *cbio, *kbio;
const char *cert_buffer = "";
const char *key_buffer = "";
cbio = BIO_new_mem_buf((void*)cert_buffer, -1);
cert = PEM_read_bio_X509(cbio, NULL, 0, NULL);
assert(cert != NULL);
SSL_CTX_use_certificate(CTX, cert);
kbio = BIO_new_mem_buf((void*)key_buffer, -1);
rsa = PEM_read_bio_RSAPrivateKey(kbio, NULL, 0, NULL);
assert(rsa != NULL);
SSL_CTX_use_RSAPrivateKey(CTX, rsa);
The other snippets will only load one certificate. The content of files like http://curl.haxx.se/ca/cacert.pem that contain a lot of different certificates need a new approach. This is adapted from openssl 1.0.1p (mostly openssl-1.0.1p\crypto\x509\by_file.c, char* buf contains the content of a *.pem file, ctx is a boost::asio::ssl::context), add error handling on your own:
BIO *cbio = BIO_new_mem_buf((void*)buf, (int)length);
X509_STORE *cts = SSL_CTX_get_cert_store(ctx.native_handle());
if(!cts || !cbio)
return false;
X509_INFO *itmp;
int i, count = 0, type = X509_FILETYPE_PEM;
STACK_OF(X509_INFO) *inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL);
if (!inf)
{
BIO_free(cbio);//cleanup
return false;
}
//itterate over all entries from the pem file, add them to the x509_store one by one
for (i = 0; i < sk_X509_INFO_num(inf); i++) {
itmp = sk_X509_INFO_value(inf, i);
if (itmp->x509) {
X509_STORE_add_cert(cts, itmp->x509);
count++;
}
if (itmp->crl) {
X509_STORE_add_crl(cts, itmp->crl);
count++;
}
}
sk_X509_INFO_pop_free(inf, X509_INFO_free); //cleanup
BIO_free(cbio);//cleanup
unsigned char *cert_data = (....);
int cert_len = (....);
X509 *cert = d2i_X509(NULL, &cert_data, cert_len);
SSL_CTX_use_certificate(ctx, cert);
unsigned char *pkey_data = /* ... */;
int pkey_len = /* ... */;
RSA *pkey = d2i_RSAPrivateKey(NULL, &pkey_data, pkey_len);
SSL_CTX_use_RSAPrivateKey(ctx, pkey);
Don't forget & before cert_data and pkey_data - and note that OpenSSL modifies these pointers.
There is another response that uses X509_STORE_add_cert, which is up-voted but incorrect. That answer is a way to do SSL_CTX_load_verify_locations in memory, but does not load the server certificate chain. Replies to that comment also indicate that it does not work.
The following code is a load-from-memory implementation of SSL_CTX_use_certificate_chain_file based on the implementation of that function in OpenSSL:
bool load_cert_chain_from_shared_mem(SSL_CTX *context, const char *cert_buffer)
{
BIO *cbio = BIO_new_mem_buf((void*)cert_buffer, -1);
if (!cbio)
return false;
X509_INFO *itmp;
int i, count = 0, type = X509_FILETYPE_PEM;
STACK_OF(X509_INFO) *inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL);
if (!inf)
{
BIO_free(cbio);
return false;
}
/* Iterate over contents of the PEM buffer, and add certs. */
BOOL first = TRUE;
for (i = 0; i < sk_X509_INFO_num(inf); i++) {
itmp = sk_X509_INFO_value(inf, i);
if (itmp->x509)
{
/* First cert is server cert. Remaining, if any, are intermediate certs. */
if (first)
{
first = FALSE;
/*
* Set server certificate. Note that this operation increments the
* reference count, which means that it is okay for cleanup to free it.
*/
if (!SSL_CTX_use_certificate(context, itmp->x509))
goto Error;
if (ERR_peek_error() != 0)
goto Error;
/* Get ready to store intermediate certs, if any. */
SSL_CTX_clear_chain_certs(context);
}
else
{
/* Add intermediate cert to chain. */
if (!SSL_CTX_add0_chain_cert(context, itmp->x509))
goto Error;
/*
* Above function doesn't increment cert reference count. NULL the info
* reference to it in order to prevent it from being freed during cleanup.
*/
itmp->x509 = NULL;
}
}
}
sk_X509_INFO_pop_free(inf, X509_INFO_free);
BIO_free(cbio);
return true;
Error:
sk_X509_INFO_pop_free(inf, X509_INFO_free);
BIO_free(cbio);
return false;
}

x509 certificate verification in C

I do have certificates in DER and PEM format, my goal is to retrieve the fields of Issuer and Subject and verify the certificate with the CA public key and simultaneously verify CA certificate with the root public key.
I am able to retrieve all the details of issuer and subject but unable to verify the certificate.
The API used:
x509 = d2i_X509_fp (fp, &x509); //READING DER Format
x509 = PEM_read_X509 (fp, &x509, NULL, NULL); //READING PEM Format
//to retrieve the Subject:
X509_NAME_oneline(X509_get_subject_name(x509), subject, sizeof (subject));
//to retrieve the Issuer:
X509_NAME_oneline(X509_get_issuer_name(x509), issuer, sizeof (issuer));
//To store the CA public key (in unsigned char *key) that will be used to verify the
//certificate (in my case always sha1WithRSAEncryption):
RSA *x = X509_get_pubkey(x509)->pkey.rsa;
bn = x->n;
//extracts the bytes from public key & convert into unsigned char buffer
buf_len = (size_t) BN_num_bytes (bn);
stored_CA_pubKey = (unsigned char *)malloc (buf_len);
i_n = BN_bn2bin (bn, (unsigned char *)stored_CA_pubKey);
if (i_n != buf_len)
LOG(ERROR," : key error\n");
if (key[0] & 0x80)
LOG(DEBUG, "00\n");
stored_CA_pubKeyLen = EVP_PKEY_size(X509_get_pubkey(x509));
For Verification I went through different approaches but I am unable to verify:
a)
i_x509_verify = X509_verify(cert_x509, ca_pubkey);
b)
/* verify the signature */
int iRet1, iRet2, iReason;
iRet1 = EVP_VerifyInit(&md_ctx, EVP_sha1());
iRet2 = EVP_VerifyUpdate(&md_ctx, cert_code, cert_code_len);
rv = EVP_VerifyFinal(&md_ctx, (const unsigned char *)stored_CA_pubKey,
stored_CA_pubKeyLen, cert_pubkey);
NOTE : cert_code and stored_CA_pubKey are unsigned char buffers.
I use following code for verifying a certificate
init CertStore:
X509_STORE* m_store = X509_STORE_new();
X509_LOOKUP* m_lookup = X509_STORE_add_lookup(m_store,X509_LOOKUP_file());
X509_STORE_load_locations(m_store, "CAFile.pem", NULL);
X509_STORE_set_default_paths(m_store);
X509_LOOKUP_load_file(m_lookup,"CAFile.pem",X509_FILETYPE_PEM)
// alternative lookup by hashdir
// X509_LOOKUP* m_lookup=X509_STORE_add_lookup(m_store,X509_LOOKUP_hash_dir());
VerifyCert:
X509_STORE_CTX *storeCtx = X509_STORE_CTX_new();
X509_STORE_CTX_init(storeCtx,m_store,cert,NULL);
X509_STORE_CTX_set_flags(storeCtx, X509_V_FLAG_CB_ISSUER_CHECK);
if (X509_verify_cert(storeCtx) == 1)
{
printf("success");
}
else
{
printf("Verificatione rror: %s",X509_verify_cert_error_string(storeCtx->error));
}
X509_STORE_CTX_free(storeCtx);
you also need to cleanup m_store
if(m_store != NULL)
{
X509_STORE_free(m_store);
m_store = NULL;
}
Take a look at my self-answered question: https://stackoverflow.com/questions/3412032/openssl-c-how-do-you-verify-a-public-key-was-issued-by-your-private-ca it goes a long way to doing what you need.
X509_STORE* m_store = NULL;
X509_LOOKUP *m_lookup = NULL;
X509_STORE_CTX *storeCtx = NULL;
m_store = X509_STORE_new();
if(NULL == m_store) goto exit;
m_lookup = X509_STORE_add_lookup(m_store, X509_LOOKUP_file());
if(NULL == m_lookup) goto exit;
X509_STORE_load_locations(m_store, CA_CERT_PATH, NULL);
X509_STORE_set_default_paths(m_store);
X509_LOOKUP_load_file(m_lookup,CA_CERT_PATH, X509_FILETYPE_ASN1);
m_lookup = X509_STORE_add_lookup(m_store, X509_LOOKUP_hash_dir());
if(NULL == m_lookup) goto exit;
storeCtx = X509_STORE_CTX_new();
if(NULL == storeCtx) goto exit;
X509_STORE_CTX_init(storeCtx,m_store,cer_x509,NULL);
X509_STORE_CTX_set_flags(storeCtx, /*X509_V_FLAG_CHECK_SS_SIGNATURE*/0x4000);
if (X509_verify_cert(storeCtx) == 1)
{
printf("success\n");
}
else
{
printf("Verification error: %s\n",X509_verify_cert_error_string(storeCtx->error));
}
exit:
if(NULL != storeCtx) X509_STORE_CTX_free(storeCtx);
if(m_store != NULL)
{
X509_STORE_free(m_store);
m_store = NULL;
}
After Doing this also I am unable to verify Self signed certificate

Resources