Skip to content

Instantly share code, notes, and snippets.

@burke
Created May 28, 2012 20:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save burke/2821083 to your computer and use it in GitHub Desktop.
Save burke/2821083 to your computer and use it in GitHub Desktop.
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/x509v3.h>
static char Cert[] = {
"-----BEGIN CERTIFICATE-----\n"
"MIIF5DCCBU2gAwIBAgIKHSG78QAAAABXCjANBgkqhkiG9w0BAQUFADBGMQswCQYD\n"
"VQQGEwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzEiMCAGA1UEAxMZR29vZ2xlIElu\n"
"dGVybmV0IEF1dGhvcml0eTAeFw0xMjA1MTYwODA3MDdaFw0xMzA1MTYwODE3MDda\n"
"MGYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1N\n"
"b3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgSW5jMRUwEwYDVQQDFAwqLmdv\n"
"b2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKlQpB0Plo5ZB58T\n"
"PYh37E+TcBpfMtp8kGKFY21bPNVEujZabhuUDeprGnIZMrIaxcP7WmYz+3Z5NEwR\n"
"q9+BHpALdT2RIowGUqfuhPAPhYPB5BwvnK20mCHWcDAj1aSO4lp09E7jXlrObvRR\n"
"xevl+vWANCy3gwUfCmzFw3E8gv5tAgMBAAGjggO3MIIDszAdBgNVHSUEFjAUBggr\n"
"BgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFMEpRTQX00DMSiPxmTeI2AiU0HYi\n"
"MB8GA1UdIwQYMBaAFL/AMOv1QxE+Z7qekfv8atrjaxIkMFsGA1UdHwRUMFIwUKBO\n"
"oEyGSmh0dHA6Ly93d3cuZ3N0YXRpYy5jb20vR29vZ2xlSW50ZXJuZXRBdXRob3Jp\n"
"dHkvR29vZ2xlSW50ZXJuZXRBdXRob3JpdHkuY3JsMGYGCCsGAQUFBwEBBFowWDBW\n"
"BggrBgEFBQcwAoZKaHR0cDovL3d3dy5nc3RhdGljLmNvbS9Hb29nbGVJbnRlcm5l\n"
"dEF1dGhvcml0eS9Hb29nbGVJbnRlcm5ldEF1dGhvcml0eS5jcnQwggKLBgNVHREE\n"
"ggKCMIICfoIMKi5nb29nbGUuY29tggpnb29nbGUuY29tgg0qLnlvdXR1YmUuY29t\n"
"ggt5b3V0dWJlLmNvbYIWKi55b3V0dWJlLW5vY29va2llLmNvbYIIeW91dHUuYmWC\n"
"CyoueXRpbWcuY29tgg8qLmdvb2dsZS5jb20uYnKCDiouZ29vZ2xlLmNvLmluggsq\n"
"Lmdvb2dsZS5lc4IOKi5nb29nbGUuY28udWuCCyouZ29vZ2xlLmNhggsqLmdvb2ds\n"
"ZS5mcoILKi5nb29nbGUucHSCCyouZ29vZ2xlLml0ggsqLmdvb2dsZS5kZYILKi5n\n"
"b29nbGUuY2yCCyouZ29vZ2xlLnBsggsqLmdvb2dsZS5ubIIPKi5nb29nbGUuY29t\n"
"LmF1gg4qLmdvb2dsZS5jby5qcIILKi5nb29nbGUuaHWCDyouZ29vZ2xlLmNvbS5t\n"
"eIIPKi5nb29nbGUuY29tLmFygg8qLmdvb2dsZS5jb20uY2+CDyouZ29vZ2xlLmNv\n"
"bS52boIPKi5nb29nbGUuY29tLnRygg0qLmFuZHJvaWQuY29tggthbmRyb2lkLmNv\n"
"bYIUKi5nb29nbGVjb21tZXJjZS5jb22CEmdvb2dsZWNvbW1lcmNlLmNvbYIQKi51\n"
"cmwuZ29vZ2xlLmNvbYIWKi5nb29nbGV0YWdtYW5hZ2VyLmNvbYIUZ29vZ2xldGFn\n"
"bWFuYWdlci5jb22CDCoudXJjaGluLmNvbYIKdXJjaGluLmNvbYIWKi5nb29nbGUt\n"
"YW5hbHl0aWNzLmNvbYIUZ29vZ2xlLWFuYWx5dGljcy5jb22CEiouY2xvdWQuZ29v\n"
"Z2xlLmNvbYIGZ29vLmdsggRnLmNvMA0GCSqGSIb3DQEBBQUAA4GBABWXkg33DZ3X\n"
"vqDoV23yqcJcu1DjMqtiDjuPjTzbXnfTSGvZQHCZSb5ysIWllX4QC8tiMafn0iza\n"
"xNbgjQQDQ3j7FRSMZ5Wj06VGTJd5gGenpVClJyLRdJcoQzP9Sd1u08glmsJG1EbG\n"
"HGkeva2hA3E/+9pqsmG6u22o1D9QgjzK\n"
"-----END CERTIFICATE-----\n"};
static int match(char*, char*);
static int hostname_matches_subject_alt_name(char*, X509*);
static int hostname_matches_subject_common_name(char*, X509*);
int hostname_matches_certificate(char *hostname, X509 *cert)
{
int san_result = hostname_matches_subject_alt_name(hostname, cert);
if (san_result > -1)
return san_result;
return hostname_matches_subject_common_name(hostname, cert);
}
// See section RFC 6125 Sections 2.4 and 3.1
static int match(char *expr, char *string)
{
int i, j;
for (i = 0, j = 0; i < strlen(expr); i++) {
if (expr[i] == '*') {
if (string[j] == '.')
return 0;
while (string[j] != '.')
j++;
}
else if (expr[i] != string[j])
return 0;
else
j++;
}
return (j == strlen(string));
}
/* Does this hostname match an entry in the subjectAltName extension?
* returns: 0 if no, 1 if yes, -1 if no subjectAltName entries were found.
*/
static int hostname_matches_subject_alt_name(char *hostname, X509 *cert)
{
int found_any_entries = 0;
int found_match;
GENERAL_NAME *namePart = NULL;
STACK_OF(GENERAL_NAME) *san =
(STACK_OF(GENERAL_NAME)*) X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
while (sk_GENERAL_NAME_num(san) > 0)
{
namePart = sk_GENERAL_NAME_pop(san);
if (namePart->type == GEN_DNS) {
found_any_entries = 1;
found_match = match(ASN1_STRING_data(namePart->d.uniformResourceIdentifier), hostname);
if (found_match)
return 1;
}
}
return (found_any_entries ? 0 : -1);
}
static int hostname_matches_subject_common_name(char *hostname, X509 *cert)
{
X509_NAME *name;
X509_NAME_ENTRY *name_entry;
char *certname;
int i, j, position;
name = X509_get_subject_name(cert);
position = -1;
for (;;) {
position = X509_NAME_get_index_by_NID(name, NID_commonName, position);
if (position == -1)
break;
name_entry = X509_NAME_get_entry(name, position);
char *certname = (char*) X509_NAME_ENTRY_get_data(name_entry)->data;
if (match(certname, hostname))
return 1;
}
return 0;
}
void test()
{
SSL_library_init();
OpenSSL_add_ssl_algorithms();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ERR_load_crypto_strings();
char data[256];
char *pass_hostname = "foo.google.com";
char *fail_hostname = "foo.bar.google.com";
X509 *x = NULL;
BIO *bio = BIO_new_mem_buf(Cert, -1);
PEM_read_bio_X509 (bio, &x, NULL, 0);
X509_NAME_oneline(X509_get_subject_name(x), data, 256);
int t;
t = hostname_matches_certificate("foo.google.com", x);
printf("%s -- foo.google.com. Expected 1, got %d\n", (t == 1 ? "PASS" : "FAIL"), t);
t = hostname_matches_certificate("foo.bar.google.com", x);
printf("%s -- foo.bar.google.com. Expected 0, got %d\n", (t == 0 ? "PASS" : "FAIL"), t);
t = hostname_matches_certificate("foo.google.co", x);
printf("%s -- foo.google.co. Expected 0, got %d\n", (t == 0 ? "PASS" : "FAIL"), t);
t = hostname_matches_certificate("foo.google.com.tr", x);
printf("%s -- foo.google.com.tr. Expected 1, got %d\n", (t == 1 ? "PASS" : "FAIL"), t);
BIO_free (bio);
}
int main()
{
test();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment