From 34afae2880c94ad0ac8b92dbfad5e0d892a6eff2 Mon Sep 17 00:00:00 2001 From: drkleena <jolausson@student.unimelb.edu.au> Date: Wed, 23 May 2018 11:27:53 +1000 Subject: [PATCH] initial commit --- .remote-sync.json | 14 + certexample | Bin 0 -> 16164 bytes certexample.c | 457 ++++++++++++++++++++++++--- makefile | 3 + output_test.csv | 13 + sample_certs/sample_input_single.csv | 1 + 6 files changed, 440 insertions(+), 48 deletions(-) create mode 100644 .remote-sync.json create mode 100755 certexample create mode 100644 makefile create mode 100644 output_test.csv create mode 100644 sample_certs/sample_input_single.csv diff --git a/.remote-sync.json b/.remote-sync.json new file mode 100644 index 0000000..2d3e8f5 --- /dev/null +++ b/.remote-sync.json @@ -0,0 +1,14 @@ +{ + "transport": "scp", + "uploadOnSave": true, + "useAtomicWrites": true, + "deleteLocal": false, + "hostname": "ubuntu@115.146.95.37", + "ignore": [ + ".remote-sync.json", + ".git/**" + ], + "watch": [], + "keyfile": "~/Desktop/private.txt", + "passphrase": "j0nas13" +} \ No newline at end of file diff --git a/certexample b/certexample new file mode 100755 index 0000000000000000000000000000000000000000..133b4413ab264e369a804e79ee90672329bf6e0f GIT binary patch literal 16164 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 literal 0 HcmV?d00001 diff --git a/certexample.c b/certexample.c index f525aba..ab7dba1 100644 --- a/certexample.c +++ b/certexample.c @@ -3,70 +3,173 @@ gcc -o certexample certexample.c -lssl -lcrypto */ #include <openssl/x509.h> +#include <openssl/asn1.h> +#include <openssl/crypto.h> +#include <openssl/asn1t.h> #include <openssl/x509v3.h> #include <openssl/bio.h> #include <openssl/pem.h> #include <openssl/err.h> #include <stdio.h> #include <string.h> +#include <assert.h> +#include <time.h> +#include <openssl/asn1_mac.h> -int main() -{ +const ASN1_TIME *X509_get0_notBefore(const X509 *x); +char** str_split(const char* a_str, const char a_delim); +char* concat(char *s1, char *s2); +char* get_basic_constraints(X509 *cert); +char* get_key_usage(X509 *cert); +char* compare_not_before(X509 *cert); +char* compare_not_after(X509 *cert); +char* get_SAN(X509 *cert); +char *get_domain_name(X509 *cert); +int matches_subject_alternative_name(const char *hostname, X509 *server_cert); +int get_public_key_length(X509 *cert); +int validate_basic_constraints(char* basic_constraints); +int validate_key_usage(char* key_usage); +int validate_key_length(int length); +int validate_CN(const char* hostname, char*cn); +int validate_wildcard_string(const char *hostname, char*hostname_with_wildcard); +int validate_CN_and_SAN(const char *url, X509 *cert); +int validate_not_before(X509 *cert); +int validate_not_after(X509 *cert); +int validate_certificate(const char *url, X509 *cert); - const char test_cert_example[] = "./cert-file2.pem"; - BIO *certificate_bio = NULL; - X509 *cert = NULL; - X509_NAME *cert_issuer = NULL; - X509_CINF *cert_inf = NULL; - STACK_OF(X509_EXTENSION) * ext_list; +int main(int argc, char **argv){ + int LINE_BUFFER=100; + char line[LINE_BUFFER]; - //initialise openSSL + FILE *csv_input = fopen(concat("./sample_certs/",argv[1]), "r"); + FILE *csv_output = fopen("output_test.csv" ,"w"); + + //for each line in the csv file, process each certificate OpenSSL_add_all_algorithms(); ERR_load_BIO_strings(); ERR_load_crypto_strings(); - //create BIO object to read certificate - certificate_bio = BIO_new(BIO_s_file()); + int n = 0; + while (fgets(line, LINE_BUFFER, csv_input) != NULL){ + + printf("CSV LINE # %d\n", n); + BIO *certificate_bio = NULL; + X509 *cert = NULL; + X509_NAME *cert_issuer = NULL; + X509_CINF *cert_inf = NULL; + STACK_OF(X509_EXTENSION) * ext_list; + certificate_bio = BIO_new(BIO_s_file()); + //here we are able to access each line + line[strlen(line)-1] = '\0'; + + + char **csv_row_elements = str_split(line, ','); + + printf("\tFILE: %s\n",csv_row_elements[0]); + printf("\tURL: %s\n",csv_row_elements[1]); + + + char *certificate_file = concat("./sample_certs/", csv_row_elements[0]); + + const char *url = csv_row_elements[1]; + //for some reason splitting keeps mututating the original string + char *unchanged_url = csv_row_elements[1]; + + FILE *fp = fopen(certificate_file, "r"); + + if (!(BIO_read_filename(certificate_bio, certificate_file))){ + fprintf(stderr, "Error in reading cert BIO filename"); + exit(EXIT_FAILURE); + } + + //load certiifcate + if (!(cert = PEM_read_bio_X509(certificate_bio, NULL, 0, NULL))){ + fprintf(stderr, "Error in loading certificate"); + exit(EXIT_FAILURE); + } + // printf ("\tBASIC CONSTRAINT: %s\n",get_basic_constraints(cert)); + // printf ("\tBASIC CONSTRAINT VALIDATION: %d\n",validate_basic_constraints(get_basic_constraints(cert))); + // + // // printf ("\tKEY USAGE: %s\n",get_key_usage(cert)); + // printf ("\tKEY USAGE VALIDATION: %d\n",validate_key_usage(get_key_usage(cert))); + // + // // printf ("\tKEY LENGTH BITS: %d\n",get_public_key_length(cert)); + // + // printf ("\tKEY LENGTH VALIDATION: %d\n",validate_key_length(get_public_key_length(cert))); + // + // // printf ("\tNot Before compared to Current: %s\n",compare_not_before(cert)); + // // printf ("\tNot After compared to Current: %s\n",compare_not_after(cert)); + // printf("\tNOT BEFORE VALIDATION %d\n", validate_not_before(cert)); + // printf("\tNOT AFTER VALIDATION %d\n", validate_not_after(cert)); + // // printf ("\tCommon Name: %s\n",get_domain_name(cert)); + // + // printf("\tCOMMON NAME AND SAN VALIDATION %d\n", validate_CN_and_SAN(url, cert)); + // printf ("%d", 0 || 1); + // printf("FINAL VALIDATION %d\n", validate_certificate(url, cert)); + // printf("\t%s\n", unchanged_url); + fprintf(csv_output,"%s,", csv_row_elements[0]); + fprintf(csv_output,"%s,", unchanged_url); + fprintf(csv_output,"%d\n", validate_certificate(url, cert)); + + // printf ("\tCOMMON NAME VALIDATION: %d\n",); + // printf ("\tMatches Subject Alternative Name Result: %d\n",); + // printf("URL: %s\n",url); + + // + // printf("URL: %s\n",url); + n++; - //Read certificate into BIO - if (!(BIO_read_filename(certificate_bio, test_cert_example))) - { - fprintf(stderr, "Error in reading cert BIO filename"); - exit(EXIT_FAILURE); - } - if (!(cert = PEM_read_bio_X509(certificate_bio, NULL, 0, NULL))) - { - fprintf(stderr, "Error in loading certificate"); - exit(EXIT_FAILURE); } + exit(0); +} +char* get_basic_constraints(X509 *cert){ - //cert contains the x509 certificate and can be used to analyse the certificate - - //********************* - // Example code of accessing certificate values - //********************* + X509_EXTENSION *ex = X509_get_ext(cert, X509_get_ext_by_NID(cert, NID_basic_constraints, -1)); - cert_issuer = X509_get_issuer_name(cert); - char issuer_cn[256] = "Issuer CN NOT FOUND"; - X509_NAME_get_text_by_NID(cert_issuer, NID_commonName, issuer_cn, 256); - printf("Issuer CommonName:%s\n", issuer_cn); + ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex); + + char buff[1024]; + OBJ_obj2txt(buff, 1024, obj, 0); + //printf("Extension: %s, ", buff); + + BUF_MEM *bptr = NULL; + char *buf = NULL; + + BIO *bio = BIO_new(BIO_s_mem()); + + X509V3_EXT_print(bio, ex, 0, 0); + + + BIO_flush(bio); + BIO_get_mem_ptr(bio, &bptr); + + //bptr->data is not NULL terminated - add null character + buf = (char *)malloc((bptr->length + 1) * sizeof(char)); + memcpy(buf, bptr->data, bptr->length); + buf[bptr->length] = '\0'; + BIO_flush(bio); + //Can print or parse value + + return buf; +} +char* get_key_usage(X509 *cert){ + + X509_EXTENSION *ex = X509_get_ext(cert, X509_get_ext_by_NID(cert, NID_ext_key_usage, -1)); - //List of extensions available at https://www.openssl.org/docs/man1.1.0/crypto/X509_REVOKED_get0_extensions.html - //Need to check extension exists and is not null - X509_EXTENSION *ex = X509_get_ext(cert, X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1)); ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex); + char buff[1024]; OBJ_obj2txt(buff, 1024, obj, 0); - printf("Extension:%s\n", buff); + //printf("Extension: %s, ", buff); BUF_MEM *bptr = NULL; char *buf = NULL; BIO *bio = BIO_new(BIO_s_mem()); - if (!X509V3_EXT_print(bio, ex, 0, 0)) - { - fprintf(stderr, "Error in reading extensions"); - } + + X509V3_EXT_print(bio, ex, 0, 0); + + BIO_flush(bio); BIO_get_mem_ptr(bio, &bptr); @@ -76,15 +179,273 @@ int main() buf[bptr->length] = '\0'; //Can print or parse value - printf("%s\n", buf); - //********************* - // End of Example code - //********************* + return buf; +} +int get_public_key_length(X509 *cert){ - X509_free(cert); - BIO_free_all(certificate_bio); - BIO_free_all(bio); - free(buf); - exit(0); -} \ No newline at end of file + EVP_PKEY *public_key = X509_get_pubkey(cert); + + RSA *rsa_key = EVP_PKEY_get1_RSA(public_key); + + int key_length_bytes = RSA_size(rsa_key); + + return (key_length_bytes*8); + +} +char* get_domain_name(X509 *cert){ + X509_NAME *x509_name = X509_get_subject_name(cert); + char *cert_cn = X509_NAME_oneline(x509_name, 0, 0); + cert_cn =(cert_cn+1); + char **chain = str_split(cert_cn, '/'); + char *domain = chain[5]; + + char **domain_clean = str_split(domain, '='); + + return domain_clean[1]; +} +char* compare_not_before(X509 *cert){ + int day, sec; + const ASN1_TIME *not_before = X509_get_notBefore(cert); + + if (!ASN1_TIME_diff(&day, &sec, NULL, not_before)){ + /* Invalid time format */ + printf("what the fuck do now\n"); + } + + if (day > 0 || sec > 0){ + return "Later"; + } + else if (day < 0 || sec < 0){ + return "Sooner"; + } + else{ + return "Same"; + } + return "invalid?"; +} +char* compare_not_after(X509 *cert){ + int day, sec; + const ASN1_TIME *not_after = X509_get_notAfter(cert); + + if (!ASN1_TIME_diff(&day, &sec, NULL, not_after)){ + /* Invalid time format */ + printf("what the fuck do now\n"); + } + + if (day > 0 || sec > 0){ + return "Later"; + } + else if (day < 0 || sec < 0){ + return "Sooner"; + } + else{ + return "Same"; + } + + return "invalid?"; +} +char* concat(char *s1, char *s2){ + //concats two strings + char *result = malloc(strlen(s1)+strlen(s2)+1); + strcpy(result, s1); + strcat(result, s2); + return result; + +} +char** str_split(const char* a_str, const char a_delim){ + char** result = 0; + size_t count = 0; + char* tmp = (char *)a_str; + char* copy = (char *)a_str; + char* last_comma = 0; + char delim[2]; + delim[0] = a_delim; + delim[1] = 0; + + /* Count how many elements will be extracted. */ + while (*tmp){ + if (a_delim == *tmp){ + count++; + last_comma = tmp; + } + tmp++; + } + /* Add space for trailing token. */ + count += last_comma < (a_str + strlen(a_str) - 1); + /* Add space for terminating null string so caller + knows where the list of returned strings ends. */ + count++; + result = malloc(sizeof(char*) * count); + if (result){ + size_t idx = 0; + char* token = strtok(copy, delim); + + while (token){ + assert(idx < count); + *(result + idx++) = strdup(token); + token = strtok(0, delim); + } + assert(idx == count - 1); + *(result + idx) = 0; + } + return result; +} +int matches_subject_alternative_name(const char *hostname, X509 *server_cert) { + + + int i; + int san_names_nb = -1; + STACK_OF(GENERAL_NAME) *san_names = NULL; + + // Try to extract the names within the SAN extension from the certificate + san_names = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL); + + + if (san_names == NULL) { + + return 0; + } + + san_names_nb = sk_GENERAL_NAME_num(san_names); + + // Check each name within the extension + for (i=0; i<san_names_nb; i++) { + const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i); + + if (current_name->type == GEN_DNS) { + // Current name is a DNS name, let's check it + char *dns_name = (char *) ASN1_STRING_data(current_name->d.dNSName); + printf ("\t%s\n", dns_name); + // Make sure there isn't an embedded NUL character in the DNS name + if (ASN1_STRING_length(current_name->d.dNSName) != strlen(dns_name)) { + + return 0; + break; + } + else { // Compare expected hostname with the DNS name + + + + if (validate_wildcard_string(hostname, dns_name) == 1) { + + return 1; + + break; + } + } + } + } + sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free); + return 0; +} +int validate_key_usage(char* key_usage){ + + //key usage may be a bunch of strings, need to get first one if this is the case + + if(strlen("TLS Web Server Authentication")!=strlen(key_usage)){ + char **key_usage_clean = str_split(key_usage, ','); + if(strcmp(key_usage_clean[0], "TLS Web Server Authentication") == 0){ + return 1; + } + + return 0; + + + } + + else{ + if(strcmp(key_usage, "TLS Web Server Authentication") == 0){ + return 1; + } + return 0; + } + +} +int validate_basic_constraints(char* basic_constraints){ + + if(strcmp(basic_constraints, "CA:FALSE")==0){ + // printf("\tBASIC CONSTRAINT PASS\n"); + return 1; + } + return 0; +} + +int validate_wildcard_string(const char *hostname, char*hostname_with_wildcard){ + char **hostname_with_wildcard_split = str_split(hostname_with_wildcard, '.'); + + char **hostname_split = str_split(hostname, '.'); + + const char *hostname_with_wildcard_right = hostname_with_wildcard_split[1]; + const char *hostname_split_right = hostname_split[1]; + + if(strcasecmp(hostname_split_right, hostname_with_wildcard_right)==0){ + printf("\t\tWILDCARD FUNCTION\t\t%s == %s\n", hostname_split_right, hostname_with_wildcard_right); + return 1; + } + return 0; +} +int validate_key_length(int length){ + if (length==2048){ + return 1; + } + return 0; +} +int validate_CN(const char* hostname, char*cn){ + if(cn[0]=='*'){ + return (validate_wildcard_string(hostname, cn)); + } + else{ + if(strcasecmp(cn, hostname)==0){ + return 1; + } + else{ + return 0; + } + } + return 0; +} +int validate_CN_and_SAN(const char *url, X509 *cert){ + + if(validate_CN(url, get_domain_name(cert)) || matches_subject_alternative_name(url, cert)){ + return 1; + } + else{return 0;} +} +int validate_not_before(X509 *cert){ + + if(strcmp(compare_not_before(cert), "Sooner")==0){ + return 1; + } + return 0; +} +int validate_not_after(X509 *cert){ + + if(strcmp(compare_not_after(cert), "Later")==0){ + return 1; + } + return 0; +} +int validate_certificate(const char *url, X509 *cert){ + // printf ("\tBASIC CONSTRAINT VALIDATION: %d\n",validate_basic_constraints(get_basic_constraints(cert))); + // printf ("\tKEY USAGE VALIDATION: %d\n",validate_key_usage(get_key_usage(cert))); + // printf ("\tKEY LENGTH VALIDATION: %d\n",validate_key_length(get_public_key_length(cert))); + // printf("\tNOT BEFORE VALIDATION %d\n", validate_not_before(cert)); + // printf("\tNOT AFTER VALIDATION %d\n", validate_not_after(cert)); + // printf("\tCOMMON NAME AND SAN VALIDATION %d\n", validate_CN_and_SAN(url, cert)); + + int a = validate_basic_constraints(get_basic_constraints(cert)); + int b = validate_key_usage(get_key_usage(cert)); + int c = validate_key_length(get_public_key_length(cert)); + int d = validate_not_before(cert); + int e = validate_not_after(cert); + // printf("%s\n", url); + int f = validate_CN_and_SAN(url, cert); + // & b & c & d & e & f + if(a&b & c & d & e& f){ + return 1; + } + else{ + return 0; + } +} diff --git a/makefile b/makefile new file mode 100644 index 0000000..f62ae4a --- /dev/null +++ b/makefile @@ -0,0 +1,3 @@ +#!/bin/bash +all: certexample.c + gcc -I /usr/local/opt/openssl/include -L /usr/local/opt/openssl/lib -o certexample certexample.c -lssl -lcrypto diff --git a/output_test.csv b/output_test.csv new file mode 100644 index 0000000..7b25d86 --- /dev/null +++ b/output_test.csv @@ -0,0 +1,13 @@ +testone.crt,www.example.com,0 +testtwo.crt,www.mydomain.com,1 +testthree.crt,www.test.com,0 +testfour.crt,www.oldsite.com,0 +testfive.crt,www.unimelb.com,0 +testsix.crt,www.codetest.com,0 +testseven.crt,www.example.com,1 +testeight.crt,www.comp30023.com,1 +testnine.crt,www.certtest.com,1 +testten.crt,www.victoria.com,1 +testeleven.crt,freeca.com,0 +testtwo.crt,www.example.com,0 +testseven.crt,example.com,0 diff --git a/sample_certs/sample_input_single.csv b/sample_certs/sample_input_single.csv new file mode 100644 index 0000000..9239412 --- /dev/null +++ b/sample_certs/sample_input_single.csv @@ -0,0 +1 @@ +testeight.crt,www.comp30023.com -- GitLab