From 79f89537c6fd3baeac03354a3381f42895fe2ca8 Mon Sep 17 00:00:00 2001 From: Nathan Skrzypczak Date: Fri, 13 Sep 2019 11:08:13 +0200 Subject: session: Add certificate store Type: feature This changes the behavior of both API calls APPLICATION_TLS_CERT_ADD & APPLICATION_TLS_KEY_ADD certificates and keys aren't bound to an app, they are passed to it via connect / listen using the message queue. This should be followed by a per protocol (QUIC/TLS) crypto_context store to save devrived structs Change-Id: I36873bc8b63b5c72776c69e8cd9febc9cae31882 Signed-off-by: Nathan Skrzypczak --- src/vnet/session/application.c | 152 ++++++++++++++++++++++++++++--- src/vnet/session/application.h | 18 ++-- src/vnet/session/application_interface.h | 23 +++++ src/vnet/session/session.api | 40 ++++++++ src/vnet/session/session_api.c | 117 ++++++++++++++++++------ src/vnet/session/session_node.c | 4 +- src/vnet/session/session_types.h | 4 +- src/vnet/tls/tls.c | 2 + src/vnet/tls/tls.h | 1 + 9 files changed, 305 insertions(+), 56 deletions(-) (limited to 'src/vnet') diff --git a/src/vnet/session/application.c b/src/vnet/session/application.c index 583c4b055ee..82c890f56ce 100644 --- a/src/vnet/session/application.c +++ b/src/vnet/session/application.c @@ -591,8 +591,6 @@ application_free (application_t * app) if (application_is_builtin (app)) application_name_table_del (app); vec_free (app->name); - vec_free (app->tls_cert); - vec_free (app->tls_key); pool_put (app_main.app_pool, app); } @@ -1305,24 +1303,20 @@ application_get_segment_manager_properties (u32 app_index) clib_error_t * vnet_app_add_tls_cert (vnet_app_add_tls_cert_args_t * a) { - application_t *app; - app = application_get (a->app_index); - if (!app) - return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED, - 0, "app %u doesn't exist", a->app_index); - app->tls_cert = vec_dup (a->cert); + /* Deprected, will be remove after 20.01 */ + app_cert_key_pair_t *ckpair; + ckpair = app_cert_key_pair_get_default (); + ckpair->cert = vec_dup (a->cert); return 0; } clib_error_t * vnet_app_add_tls_key (vnet_app_add_tls_key_args_t * a) { - application_t *app; - app = application_get (a->app_index); - if (!app) - return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED, - 0, "app %u doesn't exist", a->app_index); - app->tls_key = vec_dup (a->key); + /* Deprected, will be remove after 20.01 */ + app_cert_key_pair_t *ckpair; + ckpair = app_cert_key_pair_get_default (); + ckpair->key = vec_dup (a->key); return 0; } @@ -1375,6 +1369,22 @@ application_format_connects (application_t * app, int verbose) /* *INDENT-ON* */ } +u8 * +format_cert_key_pair (u8 * s, va_list * args) +{ + app_cert_key_pair_t *ckpair = va_arg (*args, app_cert_key_pair_t *); + int key_len = 0, cert_len = 0; + cert_len = vec_len (ckpair->cert); + key_len = vec_len (ckpair->key); + if (ckpair->cert_key_index == 0) + s = format (s, "DEFAULT (cert:%d, key:%d)", cert_len, key_len); + else + s = + format (s, "%d (cert:%d, key:%d)", ckpair->cert_key_index, cert_len, + key_len); + return s; +} + u8 * format_application (u8 * s, va_list * args) { @@ -1459,6 +1469,21 @@ application_format_all_clients (vlib_main_t * vm, int verbose) /* *INDENT-ON* */ } +static clib_error_t * +show_certificate_command_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + app_cert_key_pair_t *ckpair; + session_cli_return_if_not_enabled (); + + /* *INDENT-OFF* */ + pool_foreach (ckpair, app_main.cert_key_pair_store, ({ + vlib_cli_output (vm, "%U", format_cert_key_pair, ckpair); + })); + /* *INDENT-ON* */ + return 0; +} + static clib_error_t * show_app_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) @@ -1521,13 +1546,112 @@ show_app_command_fn (vlib_main_t * vm, unformat_input_t * input, return 0; } +/* + * Certificate store + * + */ + +static app_cert_key_pair_t * +app_cert_key_pair_alloc () +{ + app_cert_key_pair_t *ckpair; + pool_get (app_main.cert_key_pair_store, ckpair); + clib_memset (ckpair, 0, sizeof (*ckpair)); + ckpair->cert_key_index = ckpair - app_main.cert_key_pair_store; + return ckpair; +} + +app_cert_key_pair_t * +app_cert_key_pair_get_if_valid (u32 index) +{ + if (pool_is_free_index (app_main.cert_key_pair_store, index)) + return 0; + return app_cert_key_pair_get (index); +} + +app_cert_key_pair_t * +app_cert_key_pair_get (u32 index) +{ + return pool_elt_at_index (app_main.cert_key_pair_store, index); +} + +app_cert_key_pair_t * +app_cert_key_pair_get_default () +{ + /* To maintain legacy bapi */ + return app_cert_key_pair_get (0); +} + +int +vnet_app_add_cert_key_pair (vnet_app_add_cert_key_pair_args_t * a) +{ + app_cert_key_pair_t *ckpair = app_cert_key_pair_alloc (); + ckpair->cert = vec_dup (a->cert); + ckpair->key = vec_dup (a->key); + a->index = ckpair->cert_key_index; + return 0; +} + +int +vent_app_add_cert_key_interest (u32 index, u32 app_index) +{ + app_cert_key_pair_t *ckpair; + if (!(ckpair = app_cert_key_pair_get_if_valid (index))) + return -1; + vec_add1 (ckpair->app_interests, app_index); + return 0; +} + +int +vnet_app_del_cert_key_pair (u32 index) +{ + app_cert_key_pair_t *ckpair; + application_t *app; + u32 *app_index; + + if (!(ckpair = app_cert_key_pair_get_if_valid (index))) + return (VNET_API_ERROR_INVALID_VALUE); + + vec_foreach (app_index, ckpair->app_interests) + { + if ((app = application_get_if_valid (*app_index)) + && app->cb_fns.app_cert_key_pair_delete_callback) + app->cb_fns.app_cert_key_pair_delete_callback (ckpair); + } + + vec_free (ckpair->cert); + vec_free (ckpair->key); + pool_put (app_main.cert_key_pair_store, ckpair); + return 0; +} + +clib_error_t * +cert_key_pair_store_init (vlib_main_t * vm) +{ + /* Add a certificate with index 0 to support legacy apis */ + (void) app_cert_key_pair_alloc (); + return 0; +} + /* *INDENT-OFF* */ +VLIB_INIT_FUNCTION (cert_key_pair_store_init) = +{ + .runs_after = VLIB_INITS("unix_physmem_init"), +}; + VLIB_CLI_COMMAND (show_app_command, static) = { .path = "show app", .short_help = "show app [server|client] [verbose]", .function = show_app_command_fn, }; + +VLIB_CLI_COMMAND (show_certificate_command, static) = +{ + .path = "show app certificate", + .short_help = "list app certs and keys present in store", + .function = show_certificate_command_fn, +}; /* *INDENT-ON* */ /* diff --git a/src/vnet/session/application.h b/src/vnet/session/application.h index 9ec1055bbbc..a853c3cb73a 100644 --- a/src/vnet/session/application.h +++ b/src/vnet/session/application.h @@ -111,16 +111,6 @@ typedef struct application_ /** Pool of listeners for the app */ app_listener_t *listeners; - /* - * TLS & QUIC Specific - */ - - /** Certificate to be used for listen sessions */ - u8 *tls_cert; - - /** PEM encoded key */ - u8 *tls_key; - /** Preferred tls engine */ u8 tls_engine; @@ -144,6 +134,11 @@ typedef struct app_main_ * Hash table of builtin apps by name */ uword *app_by_name; + + /** + * Pool from which we allocate certificates (key, cert) + */ + app_cert_key_pair_t *cert_key_pair_store; } app_main_t; typedef struct app_init_args_ @@ -284,6 +279,9 @@ int vnet_app_worker_add_del (vnet_app_worker_add_del_args_t * a); uword unformat_application_proto (unformat_input_t * input, va_list * args); +app_cert_key_pair_t *app_cert_key_pair_get (u32 index); +app_cert_key_pair_t *app_cert_key_pair_get_if_valid (u32 index); +app_cert_key_pair_t *app_cert_key_pair_get_default (); /* Needed while we support both bapi and mq ctrl messages */ int mq_send_session_bound_cb (u32 app_wrk_index, u32 api_context, diff --git a/src/vnet/session/application_interface.h b/src/vnet/session/application_interface.h index 17f7ef209e5..fa6206a5279 100644 --- a/src/vnet/session/application_interface.h +++ b/src/vnet/session/application_interface.h @@ -21,6 +21,14 @@ #include #include +typedef struct certificate_ +{ + u32 *app_interests; /* vec of application index asking for deletion cb */ + u32 cert_key_index; /* index in cert & key pool */ + u8 *key; + u8 *cert; +} app_cert_key_pair_t; + typedef struct _stream_session_cb_vft { /** Notify server of new segment */ @@ -57,6 +65,9 @@ typedef struct _stream_session_cb_vft /** Direct TX callback for built-in application */ int (*builtin_app_tx_callback) (session_t * session); + /** Cert and key pair delete notification */ + int (*app_cert_key_pair_delete_callback) (app_cert_key_pair_t * ckpair); + } session_cb_vft_t; #define foreach_app_init_args \ @@ -158,6 +169,13 @@ typedef enum tls_engine_type_ TLS_N_ENGINES } tls_engine_type_t; +typedef struct _vnet_app_add_cert_key_pair_args_ +{ + u8 *cert; + u8 *key; + u32 index; +} vnet_app_add_cert_key_pair_args_t; + /* Application attach options */ typedef enum { @@ -236,6 +254,9 @@ int vnet_disconnect_session (vnet_disconnect_args_t * a); clib_error_t *vnet_app_add_tls_cert (vnet_app_add_tls_cert_args_t * a); clib_error_t *vnet_app_add_tls_key (vnet_app_add_tls_key_args_t * a); +int vnet_app_add_cert_key_pair (vnet_app_add_cert_key_pair_args_t * a); +int vnet_app_del_cert_key_pair (u32 index); +int vent_app_add_cert_key_interest (u32 index, u32 app_index); /* Ask for app cb on pair deletion */ typedef struct app_session_transport_ { @@ -273,6 +294,7 @@ typedef struct session_listen_msg_ u8 proto; u8 is_ip4; ip46_address_t ip; + u32 ckpair_index; } __clib_packed session_listen_msg_t; typedef struct session_listen_uri_msg_ @@ -345,6 +367,7 @@ typedef struct session_connect_msg_ u8 hostname_len; u8 hostname[16]; u64 parent_handle; + u32 ckpair_index; } __clib_packed session_connect_msg_t; typedef struct session_connect_uri_msg_ diff --git a/src/vnet/session/session.api b/src/vnet/session/session.api index 6f208ff5b0e..33e53419a8d 100644 --- a/src/vnet/session/session.api +++ b/src/vnet/session/session.api @@ -108,7 +108,46 @@ define app_attach_reply { u64 segment_handle; }; +/** \brief Add certificate and key + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param engine - crypto engine + @param cert_len - cert length (comes first) + @param certkey_len - cert and key length + @param certkey - cert & key data (due to API limitation) +*/ +define app_add_cert_key_pair { + u32 client_index; + u32 context; + u16 cert_len; + u16 certkey_len; + u8 certkey[certkey_len]; +}; + +/** \brief Add certificate and key + @param context - sender context, to match reply w/ request + @param retval - return code for the request + @param index - index in certificate store +*/ +define app_add_cert_key_pair_reply { + u32 context; + i32 retval; + u32 index; +}; + +/** \brief Delete certificate and key + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param index - index in certificate store +*/ +autoreply define app_del_cert_key_pair { + u32 client_index; + u32 context; + u32 index; +}; + /** \brief Application add TLS certificate + ### WILL BE DEPRECATED POST 20.01 ### @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param cert_len - certificate length @@ -123,6 +162,7 @@ autoreply define application_tls_cert_add { }; /** \brief Application add TLS key + ### WILL BE DEPRECATED POST 20.01 ### @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param key_len - certificate length diff --git a/src/vnet/session/session_api.c b/src/vnet/session/session_api.c index c55aab33541..c17d98c0517 100755 --- a/src/vnet/session/session_api.c +++ b/src/vnet/session/session_api.c @@ -59,6 +59,8 @@ _(SESSION_RULE_ADD_DEL, session_rule_add_del) \ _(SESSION_RULES_DUMP, session_rules_dump) \ _(APPLICATION_TLS_CERT_ADD, application_tls_cert_add) \ _(APPLICATION_TLS_KEY_ADD, application_tls_key_add) \ +_(APP_ADD_CERT_KEY_PAIR, app_add_cert_key_pair) \ +_(APP_DEL_CERT_KEY_PAIR, app_del_cert_key_pair) \ _(APP_WORKER_ADD_DEL, app_worker_add_del) \ static int @@ -1059,7 +1061,7 @@ vl_api_app_worker_add_del_t_handler (vl_api_app_worker_add_del_t * mp) application_t *app; u8 fd_flags = 0; - if (!session_main_is_enabled ()) + if (session_main_is_enabled () == 0) { rv = VNET_API_ERROR_FEATURE_DISABLED; goto done; @@ -1138,7 +1140,7 @@ vl_api_app_namespace_add_del_t_handler (vl_api_app_namespace_add_del_t * mp) u32 appns_index = 0; u8 *ns_id = 0; int rv = 0; - if (!session_main_is_enabled ()) + if (session_main_is_enabled () == 0) { rv = VNET_API_ERROR_FEATURE_DISABLED; goto done; @@ -1355,17 +1357,85 @@ vl_api_session_rules_dump_t_handler (vl_api_one_map_server_dump_t * mp) /* *INDENT-ON* */ } +static void +vl_api_app_add_cert_key_pair_t_handler (vl_api_app_add_cert_key_pair_t * mp) +{ + vl_api_app_add_cert_key_pair_reply_t *rmp; + vnet_app_add_cert_key_pair_args_t _a, *a = &_a; + u32 certkey_len, key_len, cert_len; + int rv = 0; + if (session_main_is_enabled () == 0) + { + rv = VNET_API_ERROR_FEATURE_DISABLED; + goto done; + } + + cert_len = clib_net_to_host_u16 (mp->cert_len); + if (cert_len > 10000) + { + rv = VNET_API_ERROR_INVALID_VALUE; + goto done; + } + + certkey_len = clib_net_to_host_u16 (mp->certkey_len); + if (certkey_len < cert_len) + { + rv = VNET_API_ERROR_INVALID_VALUE; + goto done; + } + + key_len = certkey_len - cert_len; + if (key_len > 10000) + { + rv = VNET_API_ERROR_INVALID_VALUE; + goto done; + } + + clib_memset (a, 0, sizeof (*a)); + vec_validate (a->cert, cert_len); + vec_validate (a->key, key_len); + clib_memcpy_fast (a->cert, mp->certkey, cert_len); + clib_memcpy_fast (a->key, mp->certkey + cert_len, key_len); + rv = vnet_app_add_cert_key_pair (a); + vec_free (a->cert); + vec_free (a->key); + +done: + /* *INDENT-OFF* */ + REPLY_MACRO2 (VL_API_APP_ADD_CERT_KEY_PAIR_REPLY, ({ + if (!rv) + rmp->index = a->index; + })); + /* *INDENT-ON* */ +} + +static void +vl_api_app_del_cert_key_pair_t_handler (vl_api_app_del_cert_key_pair_t * mp) +{ + vl_api_app_del_cert_key_pair_reply_t *rmp; + int rv = 0; + if (session_main_is_enabled () == 0) + { + rv = VNET_API_ERROR_FEATURE_DISABLED; + goto done; + } + rv = vnet_app_del_cert_key_pair (mp->index); + +done: + REPLY_MACRO (VL_API_APP_ADD_CERT_KEY_PAIR_REPLY); +} + +/* ### WILL BE DEPRECATED POST 20.01 ### */ static void vl_api_application_tls_cert_add_t_handler (vl_api_application_tls_cert_add_t * mp) { - vl_api_app_namespace_add_del_reply_t *rmp; - vnet_app_add_tls_cert_args_t _a, *a = &_a; - clib_error_t *error; + vl_api_application_tls_cert_add_reply_t *rmp; + app_cert_key_pair_t *ckpair; application_t *app; u32 cert_len; int rv = 0; - if (!session_main_is_enabled ()) + if (session_main_is_enabled () == 0) { rv = VNET_API_ERROR_FEATURE_DISABLED; goto done; @@ -1375,37 +1445,31 @@ vl_api_application_tls_cert_add_t_handler (vl_api_application_tls_cert_add_t * rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED; goto done; } - clib_memset (a, 0, sizeof (*a)); - a->app_index = app->app_index; cert_len = clib_net_to_host_u16 (mp->cert_len); if (cert_len > 10000) { rv = VNET_API_ERROR_INVALID_VALUE; goto done; } - vec_validate (a->cert, cert_len); - clib_memcpy_fast (a->cert, mp->cert, cert_len); - if ((error = vnet_app_add_tls_cert (a))) - { - rv = clib_error_get_code (error); - clib_error_report (error); - } - vec_free (a->cert); + ckpair = app_cert_key_pair_get_default (); + vec_validate (ckpair->cert, cert_len); + clib_memcpy_fast (ckpair->cert, mp->cert, cert_len); + done: REPLY_MACRO (VL_API_APPLICATION_TLS_CERT_ADD_REPLY); } +/* ### WILL BE DEPRECATED POST 20.01 ### */ static void vl_api_application_tls_key_add_t_handler (vl_api_application_tls_key_add_t * mp) { - vl_api_app_namespace_add_del_reply_t *rmp; - vnet_app_add_tls_key_args_t _a, *a = &_a; - clib_error_t *error; + vl_api_application_tls_key_add_reply_t *rmp; + app_cert_key_pair_t *ckpair; application_t *app; u32 key_len; int rv = 0; - if (!session_main_is_enabled ()) + if (session_main_is_enabled () == 0) { rv = VNET_API_ERROR_FEATURE_DISABLED; goto done; @@ -1415,22 +1479,15 @@ vl_api_application_tls_key_add_t_handler (vl_api_application_tls_key_add_t * rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED; goto done; } - clib_memset (a, 0, sizeof (*a)); - a->app_index = app->app_index; key_len = clib_net_to_host_u16 (mp->key_len); if (key_len > 10000) { rv = VNET_API_ERROR_INVALID_VALUE; goto done; } - vec_validate (a->key, key_len); - clib_memcpy_fast (a->key, mp->key, key_len); - if ((error = vnet_app_add_tls_key (a))) - { - rv = clib_error_get_code (error); - clib_error_report (error); - } - vec_free (a->key); + ckpair = app_cert_key_pair_get_default (); + vec_validate (ckpair->key, key_len); + clib_memcpy_fast (ckpair->key, mp->key, key_len); done: REPLY_MACRO (VL_API_APPLICATION_TLS_KEY_ADD_REPLY); } diff --git a/src/vnet/session/session_node.c b/src/vnet/session/session_node.c index e2e98eba19f..fde1931aaf9 100644 --- a/src/vnet/session/session_node.c +++ b/src/vnet/session/session_node.c @@ -54,6 +54,7 @@ session_mq_listen_handler (void *data) a->sep.fib_index = mp->vrf; a->sep.sw_if_index = ENDPOINT_INVALID_INDEX; a->sep.transport_proto = mp->proto; + a->sep_ext.ckpair_index = mp->ckpair_index; a->app_index = app->app_index; a->wrk_map_index = mp->wrk_index; @@ -112,6 +113,7 @@ session_mq_connect_handler (void *data) a->sep.peer.fib_index = mp->vrf; a->sep.peer.sw_if_index = ENDPOINT_INVALID_INDEX; a->sep_ext.parent_handle = mp->parent_handle; + a->sep_ext.ckpair_index = mp->ckpair_index; if (mp->hostname_len) { vec_validate (a->sep_ext.hostname, mp->hostname_len - 1); @@ -311,7 +313,7 @@ session_mq_reset_reply_handler (void *data) app_wrk = app_worker_get (s->app_wrk_index); if (!app_wrk || app_wrk->app_index != app->app_index) { - clib_warning ("App % does not own handle 0x%lx!", app->app_index, + clib_warning ("App %u does not own handle 0x%lx!", app->app_index, mp->handle); return; } diff --git a/src/vnet/session/session_types.h b/src/vnet/session/session_types.h index 03f7096c4b8..bb309f2f31c 100644 --- a/src/vnet/session/session_types.h +++ b/src/vnet/session/session_types.h @@ -44,6 +44,7 @@ typedef struct _session_endpoint_cfg u8 original_tp; u8 *hostname; u64 parent_handle; + u32 ckpair_index; } session_endpoint_cfg_t; #define SESSION_IP46_ZERO \ @@ -83,7 +84,8 @@ typedef struct _session_endpoint_cfg .app_wrk_index = ENDPOINT_INVALID_INDEX, \ .opaque = ENDPOINT_INVALID_INDEX, \ .hostname = 0, \ - .parent_handle = SESSION_INVALID_HANDLE \ + .parent_handle = SESSION_INVALID_HANDLE, \ + .ckpair_index = 0 \ } #define session_endpoint_to_transport(_sep) ((transport_endpoint_t *)_sep) diff --git a/src/vnet/tls/tls.c b/src/vnet/tls/tls.c index 4fff72f1cda..c512517f9e5 100644 --- a/src/vnet/tls/tls.c +++ b/src/vnet/tls/tls.c @@ -412,6 +412,7 @@ tls_session_accept_callback (session_t * tls_session) ctx->tls_session_handle = session_handle (tls_session); ctx->listener_ctx_index = tls_listener->opaque; ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP; + ctx->ckpair_index = lctx->ckpair_index; /* Preallocate app session. Avoids allocating a session post handshake * on tls_session rx and potentially invalidating the session pool */ @@ -625,6 +626,7 @@ tls_start_listen (u32 app_listener_index, transport_endpoint_t * tep) lctx->app_session_handle = listen_session_get_handle (app_listener); lctx->tcp_is_ip4 = sep->is_ip4; lctx->tls_ctx_engine = engine_type; + lctx->ckpair_index = sep->ckpair_index; if (tls_vfts[engine_type].ctx_start_listen (lctx)) { diff --git a/src/vnet/tls/tls.h b/src/vnet/tls/tls.h index eaba3c085b6..8b1db9890cb 100644 --- a/src/vnet/tls/tls.h +++ b/src/vnet/tls/tls.h @@ -79,6 +79,7 @@ typedef struct tls_ctx_ u8 app_closed; u8 no_app_session; u8 *srv_hostname; + u32 ckpair_index; } tls_ctx_t; typedef struct tls_main_ -- cgit 1.2.3-korg