From 68d26e1b1b5b411adce714c88532fc8889289f34 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Mon, 9 Feb 2015 10:01:57 +0100 Subject: Update OpenVPN --- main/openvpn/src/openvpn/buffer.c | 13 +++- main/openvpn/src/openvpn/buffer.h | 1 + main/openvpn/src/openvpn/error.c | 2 +- main/openvpn/src/openvpn/init.c | 24 ++++++ main/openvpn/src/openvpn/manage.c | 145 ++++++++++++++++++++++++++++++------- main/openvpn/src/openvpn/manage.h | 5 ++ main/openvpn/src/openvpn/mtu.h | 6 ++ main/openvpn/src/openvpn/mudp.c | 9 ++- main/openvpn/src/openvpn/options.c | 19 +++++ main/openvpn/src/openvpn/ssl.c | 26 +++++-- 10 files changed, 207 insertions(+), 43 deletions(-) (limited to 'main/openvpn/src') diff --git a/main/openvpn/src/openvpn/buffer.c b/main/openvpn/src/openvpn/buffer.c index 46f874b2..421d60e9 100644 --- a/main/openvpn/src/openvpn/buffer.c +++ b/main/openvpn/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; @@ -1104,6 +1107,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) { diff --git a/main/openvpn/src/openvpn/buffer.h b/main/openvpn/src/openvpn/buffer.h index 7469da63..5695f64f 100644 --- a/main/openvpn/src/openvpn/buffer.h +++ b/main/openvpn/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/main/openvpn/src/openvpn/error.c b/main/openvpn/src/openvpn/error.c index 72ebfab6..08503238 100644 --- a/main/openvpn/src/openvpn/error.c +++ b/main/openvpn/src/openvpn/error.c @@ -323,7 +323,7 @@ void x_msg_va (const unsigned int flags, const char *format, va_list arglist) fprintf (fp, "%lu.%06lu %x %s%s%s%s", tv.tv_sec, - tv.tv_usec, + (unsigned long)tv.tv_usec, flags, prefix, prefix_sep, diff --git a/main/openvpn/src/openvpn/init.c b/main/openvpn/src/openvpn/init.c index 77827a57..077b130e 100644 --- a/main/openvpn/src/openvpn/init.c +++ b/main/openvpn/src/openvpn/init.c @@ -1794,6 +1794,19 @@ do_deferred_options (struct context *c, const unsigned int found) msg (D_PUSH, "OPTIONS IMPORT: peer-id set"); c->c2.tls_multi->use_peer_id = true; c->c2.tls_multi->peer_id = c->options.peer_id; + frame_add_to_extra_frame(&c->c2.frame, +3); /* peer-id overhead */ + if ( !c->options.ce.link_mtu_defined ) + { + frame_add_to_link_mtu(&c->c2.frame, +3); + msg (D_PUSH, "OPTIONS IMPORT: adjusting link_mtu to %d", + EXPANDED_SIZE(&c->c2.frame)); + } + else + { + msg (M_WARN, "OPTIONS IMPORT: WARNING: peer-id set, but link-mtu" + " fixed by config - reducing tun-mtu to %d, expect" + " MTU problems", TUN_MTU_SIZE(&c->c2.frame) ); + } } #endif } @@ -2403,6 +2416,17 @@ do_init_frame (struct context *c) #endif #endif /* USE_COMP */ + /* packets with peer-id (P_DATA_V2) need 3 extra bytes in frame (on client) + * and need link_mtu+3 bytes on socket reception (on server). + * + * accomodate receive path in f->extra_link, which has the side effect of + * also increasing send buffers (BUF_SIZE() macro), which need to be + * allocated big enough before receiving peer-id option from server. + * + * f->extra_frame is adjusted when peer-id option is push-received + */ + frame_add_to_extra_link(&c->c2.frame, 3); + #ifdef ENABLE_FRAGMENT /* * Set frame parameter for fragment code. This is necessary because diff --git a/main/openvpn/src/openvpn/manage.c b/main/openvpn/src/openvpn/manage.c index 27164f18..6617ccd4 100644 --- a/main/openvpn/src/openvpn/manage.c +++ b/main/openvpn/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 @@ -1332,6 +1354,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")) @@ -3118,15 +3144,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; @@ -3135,10 +3160,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); @@ -3156,40 +3186,99 @@ 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) +{ + return management_query_multiline_flatten_newline(management, + NULL, "NEED-CERTIFICATE", "certificate", + &man->connection.ext_cert_state, &man->connection.ext_cert_input); +} + #endif /* diff --git a/main/openvpn/src/openvpn/manage.h b/main/openvpn/src/openvpn/manage.h index c48875c7..d9da0063 100644 --- a/main/openvpn/src/openvpn/manage.h +++ b/main/openvpn/src/openvpn/manage.h @@ -271,6 +271,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 @@ -284,6 +285,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; @@ -341,6 +344,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, @@ -423,6 +427,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); #endif diff --git a/main/openvpn/src/openvpn/mtu.h b/main/openvpn/src/openvpn/mtu.h index 29ec21fd..bccd6810 100644 --- a/main/openvpn/src/openvpn/mtu.h +++ b/main/openvpn/src/openvpn/mtu.h @@ -257,6 +257,12 @@ frame_headroom (const struct frame *f, const unsigned int flag_mask) * frame member adjustment functions */ +static inline void +frame_add_to_link_mtu (struct frame *frame, const int increment) +{ + frame->link_mtu += increment; +} + static inline void frame_add_to_extra_frame (struct frame *frame, const int increment) { diff --git a/main/openvpn/src/openvpn/mudp.c b/main/openvpn/src/openvpn/mudp.c index 3e3f7508..57118f87 100644 --- a/main/openvpn/src/openvpn/mudp.c +++ b/main/openvpn/src/openvpn/mudp.c @@ -52,20 +52,19 @@ multi_get_create_instance_udp (struct multi_context *m, bool *floated) struct multi_instance *mi = NULL; struct hash *hash = m->hash; - if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true)) + if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true) && + m->top.c2.buf.len > 0) { struct hash_element *he; const uint32_t hv = hash_value (hash, &real); struct hash_bucket *bucket = hash_bucket (hash, hv); uint8_t* ptr = BPTR(&m->top.c2.buf); uint8_t op = ptr[0] >> P_OPCODE_SHIFT; - uint32_t peer_id; - int i; /* make sure buffer has enough length to read opcode (1 byte) and peer-id (3 bytes) */ if (op == P_DATA_V2 && m->top.c2.buf.len >= (1 + 3)) { - peer_id = ntohl(*(uint32_t*)ptr) & 0xFFFFFF; + uint32_t peer_id = ntohl(*(uint32_t*)ptr) & 0xFFFFFF; if ((peer_id < m->max_clients) && (m->instances[peer_id])) { mi = m->instances[peer_id]; @@ -99,6 +98,8 @@ multi_get_create_instance_udp (struct multi_context *m, bool *floated) mi = multi_create_instance (m, &real); if (mi) { + int i; + hash_add_fast (hash, bucket, &mi->real, hv, mi); mi->did_real_hash = true; diff --git a/main/openvpn/src/openvpn/options.c b/main/openvpn/src/openvpn/options.c index e2897984..c2a377b3 100644 --- a/main/openvpn/src/openvpn/options.c +++ b/main/openvpn/src/openvpn/options.c @@ -1568,6 +1568,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 @@ -2144,6 +2149,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."); @@ -2175,6 +2182,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 @@ -2193,6 +2202,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 --external-management-key cannot be used when --pkcs12 is also specified."); + if (options->management_flags & MF_EXTERNAL_CERT) + msg(M_USAGE, "Parameter --external-management-cert cannot be used when --pkcs12 is also specified."); #endif #endif } @@ -2234,6 +2245,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)) @@ -4232,6 +4246,11 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_EXTERNAL_KEY; } + else if (streq (p[0], "management-external-cert")) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->management_flags |= MF_EXTERNAL_CERT; + } #endif #ifdef MANAGEMENT_DEF_AUTH else if (streq (p[0], "management-client-auth")) diff --git a/main/openvpn/src/openvpn/ssl.c b/main/openvpn/src/openvpn/ssl.c index 80293efd..59bb2a12 100644 --- a/main/openvpn/src/openvpn/ssl.c +++ b/main/openvpn/src/openvpn/ssl.c @@ -264,14 +264,16 @@ tls_get_cipher_name_pair (const char * cipher_name, size_t len) { return NULL; } -/** - * Max number of bytes we will add for data structures common to both data and - * control channel packets (1 byte opcode + 3 bytes peer-id). +/* + * Max number of bytes we will add + * for data structures common to both + * data and control channel packets. + * (opcode only). */ void tls_adjust_frame_parameters(struct frame *frame) { - frame_add_to_extra_frame (frame, 1 + 3); /* space for opcode + peer-id */ + frame_add_to_extra_frame (frame, 1); /* space for opcode */ } /* @@ -518,10 +520,18 @@ 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); + tls_ctx_use_external_private_key(new_ctx, INLINE_FILE_TAG, + external_certificate); + free(external_certificate); + } } #endif else -- cgit v1.2.3