added ssl
This commit is contained in:
23
Makefile
23
Makefile
@@ -1,4 +1,4 @@
|
||||
LIBRARIES = -Iinclude
|
||||
LIBRARIES = `pkg-config --libs openssl` -Iinclude
|
||||
SOURCES = ./src/* ./cmd/server.c
|
||||
OUTPUT_DIR = ./bin
|
||||
OUTPUT = -o ${OUTPUT_DIR}/PROG
|
||||
@@ -18,11 +18,20 @@ output_dir:
|
||||
|
||||
CERT_DIR = ./certs/
|
||||
|
||||
genCerts:
|
||||
mkdir -p ${CERT_DIR}
|
||||
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
|
||||
-x509 -nodes -days 365 -out ${CERT_DIR}cert.pem -keyout ${CERT_DIR}cert.pem \
|
||||
-subj "/C=US/ST=Some-State/L=[]/O=[]/CN=localhost"
|
||||
|
||||
clean:
|
||||
rm -rf $(OUTPUT_DIR) ${CERT_DIR} **.h.gch
|
||||
|
||||
genCerts:
|
||||
mkdir -p ${CERT_DIR}
|
||||
touch ${CERT_DIR}index.txt
|
||||
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
|
||||
-sha256 -nodes -out ${CERT_DIR}cacert.pem -keyout ${CERT_DIR}cakey.pem \
|
||||
-outform PEM -subj "/C=US/ST=Some-State/L=[]/O=[]/CN=localhost"
|
||||
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
|
||||
-nodes -days 365 -out ${CERT_DIR}cert.csr -keyout ${CERT_DIR}key.pem \
|
||||
-subj "/C=US/ST=Some-State/L=[]/O=[]/CN=localhost"
|
||||
openssl ca -policy signing_policy -extensions signing_req \
|
||||
-cert ./certs/cacert.pem -keyfile ./certs/cakey.pem \
|
||||
-rand_serial -config ./ca/ca.cnf \
|
||||
-out ./certs/cert.pem -infiles ./certs/cert.csr
|
||||
|
||||
|
||||
87
ca/ca.cnf
Normal file
87
ca/ca.cnf
Normal file
@@ -0,0 +1,87 @@
|
||||
HOME = .
|
||||
|
||||
####################################################################
|
||||
[ ca ]
|
||||
default_ca = CA_default # The default ca section
|
||||
|
||||
[ CA_default ]
|
||||
base_dir = ./certs
|
||||
certificate = $base_dir/cacert.pem # The CA certifcate
|
||||
private_key = $base_dir/cakey.pem # The CA private key
|
||||
new_certs_dir = $base_dir # Location for new certs after signing
|
||||
database = $base_dir/index.txt # Database index file
|
||||
serial = $base_dir/serial.txt # The current serial number
|
||||
|
||||
unique_subject = no # Set to 'no' to allow creation of
|
||||
# several certificates with same subject.
|
||||
|
||||
default_days = 1000 # How long to certify for
|
||||
default_crl_days = 30 # How long before next CRL
|
||||
default_md = sha256 # Use public key default MD
|
||||
preserve = no # Keep passed DN ordering
|
||||
|
||||
x509_extensions = ca_extensions # The extensions to add to the cert
|
||||
|
||||
email_in_dn = no # Don't concat the email in the DN
|
||||
copy_extensions = copy # Required to copy SANs from CSR to cert
|
||||
|
||||
####################################################################
|
||||
[ req ]
|
||||
default_bits = 4096
|
||||
default_keyfile = cakey.pem
|
||||
distinguished_name = ca_distinguished_name
|
||||
x509_extensions = ca_extensions
|
||||
string_mask = utf8only
|
||||
|
||||
####################################################################
|
||||
[ ca_distinguished_name ]
|
||||
countryName = Country Name (2 letter code)
|
||||
countryName_default = US
|
||||
|
||||
stateOrProvinceName = State or Province Name (full name)
|
||||
stateOrProvinceName_default = Maryland
|
||||
|
||||
localityName = Locality Name (eg, city)
|
||||
localityName_default = Baltimore
|
||||
|
||||
organizationName = Organization Name (eg, company)
|
||||
organizationName_default = Test CA, Limited
|
||||
|
||||
organizationalUnitName = Organizational Unit (eg, division)
|
||||
organizationalUnitName_default = Server Research Department
|
||||
|
||||
commonName = Common Name (e.g. server FQDN or YOUR name)
|
||||
commonName_default = Test CA
|
||||
|
||||
emailAddress = Email Address
|
||||
emailAddress_default = test@example.com
|
||||
|
||||
####################################################################
|
||||
[ ca_extensions ]
|
||||
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always, issuer
|
||||
basicConstraints = critical, CA:true
|
||||
keyUsage = keyCertSign, cRLSign
|
||||
####################################################################
|
||||
[ alternate_names ]
|
||||
|
||||
DNS.1 = localhost
|
||||
IP.1 = 127.0.0.1
|
||||
|
||||
####################################################################
|
||||
[ signing_policy ]
|
||||
countryName = optional
|
||||
stateOrProvinceName = optional
|
||||
localityName = optional
|
||||
organizationName = optional
|
||||
organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
####################################################################
|
||||
[ signing_req ]
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid,issuer
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = digitalSignature, keyEncipherment
|
||||
127
cmd/server.c
127
cmd/server.c
@@ -2,18 +2,29 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
// Local Includes
|
||||
#include "httpStruct.h"
|
||||
#include "socketHelp.h"
|
||||
#include "returnRequest.h"
|
||||
#include "server.h"
|
||||
|
||||
#define PORT 8080
|
||||
static int verbose_flag = 0;
|
||||
bool enableHTTPS = 0;
|
||||
|
||||
int printDebug(char message[]) {
|
||||
if (verbose_flag == 1) {
|
||||
printf("[Debug] %s\n", message);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parseHTTPRequest(char buffer[], struct HTTPRequest *r) {
|
||||
char temp[1];
|
||||
char temp[1]; // Used to check newlines
|
||||
char *token = calloc(8, sizeof(char));
|
||||
int line = 0;
|
||||
char *checkLine = calloc(1000, sizeof(char));;
|
||||
@@ -63,29 +74,112 @@ int parseHTTPRequest(char buffer[], struct HTTPRequest *r) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handleRequest(char buffer[], int socket) {
|
||||
int handleRequest(char buffer[], int socket, SSL *ssl) {
|
||||
struct HTTPRequest r; // Holds relevant HTTP request information
|
||||
int checkerr = 0;
|
||||
|
||||
printDebug("Received Request");
|
||||
|
||||
// Grabbing relevant information out of request
|
||||
checkerr = parseHTTPRequest(buffer, &r);
|
||||
if (checkerr != 0) { // Checking for HTTP parsing error
|
||||
printf("Error parsing: exit code %d\n", checkerr);
|
||||
return return404Request(socket);
|
||||
return return404Request(socket, ssl);
|
||||
}
|
||||
// Return response to socket
|
||||
return200Request(socket);
|
||||
return200Request(socket, ssl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[]) {
|
||||
int main(int argc, char **argv) {
|
||||
struct sockaddr_in address;
|
||||
int server_fd, new_socket;
|
||||
int checkerr = 0;
|
||||
int port = 0; // Define what port server listens on
|
||||
int checkerr = 0; // Used for error checking
|
||||
int addrlen = sizeof(address);
|
||||
|
||||
char *certFile = malloc(0);
|
||||
char *privKeyFile = malloc(0);
|
||||
|
||||
SSL_CTX *ctx = NULL;
|
||||
|
||||
char buffer[1024] = {};
|
||||
|
||||
checkerr = createSocket(PORT, &server_fd, &address, &addrlen);
|
||||
// Setting up options
|
||||
static const struct option long_options[] = {
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"port", required_argument, NULL, 'p'},
|
||||
{"cert", required_argument, NULL, 'c'},
|
||||
{"privkey", required_argument, NULL, 'k'},
|
||||
{"verbose", no_argument, &verbose_flag, 1},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
const char* usage =
|
||||
"Usage: seaweb [options]\n\n"
|
||||
" -h --help\t\t\tShows this message\n"
|
||||
" -p --port\t\t\tStarts webserver on passed port\n"
|
||||
" -c --cert\t\t\tPath to certificate\n"
|
||||
" -k --privkey\t\t\tPath to private key\n"
|
||||
"\n"
|
||||
"\n"
|
||||
" --verbose\t\t\tPrints debug messages\n"
|
||||
"\n";
|
||||
|
||||
int c;
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
c = getopt_long(argc, argv, "hp:c:k:", long_options, &option_index);
|
||||
if(c == -1) { // Break if no more options are present to parse
|
||||
break;
|
||||
}
|
||||
switch(c) {
|
||||
case 'h':
|
||||
printf("%s", usage);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'p':
|
||||
sscanf(optarg, "%d", &port);
|
||||
break;
|
||||
case 'c':
|
||||
certFile = calloc(strlen(optarg), sizeof(char));
|
||||
strcpy(certFile, optarg);
|
||||
printf("Cert: %s\n", certFile);
|
||||
break;
|
||||
case 'k':
|
||||
privKeyFile = calloc(strlen(optarg), sizeof(char));
|
||||
strcpy(privKeyFile, optarg);
|
||||
printf("Priv: %s\n", privKeyFile);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Argument checks
|
||||
if (port == 0) { // Setting default port if none is passed
|
||||
port = 8080;
|
||||
}
|
||||
if (!((strlen(certFile) > 0) == (strlen(privKeyFile) > 0))) { // XNOR of string lengths
|
||||
// Checking what flag was not passed
|
||||
if (strlen(certFile)) { // Privkey not passed
|
||||
printf("If certificate file is specified, a private key files needs to be specified\n");
|
||||
} else if (strlen(privKeyFile)) { // Cert not passed
|
||||
printf("If privkey file is specified, a certificate files needs to be specified\n");
|
||||
}
|
||||
printf("Exiting...\n");
|
||||
exit(EXIT_FAILURE);
|
||||
} else if ( (strlen(certFile) > 0) && (strlen(privKeyFile) > 0) ) { // Enabling HTTPS
|
||||
enableHTTPS = 1;
|
||||
}
|
||||
|
||||
if ( enableHTTPS == 1 ) {
|
||||
printf("Opening secure socket on port: %d\n", port);
|
||||
checkerr = createSecureSocket(port, &server_fd, &address, &addrlen, &ctx, certFile, privKeyFile);
|
||||
if ( ctx == NULL ) {
|
||||
printf("Error creating ctx\n");
|
||||
}
|
||||
} else {
|
||||
printf("Opening socket on port: %d\n", port);
|
||||
checkerr = createSocket(port, &server_fd, &address, &addrlen);
|
||||
}
|
||||
|
||||
if (checkerr != 0) {
|
||||
perror("Error creating socket");
|
||||
@@ -99,10 +193,23 @@ int main(int argc, char const *argv[]) {
|
||||
perror("Accept connection error");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
read(new_socket, buffer, 1024);
|
||||
handleRequest(buffer, new_socket);
|
||||
if ( enableHTTPS ) {
|
||||
SSL *ssl;
|
||||
ssl = SSL_new(ctx);
|
||||
SSL_set_fd(ssl, new_socket);
|
||||
SSL_accept(ssl);
|
||||
SSL_read(ssl, buffer, sizeof(buffer));
|
||||
handleRequest(buffer, new_socket, ssl);
|
||||
} else {
|
||||
read(new_socket, buffer, 1024);
|
||||
handleRequest(buffer, new_socket, NULL);
|
||||
}
|
||||
|
||||
close(new_socket);
|
||||
}
|
||||
|
||||
free(privKeyFile);
|
||||
free(certFile);
|
||||
close(server_fd);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
int returnRequest(int socket, char *message, int status);
|
||||
int return200Request(int socket);
|
||||
int return404Request(int socket);
|
||||
int return200Request(int socket, SSL *ssl);
|
||||
int return404Request(int socket, SSL *ssl);
|
||||
|
||||
4
include/server.h
Normal file
4
include/server.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
extern bool enableHTTPS;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
int createSocket(int port, int *server_fd, struct sockaddr_in *address, int *addrlen);
|
||||
int createSecureSocket(int port, int *server_fd, struct sockaddr_in *address, int *addrlen, SSL_CTX **ctx, char certFile[], char keyFile[]);
|
||||
|
||||
|
||||
@@ -1,18 +1,29 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
int returnRequest(int socket, char *message, int status) {
|
||||
send(socket, message, strlen(message), 0);
|
||||
#include "server.h"
|
||||
|
||||
int returnRequest(int socket, char *message, int status, SSL *ssl) {
|
||||
if ( enableHTTPS ) {
|
||||
SSL_write(ssl, message, strlen(message));
|
||||
SSL_get_fd(ssl);
|
||||
SSL_free(ssl);
|
||||
} else {
|
||||
send(socket, message, strlen(message), 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int return200Request(int socket) {
|
||||
int return200Request(int socket, SSL *ssl) {
|
||||
char *message = "HTTP/1.1 200 OK\nContent-Length: 6\nConnection: close\n\nhello\n";
|
||||
return returnRequest(socket, message, 200);
|
||||
return returnRequest(socket, message, 200, ssl);
|
||||
}
|
||||
|
||||
int return404Request(int socket) {
|
||||
int return404Request(int socket, SSL *ssl) {
|
||||
char *message = "HTTP/1.1 404 Not Found\nContent-Length: 12\nConnection: close\n\n404 Request\n";
|
||||
return returnRequest(socket, message, 400);
|
||||
return returnRequest(socket, message, 400, ssl);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,59 @@
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "socketHelp.h"
|
||||
|
||||
SSL_CTX* InitServerCTX() {
|
||||
SSL_METHOD *method;
|
||||
SSL_CTX *ctx;
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
method = TLS_server_method();
|
||||
ctx = SSL_CTX_new(method);
|
||||
if ( ctx == NULL ) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void LoadCertificates(SSL_CTX* ctx, char* certFile, char* keyFile) {
|
||||
// Set local certificate from certFile
|
||||
if ( SSL_CTX_use_certificate_file(ctx, certFile, SSL_FILETYPE_PEM) <= 0 ) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// Set local priv key from keyFile
|
||||
if ( SSL_CTX_use_PrivateKey_file(ctx, keyFile, SSL_FILETYPE_PEM) <=0 ) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// Verify priv key
|
||||
if ( !SSL_CTX_check_private_key(ctx) ) {
|
||||
fprintf(stderr, "Private key does not match passed certificate file\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int createSecureSocket(int port, int *server_fd, struct sockaddr_in *address, int *addrlen, SSL_CTX **ctx, char certFile[], char keyFile[]) {
|
||||
|
||||
SSL_library_init();
|
||||
*ctx = InitServerCTX();
|
||||
LoadCertificates(*ctx, certFile, keyFile);
|
||||
|
||||
if ( createSocket(port, server_fd, address, addrlen) ) {
|
||||
fprintf(stderr, "Error create socket\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int createSocket(int port, int *server_fd, struct sockaddr_in *address, int *addrlen) {
|
||||
int opt = 1;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user