]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Corrected crywrap's verification procedure.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sat, 13 Aug 2011 13:18:53 +0000 (15:18 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Sat, 13 Aug 2011 13:19:03 +0000 (15:19 +0200)
doc/manpages/crywrap.8
src/crywrap/crywrap.c
src/crywrap/crywrap.h

index e845c51a7291f36524f555637db2bacc4d3b71bb..76a6c92899c039181070f784167cb0d413e47a8f 100644 (file)
@@ -42,18 +42,17 @@ client, and only anonymous sessions will be enabled.
 .br
 Default is \fBoff\fR.
 .TP
-.BI "\-\-pem (\-p) " cert = PATH , key = PATH
+.BI "\-\-cert (\-c) " PATH
 .TP
-.BI "\-\-pem (\-p) " PATH
+.BI "\-\-key (\-k) " PATH
 .br
 The public certificate to send to clients, and the private server key.
-If one of \fIcert\fR or \fIkey\fR is omitted, the value of the other
-will be used for the missing one too.
-If no \fIcert=\fR or \fIkey=\fR tag is given, \fIPATH\fR will be used
-for both.
 .br
-Default is \fB/usr/local/etc/crywrap/server.pem\fR, unless \fB--anon\fR is also
+Default is \fB/etc/crywrap/server.pem\fR, unless \fB--anon\fR is also
 specified, in which case no certificate will be used.
+.BI "\-\-ca (\-z) " PATH
+.br
+A Certificate Authority certificate to be used for verification of client certificates.
 .TP
 .BI "\-\-verify (\-v) [" LEVEL ]
 Set the level of client certificate verification. Level one simply
index 3c1b6e87e4e59f81f10592d44e0be91f405593a1..02957794f355092f21e0257f9d4c52b93457c57f 100644 (file)
@@ -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;
         }
     }
index 5cadd5dda92eba1d013a601fa7f8e28df47603ba..62b4d7f109d4a0003474483521255828bf34eb36 100644 (file)
@@ -76,6 +76,7 @@ typedef struct
     struct sockaddr_storage *addr;
   } dest;
 
+  gnutls_priority_t priority; /**< GnuTLS priority string. */
   const char *pidfile; /**< File to store our PID in. */
   uid_t uid; /**< User ID to run as. */
   int inetd; /**< InetD-mode toggle. */