대학 전공 공부/네트워크 프로그래밍

17. OpenSSL(TLS 서버 구축)

Xerath(제라스) 2022. 6. 9. 13:58
728x90
반응형

- 어떤 서버를 구축함에 있어서 인증서가 중요함.

 

- 인증서의 chain

사용자가 서버 인증서와 서명값을 받음 - 이 인증서의 IssuerDN인 CA1에게 감 - CA1의 IssuerDN인 RootCA에 감

- CA1 인증서에 서명된 걸 노란 키로 인증, 서버 인증서에 서명된 걸 파란 키로 인증, 초록 키 받아서 인증

 

- 각국의 RootCA들끼리는 peer-to-peer로 믿어줌.

 

- TLS 서버를 구축하려면 서버에 인증서와 개인키를 생성해야 함.

 

//SSL-Server.c
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"

#define FAIL    -1

int OpenListener(int port)
{   int sd;
    struct sockaddr_in addr;

    sd = socket(PF_INET, SOCK_STREAM, 0);
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;
    if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
    {
        perror("can't bind port");
        abort();
    }
    if ( listen(sd, 10) != 0 )
    {
        perror("Can't configure listening port");
        abort();
    }
    return sd;
}

SSL_CTX* InitServerCTX(void)
{
	const SSL_METHOD *method;
    SSL_CTX *ctx;

    OpenSSL_add_all_algorithms();  /* load & register all cryptos, etc. */
    SSL_load_error_strings();   /* load all error messages */
    
	method = TLSv1_2_server_method();
    ctx = SSL_CTX_new(method);   /* create new context from method */
    if(ctx == NULL)
    {
        ERR_print_errors_fp(stderr);
        abort();
    }
	
	SSL_CTX_set_cipher_list(ctx, "ALL:eNULL");
    
	return ctx;
}

void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
    //New lines 
    if (SSL_CTX_load_verify_locations(ctx, CertFile, KeyFile) != 1)
        ERR_print_errors_fp(stderr);

    if (SSL_CTX_set_default_verify_paths(ctx) != 1)
        ERR_print_errors_fp(stderr);
    //End new lines

    /* set the local certificate from CertFile */
    if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stderr);
        abort();
    }
    /* set the private key from KeyFile (may be the same as CertFile) */
	SSL_CTX_set_default_passwd_cb_userdata(ctx, "12345678");
    if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stderr);
        abort();
    }
    /* verify private key */
    if (!SSL_CTX_check_private_key(ctx))
    {
        fprintf(stderr, "Private key does not match the public certificate\n");
        abort();
    }

    //New lines - Force the client-side have a certificate
    //SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
    //SSL_CTX_set_verify_depth(ctx, 4);
    //End new lines
}

void ShowCerts(SSL* ssl)
{
	X509 *cert;
	char *line;

	cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
	if ( cert != NULL )
	{
		printf("Server certificates:\n");
		line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
		printf("Subject: %s\n", line);
		free(line);
		line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
		printf("Issuer: %s\n", line);
		free(line);
		X509_free(cert);
	}
	else
		printf("No certificates.\n");
}

void Servlet(SSL* ssl) /* Serve the connection -- threadable */
{
	char buf[1024];
	int sd, bytes;
	
	char enter[3] = { 0x0d, 0x0a, 0x00 };
	
	char output[1024];
	strcpy(output, "HTTP/1.1 200 OK");
	strcat(output, enter);
	strcat(output, "Content-Type: text/html");
	strcat(output, enter);
	strcat(output, "Content-Length: 47");
	strcat(output, enter);
	strcat(output, enter);
	strcat(output, "<html><body><h1>Hello World!</h1></body></html>");
	
	if ( SSL_accept(ssl) == FAIL )     /* do SSL-protocol accept */
		ERR_print_errors_fp(stderr);
	else
	{
		ShowCerts(ssl);        /* get any certificates */
		bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
		if ( bytes > 0 )
		{
			buf[bytes] = 0;
			printf("Client msg: \"%s", buf);
			SSL_write(ssl, output, strlen(output)); /* send reply */
		}
		else
			ERR_print_errors_fp(stderr);
	}
	sd = SSL_get_fd(ssl);       /* get socket connection */
	SSL_free(ssl);         /* release SSL state */
	close(sd);          /* close connection */
}

int main(int argc, char **argv)
{
	SSL_CTX *ctx; // TLS 서버 구축을 위해 ctx 메모리 포인터 선언
	int server;
	char portnum[]="5000"; //port 번호 할당

	char CertFile[] = "key/certificate.crt"; //인증성 세팅
    char KeyFile[] = "key/private_key.pem"; //개인키 세팅

	SSL_library_init(); //OpenSSL 라이브러리 초기화

	ctx = InitServerCTX();        /* initialize SSL */
	LoadCertificates(ctx, CertFile, KeyFile); /* load certs */
	server = OpenListener(atoi(portnum));    /* create server socket */
	while (1)
	{
		struct sockaddr_in addr;
		socklen_t len = sizeof(addr);
		SSL *ssl;

		int client = accept(server, (struct sockaddr*)&addr, &len);  /* accept connection as usual */
		printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
		ssl = SSL_new(ctx);              /* get new SSL state with context */
		SSL_set_fd(ssl, client);      /* set connection socket to SSL state */
		Servlet(ssl);         /* service connection */
	}
	close(server);          /* close server socket */
	SSL_CTX_free(ctx);         /* release context */
}

 

728x90
반응형