Lines 29-34
Link Here
|
29 |
time I was too famous.'' |
29 |
time I was too famous.'' |
30 |
-- Unknown */ |
30 |
-- Unknown */ |
31 |
#include "ssl_private.h" |
31 |
#include "ssl_private.h" |
|
|
32 |
#include "mod_ssl.h" |
32 |
#include "util_md5.h" |
33 |
#include "util_md5.h" |
33 |
|
34 |
|
34 |
static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn); |
35 |
static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn); |
Lines 2136-2141
Link Here
|
2136 |
} |
2131 |
} |
2137 |
#endif /* HAVE_TLS_SESSION_TICKETS */ |
2132 |
#endif /* HAVE_TLS_SESSION_TICKETS */ |
2138 |
|
2133 |
|
|
|
2134 |
static int ssl_array_index(apr_array_header_t *array, |
2135 |
const char *s) |
2136 |
{ |
2137 |
int i; |
2138 |
for (i = 0; i < array->nelts; i++) { |
2139 |
const char *p = APR_ARRAY_IDX(array, i, const char*); |
2140 |
if (!strcmp(p, s)) { |
2141 |
return i; |
2142 |
} |
2143 |
} |
2144 |
return -1; |
2145 |
} |
2146 |
|
2147 |
#ifdef HAVE_TLS_ALPN |
2148 |
/* |
2149 |
* Compare to ALPN protocol proposal. Result is similar to strcmp(): |
2150 |
* 0 gives same precedence, >0 means proto1 is prefered. |
2151 |
*/ |
2152 |
static int ssl_cmp_alpn_protos(modssl_ctx_t *ctx, |
2153 |
const char *proto1, |
2154 |
const char *proto2) |
2155 |
{ |
2156 |
/* TODO: we should have a mod_ssl configuration parameter. */ |
2157 |
if (ctx && ctx->ssl_alpn_pref) { |
2158 |
int index1 = ssl_array_index(ctx->ssl_alpn_pref, proto1); |
2159 |
int index2 = ssl_array_index(ctx->ssl_alpn_pref, proto2); |
2160 |
if (index2 > index1) { |
2161 |
return (index1 >= 0)? 1 : -1; |
2162 |
} |
2163 |
else if (index1 > index2) { |
2164 |
return (index2 >= 0)? -1 : 1; |
2165 |
} |
2166 |
} |
2167 |
/* both have the same index (mabye -1 or no pref configured) and we compare |
2168 |
* the names so that spdy3 gets precedence over spdy2. That makes |
2169 |
* the outcome at least deterministic. */ |
2170 |
return strcmp((const char *)proto1, (const char *)proto2); |
2171 |
} |
2172 |
|
2173 |
/* |
2174 |
* This callback function is executed when the TLS Application Layer |
2175 |
* Protocol Negotiate Extension (ALPN, RFC 7301) is triggered by the client |
2176 |
* hello, giving a list of desired protocol names (in descending preference) |
2177 |
* to the server. |
2178 |
* The callback has to select a protocol name or return an error if none of |
2179 |
* the clients preferences is supported. |
2180 |
* The selected protocol does not have to be on the client list, according |
2181 |
* to RFC 7301, so no checks are performed. |
2182 |
* The client protocol list is serialized as length byte followed by ascii |
2183 |
* characters (not null-terminated), followed by the next protocol name. |
2184 |
*/ |
2185 |
int ssl_callback_alpn_select(SSL *ssl, |
2186 |
const unsigned char **out, unsigned char *outlen, |
2187 |
const unsigned char *in, unsigned int inlen, void *arg) |
2188 |
{ |
2189 |
conn_rec *c = (conn_rec*)SSL_get_app_data(ssl); |
2190 |
SSLConnRec *sslconn = myConnConfig(c); |
2191 |
server_rec *s = mySrvFromConn(c); |
2192 |
SSLSrvConfigRec *sc = mySrvConfig(s); |
2193 |
modssl_ctx_t *mctx = myCtxConfig(sslconn, sc); |
2194 |
const char *alpn_http1 = "http/1.1"; |
2195 |
apr_array_header_t *client_protos; |
2196 |
apr_array_header_t *proposed_protos; |
2197 |
int i; |
2198 |
|
2199 |
/* If the connection object is not available, |
2200 |
* then there's nothing for us to do. */ |
2201 |
if (c == NULL) { |
2202 |
return SSL_TLSEXT_ERR_OK; |
2203 |
} |
2204 |
|
2205 |
if (inlen == 0) { |
2206 |
// someone tries to trick us? |
2207 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02306) |
2208 |
"alpn client protocol list empty"); |
2209 |
return SSL_TLSEXT_ERR_ALERT_FATAL; |
2210 |
} |
2211 |
|
2212 |
client_protos = apr_array_make(c->pool, 0, sizeof(char *)); |
2213 |
for (i = 0; i < inlen; /**/) { |
2214 |
unsigned int plen = in[i++]; |
2215 |
if (plen + i > inlen) { |
2216 |
// someone tries to trick us? |
2217 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02306) |
2218 |
"alpn protocol identier too long"); |
2219 |
return SSL_TLSEXT_ERR_ALERT_FATAL; |
2220 |
} |
2221 |
APR_ARRAY_PUSH(client_protos, char*) = |
2222 |
apr_pstrndup(c->pool, (const char *)in+i, plen); |
2223 |
i += plen; |
2224 |
} |
2225 |
|
2226 |
/* Regardless of installed hooks, the http/1.1 protocol is always |
2227 |
* supported by us. Add it to the proposals if the client also |
2228 |
* offers it. */ |
2229 |
proposed_protos = apr_array_make(c->pool, client_protos->nelts+1, |
2230 |
sizeof(char *)); |
2231 |
if (ssl_array_index(client_protos, alpn_http1) >= 0) { |
2232 |
APR_ARRAY_PUSH(proposed_protos, const char*) = alpn_http1; |
2233 |
} |
2234 |
|
2235 |
if (sslconn->alpn_proposefns != NULL) { |
2236 |
/* Invoke our alpn_propos_proto hooks, giving other modules a chance to |
2237 |
* propose protocol names for selection. We might have several such |
2238 |
* hooks installed and if two make a proposal, we need to give |
2239 |
* preference to one. |
2240 |
*/ |
2241 |
for (i = 0; i < sslconn->alpn_proposefns->nelts; i++) { |
2242 |
ssl_alpn_propose_protos fn = |
2243 |
APR_ARRAY_IDX(sslconn->alpn_proposefns, i, |
2244 |
ssl_alpn_propose_protos); |
2245 |
|
2246 |
if (fn(c, client_protos, proposed_protos) == DONE) |
2247 |
break; |
2248 |
} |
2249 |
} |
2250 |
|
2251 |
if (proposed_protos->nelts <= 0) { |
2252 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02306) |
2253 |
"none of the client alpn protocols are supported"); |
2254 |
return SSL_TLSEXT_ERR_ALERT_FATAL; |
2255 |
} |
2256 |
|
2257 |
/* Now select the most preferred protocol from the proposals. */ |
2258 |
*out = APR_ARRAY_IDX(proposed_protos, 0, const unsigned char *); |
2259 |
for (i = 1; i < proposed_protos->nelts; ++i) { |
2260 |
const char *proto = APR_ARRAY_IDX(proposed_protos, i, const char*); |
2261 |
/* Do we prefer it over existing candidate? */ |
2262 |
if (ssl_cmp_alpn_protos(mctx, (const char *)*out, proto) < 0) { |
2263 |
*out = (const unsigned char*)proto; |
2264 |
} |
2265 |
} |
2266 |
|
2267 |
size_t len = strlen((const char*)*out); |
2268 |
if (len > 255) { |
2269 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02306) |
2270 |
"alpn negotiated protocol name too long"); |
2271 |
return SSL_TLSEXT_ERR_ALERT_FATAL; |
2272 |
} |
2273 |
*outlen = (unsigned char)len; |
2274 |
|
2275 |
return SSL_TLSEXT_ERR_OK; |
2276 |
} |
2277 |
#endif |
2278 |
#if defined(HAVE_TLS_NPN) |
2279 |
/* |
2280 |
* This callback function is executed when SSL needs to decide what protocols |
2281 |
* to advertise during Next Protocol Negotiation (NPN). It must produce a |
2282 |
* string in wire format -- a sequence of length-prefixed strings -- indicating |
2283 |
* the advertised protocols. Refer to SSL_CTX_set_next_protos_advertised_cb |
2284 |
* in OpenSSL for reference. |
2285 |
*/ |
2286 |
int ssl_callback_AdvertiseNextProtos(SSL *ssl, const unsigned char **data_out, |
2287 |
unsigned int *size_out, void *arg) |
2288 |
{ |
2289 |
conn_rec *c = (conn_rec*)SSL_get_app_data(ssl); |
2290 |
SSLConnRec *sslconn = myConnConfig(c); |
2291 |
server_rec *s = mySrvFromConn(c); |
2292 |
SSLSrvConfigRec *sc = mySrvConfig(s); |
2293 |
modssl_ctx_t *mctx = myCtxConfig(sslconn, sc); |
2294 |
apr_array_header_t *protos; |
2295 |
int num_protos; |
2296 |
unsigned int size; |
2297 |
int i, j; |
2298 |
unsigned char *data; |
2299 |
unsigned char *start; |
2300 |
const char *http11 = "http/1.1"; |
2301 |
|
2302 |
*data_out = NULL; |
2303 |
*size_out = 0; |
2304 |
|
2305 |
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c, APLOGNO(02306) |
2306 |
"advertisingNextProtos"); |
2307 |
|
2308 |
/* If the connection object is not available, or there are no NPN |
2309 |
* hooks registered, then there's nothing for us to do. */ |
2310 |
if (c == NULL || sslconn->alpn_proposefns == NULL) { |
2311 |
return SSL_TLSEXT_ERR_OK; |
2312 |
} |
2313 |
|
2314 |
/* Invoke our alpn_propose_proto hook, giving other modules a chance to |
2315 |
* add alternate protocol names to advertise. */ |
2316 |
protos = apr_array_make(c->pool, 0, sizeof(char *)); |
2317 |
for (i = 0; i < sslconn->alpn_proposefns->nelts; i++) { |
2318 |
ssl_alpn_propose_protos fn = |
2319 |
APR_ARRAY_IDX(sslconn->alpn_proposefns, i, ssl_alpn_propose_protos); |
2320 |
|
2321 |
if (fn(c, NULL, protos) == DONE) |
2322 |
break; |
2323 |
} |
2324 |
if (ssl_array_index(protos, http11) < 0) { |
2325 |
APR_ARRAY_PUSH(protos, const char*) = http11; |
2326 |
} |
2327 |
num_protos = protos->nelts; |
2328 |
|
2329 |
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c, APLOGNO(02306) |
2330 |
"alpn protos %d to advertise, %d in pref config", num_protos, mctx->ssl_alpn_pref->nelts ); |
2331 |
if (num_protos > 1 && mctx->ssl_alpn_pref && mctx->ssl_alpn_pref->nelts > 0) { |
2332 |
/* Sort the protocol names according to our configured preferences. */ |
2333 |
int insert_idx = 0; |
2334 |
for (i = 0; i < mctx->ssl_alpn_pref->nelts; ++i) { |
2335 |
const char *proto = APR_ARRAY_IDX(mctx->ssl_alpn_pref, i, const char*); |
2336 |
int idx = ssl_array_index(protos, proto); |
2337 |
if (idx > insert_idx) { |
2338 |
/* bubble found protocol up */ |
2339 |
for (j = idx; j > insert_idx; --j) { |
2340 |
((const char **)protos->elts)[j] = ((const char **)protos->elts)[j-1]; |
2341 |
} |
2342 |
((const char **)protos->elts)[insert_idx] = proto; |
2343 |
++insert_idx; |
2344 |
} |
2345 |
} |
2346 |
} |
2347 |
|
2348 |
/* We now have a list of null-terminated strings; we need to concatenate |
2349 |
* them together into a single string, where each protocol name is prefixed |
2350 |
* by its length. First, calculate how long that string will be. */ |
2351 |
size = 0; |
2352 |
for (i = 0; i < num_protos; ++i) { |
2353 |
const char *string = APR_ARRAY_IDX(protos, i, const char*); |
2354 |
unsigned int length = strlen(string); |
2355 |
/* If the protocol name is too long (the length must fit in one byte), |
2356 |
* then log an error and skip it. */ |
2357 |
if (length > 255) { |
2358 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02307) |
2359 |
"SSL NPN protocol name too long (length=%u): %s", |
2360 |
length, string); |
2361 |
continue; |
2362 |
} |
2363 |
/* Leave room for the length prefix (one byte) plus the protocol name |
2364 |
* itself. */ |
2365 |
size += 1 + length; |
2366 |
} |
2367 |
|
2368 |
/* If there is nothing to advertise (either because no modules added |
2369 |
* anything to the protos array, or because all strings added to the array |
2370 |
* were skipped), then we're done. */ |
2371 |
if (size == 0) { |
2372 |
return SSL_TLSEXT_ERR_OK; |
2373 |
} |
2374 |
|
2375 |
/* Now we can build the string. Copy each protocol name string into the |
2376 |
* larger string, prefixed by its length. */ |
2377 |
data = apr_palloc(c->pool, size * sizeof(unsigned char)); |
2378 |
start = data; |
2379 |
for (i = 0; i < num_protos; ++i) { |
2380 |
const char *string = APR_ARRAY_IDX(protos, i, const char*); |
2381 |
apr_size_t length = strlen(string); |
2382 |
if (length > 255) |
2383 |
continue; |
2384 |
*start = (unsigned char)length; |
2385 |
++start; |
2386 |
memcpy(start, string, length * sizeof(unsigned char)); |
2387 |
start += length; |
2388 |
} |
2389 |
|
2390 |
/* Success. */ |
2391 |
*data_out = data; |
2392 |
*size_out = size; |
2393 |
return SSL_TLSEXT_ERR_OK; |
2394 |
} |
2395 |
|
2396 |
#endif /* HAVE_TLS_NPN */ |
2397 |
|
2139 |
#ifdef HAVE_SRP |
2398 |
#ifdef HAVE_SRP |
2140 |
|
2399 |
|
2141 |
int ssl_callback_SRPServerParams(SSL *ssl, int *ad, void *arg) |
2400 |
int ssl_callback_SRPServerParams(SSL *ssl, int *ad, void *arg) |