Skip to content
This repository was archived by the owner on May 24, 2022. It is now read-only.

Commit b09da7e

Browse files
committed
Add SNI support
If multiple certificates are specified, try to perform Server Name Indication to serve the most appropriate one. We fall back to the last certificate presented if none of the previous ones match, making it a useful place to put a star cert. A few caveats: - Certificate names are compared as case-insensitive strings, without any special logic for dealing with wildcards. The current workaround is to always place wildcard certificates last, where they act as the default catch-all. - Certificates are examined in order. The first certificate that matches any given request will be used. - The name -> certificate mapping is stored in a singly linked list. This performs very well for use with a handful of certificates, none of which have very many Subject Alternative Names, however sites which must serve a large number of certificates or names might find a linear list scan on every new connection too slow.
1 parent d78fd49 commit b09da7e

File tree

4 files changed

+230
-62
lines changed

4 files changed

+230
-62
lines changed

Diff for: README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,11 @@ Usage
8383
-----
8484

8585
The only required argument is a path to a PEM file that contains the certificate
86-
(or a chain of certificates) and private key.
86+
(or a chain of certificates) and private key. If multiple certificates are
87+
given, `stud` will attempt to perform SNI (Server Name Indication) on new
88+
connections, by comparing the indicated name with the names on each of the
89+
certificates, in order. The first certificate that matches will be used. If none
90+
of the certificates matches, the last certificate will be used as the default.
8791

8892
Detail about the entire set of options can be found by invoking `stud -h`:
8993

Diff for: configuration.c

+28-12
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ stud_config * config_new (void) {
124124
r->BACK_IP = strdup("127.0.0.1");
125125
r->BACK_PORT = strdup("8000");
126126
r->NCORES = 1;
127-
r->CERT_FILE = NULL;
127+
r->CERT_FILES = NULL;
128128
r->CIPHER_SUITE = NULL;
129129
r->ENGINE = NULL;
130130
r->BACKLOG = 100;
@@ -161,7 +161,14 @@ void config_destroy (stud_config *cfg) {
161161
if (cfg->FRONT_PORT != NULL) free(cfg->FRONT_PORT);
162162
if (cfg->BACK_IP != NULL) free(cfg->BACK_IP);
163163
if (cfg->BACK_PORT != NULL) free(cfg->BACK_PORT);
164-
if (cfg->CERT_FILE != NULL) free(cfg->CERT_FILE);
164+
if (cfg->CERT_FILES != NULL) {
165+
struct cert_files *curr = cfg->CERT_FILES, *next;
166+
while (cfg->CERT_FILES != NULL) {
167+
next = curr->NEXT;
168+
free(curr);
169+
curr = next;
170+
}
171+
}
165172
if (cfg->CIPHER_SUITE != NULL) free(cfg->CIPHER_SUITE);
166173
if (cfg->ENGINE != NULL) free(cfg->ENGINE);
167174

@@ -689,8 +696,12 @@ void config_param_validate (char *k, char *v, stud_config *cfg, char *file, int
689696
else if (! S_ISREG(st.st_mode)) {
690697
config_error_set("Invalid x509 certificate PEM file '%s': Not a file.", v);
691698
r = 0;
692-
} else
693-
config_assign_str(&cfg->CERT_FILE, v);
699+
} else {
700+
struct cert_files *cert = calloc(1, sizeof(*cert));
701+
config_assign_str(&cert->CERT_FILE, v);
702+
cert->NEXT = cfg->CERT_FILES;
703+
cfg->CERT_FILES = cert;
704+
}
694705
}
695706
}
696707
else {
@@ -946,9 +957,11 @@ void config_print_default (FILE *fd, stud_config *cfg) {
946957
fprintf(fd, "\n");
947958

948959
fprintf(fd, "# SSL x509 certificate file. REQUIRED.\n");
960+
fprintf(fd, "# List multiple certs to use SNI. Certs are used in the order they\n");
961+
fprintf(fd, "# are listed; the last cert listed will be used if none of the others match\n");
949962
fprintf(fd, "#\n");
950963
fprintf(fd, "# type: string\n");
951-
fprintf(fd, FMT_QSTR, CFG_PEM_FILE, config_disp_str(cfg->CERT_FILE));
964+
fprintf(fd, FMT_QSTR, CFG_PEM_FILE, "");
952965
fprintf(fd, "\n");
953966

954967
fprintf(fd, "# SSL protocol.\n");
@@ -1115,7 +1128,7 @@ void config_print_usage (char *prog, stud_config *cfg) {
11151128
void config_parse_cli(int argc, char **argv, stud_config *cfg) {
11161129
static int tls = 0, ssl = 0;
11171130
static int client = 0;
1118-
int c;
1131+
int c, i;
11191132
int test_only = 0;
11201133
char *prog;
11211134

@@ -1289,19 +1302,22 @@ void config_parse_cli(int argc, char **argv, stud_config *cfg) {
12891302
config_die("Shared cache update listener is defined, but shared cache is disabled.");
12901303
#endif
12911304

1292-
// argv leftovers, do we have pem file as an argument?
1305+
// Any arguments left are presumed to be PEM files
12931306
argc -= optind;
12941307
argv += optind;
1295-
if (argv != NULL && argv[0] != NULL)
1296-
config_param_validate(CFG_PEM_FILE, argv[0], cfg, NULL, 0);
1297-
else if ((cfg->PMODE == SSL_SERVER) && (cfg->CERT_FILE == NULL || strlen(cfg->CERT_FILE) < 1))
1308+
for (i = 0; i < argc; i++) {
1309+
config_param_validate(CFG_PEM_FILE, argv[i], cfg, NULL, 0);
1310+
}
1311+
if (cfg->PMODE == SSL_SERVER && cfg->CERT_FILES == NULL) {
12981312
config_die("No x509 certificate PEM file specified!");
1313+
}
12991314

13001315
// was this only a test?
13011316
if (test_only) {
1302-
fprintf(stderr, "Trying to initialize SSL context with certificate '%s'\n", cfg->CERT_FILE);
1303-
if (! init_openssl())
1317+
fprintf(stderr, "Trying to initialize SSL contexts with your certificates");
1318+
if (!init_openssl()) {
13041319
config_die("Error initializing OpenSSL.");
1320+
}
13051321
printf("%s configuration looks ok.\n", basename(prog));
13061322
exit(0);
13071323
}

Diff for: configuration.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ typedef enum {
3131
SSL_CLIENT
3232
} PROXY_MODE;
3333

34+
struct cert_files {
35+
char *CERT_FILE;
36+
struct cert_files *NEXT;
37+
};
38+
3439
/* configuration structure */
3540
struct __stud_config {
3641
ENC_TYPE ETYPE;
@@ -46,7 +51,7 @@ struct __stud_config {
4651
char *BACK_IP;
4752
char *BACK_PORT;
4853
long NCORES;
49-
char *CERT_FILE;
54+
struct cert_files *CERT_FILES;
5055
char *CIPHER_SUITE;
5156
char *ENGINE;
5257
int BACKLOG;

0 commit comments

Comments
 (0)