]> code.delx.au - gnu-emacs/blobdiff - src/gnutls.c
Ibuffer change marks
[gnu-emacs] / src / gnutls.c
index ce4fbf9b7ef10c6150789d67ba814aabd76fcfd9..7f05ac4bc475c73fafa32188ebc9b62875ef2681 100644 (file)
@@ -5,8 +5,8 @@ This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -55,7 +55,6 @@ DEF_DLL_FN (gnutls_alert_description_t, gnutls_alert_get,
            (gnutls_session_t));
 DEF_DLL_FN (const char *, gnutls_alert_get_name,
            (gnutls_alert_description_t));
-DEF_DLL_FN (int, gnutls_alert_send_appropriate, (gnutls_session_t, int));
 DEF_DLL_FN (int, gnutls_anon_allocate_client_credentials,
            (gnutls_anon_client_credentials_t *));
 DEF_DLL_FN (void, gnutls_anon_free_client_credentials,
@@ -156,8 +155,6 @@ DEF_DLL_FN (int, gnutls_x509_crt_get_subject_unique_id,
            (gnutls_x509_crt_t, char *, size_t *));
 DEF_DLL_FN (int, gnutls_x509_crt_get_signature_algorithm,
            (gnutls_x509_crt_t));
-DEF_DLL_FN (int, gnutls_x509_crt_get_signature,
-           (gnutls_x509_crt_t, char *, size_t *));
 DEF_DLL_FN (int, gnutls_x509_crt_get_key_id,
            (gnutls_x509_crt_t, unsigned int, unsigned char *, size_t *_size));
 DEF_DLL_FN (const char*, gnutls_sec_param_get_name, (gnutls_sec_param_t));
@@ -184,7 +181,7 @@ init_gnutls_functions (void)
   HMODULE library;
   int max_log_level = 1;
 
-  if (!(library = w32_delayed_load (Qgnutls_dll)))
+  if (!(library = w32_delayed_load (Qgnutls)))
     {
       GNUTLS_LOG (1, max_log_level, "GnuTLS library not found");
       return 0;
@@ -192,7 +189,6 @@ init_gnutls_functions (void)
 
   LOAD_DLL_FN (library, gnutls_alert_get);
   LOAD_DLL_FN (library, gnutls_alert_get_name);
-  LOAD_DLL_FN (library, gnutls_alert_send_appropriate);
   LOAD_DLL_FN (library, gnutls_anon_allocate_client_credentials);
   LOAD_DLL_FN (library, gnutls_anon_free_client_credentials);
   LOAD_DLL_FN (library, gnutls_bye);
@@ -255,7 +251,6 @@ init_gnutls_functions (void)
   LOAD_DLL_FN (library, gnutls_x509_crt_get_issuer_unique_id);
   LOAD_DLL_FN (library, gnutls_x509_crt_get_subject_unique_id);
   LOAD_DLL_FN (library, gnutls_x509_crt_get_signature_algorithm);
-  LOAD_DLL_FN (library, gnutls_x509_crt_get_signature);
   LOAD_DLL_FN (library, gnutls_x509_crt_get_key_id);
   LOAD_DLL_FN (library, gnutls_sec_param_get_name);
   LOAD_DLL_FN (library, gnutls_sign_get_name);
@@ -272,7 +267,7 @@ init_gnutls_functions (void)
   max_log_level = global_gnutls_log_level;
 
   {
-    Lisp_Object name = CAR_SAFE (Fget (Qgnutls_dll, QCloaded_from));
+    Lisp_Object name = CAR_SAFE (Fget (Qgnutls, QCloaded_from));
     GNUTLS_LOG2 (1, max_log_level, "GnuTLS library loaded:",
                  STRINGP (name) ? (const char *) SDATA (name) : "unknown");
   }
@@ -282,7 +277,6 @@ init_gnutls_functions (void)
 
 # define gnutls_alert_get fn_gnutls_alert_get
 # define gnutls_alert_get_name fn_gnutls_alert_get_name
-# define gnutls_alert_send_appropriate fn_gnutls_alert_send_appropriate
 # define gnutls_anon_allocate_client_credentials fn_gnutls_anon_allocate_client_credentials
 # define gnutls_anon_free_client_credentials fn_gnutls_anon_free_client_credentials
 # define gnutls_bye fn_gnutls_bye
@@ -343,7 +337,6 @@ init_gnutls_functions (void)
 # define gnutls_x509_crt_get_key_id fn_gnutls_x509_crt_get_key_id
 # define gnutls_x509_crt_get_pk_algorithm fn_gnutls_x509_crt_get_pk_algorithm
 # define gnutls_x509_crt_get_serial fn_gnutls_x509_crt_get_serial
-# define gnutls_x509_crt_get_signature fn_gnutls_x509_crt_get_signature
 # define gnutls_x509_crt_get_signature_algorithm fn_gnutls_x509_crt_get_signature_algorithm
 # define gnutls_x509_crt_get_subject_unique_id fn_gnutls_x509_crt_get_subject_unique_id
 # define gnutls_x509_crt_get_version fn_gnutls_x509_crt_get_version
@@ -390,18 +383,18 @@ gnutls_log_function2 (int level, const char *string, const char *extra)
   message ("gnutls.c: [%d] %s %s", level, string, extra);
 }
 
-/* Log a message and an integer.  */
-static void
-gnutls_log_function2i (int level, const char *string, int extra)
-{
-  message ("gnutls.c: [%d] %s %d", level, string, extra);
-}
-
 int
 gnutls_try_handshake (struct Lisp_Process *proc)
 {
   gnutls_session_t state = proc->gnutls_state;
   int ret;
+  bool non_blocking = proc->is_non_blocking_client;
+
+  if (proc->gnutls_complete_negotiation_p)
+    non_blocking = false;
+
+  if (non_blocking)
+    proc->gnutls_p = true;
 
   do
     {
@@ -409,14 +402,12 @@ gnutls_try_handshake (struct Lisp_Process *proc)
       emacs_gnutls_handle_error (state, ret);
       QUIT;
     }
-  while (ret < 0 && gnutls_error_is_fatal (ret) == 0 &&
-        ! proc->is_non_blocking_client);
+  while (ret < 0
+        && gnutls_error_is_fatal (ret) == 0
+        && ! non_blocking);
 
   proc->gnutls_initstage = GNUTLS_STAGE_HANDSHAKE_TRIED;
 
-  if (proc->is_non_blocking_client)
-    proc->gnutls_p = 1;
-
   if (ret == GNUTLS_E_SUCCESS)
     {
       /* Here we're finally done.  */
@@ -424,7 +415,7 @@ gnutls_try_handshake (struct Lisp_Process *proc)
     }
   else
     {
-      //check_memory_full (gnutls_alert_send_appropriate (state, ret));
+      /* check_memory_full (gnutls_alert_send_appropriate (state, ret));  */
     }
   return ret;
 }
@@ -541,7 +532,10 @@ emacs_gnutls_read (struct Lisp_Process *proc, char *buf, ptrdiff_t nbyte)
   gnutls_session_t state = proc->gnutls_state;
 
   if (proc->gnutls_initstage != GNUTLS_STAGE_READY)
-    return -1;
+    {
+      errno = EAGAIN;
+      return -1;
+    }
 
   rtnval = gnutls_record_recv (state, buf, nbyte);
   if (rtnval >= 0)
@@ -650,7 +644,7 @@ emacs_gnutls_deinit (Lisp_Object proc)
 
   CHECK_PROCESS (proc);
 
-  if (XPROCESS (proc)->gnutls_p == 0)
+  if (! XPROCESS (proc)->gnutls_p)
     return Qnil;
 
   log_level = XPROCESS (proc)->gnutls_log_level;
@@ -677,7 +671,7 @@ emacs_gnutls_deinit (Lisp_Object proc)
        GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT - 1;
     }
 
