Index: src/XMPPAuthenticator.h ================================================================== --- src/XMPPAuthenticator.h +++ src/XMPPAuthenticator.h @@ -66,27 +66,20 @@ password: (OFString*)password; /** * \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 - */ -- (OFDataArray*)calculateResponseWithChallenge: (OFDataArray*)challenge; - -/** - * Checks whether the servers final message was valid - * - * \param message The servers final message - */ -- (void)parseServerFinalMessage: (OFDataArray*)message; + * \param data The continuation data send by the server + * \return The appropriate response if the data was a challenge, nil otherwise + */ +- (OFDataArray*)continueWithData: (OFDataArray*)data; - (void)setAuthzid: (OFString*)authzid; - (OFString*)authzid; - (void)setAuthcid: (OFString*)authcid; - (OFString*)authcid; - (void)setPassword: (OFString*)password; - (OFString*)password; @end Index: src/XMPPAuthenticator.m ================================================================== --- src/XMPPAuthenticator.m +++ src/XMPPAuthenticator.m @@ -91,23 +91,15 @@ - (OFString*)password { return [[password copy] autorelease]; } -- (OFDataArray*)clientFirstMessage -{ - @throw [OFNotImplementedException newWithClass: isa - selector: _cmd]; -} - -- (OFDataArray*)calculateResponseWithChallenge: (OFDataArray*)challenge -{ - @throw [OFNotImplementedException newWithClass: isa - selector: _cmd]; -} - -- (void)parseServerFinalMessage: (OFDataArray*)message -{ - @throw [OFNotImplementedException newWithClass: isa - selector: _cmd]; +- (OFDataArray*)initialMessage +{ + return nil; +} + +- (OFDataArray*)continueWithData: (OFDataArray*)challenge +{ + return nil; } @end Index: src/XMPPConnection.m ================================================================== --- src/XMPPConnection.m +++ src/XMPPConnection.m @@ -617,23 +617,30 @@ if ([[element name] isEqual: @"challenge"]) { OFXMLElement *responseTag; 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: @selector(connectionWasAuthenticated:)]) [delegate connectionWasAuthenticated: self]; @@ -778,17 +785,24 @@ } - (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]; } - (void)XMPP_sendResourceBind Index: src/XMPPPLAINAuth.m ================================================================== --- src/XMPPPLAINAuth.m +++ src/XMPPPLAINAuth.m @@ -42,11 +42,11 @@ return [[[self alloc] initWithAuthzid: authzid authcid: authcid password: password] autorelease]; } -- (OFDataArray*)clientFirstMessage +- (OFDataArray*)initialMessage { OFDataArray *message = [OFDataArray dataArrayWithItemSize: 1]; /* authzid */ if (authzid) @@ -66,19 +66,6 @@ [message addNItems: [password UTF8StringLength] fromCArray: [password UTF8String]]; 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 Index: src/XMPPSCRAMAuth.h ================================================================== --- src/XMPPSCRAMAuth.h +++ src/XMPPSCRAMAuth.h @@ -34,10 +34,11 @@ OFString *GS2Header; OFString *clientFirstMessageBare; OFDataArray *serverSignature; XMPPConnection *connection; BOOL plusAvailable; + BOOL authenticated; } /** * Creates a new autoreleased XMPPSCRAMAuth with an authcid and password. * @@ -112,6 +113,8 @@ - (uint8_t*)XMPP_HMACWithKey: (OFDataArray*)key data: (OFDataArray*)data; - (OFDataArray*)XMPP_hiWithData: (OFDataArray *)str salt: (OFDataArray *)salt_ iterationCount: (intmax_t)i; +- (OFDataArray*)XMPP_parseServerFirstMessage: (OFDataArray*)data; +- (OFDataArray*)XMPP_parseServerFinalMessage: (OFDataArray*)data; @end Index: src/XMPPSCRAMAuth.m ================================================================== --- src/XMPPSCRAMAuth.m +++ src/XMPPSCRAMAuth.m @@ -141,27 +141,31 @@ authcid = nil; [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] initWithFormat: @"%@,a=%@,", (plusAvailable ? @"p=tls-unique" : @"y"), authzid]; else GS2Header = (plusAvailable ? @"p=tls-unique,," : @"y,,"); - [cNonce release]; - cNonce = nil; cNonce = [[self XMPP_genNonce] retain]; [clientFirstMessageBare release]; clientFirstMessageBare = nil; clientFirstMessageBare = [[OFString alloc] initWithFormat: @"n=%@,r=%@", @@ -171,23 +175,39 @@ [ret addNItems: [GS2Header UTF8StringLength] fromCArray: [GS2Header UTF8String]]; [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; intmax_t iterCount = 0; OFHash *hash; OFDataArray *ret, *authMessage, *tmpArray, *salt = nil, *saltedPassword; OFString *tmpString, *sNonce = nil; - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; OFEnumerator *enumerator; OFString *comp; enum { GOT_SNONCE = 0x01, GOT_SALT = 0x02, @@ -196,13 +216,13 @@ hash = [[[hashType alloc] init] autorelease]; 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]; while ((comp = [enumerator nextObject]) != nil) { OFString *entry = [comp substringWithRange: @@ -251,18 +271,18 @@ [ret addNItems: 2 fromCArray: "r="]; [ret addNItems: [sNonce UTF8StringLength] fromCArray: [sNonce UTF8String]]; + /* + * IETF RFC 5802: + * SaltedPassword := Hi(Normalize(password), salt, i) + */ tmpArray = [OFDataArray dataArrayWithItemSize: 1]; [tmpArray addNItems: [password UTF8StringLength] fromCArray: [password UTF8String]]; - /* - * IETF RFC 5802: - * SaltedPassword := Hi(Normalize(password), salt, i) - */ saltedPassword = [self XMPP_hiWithData: tmpArray salt: salt iterationCount: iterCount]; /* @@ -272,12 +292,12 @@ * client-final-message-without-proof */ [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]]; /* @@ -345,37 +365,42 @@ fromCArray: "p="]; tmpString = [tmpArray stringByBase64Encoding]; [ret addNItems: [tmpString UTF8StringLength] fromCArray: [tmpString UTF8String]]; - [ret retain]; - [pool release]; - - return [ret autorelease]; -} - -- (void)parseServerFinalMessage: (OFDataArray*)message -{ - 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)]; + return ret; +} + +- (OFDataArray*)XMPP_parseServerFinalMessage: (OFDataArray*)data +{ + 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]]) @throw [XMPPAuthFailedException 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 { uint8_t buf[64];