You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
196 lines
5.3 KiB
196 lines
5.3 KiB
#include "openssl/err.h"
|
|
#include "openssl/ssl.h"
|
|
#include <arpa/inet.h>
|
|
#include <errno.h>
|
|
#include <netinet/in.h>
|
|
#include <resolv.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#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;
|
|
}
|
|
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 char *name = SSL_COMP_get_name(sk_SSL_COMP_value(s, i));
|
|
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) {
|
|
const COMP_METHOD *comp = SSL_get_current_compression(ssl);
|
|
if (comp == NULL) {
|
|
printf("No compression\n");
|
|
} else {
|
|
const char *name = COMP_get_name(comp);
|
|
if (name == NULL) {
|
|
fprintf(stderr, "Cannot get compression name!\n");
|
|
} else {
|
|
printf("Compression: %s\n", name);
|
|
}
|
|
}
|
|
|
|
char buf[BUF_LEN];
|
|
int sd, 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;
|
|
printf("Client msg: \"%s", buf);
|
|
SSL_write(ssl, output, strlen(output));
|
|
} else {
|
|
ERR_print_errors_fp(stderr);
|
|
}
|
|
}
|
|
sd = SSL_get_fd(ssl);
|
|
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 <port>\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;
|
|
}
|