diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-08-13 15:18:53 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-08-13 15:19:03 +0200 |
commit | 5bc1c44858973b00fcc3f9601bd30c4baa396fcb (patch) | |
tree | 4d2482d48d7cb75d2548705cfac9b6eb7a0e454f /src/crywrap/crywrap.c | |
parent | acf73200bfce0e9971b80b120206eb167e1ab1e7 (diff) | |
download | gnutls-5bc1c44858973b00fcc3f9601bd30c4baa396fcb.tar.gz |
Corrected crywrap's verification procedure.
Diffstat (limited to 'src/crywrap/crywrap.c')
-rw-r--r-- | src/crywrap/crywrap.c | 163 |
1 files changed, 82 insertions, 81 deletions
diff --git a/src/crywrap/crywrap.c b/src/crywrap/crywrap.c index 3c1b6e87e4..02957794f3 100644 --- a/src/crywrap/crywrap.c +++ b/src/crywrap/crywrap.c @@ -99,11 +99,11 @@ static pid_t crywrap_children[_CRYWRAP_MAXCONN + 2]; static pid_t main_pid = -1; /**< Pid of the main process */ static const char *pidfile = _CRYWRAP_PIDFILE; /**< File to log our PID into. */ + /** GNUTLS server credentials. */ static gnutls_certificate_server_credentials cred; static gnutls_dh_params dh_params; /**< GNUTLS DH parameters. */ -static const int dh_bits = 1024; /**< GNUTLS DH bits. */ /** Bugreport address. * Used by the argp suite. @@ -114,23 +114,31 @@ const char *argp_program_bug_address = "<bugs-gnutls@gnu.org>"; */ const char *argp_program_version = __CRYWRAP__ " " _CRYWRAP_VERSION; +/* The certificate and key files */ +static char *pem_cert = NULL; +static char *pem_key = NULL; + + /** The options CryWrap takes. * Used by the argp suite. */ static const struct argp_option _crywrap_options[] = { {NULL, 0, NULL, 0, "Mandatory options:", 1}, {"destination", 'd', "IP/PORT", 0, "IP and port to connect to", 1}, + {"listen", 'l', "IP/PORT", 0, "IP and port to listen on", 1}, {NULL, 0, NULL, 0, "TLS certificates:", 2}, - {"pem", 'p', "TYPE=PATH", 0, "Server key and certificate", 2}, - {"anon", 'a', NULL, 0, "Enable Anon-DH (don't use a certificate)", 2}, + {"key", 'k', "FILE", 0, "Server key", 2}, + {"cert", 'c', "FILE", 0, "Server certificate", 2}, + {"ca", 'z', "FILE", 0, "CA certificate", 2}, + {"anon", 'a', NULL, 0, "Enable anonymous authentication (don't use a certificate)", 2}, {"verify", 'v', "LEVEL", OPTION_ARG_OPTIONAL, - "Verify clients certificate", 2}, + "Verify clients certificate (1: verify if exists, 2: require)", 2}, {NULL, 0, NULL, 0, "Other options:", 3}, {"user", 'u', "UID", 0, "User ID to run as", 3}, {"pidfile", 'P', "PATH", 0, "File to log the PID into", 3}, + {"priority", 'p', "STRING", 0, "GnuTLS ciphersuite priority string", 3}, {"inetd", 'i', NULL, 0, "Enable inetd mode", 3}, - {"listen", 'l', "IP/PORT", 0, "IP and port to listen on", 3}, - {"debug", 'D', NULL, 0, "Do not fork", 2}, + {"debug", 'D', NULL, 0, "Do not fork", 3}, {0, 0, 0, 0, NULL, 0} }; @@ -145,27 +153,6 @@ static const struct argp _crywrap_argp = "was not used.", NULL, NULL, NULL}; -#ifndef __DOXYGEN__ -enum -{ - CRYWRAP_P_SUBOPT_CERT, - CRYWRAP_P_SUBOPT_KEY, - CRYWRAP_P_SUBOPT_END -}; -#endif - -/** Helper structure for parsing --pem subopts. - */ -static char * const _crywrap_p_subopts[] = { - [CRYWRAP_P_SUBOPT_CERT] = (char*)"cert", - [CRYWRAP_P_SUBOPT_KEY] = (char*)"key", - [CRYWRAP_P_SUBOPT_END] = NULL -}; - -/** Helper variable to set if a certificate was explictly set. - */ -static int cert_seen = 0; - /** @} */ /* Forward declaration */ @@ -351,7 +338,7 @@ static error_t _crywrap_config_parse_opt (int key, char *arg, struct argp_state *state) { crywrap_config_t *cfg = (crywrap_config_t *)state->input; - char *pem_cert, *pem_key, *subopts, *value; + int ret; switch (key) { @@ -380,41 +367,48 @@ _crywrap_config_parse_opt (int key, char *arg, struct argp_state *state) cfg->pidfile = NULL; break; case 'p': - subopts = optarg; - pem_cert = NULL; - pem_key = NULL; - while (*subopts != '\0') - switch (getsubopt (&subopts, _crywrap_p_subopts, &value)) - { - case CRYWRAP_P_SUBOPT_CERT: - pem_cert = strdup (value); - break; - case CRYWRAP_P_SUBOPT_KEY: - pem_key = strdup (value); - break; - default: - pem_cert = strdup (value); - break; - } - if (!pem_key) - pem_key = strdup (pem_cert); - if (!pem_cert) - pem_cert = strdup (pem_key); - if (gnutls_certificate_set_x509_key_file (cred, pem_cert, pem_key, - GNUTLS_X509_FMT_PEM) < 0) - argp_error (state, "error reading X.509 key or certificate file."); - cert_seen = 1; + if (arg && *arg) + { + const char* pos; + ret = gnutls_priority_init(&cfg->priority, arg, &pos); + if (ret < 0) + argp_error (state, "error in priority string at: %s.", pos); + } + break; + case 'c': + if (arg && *arg) + pem_cert = strdup (arg); + break; + case 'k': + if (arg && *arg) + pem_key = strdup (arg); + break; + break; case 'i': cfg->inetd = 1; break; case 'a': - cfg->anon = 1; + if (arg && *arg) + { + const char* pos; + ret = gnutls_priority_init(&cfg->priority, "NORMAL:+ANON-ECDH:+ANON-DH", &pos); + if (ret < 0) + argp_error (state, "error in priority string at: %s.", pos); + } cfg->verify = 0; + cfg->anon = 1; break; case 'v': cfg->verify = (arg) ? atoi (arg) : 1; break; + case 'z': + ret = gnutls_certificate_set_x509_trust_file (cred, arg, + GNUTLS_X509_FMT_PEM); + if (ret < 0) + argp_error (state, "error reading X.509 CA file: %s.", gnutls_strerror(ret)); + break; + case ARGP_KEY_END: if (!cfg->inetd) { @@ -426,18 +420,23 @@ _crywrap_config_parse_opt (int key, char *arg, struct argp_state *state) else if (!cfg->dest.addr) argp_error (state, "a destination address must be set!"); - if (cert_seen) - break; if (cfg->anon) break; - if (gnutls_certificate_set_x509_key_file (cred, _CRYWRAP_PEMFILE, + if (pem_cert == NULL || pem_key == NULL) + ret = gnutls_certificate_set_x509_key_file (cred, _CRYWRAP_PEMFILE, _CRYWRAP_PEMFILE, - GNUTLS_X509_FMT_PEM) < 0) - argp_error (state, "error reading X.509 key or certificate file."); + GNUTLS_X509_FMT_PEM); + else + ret = gnutls_certificate_set_x509_key_file (cred, pem_cert, pem_key, + GNUTLS_X509_FMT_PEM); + + if (ret < 0) + argp_error (state, "Error reading X.509 key or certificate file: %s", gnutls_strerror(ret)); break; default: return ARGP_ERR_UNKNOWN; } + return 0; } @@ -457,15 +456,18 @@ _crywrap_config_parse (int argc, char **argv) config->listen.addr = NULL; config->dest.port = 0; config->dest.addr = NULL; - + config->priority = NULL; config->uid = _CRYWRAP_UID; config->pidfile = _CRYWRAP_PIDFILE; config->inetd = 0; config->anon = 0; - config->verify = 1; + config->verify = 0; argp_parse (&_crywrap_argp, argc, argv, 0, 0, config); + if (config->priority == NULL) + gnutls_priority_init(&config->priority, "NORMAL", NULL); + return config; } /** @} */ @@ -483,25 +485,28 @@ _crywrap_config_parse (int argc, char **argv) static gnutls_session _crywrap_tls_session_create (const crywrap_config_t *config) { - gnutls_session session; + gnutls_session_t session; + int ret; gnutls_init (&session, GNUTLS_SERVER); - if (config->anon) { - gnutls_priority_set_direct(session, "NORMAL:+ANON-ECDH:+ANON-DH", NULL); gnutls_credentials_set (session, GNUTLS_CRD_ANON, cred); } else { - gnutls_priority_set_direct(session, "NORMAL", NULL); gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, cred); } - gnutls_dh_set_prime_bits (session, dh_bits); - - gnutls_handshake_set_private_extensions (session, 1); + ret = gnutls_priority_set(session, config->priority); + if (ret < 0) + { + cry_error ("Error setting priority %s: ", gnutls_strerror(ret)); + exit (4); + } - if (config->verify) + if (config->verify==1) gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST); + else if (config->verify==2) + gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUIRE); return session; } @@ -518,7 +523,7 @@ _crywrap_dh_params_generate (void) exit (3); } - if (gnutls_dh_params_generate2 (dh_params, dh_bits) < 0) + if (gnutls_dh_params_generate2 (dh_params, gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_NORMAL)) < 0) { cry_error ("%s", "Error in prime generation."); exit (3); @@ -879,21 +884,17 @@ _crywrap_do_one (const crywrap_config_t *config, int insock, int outsock) if (ret < 0) cry_log ("Error getting certificate from client: %s", gnutls_strerror (ret)); - + if (ret == 0 && status != 0) - switch (ret) - { - case GNUTLS_CERT_INVALID: - cry_log ("%s", "Client certificate not trusted or invalid"); - break; - default: - cry_log ("%s", "Unknown error while getting the certificate"); - break; - } - - if (config->verify > 1 && (ret < 0 || status != 0)) + { + if (status & GNUTLS_CERT_INVALID) + cry_log ("%s", "Client certificate not trusted or invalid"); + } + + if (config->verify > 0 && status != 0) { ret = -1; + gnutls_alert_send( session, GNUTLS_AL_FATAL, GNUTLS_A_INSUFFICIENT_SECURITY); goto error; } } |