@@ -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];