I now start the listener in the main.c file rather than proxy given that I didn't feel proxy was the right place if a normal (non-proxied) request came in. webserver.{c,h} and proxy.{c,h} had some changes relating to this. The config changed slightly - we now create a folder in ~/.config/ called yaip. This is where certificates and so on will be stored along with the user configuration I created a helper function to get files inside this directory (it changes based on xdg_config_home) and updated relevant tests. In ssl.{c,h} I have started work. If they don't exist, the tool now creates and stores a key and certificate for the CA that this tool will need to pretend to be. I still need to write tests for this.master
parent
6eaad263be
commit
bb62ed3b1f
14 changed files with 371 additions and 105 deletions
@ -0,0 +1,6 @@ |
||||
# Certificate Authority |
||||
|
||||
At some point, it would be nice if yaip does this automatically, but for now, |
||||
you need to create a certificate authority for yaip to sign requests with. |
||||
|
||||
; |
@ -0,0 +1,180 @@ |
||||
#include "ssl.h" |
||||
|
||||
|
||||
SSL_CTX* InitServerCTX(Config *config) { |
||||
const SSL_METHOD *method; |
||||
SSL_CTX *ctx; |
||||
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */ |
||||
SSL_load_error_strings(); /* load all error messages */ |
||||
method = TLS_server_method(); /* create new server-method instance */ |
||||
ctx = SSL_CTX_new(method); /* create new context from method */ |
||||
if ( ctx == NULL ) { |
||||
ERR_print_errors_fp(stderr); |
||||
abort(); |
||||
} |
||||
|
||||
//set the local certificate from CertFile
|
||||
if ( SSL_CTX_use_certificate_file(ctx, config->certfile, SSL_FILETYPE_PEM) <= 0 ){ |
||||
ERR_print_errors_fp(stderr); |
||||
abort(); |
||||
} |
||||
|
||||
//set the private key from KeyFile (may be the same as CertFile)
|
||||
if ( SSL_CTX_use_PrivateKey_file(ctx, config->keyfile, SSL_FILETYPE_PEM) <= 0 ){ |
||||
ERR_print_errors_fp(stderr); |
||||
abort(); |
||||
} |
||||
//verify private key
|
||||
if ( !SSL_CTX_check_private_key(ctx) ) |
||||
{ |
||||
fprintf(stderr, "Private key does not match the public certificate\n"); |
||||
abort(); |
||||
} |
||||
|
||||
return ctx; |
||||
} |
||||
|
||||
|
||||
// Generates a 2048-bit RSA key.
|
||||
// Largely stolen from here: https://gist.github.com/nathan-osman/5041136
|
||||
EVP_PKEY* generate_ca_key() { |
||||
// Allocate memory for the EVP_PKEY structure.
|
||||
EVP_PKEY *pkey = EVP_PKEY_new(); |
||||
if(!pkey) { |
||||
perror("Unable to create EVP_PKEY structure.\n"); |
||||
return NULL; |
||||
} |
||||
|
||||
// Generate the RSA key and assign it to pkey.
|
||||
RSA *rsa = RSA_new(); |
||||
BIGNUM *bn = BN_new(); |
||||
BN_set_word(bn, RSA_F4); |
||||
RSA_generate_key_ex(rsa, 2048, bn, NULL ); |
||||
if(!EVP_PKEY_assign_RSA(pkey, rsa)) { |
||||
perror("Unable to generate 2048-bit RSA key.\n"); |
||||
EVP_PKEY_free(pkey); |
||||
return NULL; |
||||
} |
||||
|
||||
// The key has been generated, return it.
|
||||
return pkey; |
||||
} |
||||
|
||||
|
||||
// Generates a self-signed x509 certificate.
|
||||
// Largely stolen from here: https://gist.github.com/nathan-osman/5041136
|
||||
X509* generate_ca_cert(EVP_PKEY * pkey) { |
||||
// Allocate memory for the X509 structure.
|
||||
X509 *x509 = X509_new(); |
||||
if(!x509) { |
||||
perror( "Unable to create X509 structure.\n"); |
||||
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.
|
||||
X509_gmtime_adj(X509_get_notBefore(x509), 0); |
||||
X509_gmtime_adj(X509_get_notAfter(x509), 31536000L); |
||||
|
||||
// Set the public key for our certificate.
|
||||
X509_set_pubkey(x509, pkey); |
||||
|
||||
// We want to copy the subject name to the issuer name.
|
||||
X509_NAME *name = X509_get_subject_name(x509); |
||||
|
||||
// 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); |
||||
|
||||
// Now set the issuer name.
|
||||
X509_set_issuer_name(x509, name); |
||||
|
||||
|
||||
// TODO: mitmproxy adds some extensions. I don' tknow if I need those
|
||||
// https://github.com/mitmproxy/mitmproxy/blob/3cb89069b9f70c198cc89337bd5a9b1bbf3a69d0/mitmproxy/certs.py#L190-L204
|
||||
|
||||
|
||||
// Actually sign the certificate with our key.
|
||||
if(!X509_sign(x509, pkey, EVP_sha1())) |
||||
{ |
||||
perror( "Error signing certificate.\n"); |
||||
X509_free(x509); |
||||
return NULL; |
||||
} |
||||
|
||||
|
||||
|
||||
return x509; |
||||
} |
||||
|
||||
bool create_and_save_key(char keyfile[]) { |
||||
// Generate the key
|
||||
EVP_PKEY *pkey = generate_ca_key(); |
||||
if ( pkey == NULL ){ |
||||
fprintf(stderr, "Unable to open generate key\n"); |
||||
return false; |
||||
} |
||||
|
||||
// Open the PEM file for writing the key to disk.
|
||||
FILE * pkey_file = fopen(keyfile, "wb"); |
||||
if(!pkey_file) { |
||||
fprintf(stderr, "Unable to open \"%s\" for writing.\n", keyfile); |
||||
return false; |
||||
} |
||||
// Write the key to disk.
|
||||
bool ret = PEM_write_PrivateKey(pkey_file, pkey, NULL, NULL, 0, NULL, NULL); |
||||
fclose(pkey_file); |
||||
|
||||
if(!ret) { |
||||
perror("Unable to write private key to disk.\n"); |
||||
return false; |
||||
} |
||||
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.
|
||||
FILE * x509_file = fopen(certfile, "wb"); |
||||
if(!x509_file) { |
||||
fprintf(stderr, "Unable to open \"%s\" for writing.\n", certfile); |
||||
return false; |
||||
} |
||||
|
||||
X509 *x509 = generate_ca_cert(pkey); |
||||
if ( x509 == NULL ){ |
||||
fprintf(stderr, "Unable to open generate cert\n"); |
||||
return false; |
||||
} |
||||
|
||||
// Write the certificate to disk.
|
||||
int ret = PEM_write_X509(x509_file, x509); |
||||
fclose(x509_file); |
||||
|
||||
if(!ret) { |
||||
perror("Unable to write certificate to disk.\n"); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
@ -0,0 +1,19 @@ |
||||
#ifndef SSL_H |
||||
#define SSL_H |
||||
|
||||
#include <openssl/ssl.h> |
||||
#include <openssl/err.h> |
||||
#include <openssl/x509.h> |
||||
#include <openssl/pem.h> |
||||
|
||||
#include "config.h" |
||||
|
||||
SSL_CTX* InitServerCTX(Config *config); |
||||
|
||||
EVP_PKEY* generate_ca_key(); |
||||
X509* generate_ca_cert(EVP_PKEY * pkey); |
||||
bool create_and_save_key(char keyfile[]); |
||||
bool create_and_save_cert(char keyfile[], EVP_PKEY *pkey); |
||||
EVP_PKEY* read_private_key(char keyfile[]); |
||||
|
||||
#endif /* ifndef SSL_ */ |
Loading…
Reference in new issue