Parsing X.509 Certificates with OpenSSL and C

Zakir Durumeric | October 13, 2013

While OpenSSL has become one of the defacto libraries for performing SSL and TLS operations, the library is surprisingly opaque and its documentation is, at times, abysmal. As part of our recent research, we have been performing Internet-wide scans of HTTPS hosts in order to better understand the HTTPS ecosystem (Analysis of the HTTPS Certificate EcosystemZMap: Fast Internet-Wide Scanning and its Security Applications). We use OpenSSL for many of these operations including parsing X.509 certificates. However, in order to parse and validate certificates, our team had to dig through parts of the OpenSSL code base and multiple sources of documention to find the correct functions to parse each piece of data. This post is intended to document many of these operations in a single location in order to hopefully alleviate this painful process for others.

If you have found other pieces of code particularly helpful, please don’t hesitate to send them alongand we’ll update the post. I want to note that if you’re starting to develop against OpenSSL, O’Reilly’sNetwork Security with OpenSSL is an incredibly helpful resource; the book contains many snippets and pieces of documentation that I was not able to find anywhere online. I also want to thank James Kastenwho helped find and document several of these solutions.

Creating an OpenSSL X509 Object

All of the operations we discuss start with either a single X.509 certificate or a “stack” of certificates. OpenSSL represents a single certificate with an X509 struct and a list of certificates, such as the certificate chain presented during a TLS handshake as a STACK_OF(X509). Given that the parsing and validation stems from here, it only seems reasonable to start with how to create or access an X509 object. A few common scenarios are:

1. You have initiated an SSL or TLS connection using OpenSSL.

In this case, you have access to an OpenSSL SSL struct from which you can extract the presented certificate as well as the entire certificate chain that the server presented to the client. In our specific case, we use libevent to perform TLS connections and can access the SSL struct from the libevent bufferevent: SSL *ssl = bufferevent_openssl_get_ssl(bev). This will clearly be different depending on how you complete your connection. However, once you have your SSL context, the server certificate and presented chain can be extracted as follows:

#include <openssl/x509.h>
#include <openssl/x509v3.h> X509 *cert = SSL_get_peer_certificate(ssl);
STACK_OF(X509) *sk = SSL_get_peer_cert_chain(ssl);

We have found that at times, OpenSSL will produce an empty certificate chain (SSL_get_peer_cert_chain will come back NULL) even though a client certificate has been presented (the server certificate is generally presented as the first certificate in the stack along with the remaining chain). It’s unclear to us why this happens, but it’s not a deal breaker, as it’s easy to create a new stack of certificates:

X509 *cert = SSL_get_peer_certificate(ssl);
STACK_OF(X509) *sk = sk_X509_new_null();
sk_X509_push(sk, cert);

2. You have stored a certificate on disk as a PEM file.

For reference, a PEM file is the Base64-encoded version of an X.509 certificate, which should look similar to the following:

-----BEGIN CERTIFICATE-----
MIIHIDCCBgigAwIBAgIIMrM8cLO76sYwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
iftrJvzAOMAPY5b/klZvqH6Ddubg/hUVPkiv4mr5MfWfglCQdFF1EBGNoZSFAU7y
ZkGENAvDmv+5xVCZELeiWA2PoNV4m/SW6NHrF7gz4MwQssqP9dGMbKPOF/D2nxic
TnD5WkGMCWpLgqDWWRoOrt6xf0BPWukQBDMHULlZgXzNtoGlEnwztLlnf0I/WWIS
eBSyDTeFJfopvoqXuws23X486fdKcCAV1n/Nl6y2z+uVvcyTRxY2/jegmV0n0kHf
gfcKzw==
-----END CERTIFICATE-----

In this case, you can access the certificate as follows:

#include <stdio.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h> FILE *fp = fopen(path, "r");
if (!fp) {
fprintf(stderr, "unable to open: %s\n", path);
return EXIT_FAILURE;
} X509 *cert = PEM_read_X509(fp, NULL, NULL, NULL);
if (!cert) {
fprintf(stderr, "unable to parse certificate in: %s\n", path);
fclose(fp);
return EXIT_FAILURE;
} // any additional processing would go here.. X509_free(cert);
fclose(fp);

3. You have access to the raw certificate in memory.

In the case that you have access to the raw encoding of the certificate in memory, you can parse it as follows. This is useful if you have stored raw certificates in a database or similar data store.

#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/bio.h> const unsigned char *data = ... ;
size_t len = ... ; X509 *cert = d2i_X509(NULL, &data, len);
if (!cert) {
fprintf(stderr, "unable to parse certificate in memory\n");
return EXIT_FAILURE;
} // any additional processing would go here.. X509_free(cert);

4. You have access to the Base64 encoded PEM in memory.

char* pemCertString = ..... (includes "-----BEGIN/END CERTIFICATE-----")
size_t certLen = strlen(pemCertString); BIO* certBio = BIO_new(BIO_s_mem());
BIO_write(certBio, pemCertString, certLen);
X509* certX509 = PEM_read_bio_X509(certBio, NULL, NULL, NULL);
if (!certX509) {
fprintf(stderr, "unable to parse certificate in memory\n");
return EXIT_FAILURE;
} // do stuff BIO_free(certBio);
X509_free(certX509);

Parsing Certificates

Now that we have access to a certificate in OpenSSL, we’ll focus on how to extract useful data from the certificate. We don’t include the #includes in every statement, but use the following headers throughout our codebase:

#include <openssl/x509v3.h>
#include <openssl/bn.h>
#include <openssl/asn1.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <openssl/pem.h>
#include <openssl/bio.h> OpenSSL_add_all_algorithms();

You will also need the development versions of the OpenSSL libraries and to compile with -lssl.

Subject and Issuer

The certificate subject and issuer can be easily extracted and represented as a single string as follows:

char *subj = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
char *issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);

These can be freed by calling OPENSSL_free.

By default, the subject and issuer are returned in the following form:

/C=US/ST=California/L=Mountain View/O=Google Inc/CN=*.google.com

If you want to convert these into a more traditional looking DN, such as:

C=US, ST=Texas, L=Austin, O=Polycom Inc., OU=Video Division, CN=a.digitalnetbr.net

they can be converted with the following code:

int i, curr_spot = 0;
char *s = tmpBuf + 1; /* skip the first slash */
char *c = s;
while (1) {
if (((*s == '/') && ((s[1] >= 'A') && (s[1] <= 'Z') &&
((s[2] == '=') || ((s[2] >= 'A') && (s[2] <= 'Z')
&& (s[3] == '='))))) || (*s == '\0')) {
i = s - c;
strncpy(destination + curr_spot, c, i);
curr_spot += i;
assert(curr_spot < size);
c = s + 1; /* skip following slash */
if (*s != '\0') {
strncpy(destination + curr_spot, ", ", 2);
curr_spot += 2;
}
}
if (*s == '\0')
break;
++s;
}

It is also possible to extract particular elements from the subject. For example, the following code will iterate over all the values in the subject:

X509_NAME *subj = X509_get_subject_name(cert);

for (int i = 0; i < X509_NAME_entry_count(subj); i++) {
X509_NAME_ENTRY *e = X509_NAME_get_entry(subj, i);
ASN1_STRING *d = X509_NAME_ENTRY_get_data(e);
char *str = ASN1_STRING_data(d);
}

or

for (;;) {
int lastpos = X509_NAME_get_index_by_NID(subj, NID_commonName, lastpos);
if (lastpos == -1)
break;
X509_NAME_ENTRY *e = X509_NAME_get_entry(subj, lastpos);
/* Do something with e */
}

Cryptographic (e.g. SHA-1) Fingerprint

We can calculate the SHA-1 fingerprint (or any other fingerprint) with the following code:

#define SHA1LEN 20
char buf[SHA1LEN]; const EVP_MD *digest = EVP_sha1();
unsigned len; int rc = X509_digest(cert, digest, (unsigned char*) buf, &len);
if (rc == 0 || len != SHA1LEN) {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;

This will produce the raw fingerprint. This can be converted to the human readable hex version as follows:

void hex_encode(unsigned char* readbuf, void *writebuf, size_t len)
{
for(size_t i=0; i < len; i++) {
char *l = (char*) (2*i + ((intptr_t) writebuf));
sprintf(l, "%02x", readbuf[i]);
}
} char strbuf[2*SHA1LEN+1];
hex_encode(buf, strbuf, SHA1LEN);

Version

Parsing the certificate version is straight-foward; the only oddity is that it is zero-indexed:

int version = ((int) X509_get_version(cert)) + 1;

Serial Number

Serial numbers can be arbitrarily large as well as positive or negative. As such, we handle it as a string instead of a typical integer in our processing.

#define SERIAL_NUM_LEN 1000;
char serial_number[SERIAL_NUM_LEN+1]; ASN1_INTEGER *serial = X509_get_serialNumber(cert); BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL);
if (!bn) {
fprintf(stderr, "unable to convert ASN1INTEGER to BN\n");
return EXIT_FAILURE;
} char *tmp = BN_bn2dec(bn);
if (!tmp) {
fprintf(stderr, "unable to convert BN to decimal string.\n");
BN_free(bn);
return EXIT_FAILURE;
} if (strlen(tmp) >= len) {
fprintf(stderr, "buffer length shorter than serial number\n");
BN_free(bn);
OPENSSL_free(tmp);
return EXIT_FAILURE;
} strncpy(buf, tmp, len);
BN_free(bn);
OPENSSL_free(tmp);

Signature Algorithm

The signature algorithm on a certificate is stored as an OpenSSSL NID:

int pkey_nid = OBJ_obj2nid(cert->cert_info->key->algor->algorithm);

if (pkey_nid == NID_undef) {
fprintf(stderr, "unable to find specified signature algorithm name.\n");
return EXIT_FAILURE;
}

This can be translated into a string representation (either short name or long description):

char sigalgo_name[SIG_ALGO_LEN+1];
const char* sslbuf = OBJ_nid2ln(pkey_nid); if (strlen(sslbuf) > PUBKEY_ALGO_LEN) {
fprintf(stderr, "public key algorithm name longer than allocated buffer.\n");
return EXIT_FAILURE;
} strncpy(buf, sslbuf, PUBKEY_ALGO_LEN);

This will result in a string such as sha1WithRSAEncryption or md5WithRSAEncryption.

Public Key

Parsing the public key on a certificate is type-specific. Here, we provide information on how to extract which type of key is included and to parse RSA and DSA keys:

char pubkey_algoname[PUBKEY_ALGO_LEN];

int pubkey_algonid = OBJ_obj2nid(cert->cert_info->key->algor->algorithm);

if (pubkey_algonid == NID_undef) {
fprintf(stderr, "unable to find specified public key algorithm name.\n");
return EXIT_FAILURE;
} const char* sslbuf = OBJ_nid2ln(pubkey_algonid);
assert(strlen(sslbuf) < PUBKEY_ALGO_LEN);
strncpy(buf, sslbuf, PUBKEY_ALGO_LEN); if (pubkey_algonid == NID_rsaEncryption || pubkey_algonid == NID_dsa) { EVP_PKEY *pkey = X509_get_pubkey(cert);
IFNULL_FAIL(pkey, "unable to extract public key from certificate"); RSA *rsa_key;
DSA *dsa_key;
char *rsa_e_dec, *rsa_n_hex, *dsa_p_hex, *dsa_p_hex,
*dsa_q_hex, *dsa_g_hex, *dsa_y_hex; switch(pubkey_algonid) { case NID_rsaEncryption: rsa_key = pkey->pkey.rsa;
IFNULL_FAIL(rsa_key, "unable to extract RSA public key"); rsa_e_dec = BN_bn2dec(rsa_key->e);
IFNULL_FAIL(rsa_e_dec, "unable to extract rsa exponent"); rsa_n_hex = BN_bn2hex(rsa_key->n);
IFNULL_FAIL(rsa_n_hex, "unable to extract rsa modulus"); break; case NID_dsa: dsa_key = pkey->pkey.dsa;
IFNULL_FAIL(dsa_key, "unable to extract DSA pkey"); dsa_p_hex = BN_bn2hex(dsa_key->p);
IFNULL_FAIL(dsa_p_hex, "unable to extract DSA p"); dsa_q_hex = BN_bn2hex(dsa_key->q);
IFNULL_FAIL(dsa_q_hex, "unable to extract DSA q"); dsa_g_hex = BN_bn2hex(dsa_key->g);
IFNULL_FAIL(dsa_g_hex, "unable to extract DSA g"); dsa_y_hex = BN_bn2hex(dsa_key->pub_key);
IFNULL_FAIL(dsa_y_hex, "unable to extract DSA y"); break; default:
break;
} EVP_PKEY_free(pkey);
}

Validity Period

OpenSSL represents the not-valid-after (expiration) and not-valid-before as ASN1_TIME objects, which can be extracted as follows:

ASN1_TIME *not_before = X509_get_notBefore(cert);
ASN1_TIME *not_after = X509_get_notAfter(cert);

These can be converted into ISO-8601 timestamps using the following code:

#define DATE_LEN 128

int convert_ASN1TIME(ASN1_TIME *t, char* buf, size_t len)
{
int rc;
BIO *b = BIO_new(BIO_s_mem());
rc = ASN1_TIME_print(b, t);
if (rc <= 0) {
log_error("fetchdaemon", "ASN1_TIME_print failed or wrote no data.\n");
BIO_free(b);
return EXIT_FAILURE;
}
rc = BIO_gets(b, buf, len);
if (rc <= 0) {
log_error("fetchdaemon", "BIO_gets call failed to transfer contents to buf");
BIO_free(b);
return EXIT_FAILURE;
}
BIO_free(b);
return EXIT_SUCCESS;
} char not_after_str[DATE_LEN];
convert_ASN1TIME(not_after, not_after_str, DATE_LEN); char not_before_str[DATE_LEN];
convert_ASN1TIME(not_before, not_before_str, DATE_LEN);

CA Status

Checking whether a certificate is a valid CA certificate is not a boolean operation as you might expect. There are several avenues through which a certificate can be interpreted as CA certificate. As such, instead of directly checking various X.509 extensions, it is more reliable to use X509_check_ca. Any value >= 1 is considered a CA certificate whereas 0 is not a CA certificate.

int raw = X509_check_ca(cert);

Other X.509 Extensions

Certificates can contain any other arbitrary extensions. The following code will loop through all of the extensions on a certificate and print them out:

STACK_OF(X509_EXTENSION) *exts = cert->cert_info->extensions;

int num_of_exts;
if (exts) {
num_of_exts = sk_X509_EXTENSION_num(exts);
} else {
num_of_exts = 0
} IFNEG_FAIL(num_of_exts, "error parsing number of X509v3 extensions."); for (int i=0; i < num_of_exts; i++) { X509_EXTENSION *ex = sk_X509_EXTENSION_value(exts, i);
IFNULL_FAIL(ex, "unable to extract extension from stack");
ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex);
IFNULL_FAIL(obj, "unable to extract ASN1 object from extension"); BIO *ext_bio = BIO_new(BIO_s_mem());
IFNULL_FAIL(ext_bio, "unable to allocate memory for extension value BIO");
if (!X509V3_EXT_print(ext_bio, ex, 0, 0)) {
M_ASN1_OCTET_STRING_print(ext_bio, ex->value);
} BUF_MEM *bptr;
BIO_get_mem_ptr(ext_bio, &bptr);
BIO_set_close(ext_bio, BIO_NOCLOSE); // remove newlines
int lastchar = bptr->length;
if (lastchar > 1 && (bptr->data[lastchar-1] == '\n' || bptr->data[lastchar-1] == '\r')) {
bptr->data[lastchar-1] = (char) 0;
}
if (lastchar > 0 && (bptr->data[lastchar] == '\n' || bptr->data[lastchar] == '\r')) {
bptr->data[lastchar] = (char) 0;
} BIO_free(ext_bio); unsigned nid = OBJ_obj2nid(obj);
if (nid == NID_undef) {
// no lookup found for the provided OID so nid came back as undefined.
char extname[EXTNAME_LEN];
OBJ_obj2txt(extname, EXTNAME_LEN, (const ASN1_OBJECT *) obj, 1);
printf("extension name is %s\n", extname);
} else {
// the OID translated to a NID which implies that the OID has a known sn/ln
const char *c_ext_name = OBJ_nid2ln(nid);
IFNULL_FAIL(c_ext_name, "invalid X509v3 extension name");
printf("extension name is %s\n", c_ext_name);
} printf("extension length is %u\n", bptr->length)
printf("extension value is %s\n", bptr->data)
}

Misordered Certificate Chains

At times, we’ll receive misordered certificate chains. The following code will attempt to reorder certificates to construct a rational certificate chain based on each certificate’s subject and issuer string. The algorithm is O(n^2), but we generally only receive two or three certificates and in the majority-case, they will already be in the correct order.

	STACK_OF(X509) *r_sk = sk_X509_new_null();
