Early SSL Certificates creation work done

Yaip is now able to generate simple SSL certificates for a given host.

I don't currently add any extensions to the certificates (such as
alternative names). When I get to testing it with a browser I'll see
what browsers require. However, I think I'll probably generate
certificates for each host, including sub domains, to make life easier
searching.

I've also added a util function to count lines in a file that was used
for testing some of the ssl functions.
This commit is contained in:
Jonathan Hodgson 2022-01-23 15:38:24 +00:00
parent bb62ed3b1f
commit 1beca38af6
9 changed files with 375 additions and 30 deletions

View file

@ -68,6 +68,7 @@ int startListener(unsigned int port){
int main(int argc, char**argv){
Config *config = configDefaults();
int listener;
CertList *certs = NULL;
for ( unsigned int i = 1; i < argc; i++ ){
@ -150,7 +151,7 @@ int main(int argc, char**argv){
// necesarily the hosts header
webserverRequest(request, client);
} else {
proxyRequest(request, client);
proxyRequest(request, client, certs);
}
close(client);

View file

@ -38,7 +38,7 @@ Response *upstreamGetResponse(Request *request){
}
void proxyRequest(Request *request, int client){
void proxyRequest(Request *request, int client, CertList *certs){
if ( strcmp( request->method, "CONNECT" ) == 0 ){
// If it is a connect request, we are dealing with https

View file

@ -14,9 +14,10 @@
#include "request.h"
#include "response.h"
#include "webserver.h"
#include "ssl.h"
Response *upstreamGetResponse(Request *request);
void proxyRequest(Request *request, int client);
void proxyRequest(Request *request, int client, CertList *certs);
#endif /* ifndef PROXY_H */

121
src/ssl.c
View file

@ -1,6 +1,7 @@
#include "ssl.h"
SSL_CTX* InitServerCTX(Config *config) {
const SSL_METHOD *method;
SSL_CTX *ctx;
@ -25,11 +26,10 @@ SSL_CTX* InitServerCTX(Config *config) {
abort();
}
//verify private key
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
if ( !SSL_CTX_check_private_key(ctx) ) {
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
return ctx;
}
@ -71,7 +71,7 @@ X509* generate_ca_cert(EVP_PKEY * pkey) {
return NULL;
}
// Set the serial number.
ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
// This certificate is valid from now until exactly one year from now.
@ -87,7 +87,10 @@ X509* generate_ca_cert(EVP_PKEY * pkey) {
// Set the country code and common name.
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"UK", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)"Yet Another Intercepting Proxy", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"jn.hn", -1, -1, 0);
//I want this to be a fake domain because CAs can't sign certificates with
//the same domain. I thought about using jn.hn but I want to test using
//that.
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"yaip.yaip", -1, -1, 0);
// Now set the issuer name.
X509_set_issuer_name(x509, name);
@ -98,8 +101,7 @@ X509* generate_ca_cert(EVP_PKEY * pkey) {
// Actually sign the certificate with our key.
if(!X509_sign(x509, pkey, EVP_sha1()))
{
if(!X509_sign(x509, pkey, EVP_sha1())) {
perror( "Error signing certificate.\n");
X509_free(x509);
return NULL;
@ -110,6 +112,46 @@ X509* generate_ca_cert(EVP_PKEY * pkey) {
return x509;
}
X509* generate_site_cert( EVP_PKEY *pkey, X509 *caCert, char *host ){
X509 *hostCert = X509_new();
if(!hostCert) {
perror( "Unable to create X509 structure.\n");
return NULL;
}
ASN1_INTEGER_set(X509_get_serialNumber(hostCert), 1);
// This certificate is valid from now until exactly one year from now.
X509_gmtime_adj(X509_get_notBefore(hostCert), 0);
X509_gmtime_adj(X509_get_notAfter(hostCert), 31536000L);
// Set the public key for our certificate.
X509_set_pubkey(hostCert, pkey);
// We want to copy the subject name of the ca to the issuer of the new
// certificate
X509_NAME *ca_sn = X509_get_subject_name(caCert);
X509_NAME *host_in = X509_NAME_dup( ca_sn );
X509_set_issuer_name(hostCert, host_in);
X509_NAME *host_sn = X509_get_subject_name(hostCert);
// Set the country code and common name.
X509_NAME_add_entry_by_txt(host_sn, "C", MBSTRING_ASC, (unsigned char *)"UK", -1, -1, 0);
X509_NAME_add_entry_by_txt(host_sn, "O", MBSTRING_ASC, (unsigned char *)"Yet Another Intercepting Proxy", -1, -1, 0);
X509_NAME_add_entry_by_txt(host_sn, "CN", MBSTRING_ASC, (unsigned char *)strdup(host), -1, -1, 0);
if(!X509_sign(hostCert, pkey, EVP_sha1())) {
perror( "Error signing certificate.\n");
X509_free(hostCert);
return NULL;
}
return hostCert;
}
bool create_and_save_key(char keyfile[]) {
// Generate the key
EVP_PKEY *pkey = generate_ca_key();
@ -135,24 +177,6 @@ bool create_and_save_key(char keyfile[]) {
return true;
}
EVP_PKEY* read_private_key(char keyfile[]){
FILE *fp;
EVP_PKEY *pkey;
if (! (fp = fopen(keyfile, "r"))){
perror("Error cant open certificate private key file.\n");
return NULL;
}
pkey = PEM_read_PrivateKey( fp, NULL, NULL, NULL );
if ( pkey == NULL ){
perror("Error cant read certificate private key file.\n");
}
return pkey;
}
bool create_and_save_cert(char certfile[], EVP_PKEY *pkey) {
// Open the PEM file for writing the certificate to disk.
@ -178,3 +202,46 @@ bool create_and_save_cert(char certfile[], EVP_PKEY *pkey) {
}
return true;
}
EVP_PKEY* read_private_key(char keyfile[]){
FILE *fp;
EVP_PKEY *pkey;
if (! (fp = fopen(keyfile, "r"))){
perror("Error cant open certificate private key file.\n");
return NULL;
}
pkey = PEM_read_PrivateKey( fp, NULL, NULL, NULL );
if ( pkey == NULL ){
perror("Error cant read certificate private key file.\n");
}
return pkey;
}
CertList *newCertListItem(char *host, EVP_PKEY *key, X509 *cert){
CertList *item = malloc(sizeof( CertList ));
item->host = host;
item->key = key;
item->cert = cert;
item->next = NULL;
return item;
}
CertList *getLastCertListItem(CertList *item){
if ( item == NULL ) return NULL;
while ( item->next != NULL ) item=item->next;
return item;
}
unsigned int countCertListItems(CertList *item){
unsigned int count = 0;
while ( item != NULL ){
count++;
item = item->next;
}
return count;
}

View file

@ -1,19 +1,35 @@
#ifndef SSL_H
#define SSL_H
#include <openssl/ossl_typ.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <stdlib.h>
#include "config.h"
typedef struct CertList CertList;
struct CertList {
char *host;
EVP_PKEY *key;
X509 *cert;
CertList *next;
};
SSL_CTX* InitServerCTX(Config *config);
EVP_PKEY* generate_ca_key();
X509* generate_ca_cert(EVP_PKEY * pkey);
X509* generate_site_cert( EVP_PKEY *pkey, X509 *caCert, char *host );
bool create_and_save_key(char keyfile[]);
bool create_and_save_cert(char keyfile[], EVP_PKEY *pkey);
EVP_PKEY* read_private_key(char keyfile[]);
CertList *newCertListItem(char *host, EVP_PKEY *key, X509 *cert);
CertList *getLastCertListItem(CertList *item);
unsigned int countCertListItems(CertList *item);
CertList *findCertListItem( CertList *first, char *hostname );
#endif /* ifndef SSL_ */

View file

@ -5,3 +5,22 @@ int strpos(char *haystack, char *needle) {
if ( p != NULL ) return p - haystack;
return -1;
}
int countLines(char fileName[]){
FILE *fp;
char ch;
int linesCount = 0;
fp=fopen(fileName,"r");
if(fp==NULL) {
printf("File \"%s\" does not exist!!!\n",fileName);
return -1;
}
//read character by character and check for new line
while((ch=fgetc(fp))!=EOF) {
if(ch=='\n')
linesCount++;
}
//close the file
fclose(fp);
return linesCount;
}

View file

@ -5,5 +5,6 @@
#include <string.h>
int strpos(char *haystack, char *needle);
int countLines(char fileName[]);
#endif