Skip to content
Snippets Groups Projects
Commit b09a93f7 authored by Ubuntu's avatar Ubuntu
Browse files

done

parent d834930f
No related branches found
No related tags found
No related merge requests found
/**
Example certifcate code
gcc -o certexample certexample.c -lssl -lcrypto
gcc certexample.c -I /usr/local/opt/openssl/include -L /usr/local/opt/openssl/lib -o certexample
*/
#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>
int main()
{
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);
}
//cert contains the x509 certificate and can be used to analyse the certificate
//*********************
// Example code of accessing certificate values
//*********************
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);
//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);
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");
}
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';
//Can print or parse value
printf("%s\n", buf);
//*********************
// End of Example code
//*********************
X509_free(cert);
BIO_free_all(certificate_bio);
BIO_free_all(bio);
free(buf);
exit(0);
}
\ No newline at end of file
export PATH="/usr/local/opt/openssl/bin:"$PATH
\ No newline at end of file
......@@ -6,22 +6,25 @@
#
#***************************************************************************
CC=gcc
FLAGS=-Wall -lssl -lcrypto
MAC_FLAGS= -Wall -I /usr/local/opt/openssl/include -L /usr/local/opt/openssl/lib
OUT=certcheck
TESTS=sample_certs
SRC=src/main.c
EXAMPLE_SRC=./certexample.c
CSVOUT=output.csv
compile:
$(CC) $(SRC) $(FLAGS) -o $(OUT);
mac:
$(CC) $(SRC) $(MAC_FLAGS) -o $(OUT);
clean:
rm $(OUT); rm $(CSVOUT);
clean_tests:
rm $(TESTS)/$(OUT); rm $(TESTS)/$(CSVOUT);
example:
$(CC) $(EXAMPLE_SRC) $(MAC_FLAGS) -o certexample;
compile_tests:
$(CC) $(SRC) $(FLAGS) -o $(TESTS)/$(OUT);
clean:
rm -f src/*.o; rm $(OUT);
test:
cd sample_certs/; ./testscript.sh ; cd ..;
/***************************************************************************
*
* File : main.c
* Student Id : 757931
* Name : Sebastian Baker
*
**************************************************************************/
#include <openssl/x509.h>
#include <openssl/x509v3.h>
......@@ -5,14 +12,370 @@
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <string.h>
#define EXAMPLE_USAGE "USAGE: ./certcheck test_file.csv\n"
#define NUM_ARGS 2
#define FILENAME_ARG 1
#define OUT_FILENAME "output.csv"
#define REWRITE "w"
#define READONLY "r"
#define DELIMITER ','
#define NEWLINE '\n'
#define NULL_C '\0'
#define BITS_TO_BYTES(bits) bits/8
#define START_STR_SIZE 2
#define DEFAULT_STRLEN 2048
#define VALID 1
#define ASN1_TIME_BEFORE -1
#define ASN1_TIME_AFTER 1
#define MIN_RSA_BYTES BITS_TO_BYTES(2048)
#define EXT_STARTPOS -1
#define NOT_CA_STR "CA:FALSE"
#define IS_CA_STR "CA:TRUE"
#define TLS_STR "TLS Web Server Authentication"
#define NO_CN "CN NOT FOUND"
#define SAN_DELIM ", "
#define SAN_ENTRY ":"
#define WILDCARD '*'
// Checks the validity of the positioning of the wildcard
// Wildcards must be located at the beginning of the name, followed by a '.'
#define WILDCARD_VALID(name, i) ((name[0] == WILDCARD) \
&& (i == 0) \
&& (name[1] == '.'))
// Print the name of an X509 extension in plaintext
void print_ext_name(X509_EXTENSION *ex) {
int len = DEFAULT_STRLEN;
ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex);
char buff[len];
OBJ_obj2txt(buff, len, obj, 0);
//printf("Extension:%s\n", buff);
}
// Get the value from an X509 extension in plaintext
char* get_ext_value(X509* cert, int nid) {
// Get extension object
int loc = X509_get_ext_by_NID(cert, nid, EXT_STARTPOS);
X509_EXTENSION *ex = X509_get_ext(cert, loc);
if (!ex) {return NULL;}
//print_ext_name(ex);
// Wrap the extension in a BIO
BUF_MEM *bptr = NULL;
BIO *bio = BIO_new(BIO_s_mem());
assert(X509V3_EXT_print(bio, ex, 0, 0));
BIO_flush(bio);
BIO_get_mem_ptr(bio, &bptr);
// Load extension into a string
char *str = (char *)malloc((bptr->length+1) * sizeof(char));
memcpy(str, bptr->data, bptr->length);
str[bptr->length] = NULL_C;
BIO_free_all(bio);
//printf("%s\n", str);
return str;
}
// My version of X509_cmp_current_time
int my_X509_cmp_current_time(ASN1_TIME* t) {
int daydiff = 0;
int secdiff = 0;
assert(ASN1_TIME_diff(&daydiff, &secdiff, t, NULL));
assert(daydiff/abs(daydiff) == secdiff/abs(secdiff));
if (secdiff < 0 || daydiff < 0) {
return ASN1_TIME_BEFORE;
} else {
return ASN1_TIME_AFTER;
}
}
// Verify the not before and not after dates of the certificate
int validate_date(X509* cert) {
ASN1_TIME *not_before = X509_get_notBefore(cert);
ASN1_TIME *not_after = X509_get_notAfter(cert);
if ( (my_X509_cmp_current_time(not_after) == ASN1_TIME_BEFORE)
&& (my_X509_cmp_current_time(not_before) == ASN1_TIME_AFTER)
) {
return VALID;
}
return !VALID;
}
// Validate the minimum length of the public rsa key is a secure length
int validate_RSA_min_len(X509* cert) {
// Check that key type is rsa
int key_type = OBJ_obj2nid(cert->cert_info->key->algor->algorithm);
assert(key_type);
assert(key_type == NID_rsaEncryption);
// Get the key
EVP_PKEY *key = X509_get_pubkey(cert);
assert(key);
RSA *rsa_key = key->pkey.rsa;
assert(rsa_key);
// Check the length of the key
int rsa_bytes = RSA_size(rsa_key);
assert(rsa_bytes);
if (rsa_bytes >= MIN_RSA_BYTES) {
return VALID;
}
return !VALID;
}
// Checks that BasicConstraints extension exists and contains "CA:FALSE"
int validate_BasicConstraints(X509* cert) {
char* constraints = get_ext_value(cert, NID_basic_constraints);
if (constraints) {
int not_ca = (strstr(constraints, NOT_CA_STR) != NULL)
&& (strstr(constraints, IS_CA_STR) == NULL);
free(constraints);
return not_ca ? VALID : !VALID;
}
return !VALID;
}
// Checks that ExtendedKeyUsage extension exists
// and contains "TLS Web Server Authentication"
int validate_ExtendedKeyUsage(X509* cert) {
char* ext_key_usage = get_ext_value(cert, NID_ext_key_usage);
if (ext_key_usage) {
int for_tls = (strstr(ext_key_usage, TLS_STR) != NULL);
free(ext_key_usage);
return for_tls ? VALID : !VALID;
}
return !VALID;
}
// Checks if a certificate name matches the url given
int match_url_to_name(char* url, char* name) {
int u_i = strlen(url);
int n_i = strlen(name);
while(u_i>=0 && n_i>=0) {
// Wildcard case
if (name[n_i] == WILDCARD) {
return WILDCARD_VALID(name, n_i) ? VALID : !VALID;
}
// Check if characters match
if (url[u_i] != name[n_i]) {
return !VALID;
} else if(u_i==0 && n_i==0) {
return VALID;
}
u_i--; n_i--;
}
return !VALID;
}
// Check if the url matches the CN on the certificate
int check_cn(X509* cert, char* url) {
int len = DEFAULT_STRLEN;
char* cn = (char*)calloc(len, sizeof(char));
assert(cn);
assert(strcpy(cn, NO_CN));
X509_NAME *cert_subject = X509_get_subject_name(cert);
X509_NAME_get_text_by_NID(cert_subject, NID_commonName, cn, len);
int validity = match_url_to_name(url, cn);
//printf("CN: %s\n", cn);
free(cn);
return validity;
}
int main(int argv, char** argc) {
printf("Hello, World\n");
BIO *certificate_bio = NULL;
// Check if the url matches the SAN on the certificate
int check_san(X509* cert, char* url) {
char* sans = get_ext_value(cert, NID_subject_alt_name);
if (sans == NULL) { return !VALID; }
char* stptr = sans;
char* endptr = sans;
char* name = (char*)calloc(DEFAULT_STRLEN, sizeof(char));
assert(name);
for (;;) {
name = memset(name, NULL_C, DEFAULT_STRLEN); // Clear name
stptr = strstr(endptr, SAN_ENTRY) + 1; // get ptr to start of name
endptr = strstr(stptr, SAN_DELIM); // get ptr to end of name
// copy name to name str
if (endptr == NULL) {
name = strcpy(name, stptr);
} else {
int n = endptr-stptr;
name = memcpy(name, stptr, n);
}
//printf("SAN: %s\n",name);
// match name against url
if (match_url_to_name(url, name) == VALID) {
free(name);
return VALID;
}
// Give up search when at end of list
if (endptr == NULL) {
free(name);
return !VALID;
}
}
}
// Verify the domain name in the url matches the
// CN or SAN of the certificate
int validate_domain(X509* cert, char* url) {
int cn = check_cn(cert, url) == VALID;
int san = check_san(cert, url) == VALID;
return cn || san ? VALID : !VALID;
}
// Validate a certificate
int validate_cert(X509* cert, char* url) {
int date = (validate_date(cert) == VALID);
int minkey = (validate_RSA_min_len(cert) == VALID);
int basic = (validate_BasicConstraints(cert) == VALID);
int exten = (validate_ExtendedKeyUsage(cert) == VALID);
int dom = (validate_domain(cert, url) == VALID);
int valid = date && minkey && basic && exten && dom;
if (valid) {
return VALID;
}
return !VALID;
}
// Reads X509 certificate into X509 struct
// Returned value can be used to analyse the certificate
X509* open_cert(const char* filename) {
//create BIO object to read certificate
BIO *certificate_bio = BIO_new(BIO_s_file());
//Read certificate into BIO
int read_success = BIO_read_filename(certificate_bio, filename);
assert(read_success);
// Read BIO into certificate
X509 *cert = PEM_read_bio_X509(certificate_bio, NULL, 0, NULL);
assert(cert);
BIO_free_all(certificate_bio);
return cert;
}
// Reads a portion of the input csv file into an array, delimited by delim
char* ftostr(FILE* fp, char delim) {
int size = START_STR_SIZE;
char* arr = (char*)calloc(size, sizeof(char));
assert(arr);
char tmpc;
int i = 0;
for (i=0;;i++) {
tmpc = fgetc(fp);
if (tmpc == delim || tmpc == EOF) {
// stop if reached delimiter
break;
} else if (tmpc == NULL_C) {
// Skip null chars
continue;
} else if ((i+1) >= size) {
// Extend array if necessary
size += size;
arr = (char*)realloc(arr, size*sizeof(char*));
assert(arr);
}
// Put char from stream into array output
assert(tmpc);
arr[i] = tmpc;
arr[i+1] = NULL_C;
}
return arr;
}
// Process a line in the csv
char process_line(FILE* in_fp, FILE* out_fp) {
// Read path until a comma is found
char* path = ftostr(in_fp, DELIMITER);
if (!strlen(path)) {
free(path);
return EOF;
}
// Read url until a \n is found
char* url = ftostr(in_fp, NEWLINE);
assert(strlen(url));
// Validate the certificate and print to output
X509* cert = open_cert(path);
int valid = validate_cert(cert, url);
fprintf(out_fp, "%s,%s,%d\n", path, url, valid);
X509_free(cert);
free(url);
free(path);
return !EOF;
}
// Processes a csv in accordance with assignment specs
void process_csv(char* filename) {
FILE* in_fp = fopen(filename, READONLY);
FILE* out_fp = fopen(OUT_FILENAME, REWRITE);
assert(out_fp);
assert(in_fp);
while (process_line(in_fp, out_fp) != EOF) {
}
fclose(out_fp);
fclose(in_fp);
}
int main(int argc, char* argv[]) {
//initialise openSSL
OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
if (argc != NUM_ARGS) {
printf(EXAMPLE_USAGE);
exit(EXIT_FAILURE);
}
process_csv(argv[FILENAME_ARG]);
exit(EXIT_SUCCESS);
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment