shill: move passphrase validation from WiFi to WiFiService

this paves the way for actually parsing passphrase info into
fields of a WiFiService, rather than just validating it. also,
we need this code for calls to WiFiService.SetProperty.

BUG=None
TEST=unittests

Change-Id: I8467b36e07588b99f12cc5a4ecb7cf2deb7cf068
Reviewed-on: http://gerrit.chromium.org/gerrit/8821
Reviewed-by: mukesh agrawal <quiche@chromium.org>
Tested-by: mukesh agrawal <quiche@chromium.org>
diff --git a/wifi_service.cc b/wifi_service.cc
index daeb80f..c9713ef 100644
--- a/wifi_service.cc
+++ b/wifi_service.cc
@@ -15,12 +15,15 @@
 
 #include "shill/control_interface.h"
 #include "shill/device.h"
+#include "shill/error.h"
+#include "shill/ieee80211.h"
 #include "shill/shill_event.h"
 #include "shill/wifi.h"
 #include "shill/wifi_endpoint.h"
 #include "shill/wpa_supplicant.h"
 
 using std::string;
+using std::vector;
 
 namespace shill {
 
@@ -126,6 +129,16 @@
   return ssid_;
 }
 
+void WiFiService::SetPassphrase(const string &passphrase, Error *error) {
+  if (security_ == flimflam::kSecurityWep) {
+    passphrase_ = ParseWEPPassphrase(passphrase, error);
+  } else if (security_ == flimflam::kSecurityPsk ||
+             security_ == flimflam::kSecurityWpa ||
+             security_ == flimflam::kSecurityRsn) {
+    passphrase_ = ParseWPAPassphrase(passphrase, error);
+  }
+}
+
 // private methods
 void WiFiService::ConnectTask() {
   std::map<string, DBus::Variant> params;
@@ -170,4 +183,105 @@
   return wifi_->GetRpcIdentifier();
 }
 
+// static
+string WiFiService::ParseWEPPassphrase(const string &passphrase, Error *error) {
+  unsigned int length = passphrase.length();
+
+  switch (length) {
+    case IEEE_80211::kWEP40AsciiLen:
+    case IEEE_80211::kWEP104AsciiLen:
+      break;
+    case IEEE_80211::kWEP40AsciiLen + 2:
+    case IEEE_80211::kWEP104AsciiLen + 2:
+      CheckWEPKeyIndex(passphrase, error);
+      break;
+    case IEEE_80211::kWEP40HexLen:
+    case IEEE_80211::kWEP104HexLen:
+      CheckWEPIsHex(passphrase, error);
+      break;
+    case IEEE_80211::kWEP40HexLen + 2:
+    case IEEE_80211::kWEP104HexLen + 2:
+      (CheckWEPKeyIndex(passphrase, error) ||
+       CheckWEPPrefix(passphrase, error)) &&
+          CheckWEPIsHex(passphrase.substr(2), error);
+      break;
+    case IEEE_80211::kWEP40HexLen + 4:
+    case IEEE_80211::kWEP104HexLen + 4:
+      CheckWEPKeyIndex(passphrase, error) &&
+          CheckWEPPrefix(passphrase.substr(2), error) &&
+          CheckWEPIsHex(passphrase.substr(4), error);
+      break;
+    default:
+      error->Populate(Error::kInvalidPassphrase);
+      break;
+  }
+
+  // TODO(quiche): may need to normalize passphrase format
+  if (error->IsSuccess()) {
+    return passphrase;
+  } else {
+    return "";
+  }
+}
+
+// static
+string WiFiService::ParseWPAPassphrase(const string &passphrase, Error *error) {
+  unsigned int length = passphrase.length();
+  vector<uint8> passphrase_bytes;
+
+  if (base::HexStringToBytes(passphrase, &passphrase_bytes)) {
+    if (length != IEEE_80211::kWPAHexLen &&
+        (length < IEEE_80211::kWPAAsciiMinLen ||
+         length > IEEE_80211::kWPAAsciiMaxLen)) {
+      error->Populate(Error::kInvalidPassphrase);
+    }
+  } else {
+    if (length < IEEE_80211::kWPAAsciiMinLen ||
+        length > IEEE_80211::kWPAAsciiMaxLen) {
+      error->Populate(Error::kInvalidPassphrase);
+    }
+  }
+
+  // TODO(quiche): may need to normalize passphrase format
+  if (error->IsSuccess()) {
+    return passphrase;
+  } else {
+    return "";
+  }
+}
+
+// static
+bool WiFiService::CheckWEPIsHex(const string &passphrase, Error *error) {
+  vector<uint8> passphrase_bytes;
+  if (base::HexStringToBytes(passphrase, &passphrase_bytes)) {
+    return true;
+  } else {
+    error->Populate(Error::kInvalidPassphrase);
+    return false;
+  }
+}
+
+// static
+bool WiFiService::CheckWEPKeyIndex(const string &passphrase, Error *error) {
+  if (StartsWithASCII(passphrase, "0:", false) ||
+      StartsWithASCII(passphrase, "1:", false) ||
+      StartsWithASCII(passphrase, "2:", false) ||
+      StartsWithASCII(passphrase, "3:", false)) {
+    return true;
+  } else {
+    error->Populate(Error::kInvalidPassphrase);
+    return false;
+  }
+}
+
+// static
+bool WiFiService::CheckWEPPrefix(const string &passphrase, Error *error) {
+  if (StartsWithASCII(passphrase, "0x", false)) {
+    return true;
+  } else {
+    error->Populate(Error::kInvalidPassphrase);
+    return false;
+  }
+}
+
 }  // namespace shill