sk_X509_push(r_sk, sk_X509_value(st, 0)); for (int i=1; i < sk_X509_num(st); i++) {
X509 *prev = sk_X509_value(r_sk, i-1);
X509 *next = NULL;
for (int j=1; j < sk_X509_num(st); j++) {
X509 *cand = sk_X509_value(st, j);
if (!X509_NAME_cmp(cand->cert_info->subject, prev->cert_info->issuer)
|| j == sk_X509_num(st) - 1) {
next = cand;
break;
}
}
if (next) {
sk_X509_push(r_sk, next);
} else {
// we're unable to figure out the correct stack so just use the original one provided.
sk_X509_free(r_sk);
r_sk = sk_X509_dup(st);
break;
}
}

Validating Certificates

In our scans, we oftentimes use multiple CA stores in order to emulate different browsers. Here, we describe how we create specialized stores and validate against them.

We can create a store based on a particular file with the following:

X509_STORE *s = X509_STORE_new();
if (s == NULL) {
fprintf(stderr, "unable to create new X509 store.\n");
return NULL;
}
int rc = X509_STORE_load_locations(s, store_path, NULL);
if (rc != 1) {
fprintf(stderr, "unable to load certificates at %s to store\n", store_path);
X509_STORE_free(s);
return NULL;
}
return s;

And then validate certificates against the store with the following:

X509_STORE_CTX *ctx = X509_STORE_CTX_new();
if (!ctx) {
fprintf(stderr, "unable to create STORE CTX\n");
return -1;
}
if (X509_STORE_CTX_init(ctx, store, cert, st) != 1) {
fprintf(stderr, "unable to initialize STORE CTX.\n");
X509_STORE_CTX_free(ctx);
return -1;
}
int rc = X509_verify_cert(ctx);
X509_STORE_CTX_free(ctx);
return rc;

It’s worth noting that self-signed certificates will always fail OpenSSL’s validation. While this might make sense in most client applications, we are oftentimes interested in other errors that might be present. We validate self-signed certificates by adding them into a temporary store and then validating against it. It’s a bick hackish, but is much easier than re-implementing OpenSSL’s validation techniques.

X509_STORE *s = X509_STORE_new();
int num = sk_X509_num(sk);
X509 *top = sk_X509_value(st, num-1);
X509_STORE_add_cert(s, top);
X509_STORE_CTX *ctx = X509_STORE_CTX_new();
X509_STORE_CTX_init(ctx, s, cert, st);
int rc = X509_verify_cert(ctx);
if (rc == 1) {
// validated OK. either trusted or self signed.
} else {
// validation failed
int err = X509_STORE_CTX_get_error(ctx);
} // any additional processing.. X509_STORE_CTX_free(ctx);
X509_STORE_free(s);

Sometimes you will also find that you just need to check whether a certificate has been issued by a trusted source instead of just considering whether it is currently valid, which can be done using X509_check_issued. For example, if you wanted to check whether a certificate was self-signed:

if (X509_check_issued(cert, cert) == X509_V_OK) {
is_self_signed = 1;
} else {
is_self_signed = 0;
}

Helper Functions

There are several other functions that were used in troubleshooting and might be of help while you’re developing code against OpenSSL.

Print out the basic information about a certificate:

#define MAX_LENGTH 1024

void print_certificate(X509* cert) {
char subj[MAX_LENGTH+1];
char issuer[MAX_LENGTH+1];
X509_NAME_oneline(X509_get_subject_name(cert), subj, MAX_LENGTH);
X509_NAME_oneline(X509_get_issuer_name(cert), issuer, MAX_LENGTH);
printf("certificate: %s\n", subj);
printf("\tissuer: %s\n\n", issuer);
}

Print out each certificate in a given stack:

void print_stack(STACK_OF(X509)* sk)
{
unsigned len = sk_X509_num(sk);
printf("Begin Certificate Stack:\n");
for(unsigned i=0; i<len; i++) {
X509 *cert = sk_X509_value(sk, i);
print_certificate(cert);
}
printf("End Certificate Stack\n");
}

Check whether two certificate stacks are identical:

int certparse_sk_X509_cmp(STACK_OF(X509) *a, STACK_OF(X509) *b)
{
int a_len = sk_X509_num(a);
int b_len = sk_X509_num(b);
if (a_len != b_len) {
return 1;
}
for (int i=0; i < a_len; i++) {
if (X509_cmp(sk_X509_value(a, i), sk_X509_value(b, i))) {
return 1;
}
}
return 0;
}

