diff options
author | Michael R Sweet <michael.r.sweet@gmail.com> | 2018-08-28 22:47:39 -0400 |
---|---|---|
committer | Michael R Sweet <michael.r.sweet@gmail.com> | 2018-08-28 22:47:39 -0400 |
commit | 3aeb120e10106fafc587d9c50e66909eaba38da1 (patch) | |
tree | 6aa6a3be5a02104e10c47472ddd5db8e536a41d9 /cups/http-support.c | |
parent | 59a8560a52b4a6c8d8bd79c6d3456be040c3f42e (diff) | |
download | cups-3aeb120e10106fafc587d9c50e66909eaba38da1.tar.gz |
Fix issue with HTTP Digest authentication, add unit tests (rdar://41709086)
Diffstat (limited to 'cups/http-support.c')
-rw-r--r-- | cups/http-support.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/cups/http-support.c b/cups/http-support.c index 253590843..9a167cac3 100644 --- a/cups/http-support.c +++ b/cups/http-support.c @@ -662,6 +662,111 @@ httpDecode64_2(char *out, /* I - String to write to */ /* + * '_httpDigest()' - Calculate a Digest authentication response using the + * appropriate RFC 2068/2617/7616 algorithm. + */ + +char * /* O - Response string */ +_httpDigest(char *buffer, /* I - Response buffer */ + size_t bufsize, /* I - Size of response buffer */ + const char *algorithm, /* I - algorithm value or `NULL` */ + const char *username, /* I - username value */ + const char *realm, /* I - realm value */ + const char *password, /* I - password value */ + const char *nonce, /* I - nonce value */ + unsigned nc, /* I - nc value */ + const char *cnonce, /* I - cnonce value or `NULL` */ + const char *qop, /* I - qop value */ + const char *method, /* I - HTTP method */ + const char *resource) /* I - HTTP resource path */ +{ + char ha1[65], /* Hash of username:realm:password */ + ha2[65], /* Hash of method:request-uri */ + temp[1024]; /* Temporary string */ + unsigned char hash[32]; /* Hash buffer */ + const char *hashalg; /* Hashing algorithm */ + size_t hashsize; /* Size of hash */ + + + if (algorithm) + { + /* + * Follow RFC 2617/7616... + */ + + if (!_cups_strcasecmp(algorithm, "MD5")) + { + /* + * RFC 2617 Digest with MD5 + */ + + hashalg = "md5"; + } + else if (!_cups_strcasecmp(algorithm, "SHA-256")) + { + /* + * RFC 7616 Digest with SHA-256 + */ + + hashalg = "sha2-256"; + } + else + { + /* + * Some other algorithm we don't support, skip this one... + */ + + *buffer = '\0'; + + return (NULL); + } + + /* + * Calculate digest value... + */ + + /* H(A1) = H(username:realm:password) */ + snprintf(temp, sizeof(temp), "%s:%s:%s", username, realm, password); + hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, ha1, sizeof(ha1)); + + /* H(A2) = H(method:uri) */ + snprintf(temp, sizeof(temp), "%s:%s", method, resource); + hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, ha2, sizeof(ha2)); + + /* KD = H(H(A1):nonce:nc:cnonce:qop:H(A2)) */ + snprintf(temp, sizeof(temp), "%s:%s:%08x:%s:%s:%s", ha1, nonce, nc, cnonce, qop, ha2); + hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, buffer, bufsize); + } + else + { + /* + * Use old RFC 2069 Digest method... + */ + + /* H(A1) = H(username:realm:password) */ + snprintf(temp, sizeof(temp), "%s:%s:%s", username, realm, password); + hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, ha1, sizeof(ha1)); + + /* H(A2) = H(method:uri) */ + snprintf(temp, sizeof(temp), "%s:%s", method, resource); + hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, ha2, sizeof(ha2)); + + /* KD = H(H(A1):nonce:H(A2)) */ + snprintf(temp, sizeof(temp), "%s:%s:%s", ha1, nonce, ha2); + hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, buffer, bufsize); + } + + return (buffer); +} + + +/* * 'httpEncode64()' - Base64-encode a string. * * This function is deprecated. Use the httpEncode64_2() function instead |