C++ Check CRL For Revocation



//wget http://crl3.digicert.com/ssca-ecc-g1.crl
//wget http://curl.haxx.se/ca/cacert.pem
//cat cacert.pem |tr '\n' '%' |sed -e 's/-----END CERTIFICATE-----%%[^%]\+%=\+%-----BEGIN CERTIFICATE-----/-----END CERTIFICATE-----%-----BEGIN CERTIFICATE-----/'  |tr '%' '\n' > cacerts_.pem
//sudo apt-get install libssl-dev
//g++ main.cpp -lcrypto && ./a.out
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/ssl.h>
#include <openssl/crypto.h>
#include <openssl/ocsp.h>
#include <openssl/pem.h>
#include <iostream>
#include <sstream>
#include <vector>
#include <map>
#include <string>
 
using std::cout;
using std::endl;
using std::stringstream;
using std::map;
using std::vector;
using std::string;
 
//----------------------------------------------------------------------
int is_revoked_by_crl(X509 *x509, X509 *issuer, X509_CRL *crl_file)
{
    int is_revoked = -1;
    if (issuer)
    {
        EVP_PKEY *ikey=X509_get_pubkey(issuer);
        ASN1_INTEGER *serial = X509_get_serialNumber(x509);
 
        if (crl_file && ikey && X509_CRL_verify(crl_file, ikey))
        {
            is_revoked = 0;
            STACK_OF(X509_REVOKED) *revoked_list = crl_file->crl->revoked;
            for (int j = 0; j < sk_X509_REVOKED_num(revoked_list) && !is_revoked; j++)
            {
                X509_REVOKED *entry = sk_X509_REVOKED_value(revoked_list, j);
                if (entry->serialNumber->length==serial->length)
                {
                    if (memcmp(entry->serialNumber->data, serial->data, serial->length)==0)
                    {
                        is_revoked=1;
                    }
                }
            }
        }
    }
    return is_revoked;
}
//----------------------------------------------------------------------
int verify_trust(X509 *x509, X509* issuer, X509_CRL *crl_file, const string& cacerts_pem_path)
{
    STACK_OF (X509)* chain = sk_X509_new_null();
    sk_X509_push(chain, issuer);
 
    X509_STORE *store=X509_STORE_new();
    if (store==NULL) { return 0; }
 
    X509_LOOKUP *lookup=X509_STORE_add_lookup(store,X509_LOOKUP_file());
    if (lookup==NULL) { return 0; }
 
    int q1 = X509_LOOKUP_load_file(lookup, cacerts_pem_path.c_str(), X509_FILETYPE_PEM);
    if (!q1) { return 0; }
 
    X509_STORE_CTX *csc = X509_STORE_CTX_new();
    X509_STORE_CTX_init(csc, store, x509, chain);
    X509_STORE_CTX_set_purpose(csc, X509_PURPOSE_SSL_SERVER);
 
    X509_STORE_add_crl(store, crl_file);
    X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK);
 
    int verify_result=X509_verify_cert(csc);
    if (verify_result!=1)
        cout << "Trust Failure: " << X509_verify_cert_error_string(csc->error) << endl;
 
    X509_STORE_CTX_cleanup(csc);
    X509_STORE_CTX_free(csc);
    X509_STORE_free(store);
    sk_X509_free(chain);
 
    return verify_result;
}
//----------------------------------------------------------------------
vector<string> x509_crl_urls(X509 *x509)
{
    vector<string> list;
    int nid = NID_crl_distribution_points;
    STACK_OF(DIST_POINT) * dist_points =(STACK_OF(DIST_POINT) *)X509_get_ext_d2i(x509, nid, NULL, NULL);
    for (int j = 0; j < sk_DIST_POINT_num(dist_points); j++)
    {
        DIST_POINT *dp = sk_DIST_POINT_value(dist_points, j);
        DIST_POINT_NAME    *distpoint = dp->distpoint;
        if (distpoint->type==0)//fullname GENERALIZEDNAME
        {
            for (int k = 0; k < sk_GENERAL_NAME_num(distpoint->name.fullname); k++) 
            {
                GENERAL_NAME *gen = sk_GENERAL_NAME_value(distpoint->name.fullname, k);
                ASN1_IA5STRING *asn1_str = gen->d.uniformResourceIdentifier;
                list.push_back( string( (char*)ASN1_STRING_data(asn1_str), ASN1_STRING_length(asn1_str) ) );
            }
        }
        else if (distpoint->type==1)//relativename X509NAME
        {
            STACK_OF(X509_NAME_ENTRY) *sk_relname = distpoint->name.relativename;
            for (int k = 0; k < sk_X509_NAME_ENTRY_num(sk_relname); k++) 
            {
                X509_NAME_ENTRY *e = sk_X509_NAME_ENTRY_value(sk_relname, k);
                ASN1_STRING *d = X509_NAME_ENTRY_get_data(e);
                list.push_back( string( (char*)ASN1_STRING_data(d), ASN1_STRING_length(d) ) );
            }
        }
    }
    return list;
}
//----------------------------------------------------------------------
X509 *new_x509(const char* cert_bytes)
{
    BIO *bio_mem = BIO_new(BIO_s_mem());
    BIO_puts(bio_mem, cert_bytes);
    X509 * x509 = PEM_read_bio_X509(bio_mem, NULL, NULL, NULL);
    BIO_free(bio_mem);
    return x509;
}
//----------------------------------------------------------------------
X509_CRL *new_CRL(const char* crl_filename)
{
    BIO *bio = BIO_new_file(crl_filename, "r");
    X509_CRL *crl_file=d2i_X509_CRL_bio(bio,NULL); //if (format == FORMAT_PEM) crl=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL);
    BIO_free(bio);
    return crl_file;
}
//----------------------------------------------------------------------
int main(int argc, char **argv)
{
    OpenSSL_add_all_algorithms();
 
    const char cert1_bytes[] = "-----BEGIN CERTIFICATE-----" "\n"
"MIIDszCCAzigAwIBAgIQDGv40oFewTIKpCtIVTYSOTAKBggqhkjOPQQDAjBMMQsw" "\n"
"CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSYwJAYDVQQDEx1EaWdp" "\n"
"Q2VydCBFQ0MgU2VjdXJlIFNlcnZlciBDQTAeFw0xNTA3MjgwMDAwMDBaFw0xNjA5" "\n"
"MzAxMjAwMDBaMHQxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhJbGxpbm9pczEQMA4G" "\n"
"A1UEBxMHQ2hpY2FnbzEoMCYGA1UEChMfWmFja3MgSW52ZXN0bWVudCBSZXNlYXJj" "\n"
"aCwgSW5jLjEWMBQGA1UEAxMNd3d3LnphY2tzLmNvbTBZMBMGByqGSM49AgEGCCqG" "\n"
"SM49AwEHA0IABOYOkwbEkkL/xKRUFV8xIfXYm5G/CnwpopbjZaLki/buATo2eSNd" "\n"
"0gPYzhzrfpd9HWV34Z/kO/yocvpbOTFrNDijggHSMIIBzjAfBgNVHSMEGDAWgBSj" "\n"
"neYf+do5T8Bu6JHLlaXaMeIKnzAdBgNVHQ4EFgQUtGr+7XN7qK4ZmnEDBNn7V+YI" "\n"
"QU0wIwYDVR0RBBwwGoINd3d3LnphY2tzLmNvbYIJemFja3MuY29tMA4GA1UdDwEB" "\n"
"/wQEAwIDiDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwaQYDVR0fBGIw" "\n"
"YDAuoCygKoYoaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NzY2EtZWNjLWcxLmNy" "\n"
"bDAuoCygKoYoaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NzY2EtZWNjLWcxLmNy" "\n"
"bDBCBgNVHSAEOzA5MDcGCWCGSAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczov" "\n"
"L3d3dy5kaWdpY2VydC5jb20vQ1BTMHsGCCsGAQUFBwEBBG8wbTAkBggrBgEFBQcw" "\n"
"AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEUGCCsGAQUFBzAChjlodHRwOi8v" "\n"
"Y2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRFQ0NTZWN1cmVTZXJ2ZXJDQS5j" "\n"
"cnQwDAYDVR0TAQH/BAIwADAKBggqhkjOPQQDAgNpADBmAjEA2vqnY3CyBs18df3H" "\n"
"h+DJBj8t91Ix6DKdJdrJg/HiPtg9EwQ8TRwZ5Fg4HgTmNaTiAjEAxzYXnrz9tK9N" "\n"
"DEh5AG+tvna+rzsBwEAh/rBPXeFQx2uCt9deviww57Eg4pSx5cBL" "\n"
"-----END CERTIFICATE-----" "\n";
 
    const char issuer1_bytes[] = "-----BEGIN CERTIFICATE-----" "\n"
"MIIDrDCCApSgAwIBAgIQCssoukZe5TkIdnRw883GEjANBgkqhkiG9w0BAQwFADBh" "\n"
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3" "\n"
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD" "\n"
"QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaMEwxCzAJBgNVBAYTAlVT" "\n"
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJjAkBgNVBAMTHURpZ2lDZXJ0IEVDQyBT" "\n"
"ZWN1cmUgU2VydmVyIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4ghC6nfYJN6g" "\n"
"LGSkE85AnCNyqQIKDjc/ITa4jVMU9tWRlUvzlgKNcR7E2Munn17voOZ/WpIRllNv" "\n"
"68DLP679Wz9HJOeaBy6Wvqgvu1cYr3GkvXg6HuhbPGtkESvMNCuMo4IBITCCAR0w" "\n"
"EgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwNAYIKwYBBQUHAQEE" "\n"
"KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQgYDVR0f" "\n"
"BDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xv" "\n"
"YmFsUm9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYc" "\n"
"aHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUo53mH/naOU/A" "\n"
"buiRy5Wl2jHiCp8wHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJ" "\n"
"KoZIhvcNAQEMBQADggEBAMeKoENL7HTJxavVHzA1Nm6YVntIrAVjrnuaVyRXzG/6" "\n"
"3qttnMe2uuzO58pzZNvfBDcKAEmzP58mrZGMIOgfiA4q+2Y3yDDo0sIkp0VILeoB" "\n"
"UEoxlBPfjV/aKrtJPGHzecicZpIalir0ezZYoyxBEHQa0+1IttK7igZFcTMQMHp6" "\n"
"mCHdJLnsnLWSB62DxsRq+HfmNb4TDydkskO/g+l3VtsIh5RHFPVfKK+jaEyDj2D3" "\n"
"loB5hWp2Jp2VDCADjT7ueihlZGak2YPqmXTNbk19HOuNssWvFhtOyPNV6og4ETQd" "\n"
"Ea8/B6hPatJ0ES8q/HO3X8IVQwVs1n3aAr0im0/T+Xc=" "\n"
"-----END CERTIFICATE-----" "\n";
 
    //download these files first...
    //wget http://crl3.digicert.com/ssca-ecc-g1.crl
    //wget http://curl.haxx.se/ca/cacert.pem
 
    X509 * x509 = new_x509(cert1_bytes);
    X509 * issuer = new_x509(issuer1_bytes);
    vector<string> crl_urls = x509_crl_urls(x509);
    for(size_t i=0,ix=crl_urls.size(); i<ix; i++)
    {
        cout << crl_urls[i] << endl;
    }
    X509_CRL *crl_file = new_CRL("ssca-ecc-g1.crl");
 
    int is_revoked = is_revoked_by_crl(x509, issuer, crl_file);
    if (is_revoked== 0) cout << "Method 1: Not Revoked" << endl;
    if (is_revoked== 1) cout << "Method 1: Revoked" << endl;
    if (is_revoked==-1) cout << "Method 1: Revocation Unknown" << endl;
 
    int is_trusted = verify_trust(x509, issuer, crl_file, "cacerts.pem");
    if (is_trusted== 1) cout << "Method 2: Trusted" << endl;
    if (is_trusted== 0) cout << "Method 2: Not Trusted" << endl;
    if (is_trusted==-1) cout << "Method 2: Trust Unknown" << endl;
 
    X509_CRL_free(crl_file);
    X509_free(issuer);
    X509_free(x509);
}
//----------------------------------------------------------------------
code snippets are licensed under Creative Commons CC-By-SA 3.0 (unless otherwise specified)