Validating names in SSL certificates using OpenSSL (0.9.8)

Recently I’ve battled with OpenSSL at work. One thing I needed to do was add name validation to a program that previously hasn’t had it. In an attempt to avoid obvious mistakes I went looking for existing examples for how to do it. I came across some code from Secure Programming.com, it can be found in the code from the book in “/spc-1.1/chapter10/8-unix.c”. Just too bad only a part of the code actually works as advertised. On top of that the working part uses old functions which remain in the API only for backwards compatibility.

In trying to fix up that code I wrote the following little example code for extracting CN and subjectAltName:

#include <stdlib.h>
#include <stdio.h>
 
#include <openssl/pem.h>
#include <openssl/x509v3.h>
 
void getCN( X509 * );
void getSubjectAltName( X509 * );
 
int
main( int argc, char **argv )
{
    FILE *fpem;
    X509 *cert;
 
    if( !( fpem = fopen( argv[1], "r" ))) {
        fprintf( stderr, "Couldn't open the PEM file: %s\n", argv[1] );
        return( EXIT_FAILURE );
    }
 
    if( !( cert = PEM_read_X509( fpem, NULL, NULL, NULL ))) {
        fclose( fpem );
        fprintf( stderr, "Failed to read the PEM file: %s\n", argv[1] );
        return( EXIT_FAILURE );
    }
 
    getCN( cert );
    getSubjectAltName( cert );
 
    fclose( fpem );
    return( EXIT_SUCCESS );
}
 
void
getCN( X509 *cert )
{
    printf( "## %s\n", __PRETTY_FUNCTION__ );
 
    X509_NAME *subjName;
    int idx;
 
    if( !( subjName = X509_get_subject_name( cert )))
        fprintf( stderr, "X509_get_subject_name failed" );
 
    idx = X509_NAME_get_index_by_NID( subjName, NID_commonName, -1 );
    X509_NAME_ENTRY *entry = X509_NAME_get_entry( subjName, idx );
    ASN1_STRING *entryData = X509_NAME_ENTRY_get_data( entry );
    unsigned char *utf8;
    int length = ASN1_STRING_to_UTF8( &utf8, entryData );
    printf( "CN value: %s\n", utf8 );
    printf( "CN length: %d\n", length );
    OPENSSL_free( utf8 );
 
    return;
}
 
void getSubjectAltName( X509 *cert )
{
    printf( "## %s\n", __PRETTY_FUNCTION__ );
 
    GENERAL_NAMES *sANs;
 
    if( !( sANs = X509_get_ext_d2i( cert, NID_subject_alt_name, 0, 0 ))) {
        printf( "No subjectAltName extension\n" );
        return;
    }
 
    int i, numAN = sk_GENERAL_NAME_num( sANs );
    printf( "subjectAltName entries: %d\n", numAN );
    for( i = 0; i < numAN; ++i ) {
        GENERAL_NAME *sAN = sk_GENERAL_NAME_value( sANs, i );
        // we only care about DNS entries
        if( GEN_DNS == sAN->type ) {
            unsigned char *dns;
            ASN1_STRING_to_UTF8( &dns, sAN->d.dNSName );
            printf( "subjectAltName DNS: %s\n", dns );
            OPENSSL_free( dns );
        }
    }
 
    return;
}

Based on this I should be able to finish the patch I’ve been working on.

Share

One Comment

  1. Just dropping a line to say thank you Magnus. OpenSSL documentation is horrific and this helped point me in the correct direction.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>