Check whether the subject and issuer string on a certificate are identical:

int certparse_subjeqissuer(X509 *cert)
{
char *s = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
char *i = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
int rc = strcmp(s, i);
OPENSSL_free(s);
OPENSSL_free(i);
return (!rc);
}

Convert an OpenSSL error constant into a human readable string:

const char* get_validation_errstr(long e) {
switch ((int) e) {
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
return "ERR_UNABLE_TO_GET_ISSUER_CERT";
case X509_V_ERR_UNABLE_TO_GET_CRL:
return "ERR_UNABLE_TO_GET_CRL";
case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
return "ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE";
case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
return "ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE";
case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
return "ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY";
case X509_V_ERR_CERT_SIGNATURE_FAILURE:
return "ERR_CERT_SIGNATURE_FAILURE";
case X509_V_ERR_CRL_SIGNATURE_FAILURE:
return "ERR_CRL_SIGNATURE_FAILURE";
case X509_V_ERR_CERT_NOT_YET_VALID:
return "ERR_CERT_NOT_YET_VALID";
case X509_V_ERR_CERT_HAS_EXPIRED:
return "ERR_CERT_HAS_EXPIRED";
case X509_V_ERR_CRL_NOT_YET_VALID:
return "ERR_CRL_NOT_YET_VALID";
case X509_V_ERR_CRL_HAS_EXPIRED:
return "ERR_CRL_HAS_EXPIRED";
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
return "ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD";
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
return "ERR_ERROR_IN_CERT_NOT_AFTER_FIELD";
case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
return "ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD";
case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
return "ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD";
case X509_V_ERR_OUT_OF_MEM:
return "ERR_OUT_OF_MEM";
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
return "ERR_DEPTH_ZERO_SELF_SIGNED_CERT";
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
return "ERR_SELF_SIGNED_CERT_IN_CHAIN";
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
return "ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY";
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
return "ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE";
case X509_V_ERR_CERT_CHAIN_TOO_LONG:
return "ERR_CERT_CHAIN_TOO_LONG";
case X509_V_ERR_CERT_REVOKED:
return "ERR_CERT_REVOKED";
case X509_V_ERR_INVALID_CA:
return "ERR_INVALID_CA";
case X509_V_ERR_PATH_LENGTH_EXCEEDED:
return "ERR_PATH_LENGTH_EXCEEDED";
case X509_V_ERR_INVALID_PURPOSE:
return "ERR_INVALID_PURPOSE";
case X509_V_ERR_CERT_UNTRUSTED:
return "ERR_CERT_UNTRUSTED";
case X509_V_ERR_CERT_REJECTED:
return "ERR_CERT_REJECTED";
case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
return "ERR_SUBJECT_ISSUER_MISMATCH";
case X509_V_ERR_AKID_SKID_MISMATCH:
return "ERR_AKID_SKID_MISMATCH";
case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
return "ERR_AKID_ISSUER_SERIAL_MISMATCH";
case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
return "ERR_KEYUSAGE_NO_CERTSIGN";
case X509_V_ERR_INVALID_EXTENSION:
return "ERR_INVALID_EXTENSION";
case X509_V_ERR_INVALID_POLICY_EXTENSION:
return "ERR_INVALID_POLICY_EXTENSION";
case X509_V_ERR_NO_EXPLICIT_POLICY:
return "ERR_NO_EXPLICIT_POLICY";
case X509_V_ERR_APPLICATION_VERIFICATION:
return "ERR_APPLICATION_VERIFICATION";
default:
return "ERR_UNKNOWN";
}
}

I hope this helps. As I stated earlier, if you find other pieces of information useful, let me know and we’ll get things updated. Similarly, if you find that any of the examples don’t work, let me know.

Thanks to Jordan Whitehead for various corrections.

orig url:

https://zakird.com/2013/10/13/certificate-parsing-with-openssl

