1*a8d85e88Sbluhm /* $OpenBSD: server.c,v 1.4 2018/11/09 06:30:41 bluhm Exp $ */ 29231079cSbluhm /* 39231079cSbluhm * Copyright (c) 2018 Alexander Bluhm <bluhm@openbsd.org> 49231079cSbluhm * 59231079cSbluhm * Permission to use, copy, modify, and distribute this software for any 69231079cSbluhm * purpose with or without fee is hereby granted, provided that the above 79231079cSbluhm * copyright notice and this permission notice appear in all copies. 89231079cSbluhm * 99231079cSbluhm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 109231079cSbluhm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 119231079cSbluhm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 129231079cSbluhm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 139231079cSbluhm * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 149231079cSbluhm * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 159231079cSbluhm * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 169231079cSbluhm */ 179231079cSbluhm 189231079cSbluhm #include <sys/types.h> 199231079cSbluhm #include <sys/socket.h> 209231079cSbluhm 219231079cSbluhm #include <err.h> 229231079cSbluhm #include <netdb.h> 239231079cSbluhm #include <stdio.h> 2422303e31Sbluhm #include <string.h> 259231079cSbluhm #include <unistd.h> 269231079cSbluhm 279231079cSbluhm #include <openssl/err.h> 289231079cSbluhm #include <openssl/ssl.h> 299231079cSbluhm 309231079cSbluhm #include "util.h" 319231079cSbluhm 329231079cSbluhm void __dead usage(void); 339231079cSbluhm 349231079cSbluhm void __dead 359231079cSbluhm usage(void) 369231079cSbluhm { 37*a8d85e88Sbluhm fprintf(stderr, 38*a8d85e88Sbluhm "usage: server [-vv] [-C CA] [-c crt -k key] [host port]"); 399231079cSbluhm exit(2); 409231079cSbluhm } 419231079cSbluhm 429231079cSbluhm int 439231079cSbluhm main(int argc, char *argv[]) 449231079cSbluhm { 459231079cSbluhm const SSL_METHOD *method; 469231079cSbluhm SSL_CTX *ctx; 479231079cSbluhm SSL *ssl; 489231079cSbluhm BIO *bio; 499231079cSbluhm SSL_SESSION *session; 50*a8d85e88Sbluhm int error, verify = 0; 51*a8d85e88Sbluhm char buf[256], ch; 52*a8d85e88Sbluhm char *ca = NULL, *crt = NULL, *key = NULL; 53*a8d85e88Sbluhm char *host_port, *host = "127.0.0.1", *port = "0"; 549231079cSbluhm 55*a8d85e88Sbluhm while ((ch = getopt(argc, argv, "C:c:k:v")) != -1) { 56*a8d85e88Sbluhm switch (ch) { 57*a8d85e88Sbluhm case 'C': 58*a8d85e88Sbluhm ca = optarg; 59*a8d85e88Sbluhm break; 60*a8d85e88Sbluhm case 'c': 61*a8d85e88Sbluhm crt = optarg; 62*a8d85e88Sbluhm break; 63*a8d85e88Sbluhm case 'k': 64*a8d85e88Sbluhm key = optarg; 65*a8d85e88Sbluhm break; 66*a8d85e88Sbluhm case 'v': 67*a8d85e88Sbluhm /* use twice to force client cert */ 68*a8d85e88Sbluhm verify++; 69*a8d85e88Sbluhm break; 70*a8d85e88Sbluhm default: 71*a8d85e88Sbluhm usage(); 72*a8d85e88Sbluhm } 73*a8d85e88Sbluhm } 74*a8d85e88Sbluhm argc -= optind; 75*a8d85e88Sbluhm argv += optind; 76*a8d85e88Sbluhm if (argc == 2) { 77*a8d85e88Sbluhm host = argv[0]; 78*a8d85e88Sbluhm port = argv[1]; 79*a8d85e88Sbluhm } else if (argc != 0) { 809231079cSbluhm usage(); 819231079cSbluhm } 829231079cSbluhm if (asprintf(&host_port, strchr(host, ':') ? "[%s]:%s" : "%s:%s", 839231079cSbluhm host, port) == -1) 849231079cSbluhm err(1, "asprintf host port"); 85*a8d85e88Sbluhm if ((crt == NULL && key != NULL) || (crt != NULL && key == NULL)) 86*a8d85e88Sbluhm errx(1, "certificate and private key must be used together"); 87*a8d85e88Sbluhm if (crt == NULL && asprintf(&crt, "%s.crt", host) == -1) 889231079cSbluhm err(1, "asprintf crt"); 89*a8d85e88Sbluhm if (key == NULL && asprintf(&key, "%s.key", host) == -1) 909231079cSbluhm err(1, "asprintf key"); 919231079cSbluhm 929231079cSbluhm SSL_library_init(); 939231079cSbluhm SSL_load_error_strings(); 9422303e31Sbluhm print_version(); 959231079cSbluhm 969231079cSbluhm /* setup method and context */ 97188261f9Sbluhm #if OPENSSL_VERSION_NUMBER >= 0x1010000f 98188261f9Sbluhm method = TLS_server_method(); 99188261f9Sbluhm if (method == NULL) 100188261f9Sbluhm err_ssl(1, "TLS_server_method"); 101188261f9Sbluhm #else 1029231079cSbluhm method = SSLv23_server_method(); 1039231079cSbluhm if (method == NULL) 1049231079cSbluhm err_ssl(1, "SSLv23_server_method"); 105188261f9Sbluhm #endif 1069231079cSbluhm ctx = SSL_CTX_new(method); 1079231079cSbluhm if (ctx == NULL) 1089231079cSbluhm err_ssl(1, "SSL_CTX_new"); 1099231079cSbluhm 1109231079cSbluhm /* needed when linking with OpenSSL 1.0.2p */ 1119231079cSbluhm if (SSL_CTX_set_ecdh_auto(ctx, 1) <= 0) 1129231079cSbluhm err_ssl(1, "SSL_CTX_set_ecdh_auto"); 1139231079cSbluhm 1149231079cSbluhm /* load server certificate */ 1159231079cSbluhm if (SSL_CTX_use_certificate_file(ctx, crt, SSL_FILETYPE_PEM) <= 0) 1169231079cSbluhm err_ssl(1, "SSL_CTX_use_certificate_file"); 1179231079cSbluhm if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) 1189231079cSbluhm err_ssl(1, "SSL_CTX_use_PrivateKey_file"); 1199231079cSbluhm if (SSL_CTX_check_private_key(ctx) <= 0) 1209231079cSbluhm err_ssl(1, "SSL_CTX_check_private_key"); 1219231079cSbluhm 122*a8d85e88Sbluhm /* request client certificate and verify it */ 123*a8d85e88Sbluhm if (ca != NULL) { 124*a8d85e88Sbluhm STACK_OF(X509_NAME) *x509stack; 125*a8d85e88Sbluhm 126*a8d85e88Sbluhm x509stack = SSL_load_client_CA_file(ca); 127*a8d85e88Sbluhm if (x509stack == NULL) 128*a8d85e88Sbluhm err_ssl(1, "SSL_load_client_CA_file"); 129*a8d85e88Sbluhm SSL_CTX_set_client_CA_list(ctx, x509stack); 130*a8d85e88Sbluhm if (SSL_CTX_load_verify_locations(ctx, ca, NULL) <= 0) 131*a8d85e88Sbluhm err_ssl(1, "SSL_CTX_load_verify_locations"); 132*a8d85e88Sbluhm } 133*a8d85e88Sbluhm SSL_CTX_set_verify(ctx, 134*a8d85e88Sbluhm verify == 0 ? SSL_VERIFY_NONE : 135*a8d85e88Sbluhm verify == 1 ? SSL_VERIFY_PEER : 136*a8d85e88Sbluhm SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 137*a8d85e88Sbluhm verify_callback); 138*a8d85e88Sbluhm 1399231079cSbluhm /* setup ssl and bio for socket operations */ 1409231079cSbluhm ssl = SSL_new(ctx); 1419231079cSbluhm if (ssl == NULL) 1429231079cSbluhm err_ssl(1, "SSL_new"); 1439231079cSbluhm bio = BIO_new_accept(host_port); 1449231079cSbluhm if (bio == NULL) 1459231079cSbluhm err_ssl(1, "BIO_new_accept"); 1469231079cSbluhm print_ciphers(SSL_get_ciphers(ssl)); 1479231079cSbluhm 1489231079cSbluhm /* bind, listen */ 1499231079cSbluhm if (BIO_do_accept(bio) <= 0) 1509231079cSbluhm err_ssl(1, "BIO_do_accept setup"); 1519231079cSbluhm printf("listen "); 1529231079cSbluhm print_sockname(bio); 1539231079cSbluhm 154*a8d85e88Sbluhm /* fork to background, set timeout, and accept */ 1559231079cSbluhm if (daemon(1, 1) == -1) 1569231079cSbluhm err(1, "daemon"); 157*a8d85e88Sbluhm if ((int)alarm(60) == -1) 158*a8d85e88Sbluhm err(1, "alarm"); 1599231079cSbluhm if (BIO_do_accept(bio) <= 0) 1609231079cSbluhm err_ssl(1, "BIO_do_accept wait"); 1619231079cSbluhm bio = BIO_pop(bio); 1629231079cSbluhm printf("accept "); 1639231079cSbluhm print_sockname(bio); 1649231079cSbluhm printf("accept "); 1659231079cSbluhm print_peername(bio); 1669231079cSbluhm 1679231079cSbluhm /* do ssl server handshake */ 1689231079cSbluhm SSL_set_bio(ssl, bio, bio); 1699231079cSbluhm if ((error = SSL_accept(ssl)) <= 0) 1709231079cSbluhm err_ssl(1, "SSL_accept %d", error); 1719231079cSbluhm 1729231079cSbluhm /* print session statistics */ 1739231079cSbluhm session = SSL_get_session(ssl); 1749231079cSbluhm if (session == NULL) 1759231079cSbluhm err_ssl(1, "SSL_get_session"); 1769231079cSbluhm if (SSL_SESSION_print_fp(stdout, session) <= 0) 1779231079cSbluhm err_ssl(1, "SSL_SESSION_print_fp"); 1789231079cSbluhm 1799231079cSbluhm /* write server greeting and read client hello over TLS connection */ 1809231079cSbluhm strlcpy(buf, "greeting\n", sizeof(buf)); 1819231079cSbluhm printf(">>> %s", buf); 1829231079cSbluhm if (fflush(stdout) != 0) 1839231079cSbluhm err(1, "fflush stdout"); 1849231079cSbluhm if ((error = SSL_write(ssl, buf, 9)) <= 0) 1859231079cSbluhm err_ssl(1, "SSL_write %d", error); 1869231079cSbluhm if (error != 9) 1879231079cSbluhm errx(1, "write not 9 bytes greeting: %d", error); 1889231079cSbluhm if ((error = SSL_read(ssl, buf, 6)) <= 0) 1899231079cSbluhm err_ssl(1, "SSL_read %d", error); 1909231079cSbluhm if (error != 6) 1919231079cSbluhm errx(1, "read not 6 bytes hello: %d", error); 1929231079cSbluhm buf[6] = '\0'; 1939231079cSbluhm printf("<<< %s", buf); 1949231079cSbluhm if (fflush(stdout) != 0) 1959231079cSbluhm err(1, "fflush stdout"); 1969231079cSbluhm 1979231079cSbluhm /* shutdown connection */ 1989231079cSbluhm if ((error = SSL_shutdown(ssl)) < 0) 1999231079cSbluhm err_ssl(1, "SSL_shutdown unidirectional %d", error); 2009231079cSbluhm if (error <= 0) { 2019231079cSbluhm if ((error = SSL_shutdown(ssl)) <= 0) 2029231079cSbluhm err_ssl(1, "SSL_shutdown bidirectional %d", error); 2039231079cSbluhm } 2049231079cSbluhm 2059231079cSbluhm /* cleanup and free resources */ 2069231079cSbluhm SSL_free(ssl); 2079231079cSbluhm SSL_CTX_free(ctx); 2089231079cSbluhm 2099231079cSbluhm printf("success\n"); 2109231079cSbluhm 2119231079cSbluhm return 0; 2129231079cSbluhm } 213