diff options
author | Alberto Gonzalez Iniesta <agi@inittab.org> | 2016-11-21 09:37:33 +0100 |
---|---|---|
committer | Alberto Gonzalez Iniesta <agi@inittab.org> | 2016-11-21 09:37:33 +0100 |
commit | 93b77cacdbb7e6f310c4e20f85c3a24ed5ba18ba (patch) | |
tree | 55a7688c9969ef4d01625caa58c7f679098c76eb /src/openvpn/ssl_verify.c | |
parent | daa9ef0efeb5e10a1b43820fbab3a4ff5fbd22f1 (diff) | |
parent | 20c8675ba46bda97330a4117c459a59a9f1c465e (diff) |
Merge tag 'upstream/2.4_beta1'
Upstream version 2.4~beta1
Diffstat (limited to 'src/openvpn/ssl_verify.c')
-rw-r--r-- | src/openvpn/ssl_verify.c | 209 |
1 files changed, 147 insertions, 62 deletions
diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index ca69b41..a099776 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -35,10 +35,12 @@ #include "syshead.h" -#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) +#ifdef ENABLE_CRYPTO #include "misc.h" #include "manage.h" +#include "otime.h" +#include "base64.h" #include "ssl_verify.h" #include "ssl_verify_backend.h" @@ -191,40 +193,25 @@ tls_username (const struct tls_multi *multi, const bool null) } void -cert_hash_remember (struct tls_session *session, const int error_depth, const unsigned char *sha1_hash) +cert_hash_remember (struct tls_session *session, const int error_depth, + const struct buffer *cert_hash) { if (error_depth >= 0 && error_depth < MAX_CERT_DEPTH) { if (!session->cert_hash_set) - ALLOC_OBJ_CLEAR (session->cert_hash_set, struct cert_hash_set); + { + ALLOC_OBJ_CLEAR (session->cert_hash_set, struct cert_hash_set); + } if (!session->cert_hash_set->ch[error_depth]) - ALLOC_OBJ (session->cert_hash_set->ch[error_depth], struct cert_hash); - { - struct cert_hash *ch = session->cert_hash_set->ch[error_depth]; - memcpy (ch->sha1_hash, sha1_hash, SHA_DIGEST_LENGTH); - } - } -} - -#if 0 -static void -cert_hash_print (const struct cert_hash_set *chs, int msglevel) -{ - struct gc_arena gc = gc_new (); - msg (msglevel, "CERT_HASH"); - if (chs) - { - int i; - for (i = 0; i < MAX_CERT_DEPTH; ++i) { - const struct cert_hash *ch = chs->ch[i]; - if (ch) - msg (msglevel, "%d:%s", i, format_hex(ch->sha1_hash, SHA_DIGEST_LENGTH, 0, &gc)); + ALLOC_OBJ (session->cert_hash_set->ch[error_depth], struct cert_hash); } + + struct cert_hash *ch = session->cert_hash_set->ch[error_depth]; + ASSERT (sizeof (ch->sha256_hash) == BLEN (cert_hash)); + memcpy (ch->sha256_hash, BPTR (cert_hash), sizeof (ch->sha256_hash)); } - gc_free (&gc); } -#endif void cert_hash_free (struct cert_hash_set *chs) @@ -238,7 +225,7 @@ cert_hash_free (struct cert_hash_set *chs) } } -static bool +bool cert_hash_compare (const struct cert_hash_set *chs1, const struct cert_hash_set *chs2) { if (chs1 && chs2) @@ -251,7 +238,8 @@ cert_hash_compare (const struct cert_hash_set *chs1, const struct cert_hash_set if (!ch1 && !ch2) continue; - else if (ch1 && ch2 && !memcmp (ch1->sha1_hash, ch2->sha1_hash, SHA_DIGEST_LENGTH)) + else if (ch1 && ch2 && !memcmp (ch1->sha256_hash, ch2->sha256_hash, + sizeof(ch1->sha256_hash))) continue; else return false; @@ -278,7 +266,8 @@ cert_hash_copy (const struct cert_hash_set *chs) if (ch) { ALLOC_OBJ (dest->ch[i], struct cert_hash); - memcpy (dest->ch[i]->sha1_hash, ch->sha1_hash, SHA_DIGEST_LENGTH); + memcpy (dest->ch[i]->sha256_hash, ch->sha256_hash, + sizeof(dest->ch[i]->sha256_hash)); } } } @@ -337,8 +326,6 @@ verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert, } } -#if OPENSSL_VERSION_NUMBER >= 0x00907000L || ENABLE_CRYPTO_POLARSSL - /* verify certificate ku */ if (opt->remote_cert_ku[0] != 0) { @@ -367,8 +354,6 @@ verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert, } } -#endif /* OPENSSL_VERSION_NUMBER */ - /* verify X509 name or username against --verify-x509-[user]name */ if (opt->verify_x509_type != VERIFY_X509_NONE) { @@ -397,22 +382,17 @@ verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert, */ static void verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert_depth, - const char *subject, const char *common_name -#ifdef ENABLE_X509_TRACK - , const struct x509_track *x509_track -#endif - ) + const char *subject, const char *common_name, + const struct x509_track *x509_track) { char envname[64]; char *serial = NULL; struct gc_arena gc = gc_new (); /* Save X509 fields in environment */ -#ifdef ENABLE_X509_TRACK if (x509_track) x509_setenv_track (x509_track, es, cert_depth, peer_cert); else -#endif x509_setenv (es, cert_depth, peer_cert); /* export subject name string as environmental variable */ @@ -425,13 +405,19 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert setenv_str (es, envname, common_name); #endif - /* export X509 cert SHA1 fingerprint */ + /* export X509 cert fingerprints */ { - unsigned char *sha1_hash = x509_get_sha1_hash(peer_cert, &gc); + struct buffer sha1 = x509_get_sha1_fingerprint(peer_cert, &gc); + struct buffer sha256 = x509_get_sha256_fingerprint(peer_cert, &gc); openvpn_snprintf (envname, sizeof(envname), "tls_digest_%d", cert_depth); - setenv_str (es, envname, format_hex_ex(sha1_hash, SHA_DIGEST_LENGTH, 0, 1, - ":", &gc)); + setenv_str (es, envname, + format_hex_ex(BPTR(&sha1), BLEN(&sha1), 0, 1, ":", &gc)); + + openvpn_snprintf (envname, sizeof(envname), "tls_digest_sha256_%d", + cert_depth); + setenv_str (es, envname, + format_hex_ex(BPTR(&sha256), BLEN(&sha256), 0, 1, ":", &gc)); } /* export serial number as environmental variable */ @@ -530,7 +516,8 @@ verify_cert_call_command(const char *verify_command, struct env_set *es, } } - argv_printf (&argv, "%sc %d %s", verify_command, cert_depth, subject); + argv_parse_cmd (&argv, verify_command); + argv_printf_cat (&argv, "%d %s", cert_depth, subject); argv_msg_prefix (D_TLS_DEBUG, &argv, "TLS: executing verify command"); ret = openvpn_run_script (&argv, es, 0, "--tls-verify script"); @@ -647,8 +634,8 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep /* verify level 1 cert, i.e. the CA that signed our leaf cert */ if (cert_depth == 1 && opt->verify_hash) { - unsigned char *sha1_hash = x509_get_sha1_hash(cert, &gc); - if (memcmp (sha1_hash, opt->verify_hash, SHA_DIGEST_LENGTH)) + struct buffer sha1_hash = x509_get_sha1_fingerprint(cert, &gc); + if (memcmp (BPTR (&sha1_hash), opt->verify_hash, BLEN(&sha1_hash))) { msg (D_TLS_ERRORS, "TLS Error: level-1 certificate hash verification failed"); goto cleanup; @@ -662,11 +649,8 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep session->verify_maxlevel = max_int (session->verify_maxlevel, cert_depth); /* export certificate values to the environment */ - verify_cert_set_env(opt->es, cert, cert_depth, subject, common_name -#ifdef ENABLE_X509_TRACK - , opt->x509_track -#endif - ); + verify_cert_set_env(opt->es, cert, cert_depth, subject, common_name, + opt->x509_track); /* export current untrusted IP */ setenv_untrusted (session); @@ -688,15 +672,18 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep if (opt->crl_file) { if (opt->ssl_flags & SSLF_CRL_VERIFY_DIR) - { - if (SUCCESS != verify_check_crl_dir(opt->crl_file, cert)) - goto cleanup; - } + { + if (SUCCESS != verify_check_crl_dir(opt->crl_file, cert)) + goto cleanup; + } else - { - if (SUCCESS != x509_verify_crl(opt->crl_file, cert, subject)) - goto cleanup; - } + { + if (tls_verify_crl_missing (opt)) + { + msg (D_TLS_ERRORS, "VERIFY ERROR: CRL not loaded"); + goto cleanup; + } + } } msg (D_HANDSHAKE, "VERIFY OK: depth=%d, %s", cert_depth, subject); @@ -1000,7 +987,8 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up setenv_untrusted (session); /* format command line */ - argv_printf (&argv, "%sc %s", session->opt->auth_user_pass_verify_script, tmp_file); + argv_parse_cmd (&argv, session->opt->auth_user_pass_verify_script); + argv_printf_cat (&argv, "%s", tmp_file); /* call command */ ret = openvpn_run_script (&argv, session->opt->es, 0, @@ -1030,7 +1018,9 @@ static int verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up, const char *raw_username) { int retval = OPENVPN_PLUGIN_FUNC_ERROR; +#ifdef PLUGIN_DEF_AUTH struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ +#endif /* Is username defined? */ if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username)) @@ -1154,6 +1144,63 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, string_mod_remap_name (up->username, COMMON_NAME_CHAR_CLASS); string_mod (up->password, CC_PRINT, CC_CRLF, '_'); + /* If server is configured with --auth-gen-token and we have an + * authentication token for this client, this authentication + * round will be done internally using the token instead of + * calling any external authentication modules. + */ + if (session->opt->auth_token_generate && multi->auth_token_sent + && NULL != multi->auth_token) + { + unsigned int ssl_flags = session->opt->ssl_flags; + + /* Ensure that the username has not changed */ + if (!tls_lock_username(multi, up->username)) + { + ks->authenticated = false; + goto done; + } + + /* If auth-token lifetime has been enabled, + * ensure the token has not expired + */ + if (session->opt->auth_token_lifetime > 0 + && (multi->auth_token_tstamp + session->opt->auth_token_lifetime) < now) + { + msg (D_HANDSHAKE, "Auth-token for client expired\n"); + ks->authenticated = false; + goto done; + } + + /* The core authentication of the token itself */ + if (memcmp_constant_time(multi->auth_token, up->password, + strlen(multi->auth_token)) != 0) + { + memset (multi->auth_token, 0, AUTH_TOKEN_SIZE); + free (multi->auth_token); + multi->auth_token = NULL; + multi->auth_token_sent = false; + ks->authenticated = false; + tls_deauthenticate (multi); + + msg (D_TLS_ERRORS, "TLS Auth Error: Auth-token verification " + "failed for username '%s' %s", up->username, + (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); + } + else + { + ks->authenticated = true; + + if (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) + set_common_name (session, up->username); + msg (D_HANDSHAKE, "TLS: Username/auth-token authentication " + "succeeded for username '%s' %s", + up->username, + (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); + } + goto done; + } + /* call plugin(s) and/or script */ #ifdef MANAGEMENT_DEF_AUTH if (man_def_auth == KMDA_DEF) @@ -1191,6 +1238,43 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, if (man_def_auth != KMDA_UNDEF) ks->auth_deferred = true; #endif + + if ((session->opt->auth_token_generate) && (NULL == multi->auth_token)) + { + /* Server is configured with --auth-gen-token but no token has yet + * been generated for this client. Generate one and save it. + */ + uint8_t tok[AUTH_TOKEN_SIZE]; + + if (!rand_bytes(tok, AUTH_TOKEN_SIZE)) + { + msg( M_FATAL, "Failed to get enough randomness for " + "authentication token"); + } + + /* The token should be longer than the input when + * being base64 encoded + */ + if( openvpn_base64_encode(tok, AUTH_TOKEN_SIZE, + &multi->auth_token) < AUTH_TOKEN_SIZE) + { + msg(D_TLS_ERRORS, "BASE64 encoding of token failed. " + "No auth-token will be activated now"); + if (multi->auth_token) + { + memset (multi->auth_token, 0, AUTH_TOKEN_SIZE); + free (multi->auth_token); + multi->auth_token = NULL; + } + } + else + { + multi->auth_token_tstamp = now; + dmsg (D_SHOW_KEYS, "Generated token for client: %s", + multi->auth_token); + } + } + if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME)) set_common_name (session, up->username); #ifdef ENABLE_DEF_AUTH @@ -1210,6 +1294,7 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, msg (D_TLS_ERRORS, "TLS Auth Error: Auth Username/Password verification failed for peer"); } + done: gc_free (&gc); } @@ -1270,4 +1355,4 @@ verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session) gc_free (&gc); } } -#endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) */ +#endif /* ENABLE_CRYPTO */ |