From 9d8663d0526eb7eb2b9339941acce919ba794c31 Mon Sep 17 00:00:00 2001 From: unimelb <j.fan11@student.unimelb.edu.au> Date: Thu, 24 May 2018 10:47:14 +1000 Subject: [PATCH] init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit init commit --- Makefile | 2 + assignment_2.c | 272 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 274 insertions(+) create mode 100644 Makefile create mode 100644 assignment_2.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e126f79 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +all: + gcc -o certcheck assignment_2.c -lssl -lcrypto \ No newline at end of file diff --git a/assignment_2.c b/assignment_2.c new file mode 100644 index 0000000..041055a --- /dev/null +++ b/assignment_2.c @@ -0,0 +1,272 @@ +/* +Name: Jihai Fan +Student ID: 832919 +Login name: j.fan11@student.unimelb.edu.au +Description: validate of x509 cert against DNS name +*/ + +#include <openssl/x509.h> +#include <openssl/x509v3.h> +#include <openssl/bio.h> +#include <openssl/pem.h> +#include <openssl/err.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +// get column from csv +char* getfield(char* line, int num){ + char* tok; + char *newline = strtok(line, "\n"); + for (tok = strtok(newline, ","); tok && *tok; tok = strtok(NULL, ",")){ + if (!--num) + return tok; + } + return NULL; +} + +// change the format from asn1_time to time_t +static time_t ASN1_GetTimeT(const ASN1_TIME* time){ + struct tm t; + const char* str = (const char*) time->data; + size_t i = 0; + + memset(&t, 0, sizeof(t)); + + if (time->type == V_ASN1_UTCTIME) {/* two digit year YYMMDDHHMMSS*/ + t.tm_year = (str[i++] - '0') * 10; + t.tm_year += (str[i++] - '0'); + if (t.tm_year < 70) + t.tm_year += 100; + } else if (time->type == V_ASN1_GENERALIZEDTIME) {/* four digit year YYYYMMDDHHMMSS*/ + t.tm_year = (str[i++] - '0') * 1000; + t.tm_year+= (str[i++] - '0') * 100; + t.tm_year+= (str[i++] - '0') * 10; + t.tm_year+= (str[i++] - '0'); + t.tm_year -= 1900; + } + t.tm_mon = (str[i++] - '0') * 10; + t.tm_mon += (str[i++] - '0') - 1; // -1 since January is 0 not 1. + t.tm_mday = (str[i++] - '0') * 10; + t.tm_mday+= (str[i++] - '0'); + t.tm_hour = (str[i++] - '0') * 10; + t.tm_hour+= (str[i++] - '0'); + t.tm_min = (str[i++] - '0') * 10; + t.tm_min += (str[i++] - '0'); + t.tm_sec = (str[i++] - '0') * 10; + t.tm_sec += (str[i++] - '0'); + + return mktime(&t); +} + +// compare ASN1_time with current time +int cmp_current_time(const ASN1_TIME *ctm){ + time_t current = time(NULL); + time_t ct = ASN1_GetTimeT(ctm); + double result = difftime(current, ct); + if (result < 0){ + return 1; + }else{ + return -1; + } +} + +// validate the time of certificate +int cmp_time(X509 *cert){ + int i; + i = cmp_current_time(X509_get_notBefore(cert)); + int j; + j = cmp_current_time(X509_get_notAfter(cert)); + if (i != -1 || j != 1){ // one should before current time, and another should be after + return 1; + } + return 0; +} + +// validate the rsa key length +int cmp_rsa_length(X509 *cert){ + EVP_PKEY *public_key = X509_get_pubkey(cert); + RSA *rsa_key = EVP_PKEY_get1_RSA(public_key); + int key_length = BN_num_bits(rsa_key->n); + if (key_length < 2048){ + RSA_free(rsa_key); + return 1; + } + RSA_free(rsa_key); + return 0; +} + +// validate common name +int cmp_cn(X509 *cert, char *url){ + X509_NAME *cert_issuer = X509_get_subject_name(cert); + char common_name[256] = "Issuer CN NOT FOUND"; + X509_NAME_get_text_by_NID(cert_issuer, NID_commonName, common_name, 256); + + /** + * compare from the back of dns_name + * *.test.com + * www.test.com + * |---------| + */ + int url_len = strlen(url); + int cn_len = strlen(common_name); + if (cn_len > url_len){ + return 1; + } + int wildcard = 1; + int result = strcmp(&common_name[wildcard], &url[url_len - cn_len + wildcard]); + if (result != 0){ + return 1; + } + free(cert_issuer); + return result; +} + +// validate CA +int cmp_ca(X509 *cert){ + BASIC_CONSTRAINTS *bc = X509_get_ext_d2i(cert, NID_basic_constraints, NULL, NULL); + if (bc->ca != 0){ + free(bc); + return 1; + } + free(bc); + return 0; +} + +// validate Enhenced Key Usage +int cmp_key_usage(X509 *cert){ + EXTENDED_KEY_USAGE *usage = X509_get_ext_d2i(cert, NID_ext_key_usage, NULL, NULL); + if(usage){ + for(int i = 0; i < sk_BIO_num(usage); i++){ + int result = OBJ_obj2nid(sk_ASN1_OBJECT_value(usage,i)); // get the nid of the EKU in the stack + if (result == NID_server_auth){ // NID_server_auth is the ID for TLS web server + free(usage); + return 0; + } + } + } + free(usage); + return 1; +} + +// validate subject alternative name +int cmp_san(X509 *cert, char *url){ + int san_names_nb = -1; + int result = 0; + STACK_OF(GENERAL_NAME) *san_names = NULL; + + // try to get SAN + san_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); + if (san_names == NULL) { + return 1; + } + + // length of the stack + san_names_nb = sk_GENERAL_NAME_num(san_names); + + // check each name within the extension + for (int i=0; i<san_names_nb; i++) { + const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i); + + // make sure it is a dns name + if (current_name->type == GEN_DNS) { + char *dns_name = (char *) ASN1_STRING_data(current_name->d.dNSName); + // printf("san is: %s", dns_name); + int url_len = strlen(url); + int dns_len = strlen(dns_name); + if (dns_len > url_len){ + return 1; + } + int wildcard = 1; + if(strcmp(&dns_name[wildcard], &url[url_len - dns_len + wildcard]) == 0){ + return 0; + } + } + } + sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free); + + return 1; +} + +int validate_url(X509 *cert, char *url){ + int time_result = cmp_time(cert); + int cn_result = cmp_cn(cert, &url); + int rsa_result = cmp_rsa_length(cert); + int ca_result = cmp_ca(cert); + int eku_result = cmp_key_usage(cert); + int san_result = cmp_san(cert, &url); + // printf("%i\n",time_result); + // printf("%i\n",cn_result); + // printf("%i\n",rsa_result); + // printf("%i\n",ca_result); + // printf("%i\n",eku_result); + // printf("%i\n",san_result); + int result; + // only one fo SAN and CN should be + if (cn_result == 0){ + result = time_result + rsa_result + ca_result + eku_result; + } else { + result = time_result + rsa_result + ca_result + eku_result + san_result; + } + if (result != 0){ + return 0; + } + return 1; +} + +int read_and_validate(const char *test_cert_example, const char *url){ + // 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; + + // initialise openSSL + 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()); + + // 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); + } + + // get the result + int result = validate_url(cert, url); + + X509_free(cert); + BIO_free_all(certificate_bio); + return result; +} + +int main(int argv, char** argc) +{ + + FILE* stream = fopen(argc[1], "r"); + FILE* output = fopen("output.csv", "w+"); + char line[1024]; + while (fgets(line, 1024, stream)) + { + char* tmp = strdup(line); + char* url = getfield(tmp, 2); + char* cert = getfield(tmp, 1); + int result = read_and_validate(cert, url); + printf("%s\n",url); + fprintf(output, "%s,%s,%i\n", cert, url, result); + // NOTE strtok clobbers tmp + free(tmp); + } + + exit(0); +} \ No newline at end of file -- GitLab