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
|
SOURCES = ./src/* ./cmd/server.c
|
||||||
OUTPUT_DIR = ./bin
|
OUTPUT_DIR = ./bin
|
||||||
OUTPUT = -o ${OUTPUT_DIR}/PROG
|
OUTPUT = -o ${OUTPUT_DIR}/PROG
|
||||||
@@ -18,11 +18,20 @@ output_dir:
|
|||||||
|
|
||||||
CERT_DIR = ./certs/
|
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:
|
clean:
|
||||||
rm -rf $(OUTPUT_DIR) ${CERT_DIR} **.h.gch
|
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
|
||||||
125
cmd/server.c
125
cmd/server.c
@@ -2,18 +2,29 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <getopt.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
// Local Includes
|
// Local Includes
|
||||||
#include "httpStruct.h"
|
#include "httpStruct.h"
|
||||||
#include "socketHelp.h"
|
#include "socketHelp.h"
|
||||||
#include "returnRequest.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) {
|
int parseHTTPRequest(char buffer[], struct HTTPRequest *r) {
|
||||||
char temp[1];
|
char temp[1]; // Used to check newlines
|
||||||
char *token = calloc(8, sizeof(char));
|
char *token = calloc(8, sizeof(char));
|
||||||
int line = 0;
|
int line = 0;
|
||||||
char *checkLine = calloc(1000, sizeof(char));;
|
char *checkLine = calloc(1000, sizeof(char));;
|
||||||
@@ -63,29 +74,112 @@ int parseHTTPRequest(char buffer[], struct HTTPRequest *r) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int handleRequest(char buffer[], int socket) {
|
int handleRequest(char buffer[], int socket, SSL *ssl) {
|
||||||
struct HTTPRequest r; // Holds relevant HTTP request information
|
struct HTTPRequest r; // Holds relevant HTTP request information
|
||||||
int checkerr = 0;
|
int checkerr = 0;
|
||||||
|
|
||||||
|
printDebug("Received Request");
|
||||||
|
|
||||||
// Grabbing relevant information out of request
|
// Grabbing relevant information out of request
|
||||||
checkerr = parseHTTPRequest(buffer, &r);
|
checkerr = parseHTTPRequest(buffer, &r);
|
||||||
if (checkerr != 0) { // Checking for HTTP parsing error
|
if (checkerr != 0) { // Checking for HTTP parsing error
|
||||||
printf("Error parsing: exit code %d\n", checkerr);
|
printf("Error parsing: exit code %d\n", checkerr);
|
||||||
return return404Request(socket);
|
return return404Request(socket, ssl);
|
||||||
}
|
}
|
||||||
// Return response to socket
|
// Return response to socket
|
||||||
return200Request(socket);
|
return200Request(socket, ssl);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char const *argv[]) {
|
int main(int argc, char **argv) {
|
||||||
struct sockaddr_in address;
|
struct sockaddr_in address;
|
||||||
int server_fd, new_socket;
|
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);
|
int addrlen = sizeof(address);
|
||||||
|
|
||||||
|
char *certFile = malloc(0);
|
||||||
|
char *privKeyFile = malloc(0);
|
||||||
|
|
||||||
|
SSL_CTX *ctx = NULL;
|
||||||
|
|
||||||
char buffer[1024] = {};
|
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) {
|
if (checkerr != 0) {
|
||||||
perror("Error creating socket");
|
perror("Error creating socket");
|
||||||
@@ -99,10 +193,23 @@ int main(int argc, char const *argv[]) {
|
|||||||
perror("Accept connection error");
|
perror("Accept connection error");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
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);
|
read(new_socket, buffer, 1024);
|
||||||
handleRequest(buffer, new_socket);
|
handleRequest(buffer, new_socket, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
close(new_socket);
|
close(new_socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(privKeyFile);
|
||||||
|
free(certFile);
|
||||||
|
close(server_fd);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
int returnRequest(int socket, char *message, int status);
|
int returnRequest(int socket, char *message, int status);
|
||||||
int return200Request(int socket);
|
int return200Request(int socket, SSL *ssl);
|
||||||
int return404Request(int socket);
|
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 <stdio.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
int createSocket(int port, int *server_fd, struct sockaddr_in *address, int *addrlen);
|
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 <string.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
int returnRequest(int socket, char *message, int status) {
|
#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);
|
send(socket, message, strlen(message), 0);
|
||||||
|
}
|
||||||
return 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";
|
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";
|
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 <sys/socket.h>
|
||||||
#include <netinet/in.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 createSocket(int port, int *server_fd, struct sockaddr_in *address, int *addrlen) {
|
||||||
int opt = 1;
|
int opt = 1;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user