-  XPROCESS (proc)->gnutls_p = 0;
+  XPROCESS (proc)->gnutls_p = false;
   return Qt;
 }
 
@@ -711,7 +705,9 @@ usage: (gnutls-errorp ERROR)  */
        attributes: const)
   (Lisp_Object err)
 {
-  if (EQ (err, Qt)) return Qnil;
+  if (EQ (err, Qt)
+      || EQ (err, Qgnutls_e_again))
+    return Qnil;
 
   return Qt;
 }
@@ -1162,8 +1158,7 @@ emacs_gnutls_global_deinit (void)
 }
 #endif
 
-/* VARARGS 1 */
-static void
+static void ATTRIBUTE_FORMAT_PRINTF (2, 3)
 boot_error (struct Lisp_Process *p, const char *m, ...)
 {
   va_list ap;
@@ -1172,6 +1167,7 @@ boot_error (struct Lisp_Process *p, const char *m, ...)
     pset_status (p, list2 (Qfailed, vformat_string (m, ap)));
   else
     verror (m, ap);
+  va_end (ap);
 }
 
 Lisp_Object
@@ -1184,22 +1180,21 @@ gnutls_verify_boot (Lisp_Object proc, Lisp_Object proplist)
   Lisp_Object warnings;
   int max_log_level = p->gnutls_log_level;
   Lisp_Object hostname, verify_error;
