From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Jarno Malmari Newsgroups: gmane.emacs.devel Subject: [PATCH 2/2] Initial implementation for HTTP Digest qop for url Date: Mon, 27 Mar 2017 22:47:27 +0300 Message-ID: <1490644047-24049-3-git-send-email-jarno@malmari.fi> References: <8360jgdt1p.fsf@gnu.org> <1490644047-24049-1-git-send-email-jarno@malmari.fi> NNTP-Posting-Host: blaine.gmane.org X-Trace: blaine.gmane.org 1490644190 16809 195.159.176.226 (27 Mar 2017 19:49:50 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Mon, 27 Mar 2017 19:49:50 +0000 (UTC) Cc: emacs-devel@gnu.org To: eliz@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Mon Mar 27 21:49:45 2017 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1csae6-0003SV-So for ged-emacs-devel@m.gmane.org; Mon, 27 Mar 2017 21:49:43 +0200 Original-Received: from localhost ([::1]:48683 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1csaeB-0006lF-FI for ged-emacs-devel@m.gmane.org; Mon, 27 Mar 2017 15:49:47 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:58586) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1csadG-0006jf-Nm for emacs-devel@gnu.org; Mon, 27 Mar 2017 15:48:52 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1csadF-0007CW-4c for emacs-devel@gnu.org; Mon, 27 Mar 2017 15:48:50 -0400 Original-Received: from out1-smtp.messagingengine.com ([66.111.4.25]:51425) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1csadB-0007Am-Sc; Mon, 27 Mar 2017 15:48:45 -0400 Original-Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailout.nyi.internal (Postfix) with ESMTP id 8421720E37; Mon, 27 Mar 2017 15:48:45 -0400 (EDT) Original-Received: from frontend2 ([10.202.2.161]) by compute7.internal (MEProxy); Mon, 27 Mar 2017 15:48:45 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=malmari.fi; h=cc :date:from:in-reply-to:message-id:references:subject:to :x-me-sender:x-me-sender:x-sasl-enc:x-sasl-enc; s=fm1; bh=dAFWnX KqkOpgeyCfYbkNccjVoljrW089QSGa67eFH0k=; b=Xd7KZ7ZUaBmM4COk6U43oR haUOcV7JTyAqojnzllsD/tZ1tqbfTIv06GI5zb1xaUnlkIcvVXMmLuxwwfhVaigH 7Ud5tbl9BsHG/iqKCzQsP1zJL+MQLpKy4GdplkLprZ9ms2NQKGSMK4cBqClk0rqK n7oIlMn5N6M4cZMSC+HOJSem1+IZHQhconjJJtW3/ZdoV52U3bvlqLpV8kgMcR4k dT1ZsbwcAAHU/wX74qWv3lymk91Di0GORgAVtplWNUvE7MVY23d5C6FMmFpzqbEA C/tKxod6wZha2ChZCRAUAZH2fgBSrXzj7Mb8ivpyvBHZP9Te5Uk86/yT9i8b4low == DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:date:from:in-reply-to:message-id :references:subject:to:x-me-sender:x-me-sender:x-sasl-enc :x-sasl-enc; s=fm1; bh=dAFWnXKqkOpgeyCfYbkNccjVoljrW089QSGa67eFH 0k=; b=sIwD9g2ZUOcFYPU3PayYaFzr0XOSAa6KPCfLYKbZ0LBIO7L1tqvSS5VXZ llkKo7m3holvLNYvfSPzJmjId9YrkD4acTeXib5OYZqg8xcjomgT0qVcQVsritZ8 kTm44QSHDDp9cA9bfd0CDhIlzXkAoxMnA4fiyh37D6iwlrp7N4CeaaesMZekV0e3 q/utlZFLHg87wsA4EacEfKoaMK2amHQyBWqCpsiwtC14G4ooEo1jcE6Jp7y6jtTT iGte9p8UC8G7y+7/VKfg6wEcc1ucr2a3VWNeW4pA7A0fIMhTWFV93JW791vqe1af nZ7R3529jAaC0OfCxvpnhVlvV749w== X-ME-Sender: X-Sasl-enc: gcGJCVI6zGgf22+kx4znEHdqHj4ATUlVnD1t25xwENbS 1490644125 Original-Received: from vabi.peto.intranet (a88-113-156-118.elisa-laajakaista.fi [88.113.156.118]) by mail.messagingengine.com (Postfix) with ESMTPA id DCBC4240A5; Mon, 27 Mar 2017 15:48:44 -0400 (EDT) X-Mailer: git-send-email 2.7.0.25.gfc10eb5 In-Reply-To: <1490644047-24049-1-git-send-email-jarno@malmari.fi> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.111.4.25 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:213430 Archived-At: Some servers have dropped backward compatibility with HTTP Digest Authentication without "qop". The Quality Of Protection scheme is partially implemented: only one supported qop (qop=auth), only one supported algorithm (md5), nonce count remains always as 1 (no replays) * lisp/url/url-auth.el (url-digest-auth-build-response): Hook up new functionality, or fall back to previous. (url-digest-auth-make-request-digest-qop): (url-digest-auth-make-cnonce, url-digest-auth-nonce-count): (url-digest-auth-name-value-string): Add new helper functions. * test/lisp/url/url-auth-tests.el (url-auth-test-challenges): (url-auth-test-digest-request-digest): Test the new implementation. Parts of these were accidentally already merged in the past. --- lisp/url/url-auth.el | 60 ++++++++++++++++++++++++++++++++++++----- test/lisp/url/url-auth-tests.el | 28 +++++++++++-------- 2 files changed, 71 insertions(+), 17 deletions(-) diff --git a/lisp/url/url-auth.el b/lisp/url/url-auth.el index 4c9a907..2885d4e 100644 --- a/lisp/url/url-auth.el +++ b/lisp/url/url-auth.el @@ -131,8 +131,8 @@ url-basic-auth ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Digest authorization code ;;; ------------------------ -;;; This implements the DIGEST authorization type. See the internet draft -;;; ftp://ds.internic.net/internet-drafts/draft-ietf-http-digest-aa-01.txt +;;; This implements the DIGEST authorization type. See RFC 2617 +;;; https://www.ietf.org/rfc/rfc2617.txt ;;; for the complete documentation on this type. ;;; ;;; This is very secure @@ -165,6 +165,16 @@ url-digest-auth-make-request-digest a password." (url-digest-auth-kd (url-digest-auth-colonjoin nonce ha2) ha1)) +(defsubst url-digest-auth-make-request-digest-qop (qop ha1 ha2 nonce nc cnonce) + "Construct the request-digest with qop. +QOP describes the \"quality of protection\" and algorithm to use. +All of the strings QOP, HA1, HA2, NONCE, NC, and CNONCE are +combined into a single hash value that proves to a server the +user knows a password. It's worth noting that HA2 already +depends on value of QOP." + (url-digest-auth-kd (url-digest-auth-colonjoin + nonce nc cnonce qop ha2) ha1)) + (defsubst url-digest-auth-directory-id (url realm) "Make an identifier for selecting a key in key cache. The identifier is made either from URL or REALM. It represents a @@ -179,6 +189,21 @@ url-digest-auth-server-id key cache `url-digest-auth-storage'." (format "%s:%d" (url-host url) (url-port url))) +(defun url-digest-auth-make-cnonce () + "Compute a new unique client nonce value." + (base64-encode-string + (apply 'format "%016x%04x%04x%05x%05x" (random) (current-time)) t)) + +(defun url-digest-auth-nonce-count (nonce) + "The number requests sent to server with the given NONCE. +This count includes the request we're preparing here. + +Currently, this is not implemented and will always return 1. + +Value returned is in string format with leading zeroes, such as +\"00000001\"." + (format "%08x" 1)) + (defun url-digest-auth-name-value-string (pairs) "Concatenate name-value pairs in association list PAIRS. @@ -284,12 +309,20 @@ url-digest-auth-build-response using the contents of alist ATTRS. ATTRS is expected to contain at least the server's \"nonce\" -value. It also might contain the optional \"opaque\" value." +value. It also might contain the optional \"opaque\" value. +Newer implementations conforming to RFC 2617 should also contain +qop (Quality Of Protection) and related attributes. + +Restrictions on Quality of Protection scheme: The qop value +\"auth-int\" or algorithm any other than \"MD5\" are not +implemented." + (when key (let ((user (nth 1 key)) (ha1 (nth 2 key)) (ha2 (nth 3 key)) (digest-uri (url-filename url)) + (qop (cdr-safe (assoc "qop" attrs))) (nonce (cdr-safe (assoc "nonce" attrs))) (opaque (cdr-safe (assoc "opaque" attrs)))) @@ -299,9 +332,24 @@ url-digest-auth-build-response (append (list (cons 'username user) (cons 'realm realm) (cons 'nonce nonce) - (cons 'uri digest-uri) - (cons 'response (url-digest-auth-make-request-digest - ha1 ha2 nonce))) + (cons 'uri digest-uri)) + + (cond + ((null qop) + (list (cons 'response (url-digest-auth-make-request-digest + ha1 ha2 nonce)))) + ((string= qop "auth") + (let ((nc (url-digest-auth-nonce-count nonce)) + (cnonce (url-digest-auth-make-cnonce))) + (list (cons 'qop qop) + (cons 'nc nc) + (cons 'cnonce cnonce) + (cons 'response + (url-digest-auth-make-request-digest-qop + qop ha1 ha2 nonce nc cnonce))))) + (t (message "Quality of protection \"%s\" is not implemented." qop) + nil)) + (if opaque (list (cons 'opaque opaque))))))))) diff --git a/test/lisp/url/url-auth-tests.el b/test/lisp/url/url-auth-tests.el index a6b31d7..30636db 100644 --- a/test/lisp/url/url-auth-tests.el +++ b/test/lisp/url/url-auth-tests.el @@ -104,13 +104,21 @@ url-auth-test-challenges (plist-get row :expected-ha2))))) (ert-deftest url-auth-test-digest-request-digest () - "Check digest response value when not supporting `qop'." + "Check digest response value." (dolist (row url-auth-test-challenges) - (should (string= (url-digest-auth-make-request-digest - (plist-get row :expected-ha1) - (plist-get row :expected-ha2) - (plist-get row :nonce)) - (plist-get row :expected-response))))) + (should (string= (plist-get row :expected-response) + (if (plist-member row :qop) + (url-digest-auth-make-request-digest-qop + (plist-get row :qop) + (plist-get row :expected-ha1) + (plist-get row :expected-ha2) + (plist-get row :nonce) + (plist-get row :nc) + (plist-get row :cnonce)) + (url-digest-auth-make-request-digest + (plist-get row :expected-ha1) + (plist-get row :expected-ha2) + (plist-get row :nonce))))))) (ert-deftest url-auth-test-digest-create-key () "Check user credentials in their hashed form." @@ -258,14 +266,12 @@ url-auth-test-challenges (progn ;; We don't know these, just check that they exists. (should (string-match-p ".*response=\".*?\".*" auth)) - ;; url-digest-auth doesn't return these AFAICS. -;;; (should (string-match-p ".*nc=\".*?\".*" auth)) -;;; (should (string-match-p ".*cnonce=\".*?\".*" auth)) - ) + (should (string-match-p ".*nc=\".*?\".*" auth)) + (should (string-match-p ".*cnonce=\".*?\".*" auth))) (should (string-match ".*response=\"\\(.*?\\)\".*" auth)) (should (string= (match-string 1 auth) (plist-get challenge :expected-response)))) - ))) + ))) (ert-deftest url-auth-test-digest-auth-opaque () "Check that `opaque' value is added to result when presented by -- 2.7.0.25.gfc10eb5