Initial https proxy work
The proxy can now sit between a client and a https web server. It does this by looking for a CONNECT request that conventional proxies use to open a tunnel between a client and an https server. Instead of opening an opaque tunnel, yaip immediately sends bacck a "connection established" response. This tells the client (browser normally) to proceed and initiate an HTTPS connection. I use the host that was send in the connect request to set up a fake SSL server. If we have seen the domain before, we re-use the certificate, otherwise we generate a new one and sign it using YAIP's built in certificate authority. I still need to do work on forwarding the request upstream. This is my next job. Currently, yaip responds with a valid response of "it worked". ``` $ curl https://example.com --cacert ~/.config/yaip/cert.pem It worked ``` Notice, we don't get any certificate errors because we are telling curl to trust the authority that yaip uses
This commit is contained in:
parent
1beca38af6
commit
dd71d26245
15 changed files with 330 additions and 109 deletions
10
src/main.c
10
src/main.c
|
@ -68,7 +68,10 @@ int startListener(unsigned int port){
|
||||||
int main(int argc, char**argv){
|
int main(int argc, char**argv){
|
||||||
Config *config = configDefaults();
|
Config *config = configDefaults();
|
||||||
int listener;
|
int listener;
|
||||||
CertList *certs = NULL;
|
CertificateAutority *ca = malloc( sizeof( CertificateAutority ) );
|
||||||
|
ca->cert = NULL;
|
||||||
|
ca->pkey = NULL;
|
||||||
|
ca->certs = NULL;
|
||||||
|
|
||||||
|
|
||||||
for ( unsigned int i = 1; i < argc; i++ ){
|
for ( unsigned int i = 1; i < argc; i++ ){
|
||||||
|
@ -112,6 +115,7 @@ int main(int argc, char**argv){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ca->pkey = read_private_key( config->keyfile );
|
||||||
|
|
||||||
if (!path_exists( config->certfile ) ){
|
if (!path_exists( config->certfile ) ){
|
||||||
printf("Creating cert\n");
|
printf("Creating cert\n");
|
||||||
|
@ -119,6 +123,7 @@ int main(int argc, char**argv){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ca->cert = read_cert( config->certfile );
|
||||||
|
|
||||||
listener = startListener(config->port);
|
listener = startListener(config->port);
|
||||||
|
|
||||||
|
@ -151,12 +156,11 @@ int main(int argc, char**argv){
|
||||||
// necesarily the hosts header
|
// necesarily the hosts header
|
||||||
webserverRequest(request, client);
|
webserverRequest(request, client);
|
||||||
} else {
|
} else {
|
||||||
proxyRequest(request, client, certs);
|
proxyRequest(request, client, ca);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(client);
|
close(client);
|
||||||
freeRequest( request );
|
freeRequest( request );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
90
src/proxy.c
90
src/proxy.c
|
@ -16,7 +16,7 @@ Response *upstreamGetResponse(Request *request){
|
||||||
|
|
||||||
|
|
||||||
address.sin_family = AF_INET;
|
address.sin_family = AF_INET;
|
||||||
address.sin_port = htons( 80 );
|
address.sin_port = htons( request->port );
|
||||||
// We want the request to go out to whatever the host was resolved to
|
// We want the request to go out to whatever the host was resolved to
|
||||||
memcpy( &address.sin_addr, host->h_addr_list[0], host->h_length );
|
memcpy( &address.sin_addr, host->h_addr_list[0], host->h_length );
|
||||||
|
|
||||||
|
@ -35,47 +35,77 @@ Response *upstreamGetResponse(Request *request){
|
||||||
rsp = newResponseFromSocket( client_fd );
|
rsp = newResponseFromSocket( client_fd );
|
||||||
|
|
||||||
return rsp;
|
return rsp;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void proxyRequest(Request *request, int client, CertList *certs){
|
void sendConnectionEstablished(int client){
|
||||||
|
// If it is a connect request, we are dealing with https
|
||||||
|
|
||||||
|
// 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 *response = newResponse();
|
||||||
|
connectionEstablished(response);
|
||||||
|
char *responseStr = responseToString(response);
|
||||||
|
send(client , responseStr, strlen(responseStr) , 0 );
|
||||||
|
freeResponse( response );
|
||||||
|
}
|
||||||
|
|
||||||
|
void proxyRequest(Request *request, int client, CertificateAutority *ca){
|
||||||
if ( strcmp( request->method, "CONNECT" ) == 0 ){
|
if ( strcmp( request->method, "CONNECT" ) == 0 ){
|
||||||
// If it is a connect request, we are dealing with https
|
|
||||||
|
|
||||||
// I am basically doing the same thing that mitmproxy does here
|
sendConnectionEstablished(client);
|
||||||
// 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 *response = newResponse();
|
// All we might need from the connect resquest is the host
|
||||||
connectionEstablished(response);
|
char *host = request->host;
|
||||||
char *responseStr = responseToString(response);
|
freeRequest( request );
|
||||||
send(client , responseStr, strlen(responseStr) , 0 );
|
|
||||||
|
// If we already have a host cert for the domain we're dealing with use
|
||||||
|
// it
|
||||||
|
CertList *certItem = findCertListItem( ca->certs, host );
|
||||||
|
if ( certItem == NULL ){
|
||||||
|
// If we don't, generate a new one
|
||||||
|
X509 *siteCert = generate_site_cert( ca->pkey, ca->cert, host );
|
||||||
|
certItem = newCertListItem( host, ca->pkey, siteCert );
|
||||||
|
if ( ca->certs == NULL ) ca->certs = certItem;
|
||||||
|
else getLastCertListItem(ca->certs)->next = certItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SSL_CTX *ctx;
|
||||||
|
SSL *ssl;
|
||||||
|
char buf[1024] = {0};
|
||||||
|
int bytes;
|
||||||
|
Response *response;
|
||||||
|
|
||||||
|
SSL_library_init();
|
||||||
|
|
||||||
|
ctx = setup_ctx(certItem);
|
||||||
|
|
||||||
//SSL_CTX *ctx;
|
ssl = SSL_new(ctx);
|
||||||
//SSL *ssl;
|
SSL_set_fd( ssl, client );
|
||||||
//char buf[1024] = {0};
|
|
||||||
//int bytes;
|
|
||||||
|
|
||||||
//SSL_library_init();
|
if ( SSL_accept(ssl) == -1 ){
|
||||||
//ctx = InitServerCTX(config);
|
ERR_print_errors_fp(stderr);
|
||||||
//ssl = SSL_new(ctx);
|
} else {
|
||||||
//SSL_set_fd( ssl, client );
|
bytes = SSL_read(ssl, buf, sizeof(buf));
|
||||||
|
buf[bytes] = '\0';
|
||||||
//if ( SSL_accept(ssl) == -1 ){
|
request = newRequestFromString( buf );
|
||||||
// ERR_print_errors_fp(stderr);
|
//If this request doesn't contain a host, use the one from the
|
||||||
//} else {
|
//connect request
|
||||||
// bytes = SSL_read(ssl, buf, sizeof(buf));
|
if ( strlen( request->host ) == 0 ){
|
||||||
// buf[bytes] = '\0';
|
free(request->host);
|
||||||
// printf("%s", buf);
|
request->host = strdup( host );
|
||||||
//}
|
}
|
||||||
|
response = upstreamGetResponse(request);
|
||||||
|
char *responseStr = responseToString( response );
|
||||||
|
SSL_write( ssl, responseStr, strlen(responseStr) );
|
||||||
|
}
|
||||||
|
SSL_free(ssl);
|
||||||
|
SSL_CTX_free(ctx);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Response *response = upstreamGetResponse(request);
|
Response *response = upstreamGetResponse(request);
|
||||||
|
|
|
@ -17,7 +17,9 @@
|
||||||
#include "ssl.h"
|
#include "ssl.h"
|
||||||
|
|
||||||
Response *upstreamGetResponse(Request *request);
|
Response *upstreamGetResponse(Request *request);
|
||||||
|
void sendConnectionEstablished(int client);
|
||||||
|
|
||||||
|
void proxyRequest(Request *request, int client, CertificateAutority *ca);
|
||||||
|
|
||||||
void proxyRequest(Request *request, int client, CertList *certs);
|
|
||||||
|
|
||||||
#endif /* ifndef PROXY_H */
|
#endif /* ifndef PROXY_H */
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
// https://man7.org/tlpi/code/online/dist/sockets/read_line.c.html
|
|
||||||
#include "readline.h"
|
|
||||||
|
|
||||||
/* Read characters from 'fd' until a newline is encountered. If a newline
|
|
||||||
character is not encountered in the first (n - 1) bytes, then the excess
|
|
||||||
characters are discarded. The returned string placed in 'buf' is
|
|
||||||
null-terminated and includes the newline character if it was read in the
|
|
||||||
first (n - 1) bytes. The function return value is the number of bytes
|
|
||||||
placed in buffer (which includes the newline character if encountered,
|
|
||||||
but excludes the terminating null byte). */
|
|
||||||
ssize_t fdReadLine(int fd, void *buffer, size_t n) {
|
|
||||||
ssize_t numRead; /* # of bytes fetched by last read() */
|
|
||||||
size_t totRead; /* Total bytes read so far */
|
|
||||||
char *buf;
|
|
||||||
char ch;
|
|
||||||
if (n <= 0 || buffer == NULL) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
buf = buffer; /* No pointer arithmetic on "void *" */
|
|
||||||
totRead = 0;
|
|
||||||
for (;;) {
|
|
||||||
numRead = read(fd, &ch, 1);
|
|
||||||
if (numRead == -1) {
|
|
||||||
if (errno == EINTR) /* Interrupted --> restart read() */
|
|
||||||
continue;
|
|
||||||
else
|
|
||||||
return -1; /* Some other error */
|
|
||||||
|
|
||||||
} else if (numRead == 0) { /* EOF */
|
|
||||||
if (totRead == 0) /* No bytes read; return 0 */
|
|
||||||
return 0;
|
|
||||||
else /* Some bytes read; add '\0' */
|
|
||||||
break;
|
|
||||||
|
|
||||||
} else { /* 'numRead' must be 1 if we get here */
|
|
||||||
if (totRead < n - 1) { /* Discard > (n - 1) bytes */
|
|
||||||
totRead++;
|
|
||||||
*buf++ = ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == '\n')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*buf = '\0';
|
|
||||||
return totRead;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
#ifndef READLINE_H
|
|
||||||
#define READLINE_H
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
ssize_t fdReadLine(int fd, void *buffer, size_t n);
|
|
||||||
|
|
||||||
#endif /* ifndef READLINE_H */
|
|
|
@ -83,6 +83,7 @@ void requestFirstLine( Request *req, char line[] ){
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( strlen(req->protocol) == 0 ){
|
if ( strlen(req->protocol) == 0 ){
|
||||||
|
free(req->protocol);
|
||||||
if ( req->port == 443 )
|
if ( req->port == 443 )
|
||||||
req->protocol = strdup("https");
|
req->protocol = strdup("https");
|
||||||
else
|
else
|
||||||
|
@ -122,6 +123,39 @@ Request* newRequestFromSocket(int socket){
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Request* newRequestFromString(char *string){
|
||||||
|
// We don't want to modify the original string
|
||||||
|
char *str = strdup(string);
|
||||||
|
Request *req = newRequest();
|
||||||
|
int valread;
|
||||||
|
|
||||||
|
//Find the new line
|
||||||
|
char *occurance = strchr( str, '\n' );
|
||||||
|
occurance[0] = '\0';
|
||||||
|
requestFirstLine(req, str);
|
||||||
|
str = occurance + 1;
|
||||||
|
|
||||||
|
occurance = strchr( str, '\n' );
|
||||||
|
occurance[0] = '\0';
|
||||||
|
|
||||||
|
while ( strlen(str) > 1 ){
|
||||||
|
requestAddHeader( req, str );
|
||||||
|
str = occurance + 1;
|
||||||
|
occurance = strchr( str, '\n' );
|
||||||
|
occurance[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: make requests work with a body
|
||||||
|
//contentLength = getHeader( req->headers, "content-length" );
|
||||||
|
|
||||||
|
//if ( contentLength != NULL ){
|
||||||
|
// printf( "Content length is %i\n", atoi(contentLength->value) );
|
||||||
|
//}
|
||||||
|
|
||||||
|
return req;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
char* requestToString( Request *req){
|
char* requestToString( Request *req){
|
||||||
unsigned int fullLength = strlen(req->method) + 1 + sizeof( req->path ) +
|
unsigned int fullLength = strlen(req->method) + 1 + sizeof( req->path ) +
|
||||||
//11 = [space]http/1.1\r\n
|
//11 = [space]http/1.1\r\n
|
||||||
|
|
|
@ -7,10 +7,9 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "readline.h"
|
|
||||||
#include "requestresponse.h"
|
|
||||||
|
|
||||||
#include "./util.h"
|
#include "util.h"
|
||||||
|
#include "requestresponse.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,6 +32,7 @@ typedef struct {
|
||||||
Request* newRequest();
|
Request* newRequest();
|
||||||
void requestFirstLine( Request *req, char line[] );
|
void requestFirstLine( Request *req, char line[] );
|
||||||
Request* newRequestFromSocket(int socket);
|
Request* newRequestFromSocket(int socket);
|
||||||
|
Request* newRequestFromString(char *string);
|
||||||
/*
|
/*
|
||||||
* requestToString
|
* requestToString
|
||||||
* @prarm req the request to convert
|
* @prarm req the request to convert
|
||||||
|
|
|
@ -50,6 +50,10 @@ void responseSetBody(Response *rsp, char *string, bool updateContentLength){
|
||||||
|
|
||||||
if ( updateContentLength ){
|
if ( updateContentLength ){
|
||||||
Header *contentLengthHeader = getHeader(rsp->headers, "content-length");
|
Header *contentLengthHeader = getHeader(rsp->headers, "content-length");
|
||||||
|
if ( contentLengthHeader == NULL ){
|
||||||
|
responseAddHeader( rsp, "content-length: 0" );
|
||||||
|
contentLengthHeader = getHeader(rsp->headers, "content-length");
|
||||||
|
}
|
||||||
char *value = malloc(sizeof(char) * 20);
|
char *value = malloc(sizeof(char) * 20);
|
||||||
sprintf(value, "%lu", strlen(string) );
|
sprintf(value, "%lu", strlen(string) );
|
||||||
contentLengthHeader->value = strdup(value);
|
contentLengthHeader->value = strdup(value);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "readline.h"
|
#include "util.h"
|
||||||
#include "requestresponse.h"
|
#include "requestresponse.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
41
src/ssl.c
41
src/ssl.c
|
@ -1,13 +1,14 @@
|
||||||
#include "ssl.h"
|
#include "ssl.h"
|
||||||
|
|
||||||
|
|
||||||
|
SSL_CTX* setup_ctx(CertList *certItem) {
|
||||||
SSL_CTX* InitServerCTX(Config *config) {
|
|
||||||
const SSL_METHOD *method;
|
const SSL_METHOD *method;
|
||||||
SSL_CTX *ctx;
|
SSL_CTX *ctx;
|
||||||
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
|
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
|
||||||
SSL_load_error_strings(); /* load all error messages */
|
SSL_load_error_strings(); /* load all error messages */
|
||||||
method = TLS_server_method(); /* create new server-method instance */
|
method = TLS_server_method(); /* create new server-method instance */
|
||||||
|
|
||||||
|
|
||||||
ctx = SSL_CTX_new(method); /* create new context from method */
|
ctx = SSL_CTX_new(method); /* create new context from method */
|
||||||
if ( ctx == NULL ) {
|
if ( ctx == NULL ) {
|
||||||
ERR_print_errors_fp(stderr);
|
ERR_print_errors_fp(stderr);
|
||||||
|
@ -15,18 +16,18 @@ SSL_CTX* InitServerCTX(Config *config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//set the local certificate from CertFile
|
//set the local certificate from CertFile
|
||||||
if ( SSL_CTX_use_certificate_file(ctx, config->certfile, SSL_FILETYPE_PEM) <= 0 ){
|
if ( SSL_CTX_use_certificate(ctx, certItem->cert) <= 0 ){
|
||||||
ERR_print_errors_fp(stderr);
|
ERR_print_errors_fp(stderr);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
//set the private key from KeyFile (may be the same as CertFile)
|
//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 ){
|
if ( SSL_CTX_use_PrivateKey(ctx, certItem->key) <= 0 ){
|
||||||
ERR_print_errors_fp(stderr);
|
ERR_print_errors_fp(stderr);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
//verify private key
|
//verify private key
|
||||||
if ( !SSL_CTX_check_private_key(ctx) ) {
|
if ( !SSL_CTX_check_private_key(ctx) ) {
|
||||||
fprintf(stderr, "Private key does not match the public certificate\n");
|
fprintf(stderr, "Private key does not match the public certificate\n");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
@ -35,6 +36,7 @@ SSL_CTX* InitServerCTX(Config *config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Generates a 2048-bit RSA key.
|
// Generates a 2048-bit RSA key.
|
||||||
// Largely stolen from here: https://gist.github.com/nathan-osman/5041136
|
// Largely stolen from here: https://gist.github.com/nathan-osman/5041136
|
||||||
EVP_PKEY* generate_ca_key() {
|
EVP_PKEY* generate_ca_key() {
|
||||||
|
@ -60,7 +62,6 @@ EVP_PKEY* generate_ca_key() {
|
||||||
return pkey;
|
return pkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Generates a self-signed x509 certificate.
|
// Generates a self-signed x509 certificate.
|
||||||
// Largely stolen from here: https://gist.github.com/nathan-osman/5041136
|
// Largely stolen from here: https://gist.github.com/nathan-osman/5041136
|
||||||
X509* generate_ca_cert(EVP_PKEY * pkey) {
|
X509* generate_ca_cert(EVP_PKEY * pkey) {
|
||||||
|
@ -177,7 +178,6 @@ bool create_and_save_key(char keyfile[]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool create_and_save_cert(char certfile[], EVP_PKEY *pkey) {
|
bool create_and_save_cert(char certfile[], EVP_PKEY *pkey) {
|
||||||
// Open the PEM file for writing the certificate to disk.
|
// Open the PEM file for writing the certificate to disk.
|
||||||
FILE * x509_file = fopen(certfile, "wb");
|
FILE * x509_file = fopen(certfile, "wb");
|
||||||
|
@ -204,7 +204,6 @@ bool create_and_save_cert(char certfile[], EVP_PKEY *pkey) {
|
||||||
}
|
}
|
||||||
|
|
||||||
EVP_PKEY* read_private_key(char keyfile[]){
|
EVP_PKEY* read_private_key(char keyfile[]){
|
||||||
|
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
EVP_PKEY *pkey;
|
EVP_PKEY *pkey;
|
||||||
|
|
||||||
|
@ -218,10 +217,30 @@ EVP_PKEY* read_private_key(char keyfile[]){
|
||||||
if ( pkey == NULL ){
|
if ( pkey == NULL ){
|
||||||
perror("Error cant read certificate private key file.\n");
|
perror("Error cant read certificate private key file.\n");
|
||||||
}
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
return pkey;
|
return pkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
X509* read_cert(char certfile[]){
|
||||||
|
FILE *fp;
|
||||||
|
X509 *cert;
|
||||||
|
|
||||||
|
if (! (fp = fopen(certfile, "r"))){
|
||||||
|
perror("Error cant open certificate private key file.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cert = PEM_read_X509( fp, NULL, NULL, NULL );
|
||||||
|
|
||||||
|
if ( cert == NULL ){
|
||||||
|
perror("Error cant read certificate private key file.\n");
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return cert;
|
||||||
|
}
|
||||||
|
|
||||||
CertList *newCertListItem(char *host, EVP_PKEY *key, X509 *cert){
|
CertList *newCertListItem(char *host, EVP_PKEY *key, X509 *cert){
|
||||||
CertList *item = malloc(sizeof( CertList ));
|
CertList *item = malloc(sizeof( CertList ));
|
||||||
item->host = host;
|
item->host = host;
|
||||||
|
@ -245,3 +264,9 @@ unsigned int countCertListItems(CertList *item){
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CertList *findCertListItem( CertList *item, char *host ){
|
||||||
|
while ( item != NULL && strcmp( host, item->host ) != 0 ) item = item->next;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
85
src/ssl.h
85
src/ssl.h
|
@ -18,18 +18,97 @@ struct CertList {
|
||||||
CertList *next;
|
CertList *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
SSL_CTX* InitServerCTX(Config *config);
|
typedef struct {
|
||||||
|
X509 *cert;
|
||||||
|
EVP_PKEY *pkey;
|
||||||
|
CertList *certs;
|
||||||
|
} CertificateAutority;
|
||||||
|
|
||||||
|
|
||||||
|
SSL_CTX* setup_ctx(CertList *certItem);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* generate_ca_key
|
||||||
|
* Genreates a EVP_PKEY for the certificate authority
|
||||||
|
*/
|
||||||
EVP_PKEY* generate_ca_key();
|
EVP_PKEY* generate_ca_key();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* generate_ca_cert
|
||||||
|
* Genreates a x509 cert for the certificate authority
|
||||||
|
* @param EVP_PKEY pkey - the pkey for the ca
|
||||||
|
*/
|
||||||
X509* generate_ca_cert(EVP_PKEY * pkey);
|
X509* generate_ca_cert(EVP_PKEY * pkey);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* generate_site_cert
|
||||||
|
* Genreates a signed x509 cert for the host authority
|
||||||
|
* @param EVP_PKEY pkey - the pkey for the ca
|
||||||
|
* @param X509 caCert - the cert for the ca
|
||||||
|
* @param char* host - the common name for the certificate
|
||||||
|
*/
|
||||||
X509* generate_site_cert( EVP_PKEY *pkey, X509 *caCert, char *host );
|
X509* generate_site_cert( EVP_PKEY *pkey, X509 *caCert, char *host );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create_and_save_key
|
||||||
|
* Genreates a EVP_PKEY for the CA and saves it
|
||||||
|
* @param char[] keyfile - the name of the file
|
||||||
|
*/
|
||||||
bool create_and_save_key(char keyfile[]);
|
bool create_and_save_key(char keyfile[]);
|
||||||
bool create_and_save_cert(char keyfile[], EVP_PKEY *pkey);
|
|
||||||
|
/*
|
||||||
|
* create_and_save_cert
|
||||||
|
* Genreates a cert for the CA and saves it
|
||||||
|
* @param char[] certfile - the name of the file
|
||||||
|
* @param EVP_PKEY pkey - the pkey for the ca
|
||||||
|
*/
|
||||||
|
bool create_and_save_cert(char certfile[], EVP_PKEY *pkey);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read_private_key
|
||||||
|
* Reades a priveate key from the keyfile
|
||||||
|
* @param char[] keyfile - the name of the file
|
||||||
|
*/
|
||||||
EVP_PKEY* read_private_key(char keyfile[]);
|
EVP_PKEY* read_private_key(char keyfile[]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read_cert
|
||||||
|
* Reades a cert from the certfile
|
||||||
|
* @param char[] certfile - the name of the file
|
||||||
|
*/
|
||||||
|
X509* read_cert(char certfile[]);
|
||||||
|
/*
|
||||||
|
* newCertListItem
|
||||||
|
* Creates an element of the CertList linked list
|
||||||
|
* @param char* host - the common name for the certificate
|
||||||
|
* @param EVP_PKEY key - the pkey
|
||||||
|
* @param X509 cert - the cert
|
||||||
|
*/
|
||||||
CertList *newCertListItem(char *host, EVP_PKEY *key, X509 *cert);
|
CertList *newCertListItem(char *host, EVP_PKEY *key, X509 *cert);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getLastCertListItem
|
||||||
|
* Gets the last element in the linked list
|
||||||
|
* @param CertList item - An item in the linked list
|
||||||
|
*/
|
||||||
CertList *getLastCertListItem(CertList *item);
|
CertList *getLastCertListItem(CertList *item);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* countCertListItems
|
||||||
|
* counts the elements in the linked list
|
||||||
|
* @param CertList item - the first item in the linked list
|
||||||
|
*/
|
||||||
unsigned int countCertListItems(CertList *item);
|
unsigned int countCertListItems(CertList *item);
|
||||||
CertList *findCertListItem( CertList *first, char *hostname );
|
|
||||||
|
/*
|
||||||
|
* countCertListItems
|
||||||
|
* Returns the certList item with the specified host
|
||||||
|
* @param CertList item - the first item in the linked list
|
||||||
|
* @param char* host - the host we are looking for
|
||||||
|
* returns null if not there
|
||||||
|
*/
|
||||||
|
CertList *findCertListItem( CertList *item, char *host );
|
||||||
|
|
||||||
|
|
||||||
#endif /* ifndef SSL_ */
|
#endif /* ifndef SSL_ */
|
||||||
|
|
48
src/util.c
48
src/util.c
|
@ -24,3 +24,51 @@ int countLines(char fileName[]){
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return linesCount;
|
return linesCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read characters from 'fd' until a newline is encountered. If a newline
|
||||||
|
character is not encountered in the first (n - 1) bytes, then the excess
|
||||||
|
characters are discarded. The returned string placed in 'buf' is
|
||||||
|
null-terminated and includes the newline character if it was read in the
|
||||||
|
first (n - 1) bytes. The function return value is the number of bytes
|
||||||
|
placed in buffer (which includes the newline character if encountered,
|
||||||
|
but excludes the terminating null byte). */
|
||||||
|
ssize_t fdReadLine(int fd, void *buffer, size_t n) {
|
||||||
|
ssize_t numRead; /* # of bytes fetched by last read() */
|
||||||
|
size_t totRead; /* Total bytes read so far */
|
||||||
|
char *buf;
|
||||||
|
char ch;
|
||||||
|
if (n <= 0 || buffer == NULL) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buf = buffer; /* No pointer arithmetic on "void *" */
|
||||||
|
totRead = 0;
|
||||||
|
for (;;) {
|
||||||
|
numRead = read(fd, &ch, 1);
|
||||||
|
if (numRead == -1) {
|
||||||
|
if (errno == EINTR) /* Interrupted --> restart read() */
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
return -1; /* Some other error */
|
||||||
|
|
||||||
|
} else if (numRead == 0) { /* EOF */
|
||||||
|
if (totRead == 0) /* No bytes read; return 0 */
|
||||||
|
return 0;
|
||||||
|
else /* Some bytes read; add '\0' */
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else { /* 'numRead' must be 1 if we get here */
|
||||||
|
if (totRead < n - 1) { /* Discard > (n - 1) bytes */
|
||||||
|
totRead++;
|
||||||
|
*buf++ = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == '\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*buf = '\0';
|
||||||
|
return totRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,11 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
int strpos(char *haystack, char *needle);
|
int strpos(char *haystack, char *needle);
|
||||||
int countLines(char fileName[]);
|
int countLines(char fileName[]);
|
||||||
|
ssize_t fdReadLine(int fd, void *buffer, size_t n);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#include "munit/munit.h"
|
#include "munit/munit.h"
|
||||||
|
|
||||||
#include "../src/readline.h"
|
#include "../src/util.h"
|
||||||
#include "../src/request.h"
|
#include "../src/request.h"
|
||||||
#include "../src/requestresponse.h"
|
#include "../src/requestresponse.h"
|
||||||
|
|
||||||
|
@ -160,6 +160,18 @@ MunitResult testRequestToString(const MunitParameter params[],
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MunitResult testRequestFromString(const MunitParameter params[],
|
||||||
|
void* user_data_or_fixture){
|
||||||
|
char testString[] = "GET / HTTP/1.1\r\nHost: example.com\r\nAccept: */*\r\n\r\n";
|
||||||
|
Request *req = newRequestFromString(testString);
|
||||||
|
|
||||||
|
munit_assert_string_equal( req->method, "GET" );
|
||||||
|
munit_assert_string_equal( req->path, "/" );
|
||||||
|
munit_assert_string_equal( requestToString( req ), testString );
|
||||||
|
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
MunitParameterEnum test_first_line_params[2] = {NULL, NULL};
|
MunitParameterEnum test_first_line_params[2] = {NULL, NULL};
|
||||||
|
|
||||||
static MunitTest request_tests[] = {
|
static MunitTest request_tests[] = {
|
||||||
|
@ -226,6 +238,13 @@ static MunitTest request_tests[] = {
|
||||||
NULL, /* tear_down */
|
NULL, /* tear_down */
|
||||||
MUNIT_TEST_OPTION_NONE, /* options */
|
MUNIT_TEST_OPTION_NONE, /* options */
|
||||||
NULL /* parameters */
|
NULL /* parameters */
|
||||||
|
},{
|
||||||
|
"/fromstring", /* name */
|
||||||
|
testRequestFromString, /* test */
|
||||||
|
NULL, /* setup */
|
||||||
|
NULL, /* tear_down */
|
||||||
|
MUNIT_TEST_OPTION_NONE, /* options */
|
||||||
|
NULL /* parameters */
|
||||||
},
|
},
|
||||||
/* Mark the end of the array with an entry where the test
|
/* Mark the end of the array with an entry where the test
|
||||||
* function is NULL */
|
* function is NULL */
|
||||||
|
|
|
@ -145,6 +145,37 @@ MunitResult testNewHostCertificate(const MunitParameter params[],
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MunitResult testFindCertListItem(const MunitParameter params[],
|
||||||
|
void* user_data_or_fixture){
|
||||||
|
|
||||||
|
CertList *head = newCertListItem( "example.com", NULL, NULL );
|
||||||
|
CertList *last = head;
|
||||||
|
CertList *curr;
|
||||||
|
for ( unsigned int i = 0; i < 10; i++ ){
|
||||||
|
char host[15] = {'\0'};
|
||||||
|
sprintf(host, "example%d.com", i+1);
|
||||||
|
last->next = newCertListItem( strdup(host), NULL, NULL );
|
||||||
|
last = last->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
munit_assert_int( countCertListItems( head ), ==, 11 );
|
||||||
|
|
||||||
|
curr = findCertListItem( head, "example.com" );
|
||||||
|
munit_assert_not_null( curr );
|
||||||
|
munit_assert_string_equal( curr->host, "example.com" );
|
||||||
|
|
||||||
|
curr = findCertListItem( head, "example1.com" );
|
||||||
|
munit_assert_not_null( curr );
|
||||||
|
munit_assert_string_equal( curr->host, "example1.com" );
|
||||||
|
|
||||||
|
curr = findCertListItem( head, "example5.com" );
|
||||||
|
munit_assert_not_null( curr );
|
||||||
|
munit_assert_string_equal( curr->host, "example5.com" );
|
||||||
|
|
||||||
|
curr = findCertListItem( head, "doesnt-exist.com" );
|
||||||
|
munit_assert_null( curr );
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static char* count_parameters[] = {
|
static char* count_parameters[] = {
|
||||||
"0", "1", "2", "10", "50", NULL
|
"0", "1", "2", "10", "50", NULL
|
||||||
|
@ -180,6 +211,7 @@ static MunitTest ssl_tests[] = {
|
||||||
{ "/ca/cert/save", testNewCertificateSave, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
|
{ "/ca/cert/save", testNewCertificateSave, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
|
||||||
{ "/CertList/count", testCerlistCount, NULL, NULL, MUNIT_TEST_OPTION_NONE, count_params },
|
{ "/CertList/count", testCerlistCount, NULL, NULL, MUNIT_TEST_OPTION_NONE, count_params },
|
||||||
{ "/CertList/last", testCerlistLast, NULL, NULL, MUNIT_TEST_OPTION_NONE, count_params },
|
{ "/CertList/last", testCerlistLast, NULL, NULL, MUNIT_TEST_OPTION_NONE, count_params },
|
||||||
|
{ "/CertList/find", testFindCertListItem, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
|
||||||
{ "/hostcert/new", testNewHostCertificate, NULL, NULL, MUNIT_TEST_OPTION_NONE, x509_issuer_subject_params },
|
{ "/hostcert/new", testNewHostCertificate, NULL, NULL, MUNIT_TEST_OPTION_NONE, x509_issuer_subject_params },
|
||||||
/* Mark the end of the array with an entry where the test
|
/* Mark the end of the array with an entry where the test
|
||||||
* function is NULL */
|
* function is NULL */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue