bud_error_t bud_context_set_ticket(bud_context_t* context, const char* ticket, size_t size, bud_encoding_t enc) { bud_config_t* config; bud_context_t* root; size_t max_len; int i; config = context->config; root = &config->contexts[0]; if (enc == kBudEncodingRaw) { if (size != sizeof(context->ticket_key_storage)) return bud_error(kBudErrSmallTicketKey); memcpy(context->ticket_key_storage, ticket, size); } else { ASSERT(enc == kBudEncodingBase64, "Unexpected encoding of ticket key"); max_len = sizeof(context->ticket_key_storage); if (bud_base64_decode(context->ticket_key_storage, max_len, ticket, size) < max_len) { return bud_error(kBudErrSmallTicketKey); } } context->ticket_key_on = 1; if (context->ctx != NULL) { SSL_CTX_set_tlsext_ticket_keys(context->ctx, context->ticket_key_storage, sizeof(context->ticket_key_storage)); } if (context != root) return bud_ok(); /* Update ticket key in dependent contexts */ for (i = 0; i < config->context_count + 1; i++) { bud_context_t* cur; cur = &config->contexts[i]; if (cur->ticket_key_on || cur->ctx == NULL) continue; SSL_CTX_set_tlsext_ticket_keys(cur->ctx, cur->ticket_key_storage, sizeof(cur->ticket_key_storage)); } return bud_ok(); }
int bud_client_staple_json(bud_client_t* client, JSON_Value* json) { JSON_Object* obj; const char* b64_body; size_t b64_body_len; char* body; const unsigned char* pbody; size_t body_len; OCSP_RESPONSE* resp; int status; int r; r = -1; body = NULL; obj = json_value_get_object(json); b64_body = json_object_get_string(obj, "response"); if (b64_body == NULL) goto done; b64_body_len = strlen(b64_body); body_len = bud_base64_decoded_size_fast(b64_body_len); body = malloc(body_len); if (body == NULL) goto done; body_len = bud_base64_decode(body, body_len, b64_body, b64_body_len); pbody = (const unsigned char*) body; resp = d2i_OCSP_RESPONSE(NULL, &pbody, body_len); if (resp == NULL) goto done; /* Not successful response, do not waste bandwidth on it */ status = OCSP_response_status(resp); OCSP_RESPONSE_free(resp); if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) goto done; /* Set stapling! */ client->stapling_ocsp_resp = body; client->stapling_ocsp_resp_len = body_len; body = NULL; r = 0; done: free(body); return r; }
bud_error_t bud_config_new_ssl_ctx(bud_config_t* config, bud_context_t* context) { SSL_CTX* ctx; int ecdh_nid; EC_KEY* ecdh; bud_error_t err; int options; int r; const char* ticket_key; size_t max_len; if (context->backend != NULL) { if (context->backend->keepalive == -1) context->backend->keepalive = kBudDefaultKeepalive; r = bud_config_str_to_addr(context->backend->host, context->backend->port, &context->backend->addr); if (r != 0) return bud_error_num(kBudErrPton, r); } /* Decode ticket_key */ ticket_key = context->ticket_key == NULL ? config->frontend.ticket_key : context->ticket_key; if (ticket_key != NULL) { max_len = sizeof(context->ticket_key_storage); if (bud_base64_decode(context->ticket_key_storage, max_len, ticket_key, strlen(ticket_key)) < max_len) { return bud_error(kBudErrSmallTicketKey); } } /* Choose method, tlsv1_2 by default */ if (config->frontend.method == NULL) { if (strcmp(config->frontend.security, "tls1.1") == 0) config->frontend.method = TLSv1_1_server_method(); else if (strcmp(config->frontend.security, "tls1.0") == 0) config->frontend.method = TLSv1_server_method(); else if (strcmp(config->frontend.security, "tls1.2") == 0) config->frontend.method = TLSv1_2_server_method(); else if (strcmp(config->frontend.security, "ssl3") == 0) config->frontend.method = SSLv3_server_method(); else config->frontend.method = SSLv23_server_method(); } ctx = SSL_CTX_new(config->frontend.method); if (ctx == NULL) return bud_error_str(kBudErrNoMem, "SSL_CTX"); /* Disable sessions, they won't work with cluster anyway */ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); if (config->frontend.max_send_fragment) SSL_CTX_set_max_send_fragment(ctx, config->frontend.max_send_fragment); if (ticket_key != NULL) { SSL_CTX_set_tlsext_ticket_keys(ctx, context->ticket_key_storage, sizeof(context->ticket_key_storage)); } /* ECDH curve selection */ if (context->ecdh != NULL || config->frontend.ecdh != NULL) { if (context->ecdh != NULL) ecdh_nid = OBJ_sn2nid(context->ecdh); else ecdh_nid = OBJ_sn2nid(config->frontend.ecdh); if (ecdh_nid == NID_undef) { ecdh = NULL; err = bud_error_str(kBudErrECDHNotFound, context->ecdh == NULL ? config->frontend.ecdh : context->ecdh); goto fatal; } ecdh = EC_KEY_new_by_curve_name(ecdh_nid); if (ecdh == NULL) { err = bud_error_str(kBudErrNoMem, "EC_KEY"); goto fatal; } SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE); SSL_CTX_set_tmp_ecdh(ctx, ecdh); EC_KEY_free(ecdh); } ecdh = NULL; /* Cipher suites */ if (context->ciphers != NULL) SSL_CTX_set_cipher_list(ctx, context->ciphers); else if (config->frontend.ciphers != NULL) SSL_CTX_set_cipher_list(ctx, config->frontend.ciphers); /* Disable SSL2 */ options = SSL_OP_NO_SSLv2 | SSL_OP_ALL; if (!config->frontend.ssl3) options |= SSL_OP_NO_SSLv3; if (config->frontend.server_preference) options |= SSL_OP_CIPHER_SERVER_PREFERENCE; SSL_CTX_set_options(ctx, options); #ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB if (config->context_count != 0) { SSL_CTX_set_tlsext_servername_callback(ctx, bud_config_select_sni_context); SSL_CTX_set_tlsext_servername_arg(ctx, config); } #endif /* SSL_CTRL_SET_TLSEXT_SERVERNAME_CB */ #ifdef OPENSSL_NPN_NEGOTIATED context->npn_line = bud_config_encode_npn(config, context->npn, &context->npn_line_len, &err); if (!bud_is_ok(err)) goto fatal; if (context->npn_line != NULL) { SSL_CTX_set_next_protos_advertised_cb(ctx, bud_config_advertise_next_proto, context); } #else /* !OPENSSL_NPN_NEGOTIATED */ err = bud_error(kBudErrNPNNotSupported); goto fatal; #endif /* OPENSSL_NPN_NEGOTIATED */ SSL_CTX_set_tlsext_status_cb(ctx, bud_client_stapling_cb); context->ctx = ctx; return bud_ok(); fatal: if (ecdh != NULL) EC_KEY_free(ecdh); SSL_CTX_free(ctx); return err; }