diff --git a/src/XMPPAuthenticator.h b/src/XMPPAuthenticator.h index ed84098..3f4c974 100644 --- a/src/XMPPAuthenticator.h +++ b/src/XMPPAuthenticator.h @@ -68,20 +68,13 @@ /** * \return A OFDataAray containing the initial authentication message */ -- (OFDataArray*)clientFirstMessage; +- (OFDataArray*)initialMessage; /** - * \param challenge The challenge to generate a response for - * \return The response to the given challenge + * \param data The continuation data send by the server + * \return The appropriate response if the data was a challenge, nil otherwise */ -- (OFDataArray*)calculateResponseWithChallenge: (OFDataArray*)challenge; - -/** - * Checks whether the servers final message was valid - * - * \param message The servers final message - */ -- (void)parseServerFinalMessage: (OFDataArray*)message; +- (OFDataArray*)continueWithData: (OFDataArray*)data; - (void)setAuthzid: (OFString*)authzid; - (OFString*)authzid; diff --git a/src/XMPPAuthenticator.m b/src/XMPPAuthenticator.m index 035a6aa..eebe9fd 100644 --- a/src/XMPPAuthenticator.m +++ b/src/XMPPAuthenticator.m @@ -93,21 +93,13 @@ return [[password copy] autorelease]; } -- (OFDataArray*)clientFirstMessage +- (OFDataArray*)initialMessage { - @throw [OFNotImplementedException newWithClass: isa - selector: _cmd]; + return nil; } -- (OFDataArray*)calculateResponseWithChallenge: (OFDataArray*)challenge +- (OFDataArray*)continueWithData: (OFDataArray*)challenge { - @throw [OFNotImplementedException newWithClass: isa - selector: _cmd]; -} - -- (void)parseServerFinalMessage: (OFDataArray*)message -{ - @throw [OFNotImplementedException newWithClass: isa - selector: _cmd]; + return nil; } @end diff --git a/src/XMPPConnection.m b/src/XMPPConnection.m index 2980ed2..41a4b22 100644 --- a/src/XMPPConnection.m +++ b/src/XMPPConnection.m @@ -619,19 +619,26 @@ OFDataArray *challenge = [OFDataArray dataArrayWithBase64EncodedString: [element stringValue]]; OFDataArray *response = [authModule - calculateResponseWithChallenge: challenge]; + continueWithData: challenge]; responseTag = [OFXMLElement elementWithName: @"response" namespace: XMPP_NS_SASL]; - [responseTag addChild: [OFXMLElement elementWithCharacters: - [response stringByBase64Encoding]]]; + if (response) { + if ([response count] == 0) + [responseTag addChild: [OFXMLElement + elementWithCharacters: @"="]]; + else + [responseTag addChild: [OFXMLElement + elementWithCharacters: [response + stringByBase64Encoding]]]; + } [self sendStanza: responseTag]; return; } if ([[element name] isEqual: @"success"]) { - [authModule parseServerFinalMessage: [OFDataArray + [authModule continueWithData: [OFDataArray dataArrayWithBase64EncodedString: [element stringValue]]]; if ([delegate respondsToSelector: @@ -780,13 +787,20 @@ - (void)XMPP_sendAuth: (OFString*)authName { OFXMLElement *authTag; + OFDataArray *initialMessage = [authModule initialMessage]; authTag = [OFXMLElement elementWithName: @"auth" namespace: XMPP_NS_SASL]; [authTag addAttributeWithName: @"mechanism" stringValue: authName]; - [authTag addChild: [OFXMLElement elementWithCharacters: - [[authModule clientFirstMessage] stringByBase64Encoding]]]; + if (initialMessage) { + if ([initialMessage count] == 0) + [authTag addChild: [OFXMLElement + elementWithCharacters: @"="]]; + else + [authTag addChild: [OFXMLElement elementWithCharacters: + [initialMessage stringByBase64Encoding]]]; + } [self sendStanza: authTag]; } diff --git a/src/XMPPPLAINAuth.m b/src/XMPPPLAINAuth.m index 2c2d987..345f48e 100644 --- a/src/XMPPPLAINAuth.m +++ b/src/XMPPPLAINAuth.m @@ -44,7 +44,7 @@ password: password] autorelease]; } -- (OFDataArray*)clientFirstMessage +- (OFDataArray*)initialMessage { OFDataArray *message = [OFDataArray dataArrayWithItemSize: 1]; @@ -68,17 +68,4 @@ return message; } - -- (OFDataArray*)calculateResponseWithChallenge: (OFDataArray*)challenge -{ - @throw [XMPPAuthFailedException newWithClass: isa - connection: nil - reason: @"Received a challenge " - @"during PLAIN auth"]; -} - -- (void)parseServerFinalMessage: (OFDataArray*)message -{ - return; -} @end diff --git a/src/XMPPSCRAMAuth.h b/src/XMPPSCRAMAuth.h index 1336bdc..c6f355e 100644 --- a/src/XMPPSCRAMAuth.h +++ b/src/XMPPSCRAMAuth.h @@ -36,6 +36,7 @@ OFDataArray *serverSignature; XMPPConnection *connection; BOOL plusAvailable; + BOOL authenticated; } /** @@ -114,4 +115,6 @@ - (OFDataArray*)XMPP_hiWithData: (OFDataArray *)str salt: (OFDataArray *)salt_ iterationCount: (intmax_t)i; +- (OFDataArray*)XMPP_parseServerFirstMessage: (OFDataArray*)data; +- (OFDataArray*)XMPP_parseServerFinalMessage: (OFDataArray*)data; @end diff --git a/src/XMPPSCRAMAuth.m b/src/XMPPSCRAMAuth.m index c5e11dc..893f65c 100644 --- a/src/XMPPSCRAMAuth.m +++ b/src/XMPPSCRAMAuth.m @@ -143,12 +143,18 @@ [old release]; } -- (OFDataArray*)clientFirstMessage +- (OFDataArray*)initialMessage { OFDataArray *ret = [OFDataArray dataArrayWithItemSize: 1]; + /* New authentication attempt, reset status */ + [cNonce release]; + cNonce = nil; [GS2Header release]; GS2Header = nil; + [serverSignature release]; + serverSignature = nil; + authenticated = NO; if (authzid) GS2Header = [[OFString alloc] @@ -158,8 +164,6 @@ else GS2Header = (plusAvailable ? @"p=tls-unique,," : @"y,,"); - [cNonce release]; - cNonce = nil; cNonce = [[self XMPP_genNonce] retain]; [clientFirstMessageBare release]; @@ -174,10 +178,27 @@ [ret addNItems: [clientFirstMessageBare UTF8StringLength] fromCArray: [clientFirstMessageBare UTF8String]]; + return ret; } -- (OFDataArray*)calculateResponseWithChallenge: (OFDataArray*)challenge +- (OFDataArray*)continueWithData: (OFDataArray*)data +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFDataArray *ret; + + if (!serverSignature) + ret = [self XMPP_parseServerFirstMessage: data]; + else + ret = [self XMPP_parseServerFinalMessage: data]; + + [ret retain]; + [pool release]; + + return [ret autorelease]; +} + +- (OFDataArray*)XMPP_parseServerFirstMessage: (OFDataArray*)data { size_t i; uint8_t *clientKey, *serverKey, *clientSignature; @@ -185,7 +206,6 @@ OFHash *hash; OFDataArray *ret, *authMessage, *tmpArray, *salt = nil, *saltedPassword; OFString *tmpString, *sNonce = nil; - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; OFEnumerator *enumerator; OFString *comp; enum { @@ -198,9 +218,9 @@ ret = [OFDataArray dataArrayWithItemSize: 1]; authMessage = [OFDataArray dataArrayWithItemSize: 1]; - OFString *chal = [OFString stringWithUTF8String: [challenge cArray] - length: [challenge count] * - [challenge itemSize]]; + OFString *chal = [OFString stringWithUTF8String: [data cArray] + length: [data count] * + [data itemSize]]; enumerator = [[chal componentsSeparatedByString: @","] objectEnumerator]; @@ -253,14 +273,14 @@ [ret addNItems: [sNonce UTF8StringLength] fromCArray: [sNonce UTF8String]]; - tmpArray = [OFDataArray dataArrayWithItemSize: 1]; - [tmpArray addNItems: [password UTF8StringLength] - fromCArray: [password UTF8String]]; - /* * IETF RFC 5802: * SaltedPassword := Hi(Normalize(password), salt, i) */ + tmpArray = [OFDataArray dataArrayWithItemSize: 1]; + [tmpArray addNItems: [password UTF8StringLength] + fromCArray: [password UTF8String]]; + saltedPassword = [self XMPP_hiWithData: tmpArray salt: salt iterationCount: iterCount]; @@ -274,8 +294,8 @@ [authMessage addNItems: [clientFirstMessageBare UTF8StringLength] fromCArray: [clientFirstMessageBare UTF8String]]; [authMessage addItem: ","]; - [authMessage addNItems: [challenge count] * [challenge itemSize] - fromCArray: [challenge cArray]]; + [authMessage addNItems: [data count] * [data itemSize] + fromCArray: [data cArray]]; [authMessage addItem: ","]; [authMessage addNItems: [ret count] fromCArray: [ret cArray]]; @@ -347,20 +367,24 @@ [ret addNItems: [tmpString UTF8StringLength] fromCArray: [tmpString UTF8String]]; - [ret retain]; - [pool release]; - - return [ret autorelease]; + return ret; } -- (void)parseServerFinalMessage: (OFDataArray*)message +- (OFDataArray*)XMPP_parseServerFinalMessage: (OFDataArray*)data { - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFString *mess = [OFString stringWithUTF8String: [message cArray] - length: [message count] * - [message itemSize]]; - OFString *value = [mess substringWithRange: - of_range(2, [mess length] - 2)]; + OFString *mess, *value; + + /* + * server-final-message already received, + * we were just waiting for the last word from the server + */ + if (authenticated) + return nil; + + mess = [OFString stringWithUTF8String: [data cArray] + length: [data count] * + [data itemSize]]; + value = [mess substringWithRange: of_range(2, [mess length] - 2)]; if ([mess hasPrefix: @"v="]) { if (![value isEqual: [serverSignature stringByBase64Encoding]]) @@ -368,12 +392,13 @@ newWithClass: isa connection: nil reason: @"Received wrong ServerSignature"]; + authenticated = YES; } else @throw [XMPPAuthFailedException newWithClass: isa connection: nil reason: value]; - [pool release]; + return nil; } - (OFString*)XMPP_genNonce