diff options
| author | Mili Verma <mili.verma@isode.com> | 2015-07-02 10:22:55 (GMT) |
|---|---|---|
| committer | Kevin Smith <kevin.smith@isode.com> | 2015-07-06 08:03:43 (GMT) |
| commit | 54dc62706f601bf2a19f9ecd752b531aa3bbf418 (patch) | |
| tree | d1e2d97ea66490d2db04739c339fdb4f173a12ad /Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp | |
| parent | 87137e983ed986df774a3373168a7611dff583c1 (diff) | |
| download | swift-54dc62706f601bf2a19f9ecd752b531aa3bbf418.zip swift-54dc62706f601bf2a19f9ecd752b531aa3bbf418.tar.bz2 | |
Add GSSAPI client authenticator
Test-information:
Tested on Windows using WIP code.
Unit tests pass.
Change-Id: I766294e57dc6374830b865f3e57b07b67e7d2fe2
Diffstat (limited to 'Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp')
| -rw-r--r-- | Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp b/Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp new file mode 100644 index 0000000..7423243 --- /dev/null +++ b/Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp | |||
| @@ -0,0 +1,194 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2015 Isode Limited. | ||
| 3 | * All rights reserved. | ||
| 4 | * See the COPYING file for more information. | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <Swiften/SASL/WindowsGSSAPIClientAuthenticator.h> | ||
| 8 | |||
| 9 | #include <Swiften/Base/Log.h> | ||
| 10 | #include <Swiften/SASL/WindowsAuthentication.h> | ||
| 11 | #include <Swiften/SASL/WindowsServicePrincipalName.h> | ||
| 12 | |||
| 13 | #define SECURITY_LAYER_NONE 1 | ||
| 14 | |||
| 15 | namespace Swift { | ||
| 16 | |||
| 17 | WindowsGSSAPIClientAuthenticator::WindowsGSSAPIClientAuthenticator(const std::string& hostname, const std::string& domainname) : ClientAuthenticator("GSSAPI"), step_(BuildingSecurityContext), error_(false), haveCredentialsHandle_(false), haveContextHandle_(false), haveCompleteContext_(false) { | ||
| 18 | WindowsServicePrincipalName servicePrincipalName(domainname); | ||
| 19 | servicePrincipalName.setInstanceName(hostname); | ||
| 20 | servicePrincipalNameString_ = servicePrincipalName.toString(); | ||
| 21 | |||
| 22 | errorCode_ = acquireCredentialsHandle(&credentialsHandle_); | ||
| 23 | if (isError()) { | ||
| 24 | return; | ||
| 25 | } | ||
| 26 | else { | ||
| 27 | haveCredentialsHandle_ = true; | ||
| 28 | } | ||
| 29 | |||
| 30 | buildSecurityContext(NULL); | ||
| 31 | } | ||
| 32 | |||
| 33 | WindowsGSSAPIClientAuthenticator::~WindowsGSSAPIClientAuthenticator() { | ||
| 34 | if (haveContextHandle_) { | ||
| 35 | deleteSecurityContext(&contextHandle_); | ||
| 36 | } | ||
| 37 | |||
| 38 | if (haveCredentialsHandle_) { | ||
| 39 | freeCredentialsHandle(&credentialsHandle_); | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | boost::optional<SafeByteArray> WindowsGSSAPIClientAuthenticator::getResponse() const { | ||
| 44 | SWIFT_LOG(debug) << "response_.size(): " << response_.size() << std::endl; | ||
| 45 | return response_; | ||
| 46 | } | ||
| 47 | |||
| 48 | bool WindowsGSSAPIClientAuthenticator::setChallenge(const boost::optional<ByteArray>& challengeData) { | ||
| 49 | /* Following http://tools.ietf.org/html/rfc4752, https://msdn.microsoft.com/en-us/library/windows/desktop/aa380496%28v=vs.85%29.aspx */ | ||
| 50 | |||
| 51 | if (step_ == BuildingSecurityContext) { | ||
| 52 | buildSecurityContext(challengeData); | ||
| 53 | } | ||
| 54 | else if (step_ == SecurityLayerNegotiation) { | ||
| 55 | if (!challengeData) { | ||
| 56 | SWIFT_LOG(debug) << "Empty message received from the server" << std::endl; | ||
| 57 | error_ = true; | ||
| 58 | return false; | ||
| 59 | } | ||
| 60 | |||
| 61 | SafeByteArray challenge; | ||
| 62 | errorCode_ = decryptMessage(&contextHandle_, challengeData.get(), challenge); | ||
| 63 | if (isError()) { | ||
| 64 | return false; | ||
| 65 | } | ||
| 66 | |||
| 67 | if (challenge.size() != 4) { | ||
| 68 | SWIFT_LOG(debug) << "Token received from the server of incorrect length: " << challenge.size() << std::endl; | ||
| 69 | error_ = true; | ||
| 70 | return false; | ||
| 71 | } | ||
| 72 | |||
| 73 | unsigned char* challengePointer = vecptr(challenge); | ||
| 74 | |||
| 75 | unsigned char serverSecurityLayer = challengePointer[0]; | ||
| 76 | if (serverSecurityLayer == 0) { | ||
| 77 | SWIFT_LOG(debug) << "Server supports unknown security layer, assuming no security layer" << std::endl; | ||
| 78 | serverSecurityLayer = SECURITY_LAYER_NONE; | ||
| 79 | } | ||
| 80 | else if (serverSecurityLayer == SECURITY_LAYER_NONE) { | ||
| 81 | SWIFT_LOG(debug) << "Server supports no security layer" << std::endl; | ||
| 82 | } | ||
| 83 | else { | ||
| 84 | SWIFT_LOG(debug) << "Server supports security layer" << std::endl; | ||
| 85 | } | ||
| 86 | |||
| 87 | unsigned int serverMaximumBuffer = (challengePointer[1] << 16) | | ||
| 88 | (challengePointer[2] << 8) | | ||
| 89 | (challengePointer[3] << 0); | ||
| 90 | |||
| 91 | if ((serverSecurityLayer == SECURITY_LAYER_NONE) && (serverMaximumBuffer != 0)) { | ||
| 92 | SWIFT_LOG(debug) << "Server supports no security layer but has maximum buffer size" << serverMaximumBuffer << std::endl; | ||
| 93 | error_ = true; | ||
| 94 | return false; | ||
| 95 | } | ||
| 96 | |||
| 97 | SafeByteArray message(4); | ||
| 98 | |||
| 99 | /* Commenting this out as streamSizes was not obtained before | ||
| 100 | if (message.size() > streamSizes_.cbMaximumMessage) { | ||
| 101 | error_ = true; | ||
| 102 | return false; | ||
| 103 | } */ | ||
| 104 | |||
| 105 | unsigned char* messagePointer = vecptr(message); | ||
| 106 | messagePointer[0] = SECURITY_LAYER_NONE; | ||
| 107 | |||
| 108 | /* The next 3 bytes indicate the client's maximum size buffer which is set to 0 as we do not support a security layer */ | ||
| 109 | messagePointer[1] = 0; | ||
| 110 | messagePointer[2] = 0; | ||
| 111 | messagePointer[3] = 0; | ||
| 112 | |||
| 113 | /* The authorization identity is omitted as it is the same as the authentication identity */ | ||
| 114 | |||
| 115 | errorCode_ = encryptMessage(&contextHandle_, sizes_, message, response_); | ||
| 116 | if (isError()) { | ||
| 117 | return false; | ||
| 118 | } | ||
| 119 | |||
| 120 | step_ = ServerAuthenticated; | ||
| 121 | } | ||
| 122 | |||
| 123 | if (isError()) { | ||
| 124 | return false; | ||
| 125 | } | ||
| 126 | |||
| 127 | return true; | ||
| 128 | } | ||
| 129 | |||
| 130 | bool WindowsGSSAPIClientAuthenticator::isError() { | ||
| 131 | if (error_) { | ||
| 132 | return true; | ||
| 133 | } | ||
| 134 | |||
| 135 | if (!errorCode_) { | ||
| 136 | return false; | ||
| 137 | } | ||
| 138 | |||
| 139 | return true; | ||
| 140 | } | ||
| 141 | |||
| 142 | void WindowsGSSAPIClientAuthenticator::buildSecurityContext(const boost::optional<ByteArray>& inputToken) { | ||
| 143 | ULONG contextSupported; | ||
| 144 | |||
| 145 | /* An XMPP server may not support Kerberos encryption or SASL security layer so not requesting integrity or confidentiality */ | ||
| 146 | errorCode_ = initializeSecurityContext(inputToken, servicePrincipalNameString_, &credentialsHandle_, haveContextHandle_, &contextHandle_, ISC_REQ_MUTUAL_AUTH, &contextSupported, &haveCompleteContext_, response_); | ||
| 147 | if (isError()) { | ||
| 148 | return; | ||
| 149 | } | ||
| 150 | |||
| 151 | haveContextHandle_ = true; | ||
| 152 | |||
| 153 | if (!haveCompleteContext_) { | ||
| 154 | return; | ||
| 155 | } | ||
| 156 | |||
| 157 | if (contextSupported & ISC_REQ_MUTUAL_AUTH == 0) { | ||
| 158 | SWIFT_LOG(debug) << "Mutual authentication not supported" << std::endl; | ||
| 159 | error_ = true; | ||
| 160 | return; | ||
| 161 | } | ||
| 162 | |||
| 163 | errorCode_ = queryContextAttributes(&contextHandle_, SECPKG_ATTR_SIZES, &sizes_); | ||
| 164 | if (isError()) { | ||
| 165 | return; | ||
| 166 | } | ||
| 167 | |||
| 168 | /* Commenting this out as it gives the error code 0x80090302: The function requested is not supported | ||
| 169 | errorCode_ = queryContextAttributes(&contextHandle_, SECPKG_ATTR_STREAM_SIZES, &streamSizes_); | ||
| 170 | if (isError()) { | ||
| 171 | return; | ||
| 172 | }*/ | ||
| 173 | |||
| 174 | SecPkgContext_Names names; | ||
| 175 | errorCode_ = queryContextAttributes(&contextHandle_, SECPKG_ATTR_NAMES, &names); | ||
| 176 | if (isError()) { | ||
| 177 | return; | ||
| 178 | } | ||
| 179 | |||
| 180 | userName_ = names.sUserName; | ||
| 181 | SWIFT_LOG(debug) << "User name: " << userName_ << std::endl; | ||
| 182 | |||
| 183 | std::size_t position = userName_.find("\\"); | ||
| 184 | clientName_ = userName_.substr(position + 1); | ||
| 185 | SWIFT_LOG(debug) << "Client name: " << clientName_ << std::endl; | ||
| 186 | |||
| 187 | serverName_ = userName_.substr(0, position); | ||
| 188 | SWIFT_LOG(debug) << "Server name: " << serverName_ << std::endl; | ||
| 189 | |||
| 190 | freeContextBuffer(names.sUserName); | ||
| 191 | step_ = SecurityLayerNegotiation; | ||
| 192 | } | ||
| 193 | |||
| 194 | } | ||
Swift