Re: [OAUTH-WG] Signatures spec proposal, take 2

Dirk Balfanz <balfanz@google.com> Fri, 24 September 2010 18:37 UTC

Return-Path: <balfanz@google.com>
X-Original-To: oauth@core3.amsl.com
Delivered-To: oauth@core3.amsl.com
Received: from localhost (localhost [127.0.0.1]) by core3.amsl.com (Postfix) with ESMTP id 3147D3A6A87 for <oauth@core3.amsl.com>; Fri, 24 Sep 2010 11:37:53 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -104.376
X-Spam-Level:
X-Spam-Status: No, score=-104.376 tagged_above=-999 required=5 tests=[AWL=1.600, BAYES_00=-2.599, FM_FORGED_GMAIL=0.622, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_MED=-4, USER_IN_WHITELIST=-100]
Received: from mail.ietf.org ([64.170.98.32]) by localhost (core3.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ZhrYtLlUTsa9 for <oauth@core3.amsl.com>; Fri, 24 Sep 2010 11:37:49 -0700 (PDT)
Received: from smtp-out.google.com (smtp-out.google.com [74.125.121.35]) by core3.amsl.com (Postfix) with ESMTP id DDF2B3A6AA2 for <oauth@ietf.org>; Fri, 24 Sep 2010 11:37:48 -0700 (PDT)
Received: from hpaq3.eem.corp.google.com (hpaq3.eem.corp.google.com [172.25.149.3]) by smtp-out.google.com with ESMTP id o8OIcKdZ006617 for <oauth@ietf.org>; Fri, 24 Sep 2010 11:38:20 -0700
DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=google.com; s=beta; t=1285353500; bh=h2iX6wOBknjjcstU+mjnXClVyEs=; h=MIME-Version:In-Reply-To:References:Date:Message-ID:Subject:From: To:Cc:Content-Type; b=pr07TBmksOrCi4R/97RjGX/zVcDV2MLDoxtSkyqk3uo+UVLXGv/h8CXc+TKOi5UWY +gTkMua5Ht4qzwPrTq65w==
Received: from iwn2 (iwn2.prod.google.com [10.241.68.66]) by hpaq3.eem.corp.google.com with ESMTP id o8OIcIfd029365 for <oauth@ietf.org>; Fri, 24 Sep 2010 11:38:18 -0700
Received: by iwn2 with SMTP id 2so3273629iwn.34 for <oauth@ietf.org>; Fri, 24 Sep 2010 11:38:18 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=beta; h=domainkey-signature:mime-version:received:received:in-reply-to :references:date:message-id:subject:from:to:cc:content-type; bh=k4KfuPpFsaTIiwXNE0G5K5tf/RiFLtHdo33NUepUx00=; b=YiIqxfBQqR8B3f43+zasPp1HnDxe6a0TUq8na9qRQniNMYklF/5BCuf9dSsN2A1gek kK4Ll19rgX/sMj0FGoxw==
DomainKey-Signature: a=rsa-sha1; c=nofws; d=google.com; s=beta; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; b=vxeGmQ3WkvXAnRsBbje1H2E7rIN3jhVn2muMbqMqu7Z16Fl/DAumTyOGRJgMY8OVlc zW4NDTnUEKBoia3geXBw==
MIME-Version: 1.0
Received: by 10.231.160.77 with SMTP id m13mr4287369ibx.22.1285353497442; Fri, 24 Sep 2010 11:38:17 -0700 (PDT)
Received: by 10.231.130.9 with HTTP; Fri, 24 Sep 2010 11:38:17 -0700 (PDT)
In-Reply-To: <29CE36EA-67C2-4D58-96F2-3C462A12219F@bbn.com>
References: <C8C15BD3.3AC6C%eran@hueniverse.com> <89CF75F1-4A51-4B92-8305-BC7430D36F7C@bbn.com> <AANLkTinRQDgVynrE6vdMVYBT=_+fpDMqWaL1C+BNzf_e@mail.gmail.com> <29CE36EA-67C2-4D58-96F2-3C462A12219F@bbn.com>
Date: Fri, 24 Sep 2010 11:38:17 -0700
Message-ID: <AANLkTimdZOuB+n8e2NRULgr7cQvwShKiEw+vQnDmCujw@mail.gmail.com>
From: Dirk Balfanz <balfanz@google.com>
To: "Richard L. Barnes" <rbarnes@bbn.com>
Content-Type: multipart/alternative; boundary="0016e6d447efa03db4049105ae16"
X-System-Of-Record: true
Cc: OAuth WG <oauth@ietf.org>
Subject: Re: [OAUTH-WG] Signatures spec proposal, take 2
X-BeenThere: oauth@ietf.org
X-Mailman-Version: 2.1.9
Precedence: list
List-Id: OAUTH WG <oauth.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/listinfo/oauth>, <mailto:oauth-request@ietf.org?subject=unsubscribe>
List-Archive: <http://www.ietf.org/mail-archive/web/oauth>
List-Post: <mailto:oauth@ietf.org>
List-Help: <mailto:oauth-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/oauth>, <mailto:oauth-request@ietf.org?subject=subscribe>
X-List-Received-Date: Fri, 24 Sep 2010 18:37:53 -0000

On Fri, Sep 24, 2010 at 10:08 AM, Richard L. Barnes <rbarnes@bbn.com> wrote:

> I think it's more robust to verify than to generate. In option 2, you have
>> to "guess" what the signer actually signed. To be fair, you have pretty good
>> signals, like the HTTP request line, the Host: header, etc., but in the end,
>> you don't _know_ that the signer really saw the same thing when they
>> generated the signature. I can't help but feeling that that's a bit of a
>> hack. In option 1, you always know what the signer saw when they generated
>> the signature, and it's up to you (the verifier) to decide whether that
>> matches your idea of what your endpoint looks like.
>>
>
> Generating does not imply guessing: The signer can specify what he signed
> without providing the data directly.  Quoting from another thread:
> "
> 1. Signer computes signature sig_val over data object:
>  { user_agent: "Mozilla", method: "GET" }
> 2. Signer sends { signed_fields: ['user_agent', 'method'], sig: sig_val }
> 3. Recipient reconstructs data object using signed_fields
> 4. Recipient verifies sig_val == sign(reconstructed_object)
> "
>
> If the spec is written properly, the recipient should be able to look at
> the names of the fields ('user_agent', 'method') and use them to reconstruct
> the original object.
>

User-agent and method are well-defined both for senders and receivers of
HTTP requests. What's less well-defined is the URL, which is what Eran is
objecting to. So in practice, it looks more like this:

1. Signer generates URL using some library, e.g.:
    paramsMap = new Map();
    paramsMap.put('param1', 'value1');
    paramsMap.put('param2', 'value2');

    uri = new UriBuilder()
      .setScheme(Scheme.HTTP)
      .setHost('WWW.foo.com')
      .setPath('/somePath')
      .setQueryParams(paramsMap)
      .build().toString();
   // uri now looks something like "
http://WWW.foo.com/somePath?param1=value1&param2=value2"

2. They then use a different library to send the HTTP request
    request = new GetRequest();
    request.setHeader('signed-token', sign('GET', uri));
    request.execute(uri);

The problem is that we don't know what the execute method on GetRequest does
with the URI. It probably will use a library (possibly different from the
one used in step 1) to decompose the URI back into its parts, so it can
figure out whether to use SSL, which host and port to connect to, etc. Is it
going to normalize the hostname to lowercase in the process? Is it going to
escape the query parameters? Is it going to add ":80" to the Host:-header
because that's the port it's going to connect to? Is it going to put the
query parameters into a different order?, etc., all of which would cause the
recipient of the message to put back together a _different_ URI from what
the sender saw.

OAuth1 therefore defined a bunch of rules on how to "normalize" the URI to
make sure that both the sender and the receiver saw the same URI even if the
http library does something funny. Many people thought that those rules were
too complicated. There is currently an argument over whether or not the
complexity of the rules can be hidden in libraries, and I'm personally a bit
on the fence on this. What I _do_ object to, more on a philosophical level,
is that we can never know for sure what the http library is doing to the
request, and that therefore we can never be sure whether the normalization
rules we have come up with cover all the crazy libraries out there. There is
a symmetric problem on the receiver side - where the servlet APIs may or may
not have messed with the parameters before you get to reconstruct the URI.

The JSON token proposal does something simpler: you get to see the URI as
the sender saw it (in this case with the uppercase WWW, without the :80,
etc.), and you get to decide whether that matches your endpoint. So instead
of wondering in what order the signer saw the query parameters when he
signed them, and whether they were escaped or not, you simply check that all
the query parameters that he signed (as evidenced in the JSON token) are
indeed present in the HTTP request, and vice versa, etc. It's a comparable
amount of work, but it seems cleaner, less hacky to me.

Dirk.


> The idea of allowing signed fields to change en route to the server strikes
> me as a little odd.  Sure, you could ignore the method, path, and host
> values in HTTP and just act on the enveloped data, but at that point, why
> not just do away with the overhead of HTTP and run the whole thing over TCP?
>
> --Richard
>