[转载]Parsing X.509 Certificates with OpenSSL and C的更多相关文章

  1. Nine simple steps to enable X.509 certificates on WCF- 摘自网络

    Table of contents Introduction and goal Beginner WCF FAQs Step 1: Create client and server certifica ...

  2. openssl生成pem,密钥证书的创建

    使用OpenSSL生成证书 首先得安装OpenSSL软件包openssl,安装了这个软件包之后,我们可以做这些事情: o Creation of RSA, DH and DSA Key Paramet ...

  3. 深入浅出HTTPS工作原理(转载)

    转载自: https://blog.csdn.net/wangtaomtk/article/details/80917081 深入浅出HTTPS工作原理 HTTP协议由于是明文传送,所以存在三大风险: ...

  4. 非对称加密与OpenSSL

    随着个人隐私越来越受重视, HTTPS也渐渐的流行起来, 甚至有许多网站都做到了全站HTTPS, 然而这种加密和信任机制也不断遭遇挑战,比如戴尔根证书携带私钥,Xboxlive证书私钥泻露, 还有前一 ...

  5. OpenSSL version mismatch. Built against 1000105f, you have 10001060

    http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=732940 http://ftp.debian.org/debian/pool/main/o/ope ...

  6. OpenSSL 使用拾遗(一)---- 生成 pkcs12 文件

    从本期开始,记录一些在使用 OpenSSL 过程中碰到的问题及解决办法 在 Linux 下需要生成 pkcs12 文件,立即想到 OpenSSL.键入如下命令 ~ # openssl pkcs12 - ...

  7. openssl 进行证书格式的转换

    各类证书由于存储的内容不同(如是否包含公钥/私钥是否加密存储/单一证书或多证书等).采用编码不同(DER/BASE64).标准不同(如PEM/PKCS),所以尽管X.509标准规定了证书内容规范,但证 ...

  8. Linux_install mod_ssl openssl apache

    1.下载 mod_ssl 和 apache 登入http://www.modssl.org/source/,下载 mod_ssl-2.8.31-1.3.41.targz: 2.8.31是mod_ssl ...

  9. Certificate Formats | Converting Certificates between different Formats

    Different Platforms & Devices requires SSL certificates in different formatseg:- A Windows Serve ...

随机推荐

  1. python数据结构:pandas(3)

    一.pandas数据操作: 1.处理缺失数据 (1)判断是否存在缺失值 ser_obj.isnull(),df_obj.isnull() (2)dropna:丢弃缺失数据 (3)fillna:填充缺失 ...

  2. C语言scanf的返回值

    #include <stdio.h> int main(void) { long num; long sum = 0L; int status; printf("Please e ...

  3. 内存缓存的使用Demo

    使用缓存的目的是为了使用的应用程序能更快速的响应用户输入,是程序高效的运行.有时候我们需要将远程web服务器获取的数据缓存起来,减少对同一个url多次请求. 内存缓存我们可以使用sdk中的NSURLC ...

  4. gperftools尝试

    最近在找windows下比较好用的函数时间统计的库,听同事说gperftools是跨平台的,就下载下来尝试了一把.发现它确实实现了windows上可以调用的dll库文件(tcmalloc_minima ...

  5. 洛谷P3768 简单的数学题 莫比乌斯反演+杜教筛

    题意简述 求出这个式子 \[ \sum_{i=1}^n\sum_{j=1}^n ij(i,j) \bmod p \] 做法 先用莫比乌斯反演拆一下式子 \[ \begin{split} \sum_{i ...

  6. SpringToolSuit(STS)添加了Lombok后仍然报错

    参见这篇博客 https://blog.csdn.net/qq_27442469/article/details/90612918 上面步骤做完后,在项目右键->Maven->Update ...

  7. 【leetcode】1128. Number of Equivalent Domino Pairs

    题目如下: Given a list of dominoes, dominoes[i] = [a, b] is equivalent to dominoes[j] = [c, d] if and on ...

  8. Linux学习-利用inotify和rsync实现数据的实时同步

    一.inotify简介 1.inotify介绍 异步的文件系统事件监控机制,利用事件驱动机制,而无须通过诸如cron等的 轮询机制来获取事件,linux内核从2.6.13起支持 inotify,通过i ...

  9. Rosetta Stone 不在C盘安装步骤

    本文出自:http://www.cnblogs.com/2186009311CFF/p/7500637.html Rosetta Stone默认安装在C盘的,很不好,故找到次解决方案: 总体就是移动文 ...

  10. CSS——小三角带边框带阴影

    乍一看,很简单,做小三角,首先想到的是利用border的transparent特性,可以制作出小三角的效果.但是注意,这个小三角本身就是边框制作出来的.怎么能在小三角的外边再加一层小边框呢.那就必须再 ...