diff --git a/src/XMPPConnection.h b/src/XMPPConnection.h index 06b3ee2..262d83a 100644 --- a/src/XMPPConnection.h +++ b/src/XMPPConnection.h @@ -73,6 +73,7 @@ id delegate; XMPPAuthenticator *authModule; BOOL needsSession; + BOOL encrypted; unsigned int lastID; OFString *bindID, *sessionID; XMPPRoster *roster; @@ -85,6 +86,7 @@ @property (retain) id delegate; @property (readonly, retain) XMPPRoster *roster; @property (readonly, retain, getter=socket) OFTCPSocket *sock; +@property (readonly) BOOL encrypted; #endif /** @@ -119,6 +121,11 @@ */ - (OFTCPSocket*)socket; +/** + * \return Whether the connection is encrypted + */ +- (BOOL)encrypted; + /** * Sends an OFXMLElement, usually an XMPPStanza. * diff --git a/src/XMPPConnection.m b/src/XMPPConnection.m index d55cd65..0fac880 100644 --- a/src/XMPPConnection.m +++ b/src/XMPPConnection.m @@ -61,6 +61,7 @@ @try { sock = [[OFTCPSocket alloc] init]; port = 5222; + encrypted = NO; } @catch (id e) { [self release]; @throw e; @@ -328,6 +329,11 @@ return [[sock retain] autorelease]; } +- (BOOL)encrypted +{ + return encrypted; +} + - (void)sendStanza: (OFXMLElement*)element { of_log(@"Out: %@", element); @@ -577,6 +583,8 @@ [sock release]; sock = newSock; + encrypted = YES; + if ([delegate respondsToSelector: @selector(connectionDidUpgradeToTLS:)]) [delegate connectionDidUpgradeToTLS: self]; @@ -711,16 +719,29 @@ while ((mech = [enumerator nextObject]) != nil) [mechanisms addObject: [mech stringValue]]; + if ([mechanisms containsObject: @"SCRAM-SHA-1-PLUS"]) { + authModule = [[XMPPSCRAMAuth alloc] + initWithAuthcid: username + password: password + connection: self + hash: [OFSHA1Hash class] + plusAvailable: YES]; + [self XMPP_sendAuth: @"SCRAM-SHA-1-PLUS"]; + return; + } + if ([mechanisms containsObject: @"SCRAM-SHA-1"]) { authModule = [[XMPPSCRAMAuth alloc] initWithAuthcid: username password: password - hash: [OFSHA1Hash class]]; + connection: self + hash: [OFSHA1Hash class] + plusAvailable: NO]; [self XMPP_sendAuth: @"SCRAM-SHA-1"]; return; } - if ([mechanisms containsObject: @"PLAIN"]) { + if ([mechanisms containsObject: @"PLAIN"] && encrypted) { authModule = [[XMPPPLAINAuth alloc] initWithAuthcid: username password: password]; diff --git a/src/XMPPSCRAMAuth.h b/src/XMPPSCRAMAuth.h index 7c58135..1336bdc 100644 --- a/src/XMPPSCRAMAuth.h +++ b/src/XMPPSCRAMAuth.h @@ -22,6 +22,7 @@ #import #import "XMPPAuthenticator.h" +#import "XMPPConnection.h" /** * \brief A class to authenticate using SCRAM @@ -33,6 +34,8 @@ OFString *GS2Header; OFString *clientFirstMessageBare; OFDataArray *serverSignature; + XMPPConnection *connection; + BOOL plusAvailable; } /** @@ -40,12 +43,16 @@ * * \param authcid The authcid to authenticate with * \param password The password to authenticate with + * \param connection The connection over which authentication is done * \param hash The class to use for calulating hashes + * \param plusAvailable Whether the PLUS variant was offered * \return A new autoreleased XMPPSCRAMAuth */ + SCRAMAuthWithAuthcid: (OFString*)authcid password: (OFString*)password - hash: (Class)hash; + connection: (XMPPConnection*)connection + hash: (Class)hash + plusAvailable: (BOOL)plusAvailable; /** * Creates a new autoreleased XMPPSCRAMAuth with an authzid, @@ -54,25 +61,33 @@ * \param authzid The authzid to get authorization for * \param authcid The authcid to authenticate with * \param password The password to authenticate with + * \param connection The connection over which authentication is done * \param hash The class to use for calulating hashes + * \param plusAvailable Whether the PLUS variant was offered * \return A new autoreleased XMPPSCRAMAuth */ + SCRAMAuthWithAuthzid: (OFString*)authzid authcid: (OFString*)authcid password: (OFString*)password - hash: (Class)hash; + connection: (XMPPConnection*)connection + hash: (Class)hash + plusAvailable: (BOOL)plusAvailable; /** * Initializes an already allocated XMPPSCRAMAuth with an authcid and password. * * \param authcid The authcid to authenticate with * \param password The password to authenticate with + * \param connection The connection over which authentication is done * \param hash The class to use for calulating hashes + * \param plusAvailable Whether the PLUS variant was offered * \return A initialized XMPPSCRAMAuth */ - initWithAuthcid: (OFString*)authcid password: (OFString*)password - hash: (Class)hash; + connection: (XMPPConnection*)connection + hash: (Class)hash + plusAvailable: (BOOL)plusAvailable; /** * Initializes an already allocated XMPPSCRAMAuth with a authzid, @@ -81,13 +96,17 @@ * \param authzid The authzid to get authorization for * \param authcid The authcid to authenticate with * \param password The password to authenticate with + * \param connection The connection over which authentication is done * \param hash The class to use for calulating hashes + * \param plusAvailable Whether the PLUS variant was offered * \return A initialized XMPPSCRAMAuth */ - initWithAuthzid: (OFString*)authzid authcid: (OFString*)authcid password: (OFString*)password - hash: (Class)hash; + connection: (XMPPConnection*)connection + hash: (Class)hash + plusAvailable: (BOOL)plusAvailable; - (OFString*)XMPP_genNonce; - (uint8_t*)XMPP_HMACWithKey: (OFDataArray*)key diff --git a/src/XMPPSCRAMAuth.m b/src/XMPPSCRAMAuth.m index 22e6f94..39b83e8 100644 --- a/src/XMPPSCRAMAuth.m +++ b/src/XMPPSCRAMAuth.m @@ -26,11 +26,11 @@ #endif #include - #include - #include +#import + #import "XMPPSCRAMAuth.h" #import "XMPPExceptions.h" @@ -40,44 +40,60 @@ @implementation XMPPSCRAMAuth + SCRAMAuthWithAuthcid: (OFString*)authcid password: (OFString*)password - hash: (Class)hash; + connection: (XMPPConnection*)connection_ + hash: (Class)hash + plusAvailable: (BOOL)plusAvailable_ { return [[[self alloc] initWithAuthcid: authcid password: password - hash: hash] autorelease]; + connection: connection_ + hash: hash + plusAvailable: plusAvailable_] autorelease]; } + SCRAMAuthWithAuthzid: (OFString*)authzid authcid: (OFString*)authcid password: (OFString*)password - hash: (Class)hash; + connection: (XMPPConnection*)connection_ + hash: (Class)hash + plusAvailable: (BOOL)plusAvailable_ { return [[[self alloc] initWithAuthzid: authzid authcid: authcid password: password - hash: hash] autorelease]; + connection: connection_ + hash: hash + plusAvailable: plusAvailable_] autorelease]; } - initWithAuthcid: (OFString*)authcid_ password: (OFString*)password_ - hash: (Class)hash; + connection: (XMPPConnection*)connection_ + hash: (Class)hash + plusAvailable: (BOOL)plusAvailable_ { return [self initWithAuthzid: nil authcid: authcid_ password: password_ - hash: hash]; + connection: connection_ + hash: hash + plusAvailable: plusAvailable_]; } - initWithAuthzid: (OFString*)authzid_ authcid: (OFString*)authcid_ password: (OFString*)password_ - hash: (Class)hash; + connection: (XMPPConnection*)connection_ + hash: (Class)hash + plusAvailable: (BOOL)plusAvailable_ { self = [super initWithAuthzid: authzid_ authcid: authcid_ password: password_]; hashType = hash; + plusAvailable = plusAvailable_; + connection = [connection_ retain]; return self; } @@ -88,6 +104,7 @@ [clientFirstMessageBare release]; [serverSignature release]; [cNonce release]; + [connection release]; [super dealloc]; } @@ -134,10 +151,10 @@ GS2Header = nil; if (authzid) - GS2Header = [[OFString alloc] initWithFormat: @"n,a=%@,", - authzid]; + GS2Header = [[OFString alloc] initWithFormat: @"%@,a=%@,", + (plusAvailable ? @"p=tls-unique" : @"y"), authzid]; else - GS2Header = @"n,,"; + GS2Header = plusAvailable ? @"p=tls-unique,," : @"y,,"; [cNonce release]; cNonce = nil; @@ -216,6 +233,12 @@ tmpArray = [OFDataArray dataArrayWithItemSize: 1]; [tmpArray addNItems: [GS2Header cStringLength] fromCArray: [GS2Header cString]]; + if (plusAvailable && [connection encrypted]) { + OFDataArray *channelBinding = [((SSLSocket*)[connection socket]) + channelBindingDataWithType: @"tls-unique"]; + [tmpArray addNItems: [channelBinding count] + fromCArray: [channelBinding cArray]]; + } tmpString = [tmpArray stringByBase64Encoding]; [ret addNItems: 2 fromCArray: "c="];