A little cleanup work. Still needs a configure script.
This commit is contained in:
parent
ba13fa3e3a
commit
c44fefa67c
5 changed files with 318 additions and 249 deletions
|
@ -1,6 +1,6 @@
|
|||
all:
|
||||
objfw-compile -Wall --lib 0.0 -o objxmpp *.m \
|
||||
`pkg-config --cflags --libs libidn libbsd`
|
||||
`pkg-config --cflags --libs libidn`
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so *.dylib *.dll
|
||||
|
|
|
@ -43,16 +43,21 @@
|
|||
- (OFDataArray*)clientFirstMessage
|
||||
{
|
||||
OFDataArray *message = [OFDataArray dataArrayWithItemSize: 1];
|
||||
|
||||
/* authzid */
|
||||
if (authzid)
|
||||
[message addItem: authzid];
|
||||
|
||||
/* separator */
|
||||
[message addItem: ""];
|
||||
|
||||
/* authcid */
|
||||
[message addNItems: [authcid cStringLength]
|
||||
fromCArray: [authcid cString]];
|
||||
|
||||
/* separator */
|
||||
[message addItem: ""];
|
||||
|
||||
/* passwd */
|
||||
[message addNItems: [password cStringLength]
|
||||
fromCArray: [password cString]];
|
||||
|
@ -62,10 +67,10 @@
|
|||
|
||||
- (OFDataArray*)calculateResponseWithChallenge: (OFDataArray*)challenge
|
||||
{
|
||||
@throw [XMPPAuthFailedException
|
||||
newWithClass: isa
|
||||
@throw [XMPPAuthFailedException newWithClass: isa
|
||||
connection: nil
|
||||
reason: @"Received a challenge during PLAIN auth"];
|
||||
reason: @"Received a challenge "
|
||||
@"during PLAIN auth"];
|
||||
}
|
||||
|
||||
- (void)parseServerFinalMessage: (OFDataArray*)message
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2011, Florian Zeitz <florob@babelmonkeys.de>
|
||||
* Copyright (c) 2011, Jonathan Schleifer <js@webkeks.org>
|
||||
*
|
||||
* https://webkeks.org/hg/objxmpp/
|
||||
*
|
||||
|
@ -21,10 +22,6 @@
|
|||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <bsd/stdlib.h>
|
||||
// FIXME: Remove this once libbsd includes arc4random_uniform() in it's headers
|
||||
#define fake_arc4random_uniform(upper) \
|
||||
((uint32_t) (arc4random() / (double) UINT32_MAX * upper))
|
||||
|
||||
#import "XMPPSCRAMAuth.h"
|
||||
#import "XMPPExceptions.h"
|
||||
|
@ -32,8 +29,11 @@
|
|||
#define HMAC_IPAD 0x36
|
||||
#define HMAC_OPAD 0x5c
|
||||
|
||||
@implementation XMPPSCRAMAuth
|
||||
#ifndef HAVE_ARC4RANDOM_UNIFORM
|
||||
extern uint32_t arc4random_uniform(uint32_t);
|
||||
#endif
|
||||
|
||||
@implementation XMPPSCRAMAuth
|
||||
+ SCRAMAuthWithAuthcid: (OFString*)authcid
|
||||
password: (OFString*)password
|
||||
hash: (Class)hash;
|
||||
|
@ -93,14 +93,12 @@
|
|||
OFString *old = authzid;
|
||||
|
||||
if (authzid_) {
|
||||
OFMutableString *new = [[OFMutableString alloc]
|
||||
initWithString: authzid_];
|
||||
OFMutableString *new = [[authzid_ mutableCopy] autorelease];
|
||||
[new replaceOccurrencesOfString: @"="
|
||||
withString: @"=3D"];
|
||||
[new replaceOccurrencesOfString: @","
|
||||
withString: @"=2C"];
|
||||
authzid = [new copy];
|
||||
[new release];
|
||||
authzid = [new retain];
|
||||
} else
|
||||
authzid = nil;
|
||||
|
||||
|
@ -112,44 +110,40 @@
|
|||
OFString *old = authcid;
|
||||
|
||||
if (authcid_) {
|
||||
OFMutableString *new = [[OFMutableString alloc]
|
||||
initWithString: authcid_];
|
||||
OFMutableString *new = [[authcid_ mutableCopy] autorelease];
|
||||
[new replaceOccurrencesOfString: @"="
|
||||
withString: @"=3D"];
|
||||
[new replaceOccurrencesOfString: @","
|
||||
withString: @"=2C"];
|
||||
authcid = [new copy];
|
||||
[new release];
|
||||
authcid = [new retain];
|
||||
} else
|
||||
authcid = nil;
|
||||
|
||||
[old release];
|
||||
}
|
||||
|
||||
- (OFString *)_genNonce
|
||||
- (OFString*)_genNonce
|
||||
{
|
||||
OFMutableString *nonce = [OFMutableString string];
|
||||
uint32_t res, i;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
while((res = fake_arc4random_uniform(0x5e) + 0x21) == 0x2C);
|
||||
while ((res = arc4random_uniform('~' - '!' + 1) + '!') == ',');
|
||||
[nonce appendFormat: @"%c", res];
|
||||
}
|
||||
|
||||
return nonce;
|
||||
}
|
||||
|
||||
- (uint8_t *)_hmacWithKey: (OFDataArray*)key
|
||||
- (uint8_t*)_HMACWithKey: (OFDataArray*)key
|
||||
data: (OFDataArray*)data
|
||||
{
|
||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||
OFDataArray *k = [OFDataArray dataArrayWithItemSize: 1];
|
||||
size_t i, kSize, blockSize = [hashType blockSize];
|
||||
uint8_t *kCArray = NULL, *kI = NULL, *kO = NULL;
|
||||
OFAutoreleasePool *pool = nil;
|
||||
OFDataArray *k = nil;
|
||||
OFHash *hash = nil;
|
||||
uint8_t *kCArray, *kI = NULL, *kO = NULL;
|
||||
OFHash *hash;
|
||||
|
||||
@try {
|
||||
pool = [[OFAutoreleasePool alloc] init];
|
||||
k = [OFDataArray dataArrayWithItemSize: 1];
|
||||
if (key.itemSize * key.count > blockSize) {
|
||||
hash = [[[hashType alloc] init] autorelease];
|
||||
[hash updateWithBuffer: [key cArray]
|
||||
|
@ -160,6 +154,7 @@
|
|||
[k addNItems: key.itemSize * key.count
|
||||
fromCArray: [key cArray]];
|
||||
|
||||
@try {
|
||||
kI = [self allocMemoryWithSize: blockSize * sizeof(uint8_t)];
|
||||
memset(kI, HMAC_IPAD, blockSize * sizeof(uint8_t));
|
||||
|
||||
|
@ -187,6 +182,10 @@
|
|||
fromCArray: kO];
|
||||
[k addNItems: [hashType digestSize]
|
||||
fromCArray: [hash digest]];
|
||||
} @finally {
|
||||
[self freeMemory: kI];
|
||||
[self freeMemory: kO];
|
||||
}
|
||||
|
||||
hash = [[[hashType alloc] init] autorelease];
|
||||
[hash updateWithBuffer: [k cArray]
|
||||
|
@ -194,82 +193,83 @@
|
|||
|
||||
[hash retain];
|
||||
[pool release];
|
||||
pool = nil;
|
||||
[hash autorelease];
|
||||
|
||||
return [hash digest];
|
||||
} @finally {
|
||||
[pool release];
|
||||
[self freeMemory: kI];
|
||||
[self freeMemory: kO];
|
||||
}
|
||||
}
|
||||
|
||||
- (OFDataArray *)_hiWithData: (OFDataArray *)str
|
||||
- (OFDataArray*)_hiWithData: (OFDataArray *)str
|
||||
salt: (OFDataArray *)salt_
|
||||
iterationCount: (unsigned int)i
|
||||
{
|
||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||
size_t digestSize = [hashType digestSize];
|
||||
uint8_t *result = NULL, *u, *uOld;
|
||||
unsigned int j, k;
|
||||
size_t digestSize;
|
||||
OFAutoreleasePool *pool = nil;
|
||||
OFDataArray *salty, *tmp, *ret;
|
||||
|
||||
result = [self allocMemoryWithSize: digestSize];
|
||||
|
||||
@try {
|
||||
pool = [[OFAutoreleasePool alloc] init];
|
||||
digestSize = [hashType digestSize];
|
||||
result = [self
|
||||
allocMemoryWithSize: digestSize * sizeof(uint8_t)];
|
||||
memset(result, 0, digestSize * sizeof(uint8_t));
|
||||
salty = [salt_ copy];
|
||||
memset(result, 0, digestSize);
|
||||
|
||||
salty = [[salt_ copy] autorelease];
|
||||
[salty addNItems: 4
|
||||
fromCArray: "\0\0\0\1"];
|
||||
|
||||
uOld = [self _hmacWithKey: str
|
||||
uOld = [self _HMACWithKey: str
|
||||
data: salty];
|
||||
[salty release];
|
||||
|
||||
for (j = 0; j < digestSize; j++)
|
||||
result[j] ^= uOld[j];
|
||||
|
||||
for (j = 0; j < i-1; j++) {
|
||||
for (j = 0; j < i - 1; j++) {
|
||||
tmp = [OFDataArray dataArrayWithItemSize: 1];
|
||||
[tmp addNItems: digestSize
|
||||
fromCArray: uOld];
|
||||
u = [self _hmacWithKey: str
|
||||
|
||||
u = [self _HMACWithKey: str
|
||||
data: tmp];
|
||||
|
||||
for (k = 0; k < digestSize; k++)
|
||||
result[k] ^= u[k];
|
||||
|
||||
uOld = u;
|
||||
|
||||
[pool releaseObjects];
|
||||
}
|
||||
|
||||
ret = [OFDataArray dataArrayWithItemSize: 1];
|
||||
[ret addNItems: digestSize
|
||||
fromCArray: result];
|
||||
} @finally {
|
||||
[self freeMemory: result];
|
||||
}
|
||||
|
||||
[ret retain];
|
||||
[pool release];
|
||||
pool = nil;
|
||||
|
||||
return [ret autorelease];
|
||||
} @finally {
|
||||
[pool release];
|
||||
[self freeMemory: result];
|
||||
}
|
||||
}
|
||||
|
||||
- (OFDataArray*)clientFirstMessage
|
||||
{
|
||||
OFDataArray *ret = [OFDataArray dataArrayWithItemSize: 1];
|
||||
|
||||
[GS2Header release];
|
||||
GS2Header = nil;
|
||||
|
||||
if (authzid)
|
||||
GS2Header = [[OFString alloc]
|
||||
initWithFormat: @"n,a=%@,", authzid];
|
||||
else
|
||||
GS2Header = [[OFString alloc] initWithFormat: @"n,,"];
|
||||
GS2Header = @"n,,";
|
||||
|
||||
[cNonce release];
|
||||
cNonce = nil;
|
||||
cNonce = [[self _genNonce] retain];
|
||||
|
||||
[clientFirstMessageBare release];
|
||||
clientFirstMessageBare = nil;
|
||||
clientFirstMessageBare = [[OFString alloc]
|
||||
initWithFormat: @"n=%@,r=%@", authcid, cNonce];
|
||||
|
||||
|
@ -292,28 +292,25 @@
|
|||
OFString *tmpString, *sNonce;
|
||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||
|
||||
@try {
|
||||
hash = [[[hashType alloc] init] autorelease];
|
||||
ret = [OFDataArray dataArrayWithItemSize: 1];
|
||||
authMessage = [OFDataArray dataArrayWithItemSize: 1];
|
||||
|
||||
OFString *chal = [OFString
|
||||
stringWithCString: [challenge cArray]
|
||||
length:
|
||||
[challenge count] * [challenge itemSize]];
|
||||
OFString *chal = [OFString stringWithCString: [challenge cArray]
|
||||
length: [challenge count] *
|
||||
[challenge itemSize]];
|
||||
|
||||
for (OFString *comp
|
||||
in [chal componentsSeparatedByString: @","]) {
|
||||
OFString *entry = [comp
|
||||
substringFromIndex: 2
|
||||
for (OFString *comp in [chal componentsSeparatedByString: @","]) {
|
||||
OFString *entry = [comp substringFromIndex: 2
|
||||
toIndex: [comp length]];
|
||||
|
||||
if ([comp hasPrefix: @"r="]) {
|
||||
if (![entry hasPrefix: cNonce])
|
||||
@throw [XMPPAuthFailedException
|
||||
newWithClass: isa
|
||||
connection: nil
|
||||
reason:
|
||||
@"Received wrong nonce"];
|
||||
reason: @"Received wrong nonce"];
|
||||
|
||||
sNonce = entry;
|
||||
} else if ([comp hasPrefix: @"s="])
|
||||
salt = [OFDataArray
|
||||
|
@ -374,7 +371,7 @@
|
|||
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
||||
[tmpArray addNItems: 10
|
||||
fromCArray: "Client Key"];
|
||||
clientKey = [self _hmacWithKey: saltedPassword
|
||||
clientKey = [self _HMACWithKey: saltedPassword
|
||||
data: tmpArray];
|
||||
|
||||
/*
|
||||
|
@ -391,7 +388,7 @@
|
|||
* IETF RFC 5802:
|
||||
* ClientSignature := HMAC(StoredKey, AuthMessage)
|
||||
*/
|
||||
clientSignature = [self _hmacWithKey: tmpArray
|
||||
clientSignature = [self _HMACWithKey: tmpArray
|
||||
data: authMessage];
|
||||
|
||||
/*
|
||||
|
@ -401,7 +398,7 @@
|
|||
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
||||
[tmpArray addNItems: 10
|
||||
fromCArray: "Server Key"];
|
||||
serverKey = [self _hmacWithKey: saltedPassword
|
||||
serverKey = [self _HMACWithKey: saltedPassword
|
||||
data: tmpArray];
|
||||
|
||||
/*
|
||||
|
@ -413,7 +410,7 @@
|
|||
fromCArray: serverKey];
|
||||
serverSignature = [[OFDataArray alloc] initWithItemSize: 1];
|
||||
[serverSignature addNItems: [hashType digestSize]
|
||||
fromCArray: [self _hmacWithKey: tmpArray
|
||||
fromCArray: [self _HMACWithKey: tmpArray
|
||||
data: authMessage]];
|
||||
|
||||
/*
|
||||
|
@ -436,39 +433,30 @@
|
|||
|
||||
[ret retain];
|
||||
[pool release];
|
||||
pool = nil;
|
||||
|
||||
return [ret autorelease];
|
||||
} @finally {
|
||||
[pool release];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)parseServerFinalMessage: (OFDataArray*)message
|
||||
{
|
||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||
@try {
|
||||
OFString *mess = [OFString
|
||||
stringWithCString: [message cArray]
|
||||
length: [message count] * [message itemSize]];
|
||||
|
||||
OFString *mess = [OFString stringWithCString: [message cArray]
|
||||
length: [message count] *
|
||||
[message itemSize]];
|
||||
OFString *value = [mess substringFromIndex: 2
|
||||
toIndex: [mess length]];
|
||||
|
||||
if ([mess hasPrefix: @"v="]) {
|
||||
if ([value compare:
|
||||
[serverSignature stringByBase64Encoding]])
|
||||
if (![value isEqual: [serverSignature stringByBase64Encoding]])
|
||||
@throw [XMPPAuthFailedException
|
||||
newWithClass: isa
|
||||
connection: nil
|
||||
reason:
|
||||
@"Received wrong ServerSignature"];
|
||||
reason: @"Received wrong ServerSignature"];
|
||||
} else
|
||||
@throw [XMPPAuthFailedException newWithClass: isa
|
||||
connection: nil
|
||||
reason: value];
|
||||
} @finally {
|
||||
|
||||
[pool release];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
|
76
src/arc4random_uniform.m
Normal file
76
src/arc4random_uniform.m
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 1996, David Mazieres <dm@uun.org>
|
||||
* Copyright (c) 2008, Damien Miller <djm@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Arc4 random number generator for OpenBSD.
|
||||
*
|
||||
* This code is derived from section 17.1 of Applied Cryptography,
|
||||
* second edition, which describes a stream cipher allegedly
|
||||
* compatible with RSA Labs "RC4" cipher (the actual description of
|
||||
* which is a trade secret). The same algorithm is used as a stream
|
||||
* cipher called "arcfour" in Tatu Ylonen's ssh package.
|
||||
*
|
||||
* RC4 is a registered trademark of RSA Laboratories.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Calculate a uniformly distributed random number less than upper_bound
|
||||
* avoiding "modulo bias".
|
||||
*
|
||||
* Uniformity is achieved by generating new random numbers until the one
|
||||
* returned is outside the range [0, 2**32 % upper_bound). This
|
||||
* guarantees the selected random number will be inside
|
||||
* [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
|
||||
* after reduction modulo upper_bound.
|
||||
*/
|
||||
uint32_t
|
||||
arc4random_uniform(uint32_t upper_bound)
|
||||
{
|
||||
uint32_t r, min;
|
||||
|
||||
if (upper_bound < 2)
|
||||
return 0;
|
||||
|
||||
#if (ULONG_MAX > 0xffffffffUL)
|
||||
min = 0x100000000UL % upper_bound;
|
||||
#else
|
||||
/* Calculate (2**32 % upper_bound) avoiding 64-bit math */
|
||||
if (upper_bound > 0x80000000)
|
||||
min = 1 + ~upper_bound; /* 2**32 - upper_bound */
|
||||
else {
|
||||
/* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
|
||||
min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This could theoretically loop forever but each retry has
|
||||
* p > 0.5 (worst case, usually far better) of selecting a
|
||||
* number inside the range we need, so it should rarely need
|
||||
* to re-roll.
|
||||
*/
|
||||
for (;;) {
|
||||
r = arc4random();
|
||||
if (r >= min)
|
||||
break;
|
||||
}
|
||||
|
||||
return r % upper_bound;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue