#include "openssl/err.h" #include "openssl/ssl.h" #include #include #include #include #include #include #include #include #include #include #define BACKLOG 3 #define BUF_LEN 1024 int open_server(int port) { int serverSocket = socket(AF_INET, SOCK_STREAM, 0); if (serverSocket == -1) { perror("Cannot create socket"); return -1; } if (setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) == -1) { perror("reuseaddr"); } struct sockaddr_in address; memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_addr.s_addr = htonl(INADDR_ANY); address.sin_port = htons(port); if (bind(serverSocket, (struct sockaddr *)&address, sizeof(address)) == -1) { perror("Bind failed"); return -1; } if (listen(serverSocket, BACKLOG) == -1) { perror("In listen"); return -1; } return serverSocket; } SSL_CTX *init_ssl_ctx(void) { const SSL_METHOD *method; SSL_CTX *ctx; OpenSSL_add_all_algorithms(); SSL_load_error_strings(); STACK_OF(SSL_COMP) *s = SSL_COMP_get_compression_methods(); if (s == NULL) { fprintf(stderr, "Cannot list compression methods\n"); } else if (sk_SSL_COMP_num(s) == 0) { fprintf(stderr, "This version of OpenSSL does not have any compression " "methods available, cannot enable TLS compression.\n"); } else { for (int i = 0; i < sk_SSL_COMP_num(s); i++) { const SSL_COMP *comp = sk_SSL_COMP_value(s, i); const char *name = SSL_COMP_get_name(comp); printf("Found compression method: %s\n", name); } } method = TLS_server_method(); ctx = SSL_CTX_new(method); SSL_CTX_set_security_level(ctx, 1); SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_3); SSL_CTX_clear_options(ctx, SSL_OP_NO_COMPRESSION); if (ctx == NULL) { ERR_print_errors_fp(stderr); return NULL; } SSL_CTX_set_cipher_list(ctx, "ALL:eNULL"); return ctx; } int load_certificates(SSL_CTX *ctx, const char *cert_file, const char *key_file) { if (SSL_CTX_load_verify_locations(ctx, cert_file, key_file) != 1) { ERR_print_errors_fp(stderr); return -1; } if (SSL_CTX_set_default_verify_paths(ctx) != 1) { ERR_print_errors_fp(stderr); return -1; } if (SSL_CTX_use_certificate_file(ctx, cert_file, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); return -1; } if (SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); return -1; } if (!SSL_CTX_check_private_key(ctx)) { fprintf(stderr, "Private key does not match the public certificate\n"); return -1; } return 0; } int handle_request(SSL *ssl, int fd) { char buf[BUF_LEN]; int bytes; char output[] = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\nContent-Type: " "text/plain\r\n\r\nHello World!\n"; if (SSL_accept(ssl) == -1) { const char *cipher = SSL_get_cipher(ssl); if (cipher == NULL || strcmp(cipher, "NONE")) { char error_message[] = "HTTP/1.1 400 Bad Request\r\nContent-Type: " "text/plain\r\nContent-Length: 18\r\n\r\nInvalid protocol.\n"; write(fd, error_message, strlen(error_message)); return 1; } ERR_print_errors_fp(stderr); } else { bytes = SSL_read(ssl, buf, sizeof(buf)); if (bytes > 0) { buf[bytes] = 0; SSL_write(ssl, output, strlen(output)); } else { ERR_print_errors_fp(stderr); } } SSL_free(ssl); return 0; } int main(int argc, char **argv) { SSL_CTX *ctx; int server; int port; if (argc < 2) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } else { port = atoi(argv[1]); } if (port < 1 || port > 65535) { fprintf(stderr, "Invalid port number: %s\n", argv[1]); return 1; } const char cert_file[] = "cert.pem"; const char key_file[] = "key.pem"; SSL_library_init(); ctx = init_ssl_ctx(); if (ctx == NULL) { return 1; } if (load_certificates(ctx, cert_file, key_file) == -1) { return 1; } server = open_server(port); if (server == -1) { return 1; } printf("Listening on https://localhost:%d/\n", port); while (1) { struct sockaddr_in addr; socklen_t len = sizeof(addr); SSL *ssl; int client = accept(server, (struct sockaddr *)&addr, &len); printf("Connection: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); ssl = SSL_new(ctx); SSL_set_fd(ssl, client); handle_request(ssl, client); close(client); } close(server); SSL_CTX_free(ctx); return 0; }