diff options
Diffstat (limited to 'src/openvpn')
-rw-r--r-- | src/openvpn/buffer.c | 13 | ||||
-rw-r--r-- | src/openvpn/buffer.h | 1 | ||||
-rw-r--r-- | src/openvpn/manage.c | 153 | ||||
-rw-r--r-- | src/openvpn/manage.h | 5 | ||||
-rw-r--r-- | src/openvpn/options.c | 22 | ||||
-rw-r--r-- | src/openvpn/options.h | 1 | ||||
-rw-r--r-- | src/openvpn/ssl.c | 17 |
7 files changed, 177 insertions, 35 deletions
diff --git a/src/openvpn/buffer.c b/src/openvpn/buffer.c index 46f874b..421d60e 100644 --- a/src/openvpn/buffer.c +++ b/src/openvpn/buffer.c @@ -1066,8 +1066,10 @@ buffer_list_peek (struct buffer_list *ol) } void -buffer_list_aggregate (struct buffer_list *bl, const size_t max) +buffer_list_aggregate_separator (struct buffer_list *bl, const size_t max, const char *sep) { + int sep_len = strlen(sep); + if (bl->head) { struct buffer_entry *more = bl->head; @@ -1075,7 +1077,7 @@ buffer_list_aggregate (struct buffer_list *bl, const size_t max) int count = 0; for (count = 0; more && size <= max; ++count) { - size += BLEN(&more->buf); + size += BLEN(&more->buf) + sep_len; more = more->next; } @@ -1092,6 +1094,7 @@ buffer_list_aggregate (struct buffer_list *bl, const size_t max) { struct buffer_entry *next = e->next; buf_copy (&f->buf, &e->buf); + buf_write(&f->buf, sep, sep_len); free_buf (&e->buf); free (e); e = next; @@ -1105,6 +1108,12 @@ buffer_list_aggregate (struct buffer_list *bl, const size_t max) } void +buffer_list_aggregate (struct buffer_list *bl, const size_t max) +{ + buffer_list_aggregate_separator(bl, max, ""); +} + +void buffer_list_pop (struct buffer_list *ol) { if (ol && ol->head) diff --git a/src/openvpn/buffer.h b/src/openvpn/buffer.h index 7469da6..5695f64 100644 --- a/src/openvpn/buffer.h +++ b/src/openvpn/buffer.h @@ -931,6 +931,7 @@ void buffer_list_advance (struct buffer_list *ol, int n); void buffer_list_pop (struct buffer_list *ol); void buffer_list_aggregate (struct buffer_list *bl, const size_t max); +void buffer_list_aggregate_separator (struct buffer_list *bl, const size_t max, const char *sep); struct buffer_list *buffer_list_file (const char *fn, int max_line_len); #endif /* BUFFER_H */ diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index e59776d..4f0945c 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -113,6 +113,8 @@ man_help () #ifdef MANAGMENT_EXTERNAL_KEY msg (M_CLIENT, "rsa-sig : Enter an RSA signature in response to >RSA_SIGN challenge"); msg (M_CLIENT, " Enter signature base64 on subsequent lines followed by END"); + msg (M_CLIENT, "certificate : Enter a client certificate in response to >NEED-CERT challenge"); + msg (M_CLIENT, " Enter certificate base64 on subsequent lines followed by END"); #endif msg (M_CLIENT, "signal s : Send signal s to daemon,"); msg (M_CLIENT, " s = SIGHUP|SIGTERM|SIGUSR1|SIGUSR2."); @@ -868,6 +870,12 @@ in_extra_dispatch (struct management *man) man->connection.ext_key_input = man->connection.in_extra; man->connection.in_extra = NULL; return; + case IEC_CERTIFICATE: + man->connection.ext_cert_state = EKS_READY; + buffer_list_free (man->connection.ext_cert_input); + man->connection.ext_cert_input = man->connection.in_extra; + man->connection.in_extra = NULL; + return; #endif } in_extra_reset (&man->connection, IER_RESET); @@ -1030,6 +1038,20 @@ man_rsa_sig (struct management *man) msg (M_CLIENT, "ERROR: The rsa-sig command is not currently available"); } +static void +man_certificate (struct management *man) +{ + struct man_connection *mc = &man->connection; + if (mc->ext_cert_state == EKS_SOLICIT) + { + mc->ext_cert_state = EKS_INPUT; + mc->in_extra_cmd = IEC_CERTIFICATE; + in_extra_reset (mc, IER_NEW); + } + else + msg (M_CLIENT, "ERROR: The certificate command is not currently available"); +} + #endif static void @@ -1311,6 +1333,10 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch { man_rsa_sig (man); } + else if (streq (p[0], "certificate")) + { + man_certificate (man); + } #endif #ifdef ENABLE_PKCS11 else if (streq (p[0], "pkcs11-id-count")) @@ -3097,15 +3123,14 @@ management_query_user_pass (struct management *man, #ifdef MANAGMENT_EXTERNAL_KEY -char * /* returns allocated base64 signature */ -management_query_rsa_sig (struct management *man, - const char *b64_data) +int +management_query_multiline (struct management *man, + const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input) { struct gc_arena gc = gc_new (); - char *ret = NULL; + int ret = 0; volatile int signal_received = 0; struct buffer alert_msg = clear_buf(); - struct buffer *buf; const bool standalone_disabled_save = man->persist.standalone_disabled; struct man_connection *mc = &man->connection; @@ -3114,10 +3139,15 @@ management_query_rsa_sig (struct management *man, man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */ man->persist.special_state_msg = NULL; - mc->ext_key_state = EKS_SOLICIT; + *state = EKS_SOLICIT; - alert_msg = alloc_buf_gc (strlen(b64_data)+64, &gc); - buf_printf (&alert_msg, ">RSA_SIGN:%s", b64_data); + if (b64_data) { + alert_msg = alloc_buf_gc (strlen(b64_data)+strlen(prompt)+3, &gc); + buf_printf (&alert_msg, ">%s:%s", prompt, b64_data); + } else { + alert_msg = alloc_buf_gc (strlen(prompt)+3, &gc); + buf_printf (&alert_msg, ">%s", prompt); + } man_wait_for_client_connection (man, &signal_received, 0, MWCC_OTHER_WAIT); @@ -3135,40 +3165,107 @@ management_query_rsa_sig (struct management *man, man_check_for_signals (&signal_received); if (signal_received) goto done; - } while (mc->ext_key_state != EKS_READY); + } while (*state != EKS_READY); - if (buffer_list_defined(mc->ext_key_input)) - { - buffer_list_aggregate (mc->ext_key_input, 2048); - buf = buffer_list_peek (mc->ext_key_input); - if (buf && BLEN(buf) > 0) - { - ret = (char *) malloc(BLEN(buf)+1); - check_malloc_return(ret); - memcpy(ret, buf->data, BLEN(buf)); - ret[BLEN(buf)] = '\0'; - } - } + ret = 1; } done: - if (mc->ext_key_state == EKS_READY && ret) - msg (M_CLIENT, "SUCCESS: rsa-sig command succeeded"); - else if (mc->ext_key_state == EKS_INPUT || mc->ext_key_state == EKS_READY) - msg (M_CLIENT, "ERROR: rsa-sig command failed"); + if (*state == EKS_READY && ret) + msg (M_CLIENT, "SUCCESS: %s command succeeded", cmd); + else if (*state == EKS_INPUT || *state == EKS_READY) + msg (M_CLIENT, "ERROR: %s command failed", cmd); /* revert state */ man->persist.standalone_disabled = standalone_disabled_save; man->persist.special_state_msg = NULL; in_extra_reset (mc, IER_RESET); - mc->ext_key_state = EKS_UNDEF; - buffer_list_free (mc->ext_key_input); - mc->ext_key_input = NULL; + *state = EKS_UNDEF; gc_free (&gc); return ret; } +char * /* returns allocated base64 signature */ +management_query_multiline_flatten_newline (struct management *man, + const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input) +{ + int ok; + char *result = NULL; + struct buffer *buf; + + ok = management_query_multiline(man, b64_data, prompt, cmd, state, input); + if (ok && buffer_list_defined(*input)) + { + buffer_list_aggregate_separator (*input, 10000, "\n"); + buf = buffer_list_peek (*input); + if (buf && BLEN(buf) > 0) + { + result = (char *) malloc(BLEN(buf)+1); + check_malloc_return(result); + memcpy(result, buf->data, BLEN(buf)); + result[BLEN(buf)] = '\0'; + } + } + + buffer_list_free (*input); + *input = NULL; + + return result; +} + +char * /* returns allocated base64 signature */ +management_query_multiline_flatten (struct management *man, + const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input) +{ + int ok; + char *result = NULL; + struct buffer *buf; + + ok = management_query_multiline(man, b64_data, prompt, cmd, state, input); + if (ok && buffer_list_defined(*input)) + { + buffer_list_aggregate (*input, 2048); + buf = buffer_list_peek (*input); + if (buf && BLEN(buf) > 0) + { + result = (char *) malloc(BLEN(buf)+1); + check_malloc_return(result); + memcpy(result, buf->data, BLEN(buf)); + result[BLEN(buf)] = '\0'; + } + } + + buffer_list_free (*input); + *input = NULL; + + return result; +} + +char * /* returns allocated base64 signature */ +management_query_rsa_sig (struct management *man, + const char *b64_data) +{ + return management_query_multiline_flatten(man, b64_data, "RSA_SIGN", "rsa-sign", + &man->connection.ext_key_state, &man->connection.ext_key_input); +} + + +char* management_query_cert (struct management *man, const char *cert_name) +{ + const char prompt_1[] = "NEED-CERTIFICATE:"; + struct buffer buf_prompt = alloc_buf(strlen(cert_name) + 20); + buf_write(&buf_prompt, prompt_1, strlen(prompt_1)); + buf_write(&buf_prompt, cert_name, strlen(cert_name)+1); // +1 for \0 + + char *result; + result = management_query_multiline_flatten_newline(management, + NULL, (char*)buf_bptr(&buf_prompt), "certificate", + &man->connection.ext_cert_state, &man->connection.ext_cert_input); + free_buf(&buf_prompt); + return result; +} + #endif /* diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index 1c8dda6..8d6e87e 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -268,6 +268,7 @@ struct man_connection { # define IEC_CLIENT_AUTH 1 # define IEC_CLIENT_PF 2 # define IEC_RSA_SIGN 3 +# define IEC_CERTIFICATE 4 int in_extra_cmd; struct buffer_list *in_extra; #ifdef MANAGEMENT_DEF_AUTH @@ -281,6 +282,8 @@ struct man_connection { # define EKS_READY 3 int ext_key_state; struct buffer_list *ext_key_input; + int ext_cert_state; + struct buffer_list *ext_cert_input; #endif #endif struct event_set *es; @@ -338,6 +341,7 @@ struct management *management_init (void); #define MF_UP_DOWN (1<<10) #define MF_QUERY_REMOTE (1<<11) #define MF_QUERY_PROXY (1<<12) +#define MF_EXTERNAL_CERT (1<<13) bool management_open (struct management *man, const char *addr, @@ -420,6 +424,7 @@ void management_learn_addr (struct management *management, #ifdef MANAGMENT_EXTERNAL_KEY char *management_query_rsa_sig (struct management *man, const char *b64_data); +char* management_query_cert (struct management *man, const char *cert_name); #endif diff --git a/src/openvpn/options.c b/src/openvpn/options.c index df9a641..e8cf06a 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -1576,6 +1576,11 @@ show_settings (const struct options *o) SHOW_STR (ca_file); SHOW_STR (ca_path); SHOW_STR (dh_file); +#ifdef MANAGMENT_EXTERNAL_KEY + if((o->management_flags & MF_EXTERNAL_CERT)) + SHOW_PARM ("cert_file","EXTERNAL_CERT","%s"); + else +#endif SHOW_STR (cert_file); #ifdef MANAGMENT_EXTERNAL_KEY @@ -2152,6 +2157,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne #ifdef MANAGMENT_EXTERNAL_KEY if (options->management_flags & MF_EXTERNAL_KEY) msg(M_USAGE, "Parameter --management-external-key cannot be used when --pkcs11-provider is also specified."); + if (options->management_flags & MF_EXTERNAL_CERT) + msg(M_USAGE, "Parameter --management-external-cert cannot be used when --pkcs11-provider is also specified."); #endif if (options->pkcs12_file) msg(M_USAGE, "Parameter --pkcs12 cannot be used when --pkcs11-provider is also specified."); @@ -2183,6 +2190,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne #ifdef MANAGMENT_EXTERNAL_KEY if (options->management_flags & MF_EXTERNAL_KEY) msg(M_USAGE, "Parameter --management-external-key cannot be used when --cryptoapicert is also specified."); + if (options->management_flags & MF_EXTERNAL_CERT) + msg(M_USAGE, "Parameter --management-external-cert cannot be used when --cryptoapicert is also specified."); #endif } else @@ -2200,7 +2209,9 @@ options_postprocess_verify_ce (const struct options *options, const struct conne msg(M_USAGE, "Parameter --key cannot be used when --pkcs12 is also specified."); #ifdef MANAGMENT_EXTERNAL_KEY if (options->management_flags & MF_EXTERNAL_KEY) - msg(M_USAGE, "Parameter --external-management-key cannot be used when --pkcs12 is also specified."); + msg(M_USAGE, "Parameter --management-external-key cannot be used when --pkcs12 is also specified."); + if (options->management_flags & MF_EXTERNAL_CERT) + msg(M_USAGE, "Parameter --management-external-cert cannot be used when --pkcs12 is also specified."); #endif #endif } @@ -2242,6 +2253,9 @@ options_postprocess_verify_ce (const struct options *options, const struct conne } else { +#ifdef MANAGMENT_EXTERNAL_KEY + if (!(options->management_flags & MF_EXTERNAL_CERT)) +#endif notnull (options->cert_file, "certificate file (--cert) or PKCS#12 file (--pkcs12)"); #ifdef MANAGMENT_EXTERNAL_KEY if (!(options->management_flags & MF_EXTERNAL_KEY)) @@ -4244,6 +4258,12 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_EXTERNAL_KEY; } + else if (streq (p[0], "management-external-cert") && p[1]) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->management_flags |= MF_EXTERNAL_CERT; + options->management_certificate = p[1]; + } #endif #ifdef MANAGEMENT_DEF_AUTH else if (streq (p[0], "management-client-auth")) diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 7a8b21e..25b9e3c 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -370,6 +370,7 @@ struct options /* Mask of MF_ values of manage.h */ unsigned int management_flags; + const char *management_certificate; #endif #ifdef ENABLE_PLUGIN diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 222c828..dce6c30 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -520,10 +520,19 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) } #endif #ifdef MANAGMENT_EXTERNAL_KEY - else if ((options->management_flags & MF_EXTERNAL_KEY) && options->cert_file) - { - tls_ctx_use_external_private_key(new_ctx, options->cert_file, - options->cert_file_inline); + else if ((options->management_flags & MF_EXTERNAL_KEY) && + (options->cert_file || options->management_flags & MF_EXTERNAL_CERT)) + { + if (options->cert_file) { + tls_ctx_use_external_private_key(new_ctx, options->cert_file, + options->cert_file_inline); + } else { + char *external_certificate = management_query_cert(management, + options->management_certificate); + tls_ctx_use_external_private_key(new_ctx, INLINE_FILE_TAG, + external_certificate); + free(external_certificate); + } } #endif else |