Starts work on https as well as some moving about
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.
This commit is contained in:
parent
6eaad263be
commit
bb62ed3b1f
14 changed files with 366 additions and 100 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,3 +3,4 @@
|
||||||
yaip
|
yaip
|
||||||
mynotes.md
|
mynotes.md
|
||||||
*.sqlite
|
*.sqlite
|
||||||
|
/certs
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -6,7 +6,7 @@ TESTFILES = $(wildcard tests/*.c)
|
||||||
TESTOUT = $(TESTFILES:.c=)
|
TESTOUT = $(TESTFILES:.c=)
|
||||||
OUT = yaip
|
OUT = yaip
|
||||||
CFLAGS = -Wall -g
|
CFLAGS = -Wall -g
|
||||||
LDLIBS = -lsqlite3 -lm
|
LDLIBS = -lsqlite3 -lm -lssl -lcrypto
|
||||||
CC = gcc
|
CC = gcc
|
||||||
|
|
||||||
|
|
||||||
|
|
6
docs/certificate-authority.md
Normal file
6
docs/certificate-authority.md
Normal file
|
@ -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.
|
||||||
|
|
||||||
|
;
|
37
src/config.c
37
src/config.c
|
@ -34,35 +34,50 @@ char* resolveTilde(const char *path) {
|
||||||
*/
|
*/
|
||||||
Config* configDefaults(){
|
Config* configDefaults(){
|
||||||
Config *conf = malloc( sizeof( Config ) );
|
Config *conf = malloc( sizeof( Config ) );
|
||||||
conf->database = "proxy.sqlite";
|
conf->database = strdup("proxy.sqlite");
|
||||||
conf->port = 8080;
|
conf->port = 8080;
|
||||||
conf->localConfig = "proxy.conf";
|
conf->localConfig = strdup("proxy.conf");
|
||||||
conf->userConfig = getDefaultUserConfigLoc();
|
conf->userConfig = getUserConfigFile("proxy.conf");
|
||||||
|
conf->certfile = getUserConfigFile("cert.pem");
|
||||||
|
conf->keyfile = getUserConfigFile("key.pem");
|
||||||
|
|
||||||
return conf;
|
return conf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void maybeMakeDir(const char *path){
|
||||||
|
if ( path_exists( path ) ) return;
|
||||||
|
mkdir( path, 0700 );
|
||||||
|
}
|
||||||
|
|
||||||
char* getConfigDir(){
|
char* getConfigDir(){
|
||||||
char *xdg_config_home;
|
char *xdg_config_home;
|
||||||
if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL)
|
if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL)
|
||||||
xdg_config_home = resolveTilde("~/.config");
|
xdg_config_home = resolveTilde("~/.config");
|
||||||
|
|
||||||
|
char configDir[strlen(xdg_config_home) + 6];
|
||||||
|
memset(configDir, '\0', strlen(xdg_config_home) + 6);
|
||||||
|
|
||||||
return xdg_config_home;
|
sprintf( configDir, "%s/yaip", xdg_config_home );
|
||||||
|
|
||||||
|
return strdup(configDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* getDefaultUserConfigLoc(){
|
char* getUserConfigFile(char *filename){
|
||||||
|
//This doesn't end in a slash
|
||||||
char *configDir = getConfigDir();
|
char *configDir = getConfigDir();
|
||||||
char configFile[strlen(configDir) + 11];
|
//Make sure our filename doesn't start with a slash
|
||||||
|
while ( filename[0] == '/' ) filename++;
|
||||||
|
// Allocate space for both parts, a slash and a \0
|
||||||
|
char retFile[strlen(configDir) + strlen(filename) + 2];
|
||||||
|
|
||||||
memset(configFile, '\0', strlen(configDir) + 11);
|
memset(retFile, '\0', strlen(configDir) + strlen(filename) + 2);
|
||||||
|
|
||||||
strcpy( configFile, configDir );
|
sprintf(retFile, "%s/%s", configDir, filename);
|
||||||
|
|
||||||
strcat( configFile, "/proxy.conf" );
|
return strdup(retFile);
|
||||||
|
|
||||||
return strdup(configFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void setConfig(Config *config, char option[], char value[]){
|
void setConfig(Config *config, char option[], char value[]){
|
||||||
if ( strcmp( option, "database" ) == 0 ){
|
if ( strcmp( option, "database" ) == 0 ){
|
||||||
config->database = value;
|
config->database = value;
|
||||||
|
|
|
@ -13,13 +13,16 @@ typedef struct {
|
||||||
char *localConfig; // Project Specific
|
char *localConfig; // Project Specific
|
||||||
char *userConfig; // User Specific
|
char *userConfig; // User Specific
|
||||||
unsigned int port;
|
unsigned int port;
|
||||||
|
char *certfile;
|
||||||
|
char *keyfile;
|
||||||
} Config;
|
} Config;
|
||||||
|
|
||||||
bool path_exists(const char *path);
|
bool path_exists(const char *path);
|
||||||
char* resolveTilde(const char *path);
|
char* resolveTilde(const char *path);
|
||||||
Config* configDefaults();
|
Config* configDefaults();
|
||||||
char* getConfigDir();
|
char* getConfigDir();
|
||||||
char* getDefaultUserConfigLoc();
|
void maybeMakeDir(const char *path);
|
||||||
|
char* getUserConfigFile();
|
||||||
void setConfig(Config *config, char option[], char value[]);
|
void setConfig(Config *config, char option[], char value[]);
|
||||||
void printConfig(Config *config);
|
void printConfig(Config *config);
|
||||||
|
|
||||||
|
|
114
src/main.c
114
src/main.c
|
@ -7,6 +7,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "request.h"
|
#include "request.h"
|
||||||
#include "response.h"
|
#include "response.h"
|
||||||
|
#include "ssl.h"
|
||||||
|
|
||||||
#define PACKAGE_NAME "WICTP"
|
#define PACKAGE_NAME "WICTP"
|
||||||
#define DEFAULT_DATABASE "data.sqlite"
|
#define DEFAULT_DATABASE "data.sqlite"
|
||||||
|
@ -30,6 +31,40 @@ void printHelp(){
|
||||||
printf( "\t --print-config Prints current config\n" );
|
printf( "\t --print-config Prints current config\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int startListener(unsigned int port){
|
||||||
|
//we need to act as an http server
|
||||||
|
int server_fd;
|
||||||
|
struct sockaddr_in address;
|
||||||
|
memset( &address, 0, sizeof(address) );
|
||||||
|
int addrlen = sizeof(address);
|
||||||
|
Response *response;
|
||||||
|
char *responseStr;
|
||||||
|
|
||||||
|
// Creating socket file descriptor
|
||||||
|
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
|
||||||
|
perror("socket failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
address.sin_family = AF_INET;
|
||||||
|
address.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
address.sin_port = htons( port );
|
||||||
|
|
||||||
|
// Forcefully attaching socket to the port 8080
|
||||||
|
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) != 0) {
|
||||||
|
perror("bind failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(server_fd, 3) != 0) {
|
||||||
|
perror("listen");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return server_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char**argv){
|
int main(int argc, char**argv){
|
||||||
Config *config = configDefaults();
|
Config *config = configDefaults();
|
||||||
int listener;
|
int listener;
|
||||||
|
@ -67,7 +102,24 @@ int main(int argc, char**argv){
|
||||||
db_create(config->database);
|
db_create(config->database);
|
||||||
}
|
}
|
||||||
|
|
||||||
listener = proxy_startListener(config->port);
|
maybeMakeDir( getConfigDir() );
|
||||||
|
|
||||||
|
|
||||||
|
if (!path_exists( config->keyfile ) ){
|
||||||
|
printf("Creating keyfile\n");
|
||||||
|
if ( !create_and_save_key(config->keyfile) ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path_exists( config->certfile ) ){
|
||||||
|
printf("Creating cert\n");
|
||||||
|
if ( !create_and_save_cert(config->certfile, read_private_key( config->keyfile) ) ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
listener = startListener(config->port);
|
||||||
|
|
||||||
if ( listener < 0 ){
|
if ( listener < 0 ){
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -78,8 +130,6 @@ int main(int argc, char**argv){
|
||||||
socklen_t addrlen = sizeof(addr);
|
socklen_t addrlen = sizeof(addr);
|
||||||
int client = 0;
|
int client = 0;
|
||||||
Request *request = NULL;
|
Request *request = NULL;
|
||||||
Response *response = NULL;
|
|
||||||
char *responseStr;
|
|
||||||
printf("Listening on port %i\n", config->port);
|
printf("Listening on port %i\n", config->port);
|
||||||
|
|
||||||
if ((client = accept(listener, (struct sockaddr *)&addr,
|
if ((client = accept(listener, (struct sockaddr *)&addr,
|
||||||
|
@ -93,62 +143,18 @@ int main(int argc, char**argv){
|
||||||
//thread
|
//thread
|
||||||
|
|
||||||
request = newRequestFromSocket(client);
|
request = newRequestFromSocket(client);
|
||||||
|
|
||||||
// If the host is not defined, then it is not a proxy request
|
|
||||||
// Note that the host here is where the request should be sent, not
|
|
||||||
// necesarily the hosts header
|
|
||||||
if ( strcmp( request->host, "" ) == 0 ){
|
if ( strcmp( request->host, "" ) == 0 ){
|
||||||
response = webserverGetResponse(request);
|
// If the host is not defined, then it is not a proxy request
|
||||||
|
// Note that the host here is where the request should be sent, not
|
||||||
|
// necesarily the hosts header
|
||||||
|
webserverRequest(request, client);
|
||||||
} else {
|
} else {
|
||||||
response = upstreamGetResponse(request);
|
proxyRequest(request, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
responseStr = responseToString( response );
|
|
||||||
|
|
||||||
// I'm also not convinced that strlen is the best function to use here
|
|
||||||
// When we get to dealing with binary requests / responses, they may
|
|
||||||
// well have null characters in them
|
|
||||||
send(client , responseStr, strlen(responseStr) , 0 );
|
|
||||||
|
|
||||||
printf( "\n1\n" );
|
|
||||||
close(client);
|
close(client);
|
||||||
printf( "\n2\n" );
|
|
||||||
freeRequest( request );
|
freeRequest( request );
|
||||||
printf( "\n3\n" );
|
|
||||||
freeResponse( response );
|
|
||||||
printf( "\n4\n" );
|
|
||||||
free(responseStr);
|
|
||||||
printf( "\n5\n" );
|
|
||||||
|
|
||||||
//If this is an https request - this is the first part
|
|
||||||
//if ( strcmp( request->method, "CONNECT" ) == 0 ){
|
|
||||||
|
|
||||||
// // I am basically doing the same thing that mitmproxy does here
|
|
||||||
// // We start by responding with 200 Connection Established which
|
|
||||||
// // in a normal proxy would mean that we have established a
|
|
||||||
// // connection with the remote host. However, we haven't because we
|
|
||||||
// // are going to pretend to be the host to the client and pretend to
|
|
||||||
// // be the client to the host
|
|
||||||
|
|
||||||
// response = newResponse();
|
|
||||||
// connectionEstablished(response);
|
|
||||||
// responseStr = responseToString(response);
|
|
||||||
// send(new_socket , responseStr, strlen(responseStr) , 0 );
|
|
||||||
|
|
||||||
|
|
||||||
// char line[1024] = {'\0'};
|
|
||||||
// //a length of 2 will indicate an empty line which will split the headers
|
|
||||||
// //from the body (if there is a body)
|
|
||||||
// int valread = read( new_socket, line, 1024);
|
|
||||||
// while (valread > 0){
|
|
||||||
// printf("%s", line);
|
|
||||||
// //I believe at this point all the headers are done.
|
|
||||||
// valread = read( new_socket , line, 1024);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
69
src/proxy.c
69
src/proxy.c
|
@ -38,37 +38,50 @@ Response *upstreamGetResponse(Request *request){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int proxy_startListener(unsigned int port){
|
void proxyRequest(Request *request, int client){
|
||||||
//we need to act as an http server
|
|
||||||
int server_fd;
|
|
||||||
struct sockaddr_in address;
|
|
||||||
memset( &address, 0, sizeof(address) );
|
|
||||||
int addrlen = sizeof(address);
|
|
||||||
Response *response;
|
|
||||||
char *responseStr;
|
|
||||||
|
|
||||||
// Creating socket file descriptor
|
if ( strcmp( request->method, "CONNECT" ) == 0 ){
|
||||||
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
|
// If it is a connect request, we are dealing with https
|
||||||
perror("socket failed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
address.sin_family = AF_INET;
|
// I am basically doing the same thing that mitmproxy does here
|
||||||
address.sin_addr.s_addr = INADDR_ANY;
|
// We start by responding with 200 Connection Established which
|
||||||
address.sin_port = htons( port );
|
// in a normal proxy would mean that we have established a
|
||||||
|
// connection with the remote host. However, we haven't because we
|
||||||
|
// are going to pretend to be the host to the client and pretend to
|
||||||
|
// be the client to the host
|
||||||
|
|
||||||
// Forcefully attaching socket to the port 8080
|
Response *response = newResponse();
|
||||||
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) != 0) {
|
connectionEstablished(response);
|
||||||
perror("bind failed");
|
char *responseStr = responseToString(response);
|
||||||
return -1;
|
send(client , responseStr, strlen(responseStr) , 0 );
|
||||||
}
|
|
||||||
|
|
||||||
if (listen(server_fd, 3) != 0) {
|
|
||||||
perror("listen");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return server_fd;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//SSL_CTX *ctx;
|
||||||
|
//SSL *ssl;
|
||||||
|
//char buf[1024] = {0};
|
||||||
|
//int bytes;
|
||||||
|
|
||||||
|
//SSL_library_init();
|
||||||
|
//ctx = InitServerCTX(config);
|
||||||
|
//ssl = SSL_new(ctx);
|
||||||
|
//SSL_set_fd( ssl, client );
|
||||||
|
|
||||||
|
//if ( SSL_accept(ssl) == -1 ){
|
||||||
|
// ERR_print_errors_fp(stderr);
|
||||||
|
//} else {
|
||||||
|
// bytes = SSL_read(ssl, buf, sizeof(buf));
|
||||||
|
// buf[bytes] = '\0';
|
||||||
|
// printf("%s", buf);
|
||||||
|
//}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Response *response = upstreamGetResponse(request);
|
||||||
|
char *responseStr = responseToString( response );
|
||||||
|
send(client , responseStr, strlen(responseStr) , 0 );
|
||||||
|
free( responseStr );
|
||||||
|
freeResponse( response );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,11 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "request.h"
|
#include "request.h"
|
||||||
|
#include "response.h"
|
||||||
#include "webserver.h"
|
#include "webserver.h"
|
||||||
|
|
||||||
int proxy_startListener( unsigned int port );
|
|
||||||
Response *upstreamGetResponse(Request *request);
|
Response *upstreamGetResponse(Request *request);
|
||||||
|
|
||||||
|
void proxyRequest(Request *request, int client);
|
||||||
|
|
||||||
#endif /* ifndef PROXY_H */
|
#endif /* ifndef PROXY_H */
|
||||||
|
|
180
src/ssl.c
Normal file
180
src/ssl.c
Normal file
|
@ -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;
|
||||||
|
}
|
19
src/ssl.h
Normal file
19
src/ssl.h
Normal file
|
@ -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_ */
|
|
@ -6,3 +6,18 @@ Response* webserverGetResponse( Request *req ){
|
||||||
responseSetBody(rsp, "Test", 1);
|
responseSetBody(rsp, "Test", 1);
|
||||||
return rsp;
|
return rsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void webserverRequest( Request *req, int client ){
|
||||||
|
Response *rsp = webserverGetResponse( req );
|
||||||
|
char *responseStr = responseToString( rsp );
|
||||||
|
|
||||||
|
// I'm also not convinced that strlen is the best function to use here
|
||||||
|
// When we get to dealing with binary requests / responses, they may
|
||||||
|
// well have null characters in them
|
||||||
|
send(client , responseStr, strlen(responseStr) , 0 );
|
||||||
|
|
||||||
|
free( responseStr );
|
||||||
|
freeResponse( rsp );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "response.h"
|
#include "response.h"
|
||||||
|
|
||||||
Response* webserverGetResponse( Request *req );
|
Response* webserverGetResponse( Request *req );
|
||||||
|
void webserverRequest( Request *req, int client);
|
||||||
|
|
||||||
#endif /* ifndef WEBSERVER_H
|
#endif /* ifndef WEBSERVER_H
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ MunitResult checkConfigDirWithXdg(const MunitParameter params[],
|
||||||
void* user_data_or_fixture){
|
void* user_data_or_fixture){
|
||||||
char directory[] = "/testing/xdg/directory";
|
char directory[] = "/testing/xdg/directory";
|
||||||
setenv( "XDG_CONFIG_HOME",directory, 1 );
|
setenv( "XDG_CONFIG_HOME",directory, 1 );
|
||||||
munit_assert_string_equal( directory, getConfigDir() );
|
munit_assert_string_equal( "/testing/xdg/directory/yaip", getConfigDir() );
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ MunitResult checkConfigDirWithoutXdg(const MunitParameter params[],
|
||||||
unsetenv( "XDG_CONFIG_HOME" );
|
unsetenv( "XDG_CONFIG_HOME" );
|
||||||
char dir[500] = {'\0'};
|
char dir[500] = {'\0'};
|
||||||
strcpy( dir, getenv("HOME") );
|
strcpy( dir, getenv("HOME") );
|
||||||
strcat( dir, "/.config" );
|
strcat( dir, "/.config/yaip" );
|
||||||
munit_assert_string_equal( dir, getConfigDir() );
|
munit_assert_string_equal( dir, getConfigDir() );
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
@ -55,14 +55,18 @@ MunitResult checkDefaults(const MunitParameter params[],
|
||||||
void* user_data_or_fixture){
|
void* user_data_or_fixture){
|
||||||
|
|
||||||
char directory[] = "/testing/xdg/directory";
|
char directory[] = "/testing/xdg/directory";
|
||||||
char file[] = "/testing/xdg/directory/proxy.conf";
|
char conffile[] = "/testing/xdg/directory/yaip/proxy.conf";
|
||||||
|
char certfile[] = "/testing/xdg/directory/yaip/cert.pem";
|
||||||
|
char keyfile[] = "/testing/xdg/directory/yaip/key.pem";
|
||||||
setenv( "XDG_CONFIG_HOME",directory, 1 );
|
setenv( "XDG_CONFIG_HOME",directory, 1 );
|
||||||
Config *conf = configDefaults();
|
Config *conf = configDefaults();
|
||||||
|
|
||||||
munit_assert_string_equal(conf->database, "proxy.sqlite");
|
munit_assert_string_equal(conf->database, "proxy.sqlite");
|
||||||
munit_assert_int(conf->port, ==, 8080);
|
munit_assert_int(conf->port, ==, 8080);
|
||||||
munit_assert_string_equal(conf->localConfig, "proxy.conf");
|
munit_assert_string_equal(conf->localConfig, "proxy.conf");
|
||||||
munit_assert_string_equal(conf->userConfig, file);
|
munit_assert_string_equal(conf->userConfig, conffile);
|
||||||
|
munit_assert_string_equal(conf->certfile, certfile);
|
||||||
|
munit_assert_string_equal(conf->keyfile, keyfile);
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,7 @@ MunitResult testFirstLineVersions(const MunitParameter params[],
|
||||||
void* user_data_or_fixture){
|
void* user_data_or_fixture){
|
||||||
|
|
||||||
Request *req;
|
Request *req;
|
||||||
|
printf("\nI get here\n");
|
||||||
requestTestFirstLine *line = getLineObj(params);
|
requestTestFirstLine *line = getLineObj(params);
|
||||||
if ( line->fullLine == NULL ) return MUNIT_ERROR;
|
if ( line->fullLine == NULL ) return MUNIT_ERROR;
|
||||||
req = newRequest();
|
req = newRequest();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue