[tor-commits] [vidalia/alpha] Implement SafeCookie authentication

chiiph at torproject.org chiiph at torproject.org
Thu Jul 5 00:13:45 UTC 2012


commit 34d524b6f994d27f4df243f422eed493a5226b0c
Author: Tomás Touceda <chiiph at torproject.org>
Date:   Wed Jul 4 21:10:55 2012 -0300

    Implement SafeCookie authentication
---
 changes/bug5855                                    |    3 +
 src/torcontrol/TorControl.cpp                      |   74 +++++++++++++++++--
 src/torcontrol/TorControl.h                        |    2 +-
 src/vidalia/MainWindow.cpp                         |   12 ++-
 src/vidalia/MainWindow.h                           |    2 +-
 .../plugin/extensions/qtscript_TorControl.cpp      |    2 +-
 6 files changed, 80 insertions(+), 15 deletions(-)

diff --git a/changes/bug5855 b/changes/bug5855
new file mode 100644
index 0000000..610aae8
--- /dev/null
+++ b/changes/bug5855
@@ -0,0 +1,3 @@
+  New features:
+  o Use SafeCookie authentication method if available instead of the regular
+    cookie authentication. Resolves ticket 5855.
diff --git a/src/torcontrol/TorControl.cpp b/src/torcontrol/TorControl.cpp
index 01bfb1d..c7bf85d 100644
--- a/src/torcontrol/TorControl.cpp
+++ b/src/torcontrol/TorControl.cpp
@@ -19,10 +19,18 @@
 #include "RouterStatus.h"
 #include "file.h"
 #include "stringutil.h"
+#include "crypto.h"
 
 #include <QHostAddress>
 #include <QVariantMap>
 
+#define SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT \
+  "Tor safe cookie authentication server-to-controller hash"
+#define SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT \
+  "Tor safe cookie authentication controller-to-server hash"
+#define AUTHENTICATION_COOKIE_LEN 32
+#define DIGEST256_LEN 32
+#define SAFECOOKIE_SERVER_NONCE_LEN DIGEST256_LEN
 
 /** Default constructor */
 TorControl::TorControl(ControlMethod::Method method)
@@ -333,7 +341,8 @@ TorControl::isConnected()
 bool
 TorControl::send(ControlCommand cmd, ControlReply &reply, QString *errmsg)
 {
-  if (!_authenticated and (cmd.keyword() != "AUTHENTICATE") and
+  if (!_authenticated and (cmd.keyword() != "AUTHCHALLENGE") and
+      (cmd.keyword() != "AUTHENTICATE") and
       (cmd.keyword() != "PROTOCOLINFO") and
       (cmd.keyword() != "QUIT")) {
     if (errmsg)
@@ -366,18 +375,67 @@ TorControl::send(ControlCommand cmd, QString *errmsg)
  *   "AUTHENTICATE" SP 1*HEXDIG CRLF
  */
 bool
-TorControl::authenticate(const QByteArray cookie, QString *errmsg)
+TorControl::authenticate(const QByteArray cookie, bool safe, QString *errmsg)
 {
-  ControlCommand cmd("AUTHENTICATE", base16_encode(cookie));
   ControlReply reply;
   QString str;
+  if (safe) {
+    QByteArray client_nonce = crypto_rand_bytes(DIGEST256_LEN);
+    ControlCommand cmdChallenge("AUTHCHALLENGE", QString("SAFECOOKIE %1").arg(base16_encode(client_nonce)));
 
-  if (!send(cmd, reply, &str)) {
-    emit authenticationFailed(str);
-    _shouldContinue = false;
-    _reason = str;
+    if (!send(cmdChallenge, reply, &str)) {
+      emit authenticationFailed(str);
+      _shouldContinue = false;
+      _reason = str;
 
-    return err(errmsg, str);
+      return err(errmsg, str);
+    }
+
+    QHash<QString, QString> response = string_parse_keyvals(reply.getMessage());
+    QString tmp;
+    tmp.append(cookie);
+    tmp.append(client_nonce);
+    tmp.append(base16_decode(response.value("SERVERNONCE").toAscii()));
+
+    char *client_hash = (char*)malloc(DIGEST256_LEN);
+    char *server_hash = (char*)malloc(DIGEST256_LEN);
+
+    crypto_hmac_sha256(server_hash,
+                       SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT,
+                       strlen(SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT),
+                       tmp.toAscii().data(),
+                       tmp.size());
+
+    if (!QString(server_hash).compare(response.value("SERVERHASH"))) {
+      str = "Server hash was wrong in SAFECOOKIE auth";
+      return err(errmsg, str);
+    }
+
+    crypto_hmac_sha256(client_hash,
+                       SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT,
+                       strlen(SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT),
+                       tmp.toAscii().data(),
+                       tmp.size());
+
+    ControlCommand cmd("AUTHENTICATE", base16_encode(QByteArray(client_hash, DIGEST256_LEN)));
+
+    if (!send(cmd, reply, &str)) {
+      emit authenticationFailed(str);
+      _shouldContinue = false;
+      _reason = str;
+
+      return err(errmsg, str);
+    }
+  } else {
+    ControlCommand cmd("AUTHENTICATE", base16_encode(cookie));
+
+    if (!send(cmd, reply, &str)) {
+      emit authenticationFailed(str);
+      _shouldContinue = false;
+      _reason = str;
+
+      return err(errmsg, str);
+    }
   }
   onAuthenticated();
   return true;
diff --git a/src/torcontrol/TorControl.h b/src/torcontrol/TorControl.h
index 3aa78d3..1158bbd 100644
--- a/src/torcontrol/TorControl.h
+++ b/src/torcontrol/TorControl.h
@@ -78,7 +78,7 @@ public:
   /** Check if we're connected to Tor's control socket */
   bool isConnected();
   /** Sends an authentication cookie to Tor. */
-  bool authenticate(const QByteArray cookie, QString *errmsg = 0);
+  bool authenticate(const QByteArray cookie, bool safe = true, QString *errmsg = 0);
   /** Sends an authentication password to Tor. */
   bool authenticate(const QString &password = QString(), QString *errmsg = 0);
   /** Returns true if the process has passed through auth successfully */
diff --git a/src/vidalia/MainWindow.cpp b/src/vidalia/MainWindow.cpp
index 2ea816e..e3cacb0 100644
--- a/src/vidalia/MainWindow.cpp
+++ b/src/vidalia/MainWindow.cpp
@@ -1522,7 +1522,7 @@ MainWindow::authenticate()
   QString errmsg;
 
   if (authMethod == TorSettings::CookieAuth) {
-    if(tryCookie(pi)) {
+    if(tryCookie(pi, authMethods.contains("SAFECOOKIE"))) {
       authenticated();
       return;
     } else {
@@ -1556,7 +1556,7 @@ MainWindow::authenticate()
 }
 
 bool
-MainWindow::tryCookie(const ProtocolInfo &pi)
+MainWindow::tryCookie(const ProtocolInfo &pi, bool safe)
 {
   TorSettings settings;
   /* Try to load an auth cookie and send it to Tor */
@@ -1589,8 +1589,12 @@ MainWindow::tryCookie(const ProtocolInfo &pi)
           .arg(cookie.size()));
     return false;
   }
-  vNotice("Authenticating using 'cookie' authentication.");
-  return _torControl->authenticate(cookie);
+  if (safe) {
+    vNotice("Authenticating using 'safecookie' authentication.");
+  } else {
+    vNotice("Authenticating using 'cookie' authentication.");
+  }
+  return _torControl->authenticate(cookie, safe);
 }
 
 bool
diff --git a/src/vidalia/MainWindow.h b/src/vidalia/MainWindow.h
index 4bb3ef8..e5befa3 100644
--- a/src/vidalia/MainWindow.h
+++ b/src/vidalia/MainWindow.h
@@ -95,7 +95,7 @@ private slots:
   /** Called when Vidalia has successfully authenticated to Tor. */
   void authenticated();
   /** Called when authenticated() detects that you can do auth with a cookie */
-  bool tryCookie(const ProtocolInfo &pi);
+  bool tryCookie(const ProtocolInfo &pi, bool safe = false);
   /** Called when cookie auth fails or when it's the only method configured */
   bool tryHashed();
   /** Called when Vidalia fails to authenticate to Tor. The failure reason is
diff --git a/src/vidalia/plugin/extensions/qtscript_TorControl.cpp b/src/vidalia/plugin/extensions/qtscript_TorControl.cpp
index 97cb237..67a3a7a 100644
--- a/src/vidalia/plugin/extensions/qtscript_TorControl.cpp
+++ b/src/vidalia/plugin/extensions/qtscript_TorControl.cpp
@@ -221,7 +221,7 @@ static QScriptValue qtscript_TorControl_prototype_call(QScriptContext *context,
             && qscriptvalue_cast<QString*>(context->argument(1))) {
             QByteArray _q_arg0 = qscriptvalue_cast<QByteArray>(context->argument(0));
             QString* _q_arg1 = qscriptvalue_cast<QString*>(context->argument(1));
-            bool _q_result = _q_self->authenticate(_q_arg0, _q_arg1);
+            bool _q_result = _q_self->authenticate(_q_arg0, false, _q_arg1);
             return QScriptValue(context->engine(), _q_result);
         } else if (context->argument(0).isString()
             && qscriptvalue_cast<QString*>(context->argument(1))) {



More information about the tor-commits mailing list