-  bool verify_error_all = 0;
+  bool verify_error_all = false;
   char *c_hostname;
 
   if (NILP (proplist))
     proplist = Fcdr (Fplist_get (p->childp, QCtls_parameters));
 
-  verify_error = Fplist_get (proplist, QCgnutls_bootprop_verify_error);
-  hostname = Fplist_get (proplist, QCgnutls_bootprop_hostname);
+  verify_error = Fplist_get (proplist, QCverify_error);
+  hostname = Fplist_get (proplist, QChostname);
 
   if (EQ (verify_error, Qt))
-    {
-      verify_error_all = 1;
-    }
+    verify_error_all = true;
   else if (NILP (Flistp (verify_error)))
     {
-      boot_error (p, "gnutls-boot: invalid :verify_error parameter (not a list)");
+      boot_error (p,
+                 "gnutls-boot: invalid :verify_error parameter (not a list)");
       return Qnil;
     }
 
@@ -1225,8 +1220,7 @@ gnutls_verify_boot (Lisp_Object proc, Lisp_Object proplist)
   warnings = Fplist_get (Fgnutls_peer_status (proc), intern (":warnings"));
   if (!NILP (warnings))
     {
-      Lisp_Object tail;
-      for (tail = warnings; CONSP (tail); tail = XCDR (tail))
+      for (Lisp_Object tail = warnings; CONSP (tail); tail = XCDR (tail))
         {
           Lisp_Object warning = XCAR (tail);
           Lisp_Object message = Fgnutls_peer_status_warning_describe (warning);
@@ -1238,10 +1232,11 @@ gnutls_verify_boot (Lisp_Object proc, Lisp_Object proplist)
   if (peer_verification != 0)
     {
       if (verify_error_all
-          || !NILP (Fmember (QCgnutls_bootprop_trustfiles, verify_error)))
+          || !NILP (Fmember (QCtrustfiles, verify_error)))
         {
          emacs_gnutls_deinit (proc);
-         boot_error (p, "Certificate validation failed %s, verification code %x",
+         boot_error (p,
+                     "Certificate validation failed %s, verification code %x",
                      c_hostname, peer_verification);
          return Qnil;
         }
@@ -1265,8 +1260,8 @@ gnutls_verify_boot (Lisp_Object proc, Lisp_Object proplist)
       if (ret < GNUTLS_E_SUCCESS)
        return gnutls_make_error (ret);
 
-      gnutls_verify_cert_list =
-       gnutls_certificate_get_peers (state, &gnutls_verify_cert_list_size);
+      gnutls_verify_cert_list
+       gnutls_certificate_get_peers (state, &gnutls_verify_cert_list_size);
 
       if (gnutls_verify_cert_list == NULL)
        {
@@ -1276,10 +1271,10 @@ gnutls_verify_boot (Lisp_Object proc, Lisp_Object proplist)
          return Qnil;
        }
 
-      /* We only check the first certificate in the given chain.  */
+      /* Check only the first certificate in the given chain.  */
       ret = gnutls_x509_crt_import (gnutls_verify_cert,
-                                      &gnutls_verify_cert_list[0],
-                                      GNUTLS_X509_FMT_DER);
+                                   &gnutls_verify_cert_list[0],
+                                   GNUTLS_X509_FMT_DER);
 
       if (ret < GNUTLS_E_SUCCESS)
        {
@@ -1294,26 +1289,25 @@ gnutls_verify_boot (Lisp_Object proc, Lisp_Object proplist)
       check_memory_full (err);
       if (!err)
        {
-         XPROCESS (proc)->gnutls_extra_peer_verification |=
-           CERTIFICATE_NOT_MATCHING;
+         XPROCESS (proc)->gnutls_extra_peer_verification
+           |= CERTIFICATE_NOT_MATCHING;
           if (verify_error_all
-              || !NILP (Fmember (QCgnutls_bootprop_hostname, verify_error)))
+              || !NILP (Fmember (QChostname, verify_error)))
             {
              gnutls_x509_crt_deinit (gnutls_verify_cert);
              emacs_gnutls_deinit (proc);
-             boot_error (p, "The x509 certificate does not match \"%s\"", c_hostname);
+             boot_error (p, "The x509 certificate does not match \"%s\"",
+                         c_hostname);
              return Qnil;
             }
          else
-           {
-              GNUTLS_LOG2 (1, max_log_level, "x509 certificate does not match:",
-                           c_hostname);
-           }
+           GNUTLS_LOG2 (1, max_log_level, "x509 certificate does not match:",
+                        c_hostname);
        }
     }
 
   /* Set this flag only if the whole initialization succeeded.  */
-  XPROCESS (proc)->gnutls_p = 1;
+  XPROCESS (proc)->gnutls_p = true;
 
   return gnutls_make_error (ret);
 }
@@ -1354,6 +1348,9 @@ t to do all checks.  Currently it can contain `:trustfiles' and
 :min-prime-bits is the minimum accepted number of bits the client will
 accept in Diffie-Hellman key exchange.
 
+:complete-negotiation, if non-nil, will make negotiation complete
+before returning even on non-blocking sockets.
+
 The debug level will be set for this process AND globally for GnuTLS.
 So if you set it higher or lower at any point, it affects global
 debugging.
@@ -1411,13 +1408,13 @@ one trustfile (usually a CA bundle).  */)
       return Qnil;
     }
 
-  hostname              = Fplist_get (proplist, QCgnutls_bootprop_hostname);
-  priority_string       = Fplist_get (proplist, QCgnutls_bootprop_priority);
-  trustfiles            = Fplist_get (proplist, QCgnutls_bootprop_trustfiles);
-  keylist               = Fplist_get (proplist, QCgnutls_bootprop_keylist);
-  crlfiles              = Fplist_get (proplist, QCgnutls_bootprop_crlfiles);
-  loglevel              = Fplist_get (proplist, QCgnutls_bootprop_loglevel);
-  prime_bits            = Fplist_get (proplist, QCgnutls_bootprop_min_prime_bits);
+  hostname              = Fplist_get (proplist, QChostname);
+  priority_string       = Fplist_get (proplist, QCpriority);
+  trustfiles            = Fplist_get (proplist, QCtrustfiles);
+  keylist               = Fplist_get (proplist, QCkeylist);
+  crlfiles              = Fplist_get (proplist, QCcrlfiles);
+  loglevel              = Fplist_get (proplist, QCloglevel);
+  prime_bits            = Fplist_get (proplist, QCmin_prime_bits);
 
   if (!STRINGP (hostname))
     {
@@ -1467,7 +1464,7 @@ one trustfile (usually a CA bundle).  */)
       check_memory_full (gnutls_certificate_allocate_credentials (&x509_cred));
       XPROCESS (proc)->gnutls_x509_cred = x509_cred;
 
-      verify_flags = Fplist_get (proplist, QCgnutls_bootprop_verify_flags);
+      verify_flags = Fplist_get (proplist, QCverify_flags);
       if (NUMBERP (verify_flags))
        {
          gnutls_verify_flags = XINT (verify_flags);
@@ -1642,6 +1639,8 @@ one trustfile (usually a CA bundle).  */)
        return gnutls_make_error (ret);
     }
 
+  XPROCESS (proc)->gnutls_complete_negotiation_p =
+    !NILP (Fplist_get (proplist, QCcomplete_negotiation));
   GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_SET;
   ret = emacs_gnutls_handshake (XPROCESS (proc));
   if (ret < GNUTLS_E_SUCCESS)
@@ -1688,14 +1687,14 @@ DEFUN ("gnutls-available-p", Fgnutls_available_p, Sgnutls_available_p, 0, 0, 0,
 {
 #ifdef HAVE_GNUTLS
 # ifdef WINDOWSNT
-  Lisp_Object found = Fassq (Qgnutls_dll, Vlibrary_cache);
+  Lisp_Object found = Fassq (Qgnutls, Vlibrary_cache);
   if (CONSP (found))
     return XCDR (found);
   else
     {
       Lisp_Object status;
       status = init_gnutls_functions () ? Qt : Qnil;
-      Vlibrary_cache = Fcons (Fcons (Qgnutls_dll, status), Vlibrary_cache);
+      Vlibrary_cache = Fcons (Fcons (Qgnutls, status), Vlibrary_cache);
       return status;
     }
 # else /* !WINDOWSNT */
@@ -1727,15 +1726,16 @@ syms_of_gnutls (void)
   DEFSYM (Qgnutls_x509pki, "gnutls-x509pki");
 
   /* The following are for the property list of 'gnutls-boot'.  */
-  DEFSYM (QCgnutls_bootprop_hostname, ":hostname");
-  DEFSYM (QCgnutls_bootprop_priority, ":priority");
-  DEFSYM (QCgnutls_bootprop_trustfiles, ":trustfiles");
-  DEFSYM (QCgnutls_bootprop_keylist, ":keylist");
-  DEFSYM (QCgnutls_bootprop_crlfiles, ":crlfiles");
-  DEFSYM (QCgnutls_bootprop_min_prime_bits, ":min-prime-bits");
-  DEFSYM (QCgnutls_bootprop_loglevel, ":loglevel");
-  DEFSYM (QCgnutls_bootprop_verify_flags, ":verify-flags");
-  DEFSYM (QCgnutls_bootprop_verify_error, ":verify-error");
+  DEFSYM (QChostname, ":hostname");
+  DEFSYM (QCpriority, ":priority");
+  DEFSYM (QCtrustfiles, ":trustfiles");
+  DEFSYM (QCkeylist, ":keylist");
+  DEFSYM (QCcrlfiles, ":crlfiles");
+  DEFSYM (QCmin_prime_bits, ":min-prime-bits");
+  DEFSYM (QCloglevel, ":loglevel");
+  DEFSYM (QCcomplete_negotiation, ":complete-negotiation");
+  DEFSYM (QCverify_flags, ":verify-flags");
+  DEFSYM (QCverify_error, ":verify-error");
 
   DEFSYM (Qgnutls_e_interrupted, "gnutls-e-interrupted");
   Fput (Qgnutls_e_interrupted, Qgnutls_code,