Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
C
comp30023-2018-project-2
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Shubham Jayswal
comp30023-2018-project-2
Commits
01691573
Commit
01691573
authored
May 24, 2018
by
Shubham Jayswal
Browse files
Options
Downloads
Patches
Plain Diff
Upload New File
parent
f1927e36
No related branches found
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
certexample.c
+463
-0
463 additions, 0 deletions
certexample.c
with
463 additions
and
0 deletions
certexample.c
0 → 100644
+
463
−
0
View file @
01691573
/**
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
;
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment