From efd1139571ae643d3f1c6fb304631c439f0e463d Mon Sep 17 00:00:00 2001 From: James Yonan Date: Thu, 1 Mar 2012 22:50:57 +0000 Subject: [PATCH] Implemented base64 so static challenge/response now works. Refactored some of the base Activity stuff into OpenVPNClientBase.java. Clients sending intents to OpenVPNService should use OpenVPNService.INTENT_PREFIX as a key prefix when calling putExtra. --- javacli/ovpncli.ipp | 17 ++-- openvpn/client/clicreds.hpp | 17 ++-- openvpn/common/base64.hpp | 151 ++++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+), 11 deletions(-) create mode 100644 openvpn/common/base64.hpp diff --git a/javacli/ovpncli.ipp b/javacli/ovpncli.ipp index 104b32b2..bbe84f65 100644 --- a/javacli/ovpncli.ipp +++ b/javacli/ovpncli.ipp @@ -234,7 +234,7 @@ namespace openvpn { // server list { - const Option *o = options.get_ptr("SITE_LIST"); + const Option *o = options.get_ptr("HOST_LIST"); if (o) { std::stringstream in(o->get(1)); @@ -273,11 +273,16 @@ namespace openvpn { inline void OpenVPNClient::provide_creds(const ProvideCreds& creds) { - state->creds.reset(new ClientCreds()); - state->creds->set_username(creds.username); - state->creds->set_password(creds.password); - state->creds->set_response(creds.response); - state->creds->set_replace_password_with_session_id(creds.replacePasswordWithSessionID); + ClientCreds::Ptr cc = new ClientCreds(); + cc->set_username(creds.username); + cc->set_password(creds.password); + cc->set_response(creds.response); + cc->set_replace_password_with_session_id(creds.replacePasswordWithSessionID); + + Base64::Ptr b64 = new Base64(); + cc->set_base64(b64); + + state->creds = cc; } inline Status OpenVPNClient::connect() diff --git a/openvpn/client/clicreds.hpp b/openvpn/client/clicreds.hpp index a3fc9d1b..b0f4dbdc 100644 --- a/openvpn/client/clicreds.hpp +++ b/openvpn/client/clicreds.hpp @@ -2,8 +2,10 @@ #define OPENVPN_CLIENT_CLICREDS_H #include +#include #include +#include namespace openvpn { @@ -13,6 +15,7 @@ namespace openvpn { ClientCreds() : replace_password_with_session_id(false) {} + void set_base64(const Base64::Ptr& b64_arg) { b64 = b64_arg; } void set_username(const std::string& username_arg) { username = username_arg; } void set_password(const std::string& password_arg) { password = password_arg; } void set_response(const std::string& response_arg) { response = response_arg; } @@ -22,14 +25,15 @@ namespace openvpn { std::string get_password() const { - if (response.empty()) - return password; - else + if (!response.empty() && b64) { - // fixme -- code static challenge/response // SCRV1:: - return password; + std::ostringstream os; + os << "SCRV1:" << b64->encode(password) << ':' << b64->encode(response); + return os.str(); } + else + return password; } void set_session_id(const std::string& sess_id) @@ -51,6 +55,9 @@ namespace openvpn { // If true, on successful connect, we will replace the password // with the session ID we receive from the server. bool replace_password_with_session_id; + + // Used for challenge/response encoding + Base64::Ptr b64; }; } diff --git a/openvpn/common/base64.hpp b/openvpn/common/base64.hpp new file mode 100644 index 00000000..2e5e767a --- /dev/null +++ b/openvpn/common/base64.hpp @@ -0,0 +1,151 @@ +#ifndef OPENVPN_COMMON_BASE64_H +#define OPENVPN_COMMON_BASE64_H + +#include +#include // for std::memset + +#include +#include +#include + +namespace openvpn { + + class Base64 : public RC { + public: + typedef boost::intrusive_ptr Ptr; + + OPENVPN_SIMPLE_EXCEPTION(base64_bad_map); + OPENVPN_SIMPLE_EXCEPTION(base64_decode_error); + + // altmap is "+/=" by default + Base64(const char *altmap = NULL) + { + // build encoding map + { + unsigned int i; + unsigned int j = 65; + for (i = 0; i < 62; ++i) + { + enc[i] = j++; + if (j == 91) + j = 97; + else if (j == 123) + j = 48; + } + if (!altmap) + altmap = "+/="; + enc[62] = altmap[0]; + enc[63] = altmap[1]; + equal = altmap[2]; + } + + // build decoding map + { + std::memset(dec, 0xFF, 128); + for (unsigned int i = 0; i < 64; ++i) + { + const unsigned char c = enc[i]; + if (c >= 128) + throw base64_bad_map(); + dec[c] = i; + } + } + } + + template + std::string encode(const V& data) const + { + char *s, *p; + size_t i; + unsigned int c; + const size_t size = data.size(); + + p = s = new char[size * 4 / 3 + 4]; + for (i = 0; i < size; ) { + c = data[i++] << 8; + if (i < size) + c += data[i]; + i++; + c <<= 8; + if (i < size) + c += data[i]; + i++; + p[0] = enc[(c & 0x00fc0000) >> 18]; + p[1] = enc[(c & 0x0003f000) >> 12]; + p[2] = enc[(c & 0x00000fc0) >> 6]; + p[3] = enc[c & 0x0000003f]; + if (i > size) + p[3] = equal; + if (i > size + 1) + p[2] = equal; + p += 4; + } + *p = '\0'; + const std::string ret(s); + delete [] s; + return ret; + } + + template + void decode(V& dest, const std::string& str) const + { + for (const char *p = str.c_str(); p != '\0' && (*p == equal || is_base64_char(*p)); p += 4) + { + unsigned int marker; + const unsigned int val = token_decode(p, marker); + dest.push_back((val >> 16) & 0xff); + if (marker < 2) + dest.push_back((val >> 8) & 0xff); + if (marker < 1) + dest.push_back(val & 0xff); + } + } + + private: + bool is_base64_char(const char c) const + { + const size_t idx = c; + return idx < 128 && dec[idx] != 0xFF; + } + + unsigned int decode_base64_char(const char c) const + { + const size_t idx = c; + if (idx >= 128) + throw base64_decode_error(); + const unsigned int v = dec[idx]; + if (v == 0xFF) + throw base64_decode_error(); + return v; + } + + unsigned int token_decode(const char *token, unsigned int& marker) const + { + size_t i; + unsigned int val = 0; + marker = 0; // number of equal chars seen + if (strlen(token) < 4) + throw base64_decode_error(); + for (i = 0; i < 4; i++) + { + val <<= 6; + if (token[i] == equal) + marker++; + else if (marker > 0) + throw base64_decode_error(); + else + val += decode_base64_char(token[i]); + } + if (marker > 2) + throw base64_decode_error(); + return val; + } + + unsigned char enc[64]; + unsigned char dec[128]; + unsigned char equal; + }; + +} + +#endif