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