1/*
2 * Copyright 2013-2017 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
23int main(int argc, char *argv[])
24{
25    char *port = "*:4433";
26    BIO *ssl_bio, *tmp;
27    SSL_CTX *ctx;
28    SSL_CONF_CTX *cctx;
29    char buf[512];
30    BIO *in = NULL;
31    int ret = EXIT_FAILURE, i;
32    char **args = argv + 1;
33    int nargs = argc - 1;
34
35    ctx = SSL_CTX_new(TLS_server_method());
36
37    cctx = SSL_CONF_CTX_new();
38    SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER);
39    SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CERTIFICATE);
40    SSL_CONF_CTX_set_ssl_ctx(cctx, ctx);
41    while (*args && **args == '-') {
42        int rv;
43        /* Parse standard arguments */
44        rv = SSL_CONF_cmd_argv(cctx, &nargs, &args);
45        if (rv == -3) {
46            fprintf(stderr, "Missing argument for %s\n", *args);
47            goto err;
48        }
49        if (rv < 0) {
50            fprintf(stderr, "Error in command %s\n", *args);
51            ERR_print_errors_fp(stderr);
52            goto err;
53        }
54        /* If rv > 0 we processed something so proceed to next arg */
55        if (rv > 0)
56            continue;
57        /* Otherwise application specific argument processing */
58        if (strcmp(*args, "-port") == 0) {
59            port = args[1];
60            if (port == NULL) {
61                fprintf(stderr, "Missing -port argument\n");
62                goto err;
63            }
64            args += 2;
65            nargs -= 2;
66            continue;
67        } else {
68            fprintf(stderr, "Unknown argument %s\n", *args);
69            goto err;
70        }
71    }
72
73    if (!SSL_CONF_CTX_finish(cctx)) {
74        fprintf(stderr, "Finish error\n");
75        ERR_print_errors_fp(stderr);
76        goto err;
77    }
78#ifdef ITERATE_CERTS
79    /*
80     * Demo of how to iterate over all certificates in an SSL_CTX structure.
81     */
82    {
83        X509 *x;
84        int rv;
85        rv = SSL_CTX_set_current_cert(ctx, SSL_CERT_SET_FIRST);
86        while (rv) {
87            X509 *x = SSL_CTX_get0_certificate(ctx);
88            X509_NAME_print_ex_fp(stdout, X509_get_subject_name(x), 0,
89                                  XN_FLAG_ONELINE);
90            printf("\n");
91            rv = SSL_CTX_set_current_cert(ctx, SSL_CERT_SET_NEXT);
92        }
93        fflush(stdout);
94    }
95#endif
96    /* Setup server side SSL bio */
97    ssl_bio = BIO_new_ssl(ctx, 0);
98
99    if ((in = BIO_new_accept(port)) == NULL)
100        goto err;
101
102    /*
103     * This means that when a new connection is accepted on 'in', The ssl_bio
104     * will be 'duplicated' and have the new socket BIO push into it.
105     * Basically it means the SSL BIO will be automatically setup
106     */
107    BIO_set_accept_bios(in, ssl_bio);
108
109 again:
110    /*
111     * The first call will setup the accept socket, and the second will get a
112     * socket.  In this loop, the first actual accept will occur in the
113     * BIO_read() function.
114     */
115
116    if (BIO_do_accept(in) <= 0)
117        goto err;
118
119    for (;;) {
120        i = BIO_read(in, buf, 512);
121        if (i == 0) {
122            /*
123             * If we have finished, remove the underlying BIO stack so the
124             * next time we call any function for this BIO, it will attempt
125             * to do an accept
126             */
127            printf("Done\n");
128            tmp = BIO_pop(in);
129            BIO_free_all(tmp);
130            goto again;
131        }
132        if (i < 0)
133            goto err;
134        fwrite(buf, 1, i, stdout);
135        fflush(stdout);
136    }
137
138    ret = EXIT_SUCCESS;
139 err:
140    if (ret != EXIT_SUCCESS)
141        ERR_print_errors_fp(stderr);
142    BIO_free(in);
143    return ret;
144}
145