static char *make_nonce(const struct timeval *tv) { char *buf = NULL; size_t size = 0, offset = 0; MD5_CTX md5; unsigned char hashbuf[MD5_DIGEST_LENGTH]; char hash_hex[MD5_DIGEST_LENGTH * 2 + 1]; char time_buf[32]; /* Crash if someone forgot to call http_digest_init_secret. */ if (!secret_initialized) bye("Server secret not initialized for Digest authentication. Call http_digest_init_secret."); Snprintf(time_buf, sizeof(time_buf), "%lu.%06lu", (long unsigned) tv->tv_sec, (long unsigned) tv->tv_usec); MD5_Init(&md5); MD5_Update(&md5, secret, sizeof(secret)); MD5_Update(&md5, ":", 1); MD5_Update(&md5, time_buf, strlen(time_buf)); MD5_Final(hashbuf, &md5); enhex(hash_hex, hashbuf, sizeof(hashbuf)); strbuf_sprintf(&buf, &size, &offset, "%s-%s", time_buf, hash_hex); return buf; }
/* Arguments are assumed to be non-NULL, with the exception of nc and cnonce, which may be garbage only if qop == QOP_NONE. */ static void make_response(char buf[MD5_DIGEST_LENGTH * 2 + 1], const char *username, const char *realm, const char *password, const char *method, const char *uri, const char *nonce, enum http_digest_qop qop, const char *nc, const char *cnonce) { char HA1_hex[MD5_DIGEST_LENGTH * 2 + 1], HA2_hex[MD5_DIGEST_LENGTH * 2 + 1]; unsigned char hashbuf[MD5_DIGEST_LENGTH]; MD5_CTX md5; /* Calculate H(A1). */ MD5_Init(&md5); MD5_Update(&md5, username, strlen(username)); MD5_Update(&md5, ":", 1); MD5_Update(&md5, realm, strlen(realm)); MD5_Update(&md5, ":", 1); MD5_Update(&md5, password, strlen(password)); MD5_Final(hashbuf, &md5); enhex(HA1_hex, hashbuf, sizeof(hashbuf)); /* Calculate H(A2). */ MD5_Init(&md5); MD5_Update(&md5, method, strlen(method)); MD5_Update(&md5, ":", 1); MD5_Update(&md5, uri, strlen(uri)); MD5_Final(hashbuf, &md5); enhex(HA2_hex, hashbuf, sizeof(hashbuf)); /* Calculate response. */ MD5_Init(&md5); MD5_Update(&md5, HA1_hex, strlen(HA1_hex)); MD5_Update(&md5, ":", 1); MD5_Update(&md5, nonce, strlen(nonce)); if (qop == QOP_AUTH) { MD5_Update(&md5, ":", 1); MD5_Update(&md5, nc, strlen(nc)); MD5_Update(&md5, ":", 1); MD5_Update(&md5, cnonce, strlen(cnonce)); MD5_Update(&md5, ":", 1); MD5_Update(&md5, "auth", strlen("auth")); } MD5_Update(&md5, ":", 1); MD5_Update(&md5, HA2_hex, strlen(HA2_hex)); MD5_Final(hashbuf, &md5); enhex(buf, hashbuf, sizeof(hashbuf)); }
void hexdump( char *desc, void *addr, int len ) { #define BYTE_LEN (16) // each byte is two characters (00-FF), plus the whitespace inbetween (BYTE_LEN // - 1 spaces) #define BYTE_LEN_HEXED (BYTE_LEN*2 + BYTE_LEN - 1) int i, isZero, beenZero, byte_len, hex_len; unsigned char bytes[BYTE_LEN+1], hexed[BYTE_LEN_HEXED+1]; unsigned char *pc = (unsigned char*)addr; if (desc != NULL) { printf("%s:\n", desc); } beenZero = 0; for (i = 0; i < len; i += byte_len) { hex_len = BYTE_LEN_HEXED; byte_len = MIN(BYTE_LEN, len - i); hexed[0] = '\0'; memcpy(bytes, &pc[i], byte_len); isZero = all_zero(bytes, byte_len); enhex(hexed, hex_len, bytes, byte_len); asciify(bytes, byte_len); if (!isZero) { beenZero = 0; } if (!beenZero) { hexed[hex_len] = '\0'; bytes[byte_len] = '\0'; printf("%04x %-*s %*s\n", i, hex_len, hexed, byte_len, bytes); if (isZero) { beenZero = 1; printf("*\n"); } } } printf("%04x\n", i); }
char *http_digest_proxy_authorization(const struct http_challenge *challenge, const char *username, const char *password, const char *method, const char *uri) { /* For now we authenticate successfully at most once, so we don't need a varying client nonce count. */ static const u32 nc = 0x00000001; char response_hex[MD5_DIGEST_LENGTH * 2 + 1]; unsigned char cnonce[CNONCE_LENGTH]; char cnonce_buf[CNONCE_LENGTH * 2 + 1]; char nc_buf[8 + 1]; char *buf = NULL; size_t size = 0, offset = 0; enum http_digest_qop qop; if (challenge->scheme != AUTH_DIGEST || challenge->realm == NULL || challenge->digest.nonce == NULL || challenge->digest.algorithm != ALGORITHM_MD5) return NULL; if (challenge->digest.qop & QOP_AUTH) { Snprintf(nc_buf, sizeof(nc_buf), "%08x", nc); if (!RAND_status()) return NULL; if (RAND_bytes(cnonce, sizeof(cnonce)) != 1) return NULL; enhex(cnonce_buf, cnonce, sizeof(cnonce)); qop = QOP_AUTH; } else { qop = QOP_NONE; } strbuf_append_str(&buf, &size, &offset, " Digest"); strbuf_append_str(&buf, &size, &offset, " username="******", realm="); append_quoted_string(&buf, &size, &offset, challenge->realm); strbuf_append_str(&buf, &size, &offset, ", nonce="); append_quoted_string(&buf, &size, &offset, challenge->digest.nonce); strbuf_append_str(&buf, &size, &offset, ", uri="); append_quoted_string(&buf, &size, &offset, uri); if (qop == QOP_AUTH) { strbuf_append_str(&buf, &size, &offset, ", qop=auth"); strbuf_append_str(&buf, &size, &offset, ", cnonce="); append_quoted_string(&buf, &size, &offset, cnonce_buf); strbuf_sprintf(&buf, &size, &offset, ", nc=%s", nc_buf); } make_response(response_hex, username, challenge->realm, password, method, uri, challenge->digest.nonce, qop, nc_buf, cnonce_buf); strbuf_append_str(&buf, &size, &offset, ", response="); append_quoted_string(&buf, &size, &offset, response_hex); if (challenge->digest.opaque != NULL) { strbuf_append_str(&buf, &size, &offset, ", opaque="); append_quoted_string(&buf, &size, &offset, challenge->digest.opaque); } strbuf_append_str(&buf, &size, &offset, "\r\n"); return buf; }