summaryrefslogtreecommitdiff
path: root/cups
diff options
context:
space:
mode:
authorMichael R Sweet <michael.r.sweet@gmail.com>2018-09-14 13:02:53 -0400
committerMichael R Sweet <michael.r.sweet@gmail.com>2018-09-14 13:02:53 -0400
commit16f67389a8533e9572149189a1340b737fe98a20 (patch)
tree721d34b4a273a29a6c78a95beddcd749496a3ba7 /cups
parent80f5715924d86c6da0aba6474b0d8c78c19a7be2 (diff)
More Digest authentication fixes/improvements.
Diffstat (limited to 'cups')
-rw-r--r--cups/auth.c57
-rw-r--r--cups/getputfile.c87
-rw-r--r--cups/http-private.h11
-rw-r--r--cups/http-support.c100
-rw-r--r--cups/http.c8
-rw-r--r--cups/http.h1
-rw-r--r--cups/request.c18
-rw-r--r--cups/testhttp.c2
8 files changed, 195 insertions, 89 deletions
diff --git a/cups/auth.c b/cups/auth.c
index aeebcdea4..a2651527b 100644
--- a/cups/auth.c
+++ b/cups/auth.c
@@ -1,7 +1,7 @@
/*
* Authentication functions for CUPS.
*
- * Copyright 2007-2017 by Apple Inc.
+ * Copyright 2007-2018 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products.
*
* This file contains Kerberos support code, copyright 2006 by
@@ -113,9 +113,7 @@ cupsDoAuthentication(
*www_auth, /* WWW-Authenticate header */
*schemedata; /* Scheme-specific data */
char scheme[256], /* Scheme name */
- prompt[1024], /* Prompt for user */
- realm[HTTP_MAX_VALUE], /* realm="xyz" string */
- nonce[HTTP_MAX_VALUE]; /* nonce="xyz" string */
+ prompt[1024]; /* Prompt for user */
int localauth; /* Local authentication result */
_cups_globals_t *cg; /* Global data */
@@ -253,6 +251,7 @@ cupsDoAuthentication(
httpEncode64_2(encode, sizeof(encode), http->userpass, (int)strlen(http->userpass));
httpSetAuthString(http, "Basic", encode);
+ break;
}
else if (!_cups_strcasecmp(scheme, "Digest"))
{
@@ -260,13 +259,12 @@ cupsDoAuthentication(
* Digest authentication...
*/
- int i; /* Looping var */
- char algorithm[65], /* Hashing algorithm */
- opaque[HTTP_MAX_VALUE],
- /* Opaque data from server */
- cnonce[65], /* cnonce value */
- kd[65], /* Final MD5/SHA-256 digest */
- digest[1024]; /* Digest auth data */
+ char nonce[HTTP_MAX_VALUE]; /* nonce="xyz" string */
+
+ cups_auth_param(schemedata, "algorithm", http->algorithm, sizeof(http->algorithm));
+ cups_auth_param(schemedata, "opaque", http->opaque, sizeof(http->opaque));
+ cups_auth_param(schemedata, "nonce", nonce, sizeof(nonce));
+ cups_auth_param(schemedata, "realm", http->realm, sizeof(http->realm));
if (strcmp(nonce, http->nonce))
{
@@ -276,41 +274,8 @@ cupsDoAuthentication(
else
http->nonce_count ++;
- cups_auth_param(schemedata, "opaque", opaque, sizeof(opaque));
- cups_auth_param(schemedata, "nonce", nonce, sizeof(nonce));
- cups_auth_param(schemedata, "realm", realm, sizeof(realm));
-
- for (i = 0; i < 64; i ++)
- cnonce[i] = "0123456789ABCDEF"[CUPS_RAND() & 15];
- cnonce[64] = '\0';
-
- if (cups_auth_param(schemedata, "algorithm", algorithm, sizeof(algorithm)))
- {
- /*
- * Calculate and pass the RFC 2617/7616 WWW-Authenticate header...
- */
-
- if (!_httpDigest(kd, sizeof(kd), algorithm, cupsUser(), realm, strchr(http->userpass, ':') + 1, nonce, http->nonce_count, cnonce, "auth", method, resource))
- continue;
-
- if (opaque[0])
- snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", algorithm=%s, qop=auth, opaque=\"%s\", cnonce=\"%s\", nc=%08x, uri=\"%s\", response=\"%s\"", cupsUser(), realm, nonce, algorithm, opaque, cnonce, http->nonce_count, resource, kd);
- else
- snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", algorithm=%s, qop=auth, cnonce=\"%s\", nc=%08x, uri=\"%s\", response=\"%s\"", cupsUser(), realm, nonce, algorithm, cnonce, http->nonce_count, resource, kd);
- }
- else
- {
- /*
- * Calculate and pass the old RFC 2069 WWW-Authenticate header...
- */
-
- if (!_httpDigest(kd, sizeof(kd), NULL, cupsUser(), realm, strchr(http->userpass, ':') + 1, nonce, http->nonce_count, NULL, NULL, method, resource))
- continue;
-
- snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"", cupsUser(), realm, nonce, resource, kd);
- }
-
- httpSetAuthString(http, "Digest", digest);
+ if (_httpSetDigestAuthString(http, method, resource))
+ break;
}
}
diff --git a/cups/getputfile.c b/cups/getputfile.c
index c50cf0d59..ba88973c0 100644
--- a/cups/getputfile.c
+++ b/cups/getputfile.c
@@ -1,10 +1,11 @@
/*
* Get/put file functions for CUPS.
*
- * Copyright 2007-2014 by Apple Inc.
+ * Copyright 2007-2018 by Apple Inc.
* Copyright 1997-2006 by Easy Software Products.
*
- * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
+ * Licensed under Apache License v2.0. See the file "LICENSE" for more
+ * information.
*/
/*
@@ -39,6 +40,8 @@ cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA
http_status_t status; /* HTTP status from server */
char if_modified_since[HTTP_MAX_VALUE];
/* If-Modified-Since header */
+ int new_auth = 0; /* Using new auth information? */
+ int digest; /* Are we using Digest authentication? */
/*
@@ -79,9 +82,42 @@ cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA
}
httpClearFields(http);
- httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE, if_modified_since);
+ digest = http->authstring && !strncmp(http->authstring, "Digest ", 7);
+
+ if (digest && !new_auth)
+ {
+ /*
+ * Update the Digest authentication string...
+ */
+
+ if (http->nextnonce[0])
+ {
+ strlcpy(http->nonce, http->nextnonce, sizeof(http->nonce));
+ http->nonce_count = 1;
+ http->nextnonce[0] = '\0';
+ }
+ else
+ http->nonce_count ++;
+
+ _httpSetDigestAuthString(http, "GET", resource);
+ }
+
+#ifdef HAVE_GSSAPI
+ if (http->authstring && !strncmp(http->authstring, "Negotiate", 9) && !new_auth)
+ {
+ /*
+ * Do not use cached Kerberos credentials since they will look like a
+ * "replay" attack...
+ */
+
+ _cupsSetNegotiateAuthString(http, "GET", resource);
+ }
+#endif /* HAVE_GSSAPI */
+
+ httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
+
if (httpGet(http, resource))
{
if (httpReconnect2(http, 30000, NULL))
@@ -96,6 +132,8 @@ cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA
}
}
+ new_auth = 0;
+
while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE);
if (status == HTTP_STATUS_UNAUTHORIZED)
@@ -110,6 +148,8 @@ cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA
* See if we can do authentication...
*/
+ new_auth = 1;
+
if (cupsDoAuthentication(http, "GET", resource))
{
status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
@@ -261,6 +301,8 @@ cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA
int retries; /* Number of retries */
char buffer[8192]; /* Buffer for file */
http_status_t status; /* HTTP status from server */
+ int new_auth = 0; /* Using new auth information? */
+ int digest; /* Are we using Digest authentication? */
/*
@@ -303,10 +345,43 @@ cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA
http->authstring));
httpClearFields(http);
- httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked");
httpSetExpect(http, HTTP_STATUS_CONTINUE);
+ digest = http->authstring && !strncmp(http->authstring, "Digest ", 7);
+
+ if (digest && !new_auth)
+ {
+ /*
+ * Update the Digest authentication string...
+ */
+
+ if (http->nextnonce[0])
+ {
+ strlcpy(http->nonce, http->nextnonce, sizeof(http->nonce));
+ http->nonce_count = 1;
+ http->nextnonce[0] = '\0';
+ }
+ else
+ http->nonce_count ++;
+
+ _httpSetDigestAuthString(http, "PUT", resource);
+ }
+
+#ifdef HAVE_GSSAPI
+ if (http->authstring && !strncmp(http->authstring, "Negotiate", 9) && !new_auth)
+ {
+ /*
+ * Do not use cached Kerberos credentials since they will look like a
+ * "replay" attack...
+ */
+
+ _cupsSetNegotiateAuthString(http, "PUT", resource);
+ }
+#endif /* HAVE_GSSAPI */
+
+ httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
+
if (httpPut(http, resource))
{
if (httpReconnect2(http, 30000, NULL))
@@ -377,6 +452,8 @@ cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA
DEBUG_printf(("2cupsPutFd: status=%d", status));
+ new_auth = 0;
+
if (status == HTTP_STATUS_UNAUTHORIZED)
{
/*
@@ -389,6 +466,8 @@ cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA
* See if we can do authentication...
*/
+ new_auth = 1;
+
if (cupsDoAuthentication(http, "PUT", resource))
{
status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
diff --git a/cups/http-private.h b/cups/http-private.h
index 047a69253..db71ede28 100644
--- a/cups/http-private.h
+++ b/cups/http-private.h
@@ -353,6 +353,15 @@ struct _http_s /**** HTTP connection structure ****/
Bytef *sbuffer; /* (De)compression buffer */
# endif /* HAVE_LIBZ */
+ /**** New in CUPS 2.2.9 ****/
+ char algorithm[65], /* Algorithm from WWW-Authenticate */
+ nextnonce[HTTP_MAX_VALUE],
+ /* Next nonce value from Authentication-Info */
+ opaque[HTTP_MAX_VALUE],
+ /* Opaque value from WWW-Authenticate */
+ realm[HTTP_MAX_VALUE];
+ /* Realm from WWW-Authenticate */
+
/**** New in CUPS 2.3 ****/
char *fields[HTTP_FIELD_MAX],
/* Allocated field values */
@@ -423,7 +432,6 @@ extern http_tls_credentials_t
_httpCreateCredentials(cups_array_t *credentials);
extern char *_httpDecodeURI(char *dst, const char *src,
size_t dstsize);
-extern char *_httpDigest(char *buffer, size_t bufsize, const char *algorithm, const char *username, const char *realm, const char *password, const char *nonce, unsigned nc, const char *cnonce, const char *qop, const char *method, const char *resource);
extern void _httpDisconnect(http_t *http);
extern char *_httpEncodeURI(char *dst, const char *src,
size_t dstsize);
@@ -432,6 +440,7 @@ extern const char *_httpResolveURI(const char *uri, char *resolved_uri,
size_t resolved_size, int options,
int (*cb)(void *context),
void *context);
+extern int _httpSetDigestAuthString(http_t *http, const char *method, const char *resource);
extern const char *_httpStatus(cups_lang_t *lang, http_status_t status);
extern void _httpTLSInitialize(void);
extern size_t _httpTLSPending(http_t *http);
diff --git a/cups/http-support.c b/cups/http-support.c
index fd6750bfa..cd423aefd 100644
--- a/cups/http-support.c
+++ b/cups/http-support.c
@@ -662,41 +662,52 @@ httpDecode64_2(char *out, /* I - String to write to */
/*
- * '_httpDigest()' - Calculate a Digest authentication response using the
- * appropriate RFC 2068/2617/7616 algorithm.
+ * '_httpSetDigestAuthString()' - 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 */
+int /* O - 1 on success, 0 on failure */
+_httpSetDigestAuthString(
+ http_t *http, /* I - HTTP connection */
+ 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 */
-
-
- DEBUG_printf(("2_httpDigest(buffer=%p, bufsize=" CUPS_LLFMT ", algorithm=\%s\", username=\"%s\", realm=\"%s\", password=\"%d chars\", nonce=\"%s\", nc=%u, cnonce=\"%s\", qop=\"%s\", method=\"%s\", resource=\"%s\")", buffer, CUPS_LLCAST bufsize, algorithm, username, realm, (int)strlen(password), nonce, nc, cnonce, qop, method, resource));
+ char kd[65], /* Final MD5/SHA-256 digest */
+ ha1[65], /* Hash of username:realm:password */
+ ha2[65], /* Hash of method:request-uri */
+ username[HTTP_MAX_VALUE],
+ /* username:password */
+ *password, /* Pointer to password */
+ temp[1024], /* Temporary string */
+ digest[1024]; /* Digest auth data */
+ unsigned char hash[32]; /* Hash buffer */
+ size_t hashsize; /* Size of hash */
+
+
+ DEBUG_printf(("2_httpSetDigestAuthString(http=%p, method=\"%s\", resource=\"%s\")", http, method, resource));
+
+ strlcpy(username, http->userpass, sizeof(username));
+ if ((password = strchr(username, ':')) != NULL)
+ *password++ = '\0';
+ else
+ return (0);
- if (algorithm)
+ if (http->algorithm[0])
{
/*
* Follow RFC 2617/7616...
*/
- if (!_cups_strcasecmp(algorithm, "MD5"))
+ int i; /* Looping var */
+ char cnonce[65]; /* cnonce value */
+ const char *hashalg; /* Hashing algorithm */
+
+ for (i = 0; i < 64; i ++)
+ cnonce[i] = "0123456789ABCDEF"[CUPS_RAND() & 15];
+ cnonce[64] = '\0';
+
+ if (!_cups_strcasecmp(http->algorithm, "MD5"))
{
/*
* RFC 2617 Digest with MD5
@@ -704,7 +715,7 @@ _httpDigest(char *buffer, /* I - Response buffer */
hashalg = "md5";
}
- else if (!_cups_strcasecmp(algorithm, "SHA-256"))
+ else if (!_cups_strcasecmp(http->algorithm, "SHA-256"))
{
/*
* RFC 7616 Digest with SHA-256
@@ -718,9 +729,7 @@ _httpDigest(char *buffer, /* I - Response buffer */
* Some other algorithm we don't support, skip this one...
*/
- *buffer = '\0';
-
- return (NULL);
+ return (0);
}
/*
@@ -728,7 +737,7 @@ _httpDigest(char *buffer, /* I - Response buffer */
*/
/* H(A1) = H(username:realm:password) */
- snprintf(temp, sizeof(temp), "%s:%s:%s", username, realm, password);
+ snprintf(temp, sizeof(temp), "%s:%s:%s", username, http->realm, password);
hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash));
cupsHashString(hash, hashsize, ha1, sizeof(ha1));
@@ -738,9 +747,18 @@ _httpDigest(char *buffer, /* I - Response buffer */
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);
+ snprintf(temp, sizeof(temp), "%s:%s:%08x:%s:%s:%s", ha1, http->nonce, http->nonce_count, cnonce, "auth", ha2);
hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash));
- cupsHashString(hash, hashsize, buffer, bufsize);
+ cupsHashString(hash, hashsize, kd, sizeof(kd));
+
+ /*
+ * Pass the RFC 2617/7616 WWW-Authenticate header...
+ */
+
+ if (http->opaque[0])
+ snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", algorithm=%s, qop=auth, opaque=\"%s\", cnonce=\"%s\", nc=%08x, uri=\"%s\", response=\"%s\"", cupsUser(), http->realm, http->nonce, http->algorithm, http->opaque, cnonce, http->nonce_count, resource, kd);
+ else
+ snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", algorithm=%s, qop=auth, cnonce=\"%s\", nc=%08x, uri=\"%s\", response=\"%s\"", username, http->realm, http->nonce, http->algorithm, cnonce, http->nonce_count, resource, kd);
}
else
{
@@ -749,7 +767,7 @@ _httpDigest(char *buffer, /* I - Response buffer */
*/
/* H(A1) = H(username:realm:password) */
- snprintf(temp, sizeof(temp), "%s:%s:%s", username, realm, password);
+ snprintf(temp, sizeof(temp), "%s:%s:%s", username, http->realm, password);
hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash));
cupsHashString(hash, hashsize, ha1, sizeof(ha1));
@@ -759,12 +777,20 @@ _httpDigest(char *buffer, /* I - Response buffer */
cupsHashString(hash, hashsize, ha2, sizeof(ha2));
/* KD = H(H(A1):nonce:H(A2)) */
- snprintf(temp, sizeof(temp), "%s:%s:%s", ha1, nonce, ha2);
+ snprintf(temp, sizeof(temp), "%s:%s:%s", ha1, http->nonce, ha2);
hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash));
- cupsHashString(hash, hashsize, buffer, bufsize);
+ cupsHashString(hash, hashsize, kd, sizeof(kd));
+
+ /*
+ * Pass the old RFC 2069 WWW-Authenticate header...
+ */
+
+ snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"", username, http->realm, http->nonce, resource, kd);
}
- return (buffer);
+ httpSetAuthString(http, "Digest", digest);
+
+ return (1);
}
diff --git a/cups/http.c b/cups/http.c
index d9332cc83..56546a6c4 100644
--- a/cups/http.c
+++ b/cups/http.c
@@ -101,7 +101,8 @@ static const char * const http_fields[] =
"WWW-Authenticate",
"Accept-Encoding",
"Allow",
- "Server"
+ "Server",
+ "Authentication-Info"
};
@@ -2874,7 +2875,12 @@ _httpUpdate(http_t *http, /* I - HTTP connection */
httpSetCookie(http, value);
}
else if ((field = httpFieldValue(line)) != HTTP_FIELD_UNKNOWN)
+ {
http_add_field(http, field, value, 1);
+
+ if (field == HTTP_FIELD_AUTHENTICATION_INFO)
+ httpGetSubField2(http, HTTP_FIELD_AUTHENTICATION_INFO, "nextnonce", http->nextnonce, (int)sizeof(http->nextnonce));
+ }
#ifdef DEBUG
else
DEBUG_printf(("1_httpUpdate: unknown field %s seen!", line));
diff --git a/cups/http.h b/cups/http.h
index 50083cb0d..67373e510 100644
--- a/cups/http.h
+++ b/cups/http.h
@@ -176,6 +176,7 @@ typedef enum http_field_e /**** HTTP field names ****/
HTTP_FIELD_ACCEPT_ENCODING, /* Accepting-Encoding field @since CUPS 1.7/macOS 10.9@ */
HTTP_FIELD_ALLOW, /* Allow field @since CUPS 1.7/macOS 10.9@ */
HTTP_FIELD_SERVER, /* Server field @since CUPS 1.7/macOS 10.9@ */
+ HTTP_FIELD_AUTHENTICATION_INFO, /* Authentication-Info field (@since CUPS 2.2.9) */
HTTP_FIELD_MAX /* Maximum field index */
} http_field_t;
diff --git a/cups/request.c b/cups/request.c
index 4b3d032f6..924bb6fc0 100644
--- a/cups/request.c
+++ b/cups/request.c
@@ -680,6 +680,24 @@ cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP
digest = http->authstring && !strncmp(http->authstring, "Digest ", 7);
+ if (digest)
+ {
+ /*
+ * Update the Digest authentication string...
+ */
+
+ if (http->nextnonce[0])
+ {
+ strlcpy(http->nonce, http->nextnonce, sizeof(http->nonce));
+ http->nonce_count = 1;
+ http->nextnonce[0] = '\0';
+ }
+ else
+ http->nonce_count ++;
+
+ _httpSetDigestAuthString(http, "POST", resource);
+ }
+
#ifdef HAVE_GSSAPI
if (http->authstring && !strncmp(http->authstring, "Negotiate", 9))
{
diff --git a/cups/testhttp.c b/cups/testhttp.c
index 6e42562fc..1480d04b5 100644
--- a/cups/testhttp.c
+++ b/cups/testhttp.c
@@ -336,6 +336,7 @@ main(int argc, /* I - Number of command-line arguments */
if (!j)
puts("PASS");
+#if 0
/*
* _httpDigest()
*/
@@ -367,6 +368,7 @@ main(int argc, /* I - Number of command-line arguments */
}
else
puts("PASS");
+#endif /* 0 */
/*
* httpGetHostname()