ObjXMPP  Check-in [7bcda1b5e6]

Overview
Comment:Add support for SCRAM-SHA-1-PLUS
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 7bcda1b5e6151c8631729cda00abf2146009fb756770830189b53eedc4ece36c
User & Date: florob@babelmonkeys.de on 2011-09-10 14:08:25
Other Links: manifest | tags
Context
2011-09-10
16:17
Use an OFSet for mechanisms. check-in: 8e3aaca400 user: js tags: trunk
14:08
Add support for SCRAM-SHA-1-PLUS check-in: 7bcda1b5e6 user: florob@babelmonkeys.de tags: trunk
2011-09-09
22:10
Fix broken enum used as a bitmap. check-in: 34584bd493 user: js tags: trunk
Changes

Modified src/XMPPConnection.h from [413ddf29d0] to [10b4b0b8c1].

69
70
71
72
73
74
75

76
77
78
79
80
81
82
83
84
85
86
87

88
89
90
91
92
93
94
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96







+












+







	OFXMLElementBuilder *elementBuilder, *oldElementBuilder;
	OFString *username, *password, *server, *domain, *resource;
	XMPPJID *JID;
	uint16_t port;
	id <XMPPConnectionDelegate, OFObject> delegate;
	XMPPAuthenticator *authModule;
	BOOL needsSession;
	BOOL encrypted;
	unsigned int lastID;
	OFString *bindID, *sessionID;
	XMPPRoster *roster;
}

#ifdef OF_HAVE_PROPERTIES
@property (copy) OFString *username, *password, *server, *domain, *resource;
@property (copy, readonly) XMPPJID *JID;
@property (assign) uint16_t port;
@property (retain) id <XMPPConnectionDelegate> delegate;
@property (readonly, retain) XMPPRoster *roster;
@property (readonly, retain, getter=socket) OFTCPSocket *sock;
@property (readonly) BOOL encrypted;
#endif

/**
 * \return A new autoreleased XMPPConnection
 */
+ connection;

115
116
117
118
119
120
121





122
123
124
125
126
127
128
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135







+
+
+
+
+







	 withLength: (size_t)length;

/**
 * \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
 */
- (void)sendStanza: (OFXMLElement*)element;

Modified src/XMPPConnection.m from [3969663589] to [6ede1f3c36].

57
58
59
60
61
62
63

64
65
66
67
68
69
70
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71







+







- init
{
	self = [super init];

	@try {
		sock = [[OFTCPSocket alloc] init];
		port = 5222;
		encrypted = NO;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
323
324
325
326
327
328
329





330
331
332
333
334
335
336
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342







+
+
+
+
+







	oldElementBuilder = nil;
}

- (OFTCPSocket*)socket
{
	return [[sock retain] autorelease];
}

- (BOOL)encrypted
{
	return encrypted;
}

- (void)sendStanza: (OFXMLElement*)element
{
	of_log(@"Out: %@", element);
	[sock writeString: [element XMLString]];
}

572
573
574
575
576
577
578


579
580
581
582
583
584
585
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593







+
+







		if ([delegate respondsToSelector:
		    @selector(connectionWillUpgradeToTLS:)])
			[delegate connectionWillUpgradeToTLS: self];

		newSock = [[SSLSocket alloc] initWithSocket: sock];
		[sock release];
		sock = newSock;

		encrypted = YES;

		if ([delegate respondsToSelector:
		    @selector(connectionDidUpgradeToTLS:)])
			[delegate connectionDidUpgradeToTLS: self];

		/* Stream restart */
		[self XMPP_startStream];
706
707
708
709
710
711
712











713
714
715
716
717

718


719
720
721
722
723

724
725
726
727
728
729
730
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737

738
739
740
741
742
743

744
745
746
747
748
749
750
751







+
+
+
+
+
+
+
+
+
+
+





+
-
+
+




-
+







	if (mechs != nil) {
		OFEnumerator *enumerator;
		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
				 connection: self
				       hash: [OFSHA1Hash class]];
				       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;
		}

Modified src/XMPPSCRAMAuth.h from [888f15c064] to [92e99aa4e3].

18
19
20
21
22
23
24

25
26
27
28
29
30
31
32
33
34
35


36
37
38
39
40
41
42

43

44
45
46
47

48


49
50
51
52
53
54
55
56

57

58
59
60
61
62

63


64
65
66
67
68
69

70

71
72
73
74

75


76
77
78
79
80
81
82
83

84

85
86
87
88
89

90


91
92
93
94
95
96
97
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

108
109
110
111
112
113
114
115
116







+











+
+







+

+




+
-
+
+








+

+





+
-
+
+






+

+




+
-
+
+








+

+





+
-
+
+







 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import <ObjFW/ObjFW.h>
#import "XMPPAuthenticator.h"
#import "XMPPConnection.h"

/**
 * \brief A class to authenticate using SCRAM
 */
@interface XMPPSCRAMAuth: XMPPAuthenticator
{
	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
	    connection: (XMPPConnection*)connection
		  hash: (Class)hash;
		  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
	    connection: (XMPPConnection*)connection
		  hash: (Class)hash;
		  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
       connection: (XMPPConnection*)connection
	     hash: (Class)hash;
	     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
       connection: (XMPPConnection*)connection
	     hash: (Class)hash;
	     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;

Modified src/XMPPSCRAMAuth.m from [c846c79eb6] to [87baaa29de].

22
23
24
25
26
27
28
29
30

31
32

33
34
35
36
37
38
39
40
41
42

43


44
45
46

47


48
49
50
51
52

53


54
55
56
57

58


59
60
61
62

63


64
65
66
67

68


69
70
71
72
73

74


75
76
77
78
79
80


81
82
83
84
85
86
87
88
89
90

91
92
93
94
95
96
97
22
23
24
25
26
27
28

29
30
31

32
33
34
35
36
37
38
39
40
41
42
43

44
45
46
47
48
49

50
51
52
53
54
55
56
57

58
59
60
61
62
63
64

65
66
67
68
69
70
71

72
73
74
75
76
77
78

79
80
81
82
83
84
85
86

87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114







-

+

-
+










+
-
+
+



+
-
+
+





+
-
+
+




+
-
+
+




+
-
+
+




+
-
+
+





+
-
+
+






+
+










+







 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <string.h>

#include <assert.h>
#include <openssl/rand.h>

#include <openssl/rand.h>
#import <ObjOpenSSL/SSLSocket.h>

#import "XMPPSCRAMAuth.h"
#import "XMPPExceptions.h"

#define HMAC_IPAD 0x36
#define HMAC_OPAD 0x5c

@implementation XMPPSCRAMAuth
+ SCRAMAuthWithAuthcid: (OFString*)authcid
	      password: (OFString*)password
	    connection: (XMPPConnection*)connection_
		  hash: (Class)hash;
		  hash: (Class)hash
	 plusAvailable: (BOOL)plusAvailable_
{
	return [[[self alloc] initWithAuthcid: authcid
				     password: password
				   connection: connection_
					 hash: hash] autorelease];
					 hash: hash
				plusAvailable: plusAvailable_] autorelease];
}

+ SCRAMAuthWithAuthzid: (OFString*)authzid
	       authcid: (OFString*)authcid
	      password: (OFString*)password
	    connection: (XMPPConnection*)connection_
		  hash: (Class)hash;
		  hash: (Class)hash
	 plusAvailable: (BOOL)plusAvailable_
{
	return [[[self alloc] initWithAuthzid: authzid
				      authcid: authcid
				     password: password
				   connection: connection_
					 hash: hash] autorelease];
					 hash: hash
				plusAvailable: plusAvailable_] autorelease];
}

- initWithAuthcid: (OFString*)authcid_
	 password: (OFString*)password_
       connection: (XMPPConnection*)connection_
	     hash: (Class)hash;
	     hash: (Class)hash
    plusAvailable: (BOOL)plusAvailable_
{
	return [self initWithAuthzid: nil
			     authcid: authcid_
			    password: password_
			  connection: connection_
				hash: hash];
				hash: hash
		       plusAvailable: plusAvailable_];
}

- initWithAuthzid: (OFString*)authzid_
	  authcid: (OFString*)authcid_
	 password: (OFString*)password_
       connection: (XMPPConnection*)connection_
	     hash: (Class)hash;
	     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
{
	[GS2Header release];
	[clientFirstMessageBare release];
	[serverSignature release];
	[cNonce release];
	[connection release];

	[super dealloc];
}

- (void)setAuthzid: (OFString*)authzid_
{
	OFString *old = authzid;
130
131
132
133
134
135
136
137
138


139
140

141
142
143
144
145
146
147
147
148
149
150
151
152
153


154
155
156

157
158
159
160
161
162
163
164







-
-
+
+

-
+







{
	OFDataArray *ret = [OFDataArray dataArrayWithItemSize: 1];

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

	[clientFirstMessageBare release];
	clientFirstMessageBare = nil;
212
213
214
215
216
217
218






219
220
221
222
223
224
225
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248







+
+
+
+
+
+







		@throw [OFInvalidServerReplyException newWithClass: isa];

	// Add c=<base64(GS2Header+channelBindingData)>
	// 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]];

	// Add r=<nonce>