diff --git a/src/sasl.c b/src/sasl.c index 75cf3ac..5378457 100644 --- a/src/sasl.c +++ b/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;