Index: src/XMPPConnection.h ================================================================== --- src/XMPPConnection.h +++ src/XMPPConnection.h @@ -71,10 +71,11 @@ XMPPJID *JID; uint16_t port; id delegate; XMPPAuthenticator *authModule; BOOL needsSession; + BOOL encrypted; unsigned int lastID; OFString *bindID, *sessionID; XMPPRoster *roster; } @@ -83,10 +84,11 @@ @property (copy, readonly) XMPPJID *JID; @property (assign) uint16_t port; @property (retain) id delegate; @property (readonly, retain) XMPPRoster *roster; @property (readonly, retain, getter=socket) OFTCPSocket *sock; +@property (readonly) BOOL encrypted; #endif /** * \return A new autoreleased XMPPConnection */ @@ -117,10 +119,15 @@ /** * \return The socket used by the XMPPConnection */ - (OFTCPSocket*)socket; +/** + * \return Whether the connection is encrypted + */ +- (BOOL)encrypted; + /** * Sends an OFXMLElement, usually an XMPPStanza. * * \param element The element to send */ Index: src/XMPPConnection.m ================================================================== --- src/XMPPConnection.m +++ src/XMPPConnection.m @@ -59,10 +59,11 @@ self = [super init]; @try { sock = [[OFTCPSocket alloc] init]; port = 5222; + encrypted = NO; } @catch (id e) { [self release]; @throw e; } @@ -325,10 +326,15 @@ - (OFTCPSocket*)socket { return [[sock retain] autorelease]; } + +- (BOOL)encrypted +{ + return encrypted; +} - (void)sendStanza: (OFXMLElement*)element { of_log(@"Out: %@", element); [sock writeString: [element XMLString]]; @@ -574,10 +580,12 @@ [delegate connectionWillUpgradeToTLS: self]; newSock = [[SSLSocket alloc] initWithSocket: sock]; [sock release]; sock = newSock; + + encrypted = YES; if ([delegate respondsToSelector: @selector(connectionDidUpgradeToTLS:)]) [delegate connectionDidUpgradeToTLS: self]; @@ -708,21 +716,34 @@ OFXMLElement *mech; enumerator = [[mechs children] objectEnumerator]; 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]; [self XMPP_sendAuth: @"PLAIN"]; return; Index: src/XMPPSCRAMAuth.h ================================================================== --- src/XMPPSCRAMAuth.h +++ src/XMPPSCRAMAuth.h @@ -20,10 +20,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ #import #import "XMPPAuthenticator.h" +#import "XMPPConnection.h" /** * \brief A class to authenticate using SCRAM */ @interface XMPPSCRAMAuth: XMPPAuthenticator @@ -31,68 +32,86 @@ Class hashType; OFString *cNonce; OFString *GS2Header; OFString *clientFirstMessageBare; OFDataArray *serverSignature; + XMPPConnection *connection; + BOOL plusAvailable; } /** * Creates a new autoreleased 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 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, * authcid and password. * * \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, * authcid and password. * * \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 data: (OFDataArray*)data; - (OFDataArray*)XMPP_hiWithData: (OFDataArray *)str salt: (OFDataArray *)salt_ iterationCount: (intmax_t)i; @end Index: src/XMPPSCRAMAuth.m ================================================================== --- src/XMPPSCRAMAuth.m +++ src/XMPPSCRAMAuth.m @@ -24,14 +24,14 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include - #include - #include + +#import #import "XMPPSCRAMAuth.h" #import "XMPPExceptions.h" #define HMAC_IPAD 0x36 @@ -38,48 +38,64 @@ #define HMAC_OPAD 0x5c @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; } - (void)dealloc @@ -86,10 +102,11 @@ { [GS2Header release]; [clientFirstMessageBare release]; [serverSignature release]; [cNonce release]; + [connection release]; [super dealloc]; } - (void)setAuthzid: (OFString*)authzid_ @@ -132,14 +149,14 @@ [GS2Header release]; 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; cNonce = [[self XMPP_genNonce] retain]; @@ -214,10 +231,16 @@ // Add c= // XXX: No channel binding for now 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="]; [ret addNItems: [tmpString cStringLength] fromCArray: [tmpString cString]];