Fix XMPPAuthenticator to support non-optimized message flow
While RFC6120 allows and encourages sending data with the success message it is also legal to send the same data as a challenge and await an empty response. This rework honors that fact.
This commit is contained in:
parent
64f131641f
commit
74727c159c
6 changed files with 83 additions and 69 deletions
|
@ -68,20 +68,13 @@
|
||||||
/**
|
/**
|
||||||
* \return A OFDataAray containing the initial authentication message
|
* \return A OFDataAray containing the initial authentication message
|
||||||
*/
|
*/
|
||||||
- (OFDataArray*)clientFirstMessage;
|
- (OFDataArray*)initialMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \param challenge The challenge to generate a response for
|
* \param data The continuation data send by the server
|
||||||
* \return The response to the given challenge
|
* \return The appropriate response if the data was a challenge, nil otherwise
|
||||||
*/
|
*/
|
||||||
- (OFDataArray*)calculateResponseWithChallenge: (OFDataArray*)challenge;
|
- (OFDataArray*)continueWithData: (OFDataArray*)data;
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the servers final message was valid
|
|
||||||
*
|
|
||||||
* \param message The servers final message
|
|
||||||
*/
|
|
||||||
- (void)parseServerFinalMessage: (OFDataArray*)message;
|
|
||||||
|
|
||||||
- (void)setAuthzid: (OFString*)authzid;
|
- (void)setAuthzid: (OFString*)authzid;
|
||||||
- (OFString*)authzid;
|
- (OFString*)authzid;
|
||||||
|
|
|
@ -93,21 +93,13 @@
|
||||||
return [[password copy] autorelease];
|
return [[password copy] autorelease];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (OFDataArray*)clientFirstMessage
|
- (OFDataArray*)initialMessage
|
||||||
{
|
{
|
||||||
@throw [OFNotImplementedException newWithClass: isa
|
return nil;
|
||||||
selector: _cmd];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (OFDataArray*)calculateResponseWithChallenge: (OFDataArray*)challenge
|
- (OFDataArray*)continueWithData: (OFDataArray*)challenge
|
||||||
{
|
{
|
||||||
@throw [OFNotImplementedException newWithClass: isa
|
return nil;
|
||||||
selector: _cmd];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)parseServerFinalMessage: (OFDataArray*)message
|
|
||||||
{
|
|
||||||
@throw [OFNotImplementedException newWithClass: isa
|
|
||||||
selector: _cmd];
|
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -619,19 +619,26 @@
|
||||||
OFDataArray *challenge = [OFDataArray
|
OFDataArray *challenge = [OFDataArray
|
||||||
dataArrayWithBase64EncodedString: [element stringValue]];
|
dataArrayWithBase64EncodedString: [element stringValue]];
|
||||||
OFDataArray *response = [authModule
|
OFDataArray *response = [authModule
|
||||||
calculateResponseWithChallenge: challenge];
|
continueWithData: challenge];
|
||||||
|
|
||||||
responseTag = [OFXMLElement elementWithName: @"response"
|
responseTag = [OFXMLElement elementWithName: @"response"
|
||||||
namespace: XMPP_NS_SASL];
|
namespace: XMPP_NS_SASL];
|
||||||
[responseTag addChild: [OFXMLElement elementWithCharacters:
|
if (response) {
|
||||||
[response stringByBase64Encoding]]];
|
if ([response count] == 0)
|
||||||
|
[responseTag addChild: [OFXMLElement
|
||||||
|
elementWithCharacters: @"="]];
|
||||||
|
else
|
||||||
|
[responseTag addChild: [OFXMLElement
|
||||||
|
elementWithCharacters: [response
|
||||||
|
stringByBase64Encoding]]];
|
||||||
|
}
|
||||||
|
|
||||||
[self sendStanza: responseTag];
|
[self sendStanza: responseTag];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([[element name] isEqual: @"success"]) {
|
if ([[element name] isEqual: @"success"]) {
|
||||||
[authModule parseServerFinalMessage: [OFDataArray
|
[authModule continueWithData: [OFDataArray
|
||||||
dataArrayWithBase64EncodedString: [element stringValue]]];
|
dataArrayWithBase64EncodedString: [element stringValue]]];
|
||||||
|
|
||||||
if ([delegate respondsToSelector:
|
if ([delegate respondsToSelector:
|
||||||
|
@ -780,13 +787,20 @@
|
||||||
- (void)XMPP_sendAuth: (OFString*)authName
|
- (void)XMPP_sendAuth: (OFString*)authName
|
||||||
{
|
{
|
||||||
OFXMLElement *authTag;
|
OFXMLElement *authTag;
|
||||||
|
OFDataArray *initialMessage = [authModule initialMessage];
|
||||||
|
|
||||||
authTag = [OFXMLElement elementWithName: @"auth"
|
authTag = [OFXMLElement elementWithName: @"auth"
|
||||||
namespace: XMPP_NS_SASL];
|
namespace: XMPP_NS_SASL];
|
||||||
[authTag addAttributeWithName: @"mechanism"
|
[authTag addAttributeWithName: @"mechanism"
|
||||||
stringValue: authName];
|
stringValue: authName];
|
||||||
|
if (initialMessage) {
|
||||||
|
if ([initialMessage count] == 0)
|
||||||
|
[authTag addChild: [OFXMLElement
|
||||||
|
elementWithCharacters: @"="]];
|
||||||
|
else
|
||||||
[authTag addChild: [OFXMLElement elementWithCharacters:
|
[authTag addChild: [OFXMLElement elementWithCharacters:
|
||||||
[[authModule clientFirstMessage] stringByBase64Encoding]]];
|
[initialMessage stringByBase64Encoding]]];
|
||||||
|
}
|
||||||
|
|
||||||
[self sendStanza: authTag];
|
[self sendStanza: authTag];
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
password: password] autorelease];
|
password: password] autorelease];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (OFDataArray*)clientFirstMessage
|
- (OFDataArray*)initialMessage
|
||||||
{
|
{
|
||||||
OFDataArray *message = [OFDataArray dataArrayWithItemSize: 1];
|
OFDataArray *message = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
|
|
||||||
|
@ -68,17 +68,4 @@
|
||||||
|
|
||||||
return message;
|
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
|
@end
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
OFDataArray *serverSignature;
|
OFDataArray *serverSignature;
|
||||||
XMPPConnection *connection;
|
XMPPConnection *connection;
|
||||||
BOOL plusAvailable;
|
BOOL plusAvailable;
|
||||||
|
BOOL authenticated;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -114,4 +115,6 @@
|
||||||
- (OFDataArray*)XMPP_hiWithData: (OFDataArray *)str
|
- (OFDataArray*)XMPP_hiWithData: (OFDataArray *)str
|
||||||
salt: (OFDataArray *)salt_
|
salt: (OFDataArray *)salt_
|
||||||
iterationCount: (intmax_t)i;
|
iterationCount: (intmax_t)i;
|
||||||
|
- (OFDataArray*)XMPP_parseServerFirstMessage: (OFDataArray*)data;
|
||||||
|
- (OFDataArray*)XMPP_parseServerFinalMessage: (OFDataArray*)data;
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -143,12 +143,18 @@
|
||||||
[old release];
|
[old release];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (OFDataArray*)clientFirstMessage
|
- (OFDataArray*)initialMessage
|
||||||
{
|
{
|
||||||
OFDataArray *ret = [OFDataArray dataArrayWithItemSize: 1];
|
OFDataArray *ret = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
|
|
||||||
|
/* New authentication attempt, reset status */
|
||||||
|
[cNonce release];
|
||||||
|
cNonce = nil;
|
||||||
[GS2Header release];
|
[GS2Header release];
|
||||||
GS2Header = nil;
|
GS2Header = nil;
|
||||||
|
[serverSignature release];
|
||||||
|
serverSignature = nil;
|
||||||
|
authenticated = NO;
|
||||||
|
|
||||||
if (authzid)
|
if (authzid)
|
||||||
GS2Header = [[OFString alloc]
|
GS2Header = [[OFString alloc]
|
||||||
|
@ -158,8 +164,6 @@
|
||||||
else
|
else
|
||||||
GS2Header = (plusAvailable ? @"p=tls-unique,," : @"y,,");
|
GS2Header = (plusAvailable ? @"p=tls-unique,," : @"y,,");
|
||||||
|
|
||||||
[cNonce release];
|
|
||||||
cNonce = nil;
|
|
||||||
cNonce = [[self XMPP_genNonce] retain];
|
cNonce = [[self XMPP_genNonce] retain];
|
||||||
|
|
||||||
[clientFirstMessageBare release];
|
[clientFirstMessageBare release];
|
||||||
|
@ -174,10 +178,27 @@
|
||||||
[ret addNItems: [clientFirstMessageBare UTF8StringLength]
|
[ret addNItems: [clientFirstMessageBare UTF8StringLength]
|
||||||
fromCArray: [clientFirstMessageBare UTF8String]];
|
fromCArray: [clientFirstMessageBare UTF8String]];
|
||||||
|
|
||||||
|
|
||||||
return ret;
|
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;
|
size_t i;
|
||||||
uint8_t *clientKey, *serverKey, *clientSignature;
|
uint8_t *clientKey, *serverKey, *clientSignature;
|
||||||
|
@ -185,7 +206,6 @@
|
||||||
OFHash *hash;
|
OFHash *hash;
|
||||||
OFDataArray *ret, *authMessage, *tmpArray, *salt = nil, *saltedPassword;
|
OFDataArray *ret, *authMessage, *tmpArray, *salt = nil, *saltedPassword;
|
||||||
OFString *tmpString, *sNonce = nil;
|
OFString *tmpString, *sNonce = nil;
|
||||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
|
||||||
OFEnumerator *enumerator;
|
OFEnumerator *enumerator;
|
||||||
OFString *comp;
|
OFString *comp;
|
||||||
enum {
|
enum {
|
||||||
|
@ -198,9 +218,9 @@
|
||||||
ret = [OFDataArray dataArrayWithItemSize: 1];
|
ret = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
authMessage = [OFDataArray dataArrayWithItemSize: 1];
|
authMessage = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
|
|
||||||
OFString *chal = [OFString stringWithUTF8String: [challenge cArray]
|
OFString *chal = [OFString stringWithUTF8String: [data cArray]
|
||||||
length: [challenge count] *
|
length: [data count] *
|
||||||
[challenge itemSize]];
|
[data itemSize]];
|
||||||
|
|
||||||
enumerator =
|
enumerator =
|
||||||
[[chal componentsSeparatedByString: @","] objectEnumerator];
|
[[chal componentsSeparatedByString: @","] objectEnumerator];
|
||||||
|
@ -253,14 +273,14 @@
|
||||||
[ret addNItems: [sNonce UTF8StringLength]
|
[ret addNItems: [sNonce UTF8StringLength]
|
||||||
fromCArray: [sNonce UTF8String]];
|
fromCArray: [sNonce UTF8String]];
|
||||||
|
|
||||||
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
|
||||||
[tmpArray addNItems: [password UTF8StringLength]
|
|
||||||
fromCArray: [password UTF8String]];
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IETF RFC 5802:
|
* IETF RFC 5802:
|
||||||
* SaltedPassword := Hi(Normalize(password), salt, i)
|
* SaltedPassword := Hi(Normalize(password), salt, i)
|
||||||
*/
|
*/
|
||||||
|
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
|
[tmpArray addNItems: [password UTF8StringLength]
|
||||||
|
fromCArray: [password UTF8String]];
|
||||||
|
|
||||||
saltedPassword = [self XMPP_hiWithData: tmpArray
|
saltedPassword = [self XMPP_hiWithData: tmpArray
|
||||||
salt: salt
|
salt: salt
|
||||||
iterationCount: iterCount];
|
iterationCount: iterCount];
|
||||||
|
@ -274,8 +294,8 @@
|
||||||
[authMessage addNItems: [clientFirstMessageBare UTF8StringLength]
|
[authMessage addNItems: [clientFirstMessageBare UTF8StringLength]
|
||||||
fromCArray: [clientFirstMessageBare UTF8String]];
|
fromCArray: [clientFirstMessageBare UTF8String]];
|
||||||
[authMessage addItem: ","];
|
[authMessage addItem: ","];
|
||||||
[authMessage addNItems: [challenge count] * [challenge itemSize]
|
[authMessage addNItems: [data count] * [data itemSize]
|
||||||
fromCArray: [challenge cArray]];
|
fromCArray: [data cArray]];
|
||||||
[authMessage addItem: ","];
|
[authMessage addItem: ","];
|
||||||
[authMessage addNItems: [ret count]
|
[authMessage addNItems: [ret count]
|
||||||
fromCArray: [ret cArray]];
|
fromCArray: [ret cArray]];
|
||||||
|
@ -347,20 +367,24 @@
|
||||||
[ret addNItems: [tmpString UTF8StringLength]
|
[ret addNItems: [tmpString UTF8StringLength]
|
||||||
fromCArray: [tmpString UTF8String]];
|
fromCArray: [tmpString UTF8String]];
|
||||||
|
|
||||||
[ret retain];
|
return ret;
|
||||||
[pool release];
|
|
||||||
|
|
||||||
return [ret autorelease];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)parseServerFinalMessage: (OFDataArray*)message
|
- (OFDataArray*)XMPP_parseServerFinalMessage: (OFDataArray*)data
|
||||||
{
|
{
|
||||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
OFString *mess, *value;
|
||||||
OFString *mess = [OFString stringWithUTF8String: [message cArray]
|
|
||||||
length: [message count] *
|
/*
|
||||||
[message itemSize]];
|
* server-final-message already received,
|
||||||
OFString *value = [mess substringWithRange:
|
* we were just waiting for the last word from the server
|
||||||
of_range(2, [mess length] - 2)];
|
*/
|
||||||
|
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 ([mess hasPrefix: @"v="]) {
|
||||||
if (![value isEqual: [serverSignature stringByBase64Encoding]])
|
if (![value isEqual: [serverSignature stringByBase64Encoding]])
|
||||||
|
@ -368,12 +392,13 @@
|
||||||
newWithClass: isa
|
newWithClass: isa
|
||||||
connection: nil
|
connection: nil
|
||||||
reason: @"Received wrong ServerSignature"];
|
reason: @"Received wrong ServerSignature"];
|
||||||
|
authenticated = YES;
|
||||||
} else
|
} else
|
||||||
@throw [XMPPAuthFailedException newWithClass: isa
|
@throw [XMPPAuthFailedException newWithClass: isa
|
||||||
connection: nil
|
connection: nil
|
||||||
reason: value];
|
reason: value];
|
||||||
|
|
||||||
[pool release];
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (OFString*)XMPP_genNonce
|
- (OFString*)XMPP_genNonce
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue