Fix #3: broken DIGEST-MD5 auth with ejabberd.
This commit is contained in:
49
src/sasl.c
49
src/sasl.c
@@ -128,11 +128,10 @@ static hash_t *_parse_digest_challenge(xmpp_ctx_t *ctx, const char *msg)
|
||||
t++;
|
||||
while ((*t != *s) && (*t != '\0'))
|
||||
t++;
|
||||
value = _make_string(ctx, (char *)s+1, (t-s-1));
|
||||
if (*t == *s) {
|
||||
value = _make_string(ctx, (char *)s+1, (t-s-2));
|
||||
s = t + 1;
|
||||
} else {
|
||||
value = _make_string(ctx, (char *)s+1, (t-s-1));
|
||||
s = t;
|
||||
}
|
||||
/* otherwise, accumulate a value ending in ',' or '\0' */
|
||||
@@ -189,7 +188,7 @@ static char *_add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key,
|
||||
value = hash_get(table, key);
|
||||
if (value == NULL) {
|
||||
xmpp_error(ctx, "SASL", "couldn't retrieve value for '%s'", key);
|
||||
value = "\"\"";
|
||||
value = "";
|
||||
}
|
||||
if (quote) {
|
||||
qvalue = _make_quoted(ctx, value);
|
||||
@@ -222,13 +221,12 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
||||
const char *jid, const char *password) {
|
||||
hash_t *table;
|
||||
char *result = NULL;
|
||||
char *node, *domain;
|
||||
char *node, *domain, *realm;
|
||||
char *value;
|
||||
unsigned char *A1, *A2; /* MD5 hashed versions */
|
||||
char *response;
|
||||
int rlen;
|
||||
struct MD5Context MD5;
|
||||
unsigned char digest[16];
|
||||
unsigned char digest[16], HA1[16], HA2[16];
|
||||
char hex[32];
|
||||
|
||||
/* our digest response is
|
||||
@@ -237,7 +235,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
||||
))
|
||||
|
||||
where KD(k, s) = MD5(k ':' s),
|
||||
A1 = MD5( node ':' domain ':' password ) ':' nonce ':' cnonce
|
||||
A1 = MD5( node ':' realm ':' password ) ':' nonce ':' cnonce
|
||||
A2 = "AUTHENTICATE" ':' "xmpp/" domain
|
||||
|
||||
If there is an authzid it is ':'-appended to A1 */
|
||||
@@ -252,6 +250,14 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
||||
node = xmpp_jid_node(ctx, jid);
|
||||
domain = xmpp_jid_domain(ctx, jid);
|
||||
|
||||
/* generate default realm of domain if one didn't come from the
|
||||
server */
|
||||
realm = hash_get(table, "realm");
|
||||
if (realm == NULL || strlen(realm) == 0) {
|
||||
hash_add(table, "realm", xmpp_strdup(ctx, domain));
|
||||
realm = hash_get(table, "realm");
|
||||
}
|
||||
|
||||
/* add our response fields */
|
||||
hash_add(table, "username", xmpp_strdup(ctx, node));
|
||||
/* TODO: generate a random cnonce */
|
||||
@@ -266,17 +272,19 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
||||
|
||||
/* generate response */
|
||||
|
||||
/* construct MD5(A1) */
|
||||
/* construct MD5(node : realm : password) */
|
||||
MD5Init(&MD5);
|
||||
MD5Update(&MD5, (unsigned char *)node, strlen(node));
|
||||
MD5Update(&MD5, (unsigned char *)":", 1);
|
||||
MD5Update(&MD5, (unsigned char *)domain, strlen(domain));
|
||||
MD5Update(&MD5, (unsigned char *)realm, strlen(realm));
|
||||
MD5Update(&MD5, (unsigned char *)":", 1);
|
||||
MD5Update(&MD5, (unsigned char *)password, strlen(password));
|
||||
MD5Final(digest, &MD5);
|
||||
|
||||
/* digest now contains the first field of A1 */
|
||||
|
||||
MD5Init(&MD5);
|
||||
MD5Update(&MD5, (unsigned char *)digest, 16);
|
||||
MD5Update(&MD5, digest, 16);
|
||||
MD5Update(&MD5, (unsigned char *)":", 1);
|
||||
value = hash_get(table, "nonce");
|
||||
MD5Update(&MD5, (unsigned char *)value, strlen(value));
|
||||
@@ -285,28 +293,32 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
||||
MD5Update(&MD5, (unsigned char *)value, strlen(value));
|
||||
MD5Final(digest, &MD5);
|
||||
|
||||
A1 = xmpp_alloc(ctx, 16);
|
||||
memcpy(A1, digest, 16);
|
||||
/* now digest is MD5(A1) */
|
||||
memcpy(HA1, digest, 16);
|
||||
|
||||
/* construct MD5(A2) */
|
||||
MD5Init(&MD5);
|
||||
MD5Update(&MD5, (unsigned char *)"AUTHENTICATE:", 13);
|
||||
value = hash_get(table, "digest-uri");
|
||||
MD5Update(&MD5, (unsigned char *)value, strlen(value));
|
||||
if (strcmp(hash_get(table, "qop"), "auth") != 0) {
|
||||
MD5Update(&MD5, (unsigned char *)":00000000000000000000000000000000",
|
||||
33);
|
||||
}
|
||||
MD5Final(digest, &MD5);
|
||||
|
||||
A2 = xmpp_alloc(ctx, 16);
|
||||
memcpy(A2, digest, 16);
|
||||
memcpy(HA2, digest, 16);
|
||||
|
||||
/* construct response */
|
||||
MD5Init(&MD5);
|
||||
_digest_to_hex((char *)A1, hex);
|
||||
_digest_to_hex((char *)HA1, hex);
|
||||
MD5Update(&MD5, (unsigned char *)hex, 32);
|
||||
MD5Update(&MD5, (unsigned char *)":", 1);
|
||||
value = hash_get(table, "nonce");
|
||||
MD5Update(&MD5, (unsigned char *)value, strlen(value));
|
||||
MD5Update(&MD5, (unsigned char *)":", 1);
|
||||
MD5Update(&MD5, (unsigned char *)"00000001", 8);
|
||||
value = hash_get(table, "nc");
|
||||
MD5Update(&MD5, (unsigned char *)value, strlen(value));
|
||||
MD5Update(&MD5, (unsigned char *)":", 1);
|
||||
value = hash_get(table, "cnonce");
|
||||
MD5Update(&MD5, (unsigned char *)value, strlen(value));
|
||||
@@ -314,7 +326,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
||||
value = hash_get(table, "qop");
|
||||
MD5Update(&MD5, (unsigned char *)value, strlen(value));
|
||||
MD5Update(&MD5, (unsigned char *)":", 1);
|
||||
_digest_to_hex((char *)A2, hex);
|
||||
_digest_to_hex((char *)HA2, hex);
|
||||
MD5Update(&MD5, (unsigned char *)hex, 32);
|
||||
MD5Final(digest, &MD5);
|
||||
|
||||
@@ -324,9 +336,6 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
||||
response[32] = '\0';
|
||||
hash_add(table, "response", response);
|
||||
|
||||
xmpp_free(ctx, A1);
|
||||
xmpp_free(ctx, A2);
|
||||
|
||||
/* construct reply */
|
||||
result = NULL;
|
||||
rlen = 0;
|
||||
|
||||
Reference in New Issue
Block a user