1 /* 2 * Copyright 2013-2025 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 /* 11 * A minimal program to serve an SSL connection. It uses blocking. It use the 12 * SSL_CONF API with the command line. cc -I../../include server-arg.c 13 * -L../.. -lssl -lcrypto -ldl 14 */ 15 16 #include <stdio.h> 17 #include <string.h> 18 #include <signal.h> 19 #include <stdlib.h> 20 #include <openssl/err.h> 21 #include <openssl/ssl.h> 22 23 int main(int argc, char *argv[]) 24 { 25 char *port = "*:4433"; 26 BIO *ssl_bio = NULL; 27 BIO *tmp; 28 SSL_CTX *ctx; 29 SSL_CONF_CTX *cctx; 30 char buf[512]; 31 BIO *in = NULL; 32 int ret = EXIT_FAILURE, i; 33 char **args = argv + 1; 34 int nargs = argc - 1; 35 36 ctx = SSL_CTX_new(TLS_server_method()); 37 38 cctx = SSL_CONF_CTX_new(); 39 SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER); 40 SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CERTIFICATE); 41 SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); 42 while (*args && **args == '-') { 43 int rv; 44 /* Parse standard arguments */ 45 rv = SSL_CONF_cmd_argv(cctx, &nargs, &args); 46 if (rv == -3) { 47 fprintf(stderr, "Missing argument for %s\n", *args); 48 goto err; 49 } 50 if (rv < 0) { 51 fprintf(stderr, "Error in command %s\n", *args); 52 ERR_print_errors_fp(stderr); 53 goto err; 54 } 55 /* If rv > 0 we processed something so proceed to next arg */ 56 if (rv > 0) 57 continue; 58 /* Otherwise application specific argument processing */ 59 if (strcmp(*args, "-port") == 0) { 60 port = args[1]; 61 if (port == NULL) { 62 fprintf(stderr, "Missing -port argument\n"); 63 goto err; 64 } 65 args += 2; 66 nargs -= 2; 67 continue; 68 } else { 69 fprintf(stderr, "Unknown argument %s\n", *args); 70 goto err; 71 } 72 } 73 74 if (!SSL_CONF_CTX_finish(cctx)) { 75 fprintf(stderr, "Finish error\n"); 76 ERR_print_errors_fp(stderr); 77 goto err; 78 } 79 #ifdef ITERATE_CERTS 80 /* 81 * Demo of how to iterate over all certificates in an SSL_CTX structure. 82 */ 83 { 84 X509 *x; 85 int rv; 86 rv = SSL_CTX_set_current_cert(ctx, SSL_CERT_SET_FIRST); 87 while (rv) { 88 X509 *x = SSL_CTX_get0_certificate(ctx); 89 X509_NAME_print_ex_fp(stdout, X509_get_subject_name(x), 0, 90 XN_FLAG_ONELINE); 91 printf("\n"); 92 rv = SSL_CTX_set_current_cert(ctx, SSL_CERT_SET_NEXT); 93 } 94 fflush(stdout); 95 } 96 #endif 97 /* Setup server side SSL bio */ 98 ssl_bio = BIO_new_ssl(ctx, 0); 99 100 if ((in = BIO_new_accept(port)) == NULL) 101 goto err; 102 103 /* 104 * This means that when a new connection is accepted on 'in', The ssl_bio 105 * will be 'duplicated' and have the new socket BIO push into it. 106 * Basically it means the SSL BIO will be automatically setup 107 */ 108 BIO_set_accept_bios(in, ssl_bio); 109 ssl_bio = NULL; 110 111 again: 112 /* 113 * The first call will setup the accept socket, and the second will get a 114 * socket. In this loop, the first actual accept will occur in the 115 * BIO_read() function. 116 */ 117 118 if (BIO_do_accept(in) <= 0) 119 goto err; 120 121 for (;;) { 122 i = BIO_read(in, buf, 512); 123 if (i == 0) { 124 /* 125 * If we have finished, remove the underlying BIO stack so the 126 * next time we call any function for this BIO, it will attempt 127 * to do an accept 128 */ 129 printf("Done\n"); 130 tmp = BIO_pop(in); 131 BIO_free_all(tmp); 132 goto again; 133 } 134 if (i < 0) 135 goto err; 136 fwrite(buf, 1, i, stdout); 137 fflush(stdout); 138 } 139 140 ret = EXIT_SUCCESS; 141 err: 142 if (ret != EXIT_SUCCESS) 143 ERR_print_errors_fp(stderr); 144 BIO_free(in); 145 BIO_free_all(ssl_bio); 146 return ret; 147 } 148