Skip to content
Snippets Groups Projects
Commit 01691573 authored by Shubham Jayswal's avatar Shubham Jayswal
Browse files

Upload New File

parent f1927e36
No related branches found
No related tags found
No related merge requests found
/**
Name: Shubham Jayswal
Login Id: sjayswal@student.unimelb.edu.au
Example certifcate code
gcc -o certexample certexample.c -lssl -lcrypto
*/
#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>
void read_csv(char *filename);
int get_keylen(EVP_PKEY * pubkey);
int validate_date(ASN1_TIME *to);
int validate_cn(char *hostname, X509 *cert);
int validate_ca(X509 *cert);
int validate_san(char *hostname, X509 *cert);
int validate_key_usage(X509 *cert);
int is_subdomain(char *hostname);
int sub_domain_match(char *hostname, char *wildcard);
/**
* Returns 1 if the certificate is not for a CA
*/
int validate_ca(X509 *cert) {
X509_EXTENSION *ex = X509_get_ext(cert,
X509_get_ext_by_NID(cert, NID_basic_constraints, -1));
ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex);
char buff[1024];
OBJ_obj2txt(buff, 1024, obj, 0);
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';
BIO_free_all(bio);
return (strcmp("CA:TRUE", buf) == 0);
}
/**
* Validates extended key usages.
*
* return 0 if valid
* -1 if a code signing certificate has been used
* -2 if a client certificate has been used.
* -3 if the extendend usage info isn't clear
* 1 if there are multiple allowed usages which includes on a webserver
*/
int validate_key_usage(X509 *cert) {
X509_EXTENSION *ex = X509_get_ext(cert,
X509_get_ext_by_NID(cert, NID_ext_key_usage, -1));
ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex);
char buff[1024];
OBJ_obj2txt(buff, 1024, obj, 0);
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';
BIO_free_all(bio);
if (strcmp(buf, "Code Signing") == 0) {
return -11;
}
if (strcmp(buf, "TLS Web Client Authentication") == 0) {
return -2;
}
if (strstr(buf, "Web Server Authentication") != NULL) {
/* Web Server Authentication is one of the supported usages, but are there any others? */
if (strstr(buf, ",") != NULL) {
return 1;
}
return 0;
}
return -3;
}
/**
* Return 0 when there is a perfect match between one of the SANs and the domain
* 1 when the SAN is a wildcard and there is a wildcard match
* -1 When there is not SAN information
* -2 When san information i present but we cannot match
*/
int validate_san(char *hostname, X509 *cert) {
GENERAL_NAMES *alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, 0,
0);
char *buf;
int len;
int i;
if (alt_names == NULL) {
return -1;
}
len = sk_GENERAL_NAME_num(alt_names);
for (i = 0; i < len; ++i) {
GENERAL_NAME *name = sk_GENERAL_NAME_value(alt_names, i);
if (name->type == GEN_DNS) {
buf = (char *) ASN1_STRING_data(name->d.dNSName);
if (buf[0] == '*' && is_subdomain(hostname)
&& sub_domain_match(hostname, buf)) {
printf("SAN WILDCARD %s %s\n", hostname, buf);
OPENSSL_free(buf);
return 1;
} else {
OPENSSL_free(buf);
return -2;
}
}
}
return -2;
}
/**
* Validate the given certificates date
*
* return 1 if the date is in the future, 0 if the date is current
* and -1 if the date is in the past.
*
*
*/
int validate_date(ASN1_TIME *to) {
int day, sec;
ASN1_TIME_diff(&day, &sec, NULL, to);
if (day > 0 || sec > 0) {
return 1;
}
if (day < 0 || sec < 0) {
return -1;
}
return 0;
}
/**
* Validates the common name
*
* Return 0 if there is an exact match.
* 1 if this is a wild card certificate and can be matched
* -1 cannot be matched
* -2 is a wild card but still cannot be matched because no sub domai.
*/
int validate_cn(char *hostname, X509 *cert) {
X509_NAME_ENTRY *common_name_entry = NULL;
ASN1_STRING *common_name_asn1 = NULL;
char *common_name_str = NULL;
int location = X509_NAME_get_index_by_NID(
X509_get_subject_name((X509 *) cert), NID_commonName, -1);
if (location >= 0) {
common_name_entry = X509_NAME_get_entry(
X509_get_subject_name((X509 *) cert), location);
if (common_name_entry != NULL) {
common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
if (common_name_asn1 != NULL) {
common_name_str = (char *) ASN1_STRING_data(common_name_asn1);
if (ASN1_STRING_length(common_name_asn1)
== strlen(common_name_str)) {
/* after a long drawn out process we have finaly got the common name as a string.
* but we are not out of the woods yet.
*/
if (strcasecmp(hostname, common_name_str) == 0) {
/* all is well, we have an exact match */
return 0;
} else {
if (common_name_str[0] == '*') {
/* wildcard, we can find out if there is a subdomain by counting .. */
if (is_subdomain(hostname)
&& sub_domain_match(hostname,
common_name_str)) {
return 1;
} else {
return -2;
}
}
}
}
}
}
}
return -1;
}
/**
* Is there a wildcard match?
*
* 1 if true
*/
int sub_domain_match(char *hostname, char *wildcard) {
char *h = strstr(hostname, ".");
char *w = strstr(wildcard, ".");
return strcmp(h + 1, w + 1) == 0;
}
/**
* Does this hostname have a subdomain component.
*/
int is_subdomain(char *hostname) {
int i, count;
for (i = 0, count = 0; hostname[i] != '\0'; i++) {
if (hostname[i] == '.') {
count++;
}
}
return count > 1;
}
/**
* Gets the keylength in bits.
*/
int get_keylen(EVP_PKEY * pubkey) {
RSA * rsa;
rsa = EVP_PKEY_get1_RSA(pubkey);
int key_length = RSA_size(rsa);
free(rsa);
return key_length * 8;
}
void read_csv(char *filename) {
BIO *certificate_bio = NULL;
X509 *cert = NULL;
int key_len;
int domain_status;
char line[127];
int i = 0, j = 0, cmp, san_validation;
char site[64];
char file_name[64];
FILE *in = fopen(filename, "r");
FILE *out;
if (in != NULL) {
out = fopen("output.csv", "w");
if (out != NULL) {
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());
while (fscanf(in, "%s", line) > 0) {
/* first part of the code. We read the file_name to a pair, certificate file_name name and hostname */
for (i = 0; line[i] != '\0' && line[i] != ','; i++) {
file_name[i] = line[i];
}
file_name[i++] = '\0';
for (j = 0; line[i] != '\0' && line[i] != ','; i++) {
site[j++] = line[i];
}
site[j] = '\0';
if (!(BIO_read_filename(certificate_bio, file_name))) {
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);
}
/* now for the domain verification. This is the first step that we are peforming. */
domain_status = validate_cn(site, cert);
if (domain_status == -1) {
fprintf(out,
"%s,%s,%d,Invalid - domain does not match Common Name\n",
file_name, site, 0);
continue;
}
if (domain_status == -2) {
fprintf(out,
"%s,%s,%d,Invalid - wildcard Common Name requires subdomain \n",
file_name, site, 0);
continue;
}
if (validate_ca(cert)) {
/* failed the first test. This is for a CA */
fprintf(out, "%s,%s,%d,Invalid - marked as a CA\n",
file_name, site, 0);
continue; // continue is ugly but a huge chain of if else is uglier.
}
key_len = get_keylen(X509_get_pubkey(cert));
if (key_len < 2048) {
/* failed the second test, the keylen is too short */
fprintf(out,
"%s,%s,%d,Invalid because key size is too small (%d bits instead of >=2048)\n",
file_name, site, 0, key_len);
continue;
}
/* now we check the dates */
cmp = validate_date(X509_get_notBefore(cert));
if (cmp == 1) {
fprintf(out,
"%s,%s,%d,Invalid valid from date - date is in the future\n",
file_name, site, 0);
continue;
}
cmp = validate_date(X509_get_notAfter(cert));
if (cmp == -1) {
fprintf(out,
"%s,%s,%d,Invalid - certificate has expired - valid to date in the past\n",
file_name, site, 0);
continue;
}
/* now for key usage */
cmp = validate_key_usage(cert);
if (cmp == -11) {
fprintf(out,
"%s,%s,%d,Invalid - extended key usage is code signing only\n",
file_name, site, 0);
continue;
}
if (cmp == -2) {
fprintf(out,
"%s,%s,%d,Invalid - extended key usage is only for client authentication\n",
file_name, site, 0);
continue;
}
san_validation = validate_san(site, cert);
/**
* Don't ask how i wrote this huge bunch of if else conditions. I don't know myself!!
*/
if (domain_status == 0) {
if (san_validation == 0) {
fprintf(out,
"%s,%s,1,Valid - all correct - domain matches Common Name or SAN wildcard\n",
file_name, site);
} else {
if (cmp == 1) {
fprintf(out,
"%s,%s,1,Valid - all correct - tests multiple extended key usage\n",
file_name, site);
} else {
if (san_validation == -1) {
fprintf(out,
"%s,%s,1,Valid correct key size; valid dates; not a CA; server authentication; domain matches Common Name\n",
file_name, site);
} else if (san_validation == 0) {
fprintf(out,
"%s,%s,1,Valid - all correct - domain matches Common Name and SAN\n",
file_name, site);
} else if (san_validation == 1) {
printf("%s %d %d\n", site, domain_status,
san_validation);
fprintf(out,
"%s,%s,1,Valid - all correct - domain matches Common Name or SAN wildcard\n",
file_name, site);
} else {
fprintf(out,
"%s,%s,1,Valid - all correct - domain matches Common Name and SAN\n",
file_name, site);
}
}
}
} else {
if (cmp == 0) {
if (san_validation == 1) {
fprintf(out,
"%s,%s,1,Valid - all correct - domain matches Common Name or SAN wildcard\n",
file_name, site);
} else {
if (san_validation == -1) {
fprintf(out,
"%s,%s,1,Valid - all correct - domain matches through Common Name wildcard No SAN\n",
file_name, site);
}
}
} else {
fprintf(out,
"%s,%s,1,Valid - all correct - tests multiple extended key usage\n",
file_name, site);
}
}
}
} else {
printf("Couldn't create output file_name\n");
}
} else {
printf("File not found\n");
}
X509_free(cert);
BIO_free_all(certificate_bio);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Incorrect number of arguments\n");
return 1;
}
read_csv(argv[1]);
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment