Re: [Acme] Resend: [Gen-art] Genart telechat review of draft-ietf-acme-acme-07]
Richard Barnes <rlb@ipv.sx> Tue, 28 November 2017 20:57 UTC
Return-Path: <rlb@ipv.sx>
X-Original-To: acme@ietfa.amsl.com
Delivered-To: acme@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id 9953812773A for <acme@ietfa.amsl.com>; Tue, 28 Nov 2017 12:57:41 -0800 (PST)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -2.598
X-Spam-Level:
X-Spam-Status: No, score=-2.598 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_LOW=-0.7, URIBL_BLOCKED=0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (2048-bit key) header.d=ipv-sx.20150623.gappssmtp.com
Received: from mail.ietf.org ([4.31.198.44]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id jPVOZN4dqvwR for <acme@ietfa.amsl.com>; Tue, 28 Nov 2017 12:57:35 -0800 (PST)
Received: from mail-wm0-x22e.google.com (mail-wm0-x22e.google.com [IPv6:2a00:1450:400c:c09::22e]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 3B175120227 for <acme@ietf.org>; Tue, 28 Nov 2017 12:57:34 -0800 (PST)
Received: by mail-wm0-x22e.google.com with SMTP id 9so2148040wme.4 for <acme@ietf.org>; Tue, 28 Nov 2017 12:57:34 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ipv-sx.20150623.gappssmtp.com; s=20150623; h=mime-version:in-reply-to:references:from:date:message-id:subject:to; bh=+lpDpXStYkGj3nP1UFLCCbmqW7wiB6af504a9PVO6Ac=; b=ul8nZH1Z1VENjV/kmxNc/67r/Jm7aD0/oHdNVLWfmxMq2G9upZ6LncfpQRxuR6EM7w Uw0EOBI/HTBR8gVEMeduDuazvz+OCs1c9KrRNK4N2Vw1Z1wckOT3inXxRQu9PKckPQ+O SOPDvwY7+RcxZuevYDvlDzqhnYEpkc1NmupM0LIrAdKVWjZC69MPWq74WZ9ktnWLahKV Yha7BZz/7yZr9FYfOur0Vd9zxUe4nQF/S0Zc9j1jlLHJOSb4F/8dpsg/l7ckKhN0/jem ZbEn+pxo8I/6PWwPs6wZ627PCc54t9TCkWyyD2xPBnfFHTmmpPSLGsqZyO4PSnITfr9t tWGw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to; bh=+lpDpXStYkGj3nP1UFLCCbmqW7wiB6af504a9PVO6Ac=; b=lMGKPfmo74ZXnAd8r2JbhhHQjGv66XThLBfgqasLkdRJWLuKbJvzkzN3K4sznLvtql QAYRFiIXAtFGwwNwUGfYTX1jfUeig6zJtAjhSyTaPed0zgtUVEPWiDXPxk/sUc15KP9D gy3F4GzH6ZD9nSs1d/O0CVFaZuqHS1o/yqgHUpTIQyt5iRZf365ZKMFQb7LwKHN4mwFY ACX42dfP5WOJKv0c8+Y3eJ73JFv4CMyX4W6zZqaeKU2tbvh4qwn2sALyeSYPOJE/Nnpt FHICEJHQrtfkR2rtKm9WDnTpSTFVoEI1vN/lTf71L5qBkRdUfKl+05R4yBc+zU8IR3TD 4JTQ==
X-Gm-Message-State: AJaThX6nE663DeMTiazauE4vCUndXWHm6WR4i0jOTiKKO8r+tN7uDHVL h2rHHt0HDCqFcDT4c20H11uRt49Rjn96qf8XYzEiXg==
X-Google-Smtp-Source: AGs4zMazAHIMBZMQDS/4M1e4q5N0T96lPANJS5eYdsKrYrbit2m76I+QGI4Rv74kN/npag9mbG8fL5kKcmTK6CJGleY=
X-Received: by 10.28.175.8 with SMTP id y8mr460914wme.21.1511902652091; Tue, 28 Nov 2017 12:57:32 -0800 (PST)
MIME-Version: 1.0
Received: by 10.28.167.74 with HTTP; Tue, 28 Nov 2017 12:57:31 -0800 (PST)
In-Reply-To: <CAL02cgQjwPEq1Y+m+W1JcW-6KMmf_xp6rJ8AD_4djvNbC1FnqA@mail.gmail.com>
References: <87d14kuuga.fsf@hobgoblin.ariadne.com> <CAL02cgQjwPEq1Y+m+W1JcW-6KMmf_xp6rJ8AD_4djvNbC1FnqA@mail.gmail.com>
From: Richard Barnes <rlb@ipv.sx>
Date: Tue, 28 Nov 2017 15:57:31 -0500
Message-ID: <CAL02cgQNKWzE_rnOK0RbVEj-BH3s+7c-8N7X2p_6ZjaMYb_Nhg@mail.gmail.com>
To: "Dale R. Worley" <worley@ariadne.com>, "acme@ietf.org" <acme@ietf.org>, Alissa Cooper <alissa@cooperw.in>
Content-Type: multipart/alternative; boundary="001a11444ab283680c055f1144e9"
Archived-At: <https://mailarchive.ietf.org/arch/msg/acme/gl1Fvw9dPW-Eginj4LJNA1EjvN8>
Subject: Re: [Acme] Resend: [Gen-art] Genart telechat review of draft-ietf-acme-acme-07]
X-BeenThere: acme@ietf.org
X-Mailman-Version: 2.1.22
Precedence: list
List-Id: Automated Certificate Management Environment <acme.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/acme>, <mailto:acme-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/acme/>
List-Post: <mailto:acme@ietf.org>
List-Help: <mailto:acme-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/acme>, <mailto:acme-request@ietf.org?subject=subscribe>
X-List-Received-Date: Tue, 28 Nov 2017 20:57:41 -0000
Re-adding the list / AD. On Tue, Nov 28, 2017 at 3:51 PM, Richard Barnes <rlb@ipv.sx> wrote: > Hi Dale, > > Thanks for the detailed review. I've posted updates in a PR for your > review: > > https://github.com/ietf-wg-acme/acme/pull/358 > > FWIW, these sorts of detailed comments will get addressed much more > quickly if they are submitted in PR form. > > Responses inline below, tagged with [RLB]. > > --Richard > > > > > On Tue, Nov 14, 2017 at 9:49 PM, Dale R. Worley <worley@ariadne.com> > wrote: > > > > From: Dale Worley <worley@ariadne.com> > To: <gen-art@ietf.org> > Date: Tue, 24 Oct 2017 18:55:40 -0700 > Archived-At: <https://mailarchive.ietf.org/arch/msg/gen-art/ > xI8YgzTpDS5KXRBaR0app5ynoQA> > Subject: [Gen-art] Genart telechat review of draft-ietf-acme-acme-07 > Cc: draft-ietf-acme-acme.all@ietf.org, acme@ietf.org, ietf@ietf.org > > Reviewer: Dale Worley > Review result: On the Right Track > > I am the assigned Gen-ART reviewer for this draft. The General Area > Review Team (Gen-ART) reviews all IETF documents being processed by > the IESG for the IETF Chair. Please wait for direction from your > document shepherd or AD before posting a new version of the draft. > > For more information, please see the FAQ at > <https://wiki.tools.ietf.org/area/gen/wiki/GenArtfaq>. > > Document: draft-ietf-acme-acme-07 > Reviewer: Dale R. Worley > Review Date: 2017-10-24 > IETF LC End Date: 2017-09-14 > IESG Telechat date: 2017-10-26 > > Summary: > > This draft is on the right track but has open issues, described in the > review. > > My general impression is that this is a sound piece of work, and > apparently one that satisfies a serious practical need. But this > draft has a large number of open issues, and really needs a careful, > thorough clean-up pass. And until that's done, it's not clear what > genuine problems might be lurking. > > I haven't put in the time I would have liked to, so some of the issues > I've detected might prove to be nonexistent. A lot of these issues > are simply English usage. The structure of the exposition needs to be > improved, including pulling the specialized vocabulary into a > glossary, providing overviews of processes whose multiple details are > discussed, etc. Some issues are technical slips, like missing > required fields in HTTP messages. Some seem to be more substantial > technical issues -- What is the versioning and extensibility system? > What are the requirements on POST operations that effectively carry no > more information than that the operation happens? And one question -- > the terms of service agreement -- seems to brush into legal > territory. The number and variety of these minor problems suggests > that the whole work needs to be thought through more carefully before > being frozen. > > Within that context, I will not attempt to sort these items into > categories or rate them on importance, but just list them in order by > parts of the text that they relate to. And note that a number of > these items are mentioned relative to only one of several places in > the text they apply to. > > ---------------------------------------------------------------------- > > There's a lot of talk about accounts, but no overview of the lifecycle > of an account. Compare to the presentation of the overview of the > lifecycle of a certificate request. > > There should be blanket policies on whether and where non-standard > fields can be included by both client and server. > > Also, there ought to be versioning of Acme itself. > > Abstract > > Certificates in PKI using X.509 (PKIX) are used for a number of > purposes, the most significant of which is the authentication of > domain names. > > I'm no expert here, but it seems to me that "the authentication of > domain names" is not correct -- only actors can be authenticated. I > think the accurate phrasing is "the authentication of servers (TLS, > HTTPS, etc.) which act on behalf of domain names". (This would be a > minor matter in the body, especially if this elision was universally > used in the field, but an abstract should require little context.) > > Ditto for the first paragraph of section 1. > > > [RLB] This is standard usage, and it seems to me that all of the > alternatives are less clear. > > > > > DISCLAIMER: This is a work in progress draft of ACME and has not yet > had a thorough security analysis. > > I assume that this is going to be removed once this document is > published as an RFC. If the RFC hadn't had a thorough security > analysis, there would be no value in publishing it as an RFC. However > there is no attached statement indicating when this statement is to be > removed. What is actually going on here? > > > [RLB] This is a legacy of earlier versions. Proposed for removal in #357 > > https://github.com/ietf-wg-acme/acme/pull/357 > > > > Table of Contents > > 6.4. Replay protection > 6.4.2. "nonce" (Nonce) JWS header parameter > 6.5. Rate limits > > These section titles aren't capitalized the same way as the other > section titles. > > > [RLB] Fixed. Also, "Threat model". > > > > > 1. Introduction > > Existing Web PKI certificate authorities tend to run on a set of ad > hoc protocols for certificate issuance and identity verification. > > s/run on/use/? > > > [RLB] Done. > > > > a typical user experience is something like: > > I think you want to broaden this to "a typical protocol is". That > doesn't change things much, because the user is one endpoint of the > protocol. But you don't want to de-emphasize what the CA does, > either. (I reflexively think of this as a protocol problem, whereas > the authors probably reflexively think of this as a user experience > problem.) > > > [RLB] The problem with the legacy "protocol" is that it is not automated, > which implies a bad UX, which implies that security doesn't scale. I don't > think a change is needed here. > > > > * Put a CA-provided challenge at a DNS location corresponding to > the target domain. > > What does "corresponding to" mean? I think you want "in a DNS record > for the target domain". > > > [RLB] Done. > > > > * Receive CA challenge at a (hopefully) administrator-controlled > email address corresponding to the domain and then respond to > it on the CA's web page. > > s/CA challenge/CA-provided challenge/ for parallelism. > > > [RLB] Done. > > > s/corresponding to the domain/within the domain/? > > > [RLB] No, "corresponding to", e.g., via WHOIS. > > > > It seems that there should be an item between the third and fourth > items: > > o The CA makes the newly issued certificate accessible to the > user (via the CA's web site? via e-mail?) > > > [RLB] Disagree, not substantive to the UX story. > > > > > -- > > This document describes an extensible framework for automating the > issuance and domain validation procedure, thereby allowing servers > and infrastructural software to obtain certificates without user > interaction. Use of this protocol should radically simplify the > deployment of HTTPS and the practicality of PKIX authentication for > other protocols based on Transport Layer Security (TLS) [RFC5246]. > > I think you need some background on why this matters. In the naive > default model, someone wants to set up a web server and needs to > obtain a certificate. Yes, this will require 1 to 3 hours, but it's a > one-time cost over the life of the web site. And I doubt that getting > one's self plugged into the Acme system of a CA will take *less* time. > > > [RLB] The "set up a web server" model accounts for a vanishingly small > portion of the web these days; most things run on hosting providers. And > several hosting providers are already using earlier versions of ACME to > enable "one-click" or "zero-click" HTTPS for hosted sites. > > Even for the self-hosting crowd, there are multiple web servers now that > provide instant HTTPS using ACME. > > https://www.youtube.com/watch?v=nk4EWHvvZtI > https://letsencrypt.org/2017/10/17/acme-support-in-apache-httpd.html > > > > Your model seems to be an operator that wants to set up many servers > that are authenticatable to many different identities, with each > identity being initially vouched for by the same operator. But this > suggests that the multiple identities are third parties that are in > some way subordinate or derived identities to the operator's identity, > either "departments" within one entity, or customers of a vendor. > > In particular, how does Acme work relative to the case where a service > provider claims it is setting up a web site for a third party? > > [RLB] This distinction is never made in practice. For example, the CDN > for example.com is indistinguishable from example.com from the vantage > point of a client or CA. Where some separation is desired, see > https://tools.ietf.org/html/draft-ietf-acme-star > > > [ruminations deleted] I think you need to underline that this only > handles the DV case, and not the OV and EV cases. > > [RLB] This is not true. The "external account binding" feature lets you > associate OV/EV authorizations with an ACME account, allowing the issuance > of EV certificates via ACME. And if you look back through the list > archives, there are multiple CAs that have said they intend to deploy it in > this way. > > > On the first > reading, I overlooked the bit about "automating the issuance and > domain validation procedure", and immediately started wondering how > Acme prevents a service provider from generating bogus web servers for > third parties, and thinking it doesn't. But I reflexively think of > certificates in terms of OV rather than DV. I suspect many readers > also make this assumption. > > 2. Deployment Model and Operator Experience > > The guiding use case for ACME is obtaining certificates for websites > (HTTPS [RFC2818]). > > You probably want to emphasize "obtaining domain validation-type > certificates ". > > [RLB] No. See above. > > > Prior to ACME, when deploying an HTTPS server, an operator typically > > This is the first use of "operator", so you probably want to say "the > server operator". > > [RLB] Done. > > > o The ACME client prompts the operator for the intended domain > name(s) that the web server is to stand for. > > Probably want to say "The operator's ACME client" to make it clear > that the client is working for/controlled by/attached to/located at > the operator. > > [RLB] Done. > > > o In the background, the ACME client contacts the CA and requests > that it issue a certificate for the intended domain name(s). > > It seems that all of the remaining steps are "in the background", as > they can run to completion without operator intervention. So I think > you want to emphasize "In the background" as an assertion about the > remaining steps as a group. > > [RLB] Disagree. > > > o The CA verifies that the client controls the requested domain > name(s). > > "here a miracle happens" -- I think you want to flesh this out or > provide a reference to the previous discussion, and especially > emphasize that the Internet operations are carried out by the Acme > client. E.g., "The ACME client proves to the CA that the operator > controls the domain by one of the above-described methods." But maybe > I'm being too fussy about the words "controls the requested domain > name(s)". > > > [RLB] Done. > > > o Once the CA is satisfied, the certificate is issued > > There's no point using the passive when the subject has already been > used in the sentence: "Once the CA is satisfied, it issues the > certificate". > > [RLB] Done. > > > In this way, it would be nearly as easy to deploy with a CA-issued > certificate as with a self-signed certificate. > > As someone who detests setting up yet another account for yet another > web site, I would like you to modify this to, "once the operator has > an ACME relationship with one or more CAs, it would be nearly ...". > > [Check how much work the operator needs to get his ACME client > connected to a CA. If this is easy, emphasize it in the intro, as > it's a major virtue of ACME!] > > [RLB] Disagree. (Well, I agree that it's a major virtue of ACME. I > disagree that a text change is needed.) > > > 3. Terminology > > The two main roles in ACME are "client" and "server". The ACME > client uses the protocol to ... > > An ACME client is represented by an "account key pair". The client > uses the private key ... > > These two paragraphs contain two sentences of terminology definition > and two paragraphs of setting up the structure of the ACME > client/server system. That's not a bad thing, but it's more than > simply "Terminology". > > Conversely, there's a lot of terminology in this draft that isn't > defined here. Probably foremost is "operator", but there should also > be some explanation of the use of "response" when that is used to > describe an HTTP *request*. > > One approach would be to move most of these two paragraphs into the > beginning of section 4, and then expanding section 3 to include > various terms that might not be familiar to people not fully involved > in certificate-issuance procedures. > > [RLB] Disagree. > > > The server uses the public key to verify the > authenticity and integrity of messages from the client. > > What information is given to the server by authenticating the request > using the public key? One possibility is that the server only needs > to know that two requests came from "the same" Acme client, in which > case all it needs to check is that both were signed by the same key. > But if the key conveys identity information to the server, how is that > managed? That should be described (or referenced) at the very > beginning of the protocol description, as that is the first action of > the Acme protocol, setting up the client and connecting it to the CA. > > [RLB] This is all specified in the account management sections below. > > > In many ways, ACME functions much like a traditional CA, > > I think you mean, "In many ways, an ACME server functions ...". > > [RLB] Done. > > > ACME allows a client to request certificate management actions using > a set of JavaScript Object Notation (JSON) messages carried over > HTTPS. In many ways, ACME functions much like a traditional CA, in > which a user creates an account, requests a certificate, and proves > control of the domains in that certificate in order for the CA to > sign the requested certificate. > > The first sentence of this paragraph should go after the part about > setting up the client/server relationship. The second sentence is > actually overview for all of section 4 and should stay at the > beginning of the section. > > [RLB] Disagree. > > > The server then validates the challenges to check that the client > has accomplished them. > > You may want to say "validates the responses to the challenges". (I'm > from an environment where the phrase "challenge/response" is used a > lot.) > > [RLB] Done. > > > the server will issue the requested certificate and make it > available to the client. > > If the Acme protocol can actually carry the certificate to the client, > you probably want to make that clear in this sentence. "and send it > to the client"? > > [RLB] Disagree. > > > Order > Signature -------> > > Required > <------- > Authorizations > > I assume that messages from the server are also signed. (How is the > client to authenticate that it is talking to the server it thinks it's > talking to?) I'd say, "the server's signatures also ought to be > shown", but at this level of detail, I probably prefer that the > signatures not be shown, as they seem to cause me visual clutter. > > [RLB] As is detailed below, the server's responses are authenticated using > HTTPS server authentication. > > > This chart seems to leave out a lot of steps. Perhaps: > > Order -------> > > <------- Required > Authorizations > > [Perform response actions.] > > Response Notification -------> > > [Verify response > actions.] > > <------- > Certificate > > [RLB] Disagree. > > > 6.2. Request Authentication > > * "jwk" (JSON Web Key, only for requests to new-account and > revoke-cert resources) > > For new-account requests, and for revoke-cert requests authenticated > by certificate key, there MUST be a "jwk" field. > > These two requirements don't appear to be the same. > > [RLB] These are not inconsistent. The first says that the MUST only > applies for those two request types, and the second reiterates that the > MUST applies for those two request types. > > > If the client sends a JWS signed with an algorithm that the server > does not support, then the server MUST return an error with status > code 400 (Bad Request) and type > "urn:ietf:params:acme:error:badSignatureAlgorithm". > > This is hard to understand until the type field is introduced below. > (The type field doesn't seem to be a standard feature of JWS.) Easier > wold be > > If the client sends a JWS signed with an algorithm that the server > does not support, then the server MUST return an error document > with status > code 400 (Bad Request) and > "urn:ietf:params:acme:error:badSignatureAlgorithm" in the "type" > field. > > [RLB] Disagree. > > > 6.3. Request URL Integrity > > As noted in Section 6.2 above, all ACME request objects carry a > "url" > header parameter in their protected header. > > Actually, section 6.2 calls it a "field". You should use consistent > terminology, particularly given that in the context of HTTP, the term > "header" has a special meaning. (What is the general usage in JWS > discussions?) > > [RLB] JWS also has a header, in fact two headers, a "protected" and > "unprotected" headers. The contents of these headers are called "header > parameters". This section is consistent with this usage. > > > Except for the directory resource, all ACME resources are addressed > with URLs provided to the client by the server. For these > resources, > the client MUST set the "url" header parameter to the exact string > provided by the server (rather than performing any re-encoding on > the > URL). The server SHOULD perform the corresponding string equality > check, configuring each resource with the URL string provided to > clients and having the resource check that requests have the same > string in their "url" header parameter. > > This is awkwardly phrased. Perhaps: > > Except for the directory resource, all ACME resources are addressed > with URLs provided to the client by the server. When addressing > these resources, the client MUST set the "url" header parameter to > the exact string provided by the server (rather than performing any > re-encoding on the URL). Conversely, the server MUST provide > clients with the URLs by which the resources can be addressed > through the server, and it SHOULD verify that the "url" header > parameter the client provides when accessing a resource is the same > string as the server provides clients for that resource. > > [RLB] Done (slightly differently). > > > 6.3.1. "url" (URL) JWS header parameter > > Perhaps the last two paragraphs of section 6.3 should be moved into > this section. > > This text is not as exact as I'd like. What does "to which this JWS > object is directed" mean? Do you mean "The request that contains this > object is not valid unless the HTTP request URL is exactly the same > string as the value of this header parameter." And the phrase "be a > string representing the URL" is extremely dangerous. Remember that a > URL *is* a string, and if you mess with character encodings or the > like, you get a *different* URL, albeit one that some process might > consider "equivalent" to the original URL for some purposes. > > I'm not up to date on HTTP, but there are some complications regarding > what the "request URI" of a request is; it's not always just the value > of the "request-URI" field of the request-line. There's probably a > set terminology for this concept; it would be wise to align with it. > > [RLB] There are a fair number of ambiguities around URLs. This WG has > tried to steer clear of them in the context of ACME using the string > comparison text above. For this header parameter, the specific semantic of > the string will be application-dependent, as with many other JWS fields. > > > 6.4. Replay protection > > In order to protect ACME resources from any possible replay attacks, > > Could this be shortened to "In order to protect ACME resources from > replay attacks, ..."? > > [RLB] Disagree. > > > Every JWS sent by an ACME client MUST include, in its protected > header, > > It's vague here what "JWS" means as an unqualified noun. I suspect, > "JWS object", but some other uses suggest that there is a larger JWS > construct within which the "object" is the "payload". In any case, > the terminology should be brought into alignment with the JWS > standard(s). > > [RLB] As noted above, this is standard JWS usage. > > > It's not clear why the nonces are provided in the Replay-Nonce header > rather than being provided in the JWS response. Compare when the > client sends the nonce, when it is provide inside the JWS object. > Indeed, this seems to be a layering violation -- the nonce is sent by > the server in a header, but sent by the client in the JWS. It would > be cleaner to send the nonce in both directions in a header, or send > it in both directions in the JWS. Perhaps the standard JWS > practice is to do it this way -- but the existence of section 6.4.1 > suggests otherwise. > > [RLB] Response bodies are not JWS objects. It's true that there is some > asymmetry here, but it has not been a problem in for deployments in > practice. > > > It might be worth noting that it is acceptable for the server to > "expire" unused nonces by not accepting nonces that were provided in > responses too far in the past. (Assuming you want to allow it.) > Since a client is required to retry requests that are rejected due to > nonce failure, and that retry is expected to be done promptly, this > behavior does not cause protocol failure. As written, this section > suggests that a server MUST NOT reject a request as long as the nonce > is valid, regardless of how long ago the nonce was issued. > > [RLB] There is no requirement at all that a server accept any given nonce, > only that it must NOT accept some nonces. > > > 6.4.1. Replay-Nonce > > This section reads very awkwardly. I think the intention is to > provide a specification of the Reply-Nonce header field that stands > alone. But it is a specification only in regard to the syntax of the > field, not the semantics. OTOH, the first sentence of the section > seems to be trying to describe the semantics of the field, which is > confusing since it is nowhere near complete. If you want to say > "generally, this field is to provide nonces that clients can use to > uniquely identify requests" you want to be careful to qualify it with > some statement that the exact usage is described in other > specifications. Wording this correctly could get awkward. > > [RLB] The semantics are described in the previous section. > > > The phrase "unique to each message" isn't clear with regard to scope. > Is it like SIP Call-Ids, which are unique over all space and time? Or > just unique over the history of the server? > > The language is not as clear as I'd like about where it appears. > Better to say "The server provides this header field in responses to > carry a server-generated nonce to the client..." and "The Replay-Nonce > header field MUST only be carried in HTTP response messages." > > [RLB] Disagree. > > > 6.4.2. "nonce" (Nonce) JWS header parameter > > Again, this section hints at but does not specify the semantics of the > datum. > > [RLB] As above, the semantics are application-specific. > > > > 6.5. Rate limits > > Creation of resources can be rate limited to ensure fair usage and > prevent abuse. Once the rate limit is exceeded, the server MUST > respond with an error with the type > "urn:ietf:params:acme:error:rateLimited". Additionally, the server > SHOULD send a "Retry-After" header indicating when the current > request may succeed again. If multiple rate limits are in place, > that is the time where all rate limits allow access again for the > current request with exactly the same parameters. > > This is written as of rate limiting is some sort of global correctness > property -- which can't be reduced to any property observable by > either client or server. The first sentence doesn't even state that > it's the *server* that can limit rates! Better is to clarify the > intentions and roles of the various actors: > > A server MAY limit the rate at which it accepts various requests > from various clients, e.g., to ensure fair usage and prevent abuse. > If a server desires to postpone submission of a particular request, > it MUST respond with an error with the type > "urn:ietf:params:acme:error:rateLimited". Additionally, the server > SHOULD [I can't see a reason why this isn't MUST] include a > "Retry-After" header indicating the time interval after which all > limitations the server is currently applying to this request will > permit processing of this request. Different requests (even if from > the same client) may be subject to different rate limits; the > Retry-After value gives no information about other requests. > > [RLB] Added "by servers" > > > -- > > In addition to the human readable "detail" field of the error > response, the server MAY send one or multiple tokens in the "Link" > header pointing to documentation about the specific hit rate limits > using the "urn:ietf:params:acme:documentation" relation. > > What does "token" mean here? From context, I think you mean > "link-value" (after RFC 5988), or better, "URI". > > [RLB] Changed "tokens" to "link relations" (after RFC 8288) > > > Also, the value "urn:ietf:params:acme:documentation" doesn't seem to > be placed in the IANA registry described in section 9.6. > > [RLB] Changed to use the standard "help" link relation type. > > > 6.6. Errors > > this document defines the > following standard tokens for use in the "type" field (within the > "urn:ietf:params:acme:error:" namespace): > > This isn't correct terminology. The namespace of these URNs is > "ietf". Part of the problem is that there isn't a standardized term > for the parts of a URN that are separated by colons, despite that > almost all URN namespaces use colons as major separators. I think > this version is both correct and readable: > > ... this document defines the following standard URIs for use in > the "type" field (where each listed token is appended to > "urn:ietf:params:acme:error:" to make the URI): > > +-----------------------+----------------------------------- > --------+ > | Token | Description > | > +-----------------------+----------------------------------- > --------+ > | badCSR | The CSR is unacceptable (e.g., due to a > | > | | short key) > | > > [RLB] Disagree. The nuances of URN terminology are not relevant to interop > here. > > > -- > > This list is not exhaustive. The server MAY return errors whose > "type" field is set to a URI other than those defined above. > Servers > MUST NOT use the ACME URN [RFC3553] namespace for errors other than > the standard types. > > "namespace" isn't really correct here, but I think "sub-namespace" is. > > [RLB] Disagree, as above. > > > Clients SHOULD display the "detail" field of all errors. > > s/display/display to the user/ > > [RLB] Disagree. > > > 7.1. Resources > > Each > function is listed in a directory along with its corresponding URL, > so clients only need to be configured with the directory URL. > > s/a directory/the directory resource/ > > [RLB] Disagree. > > > The "up" link relation from "cert" to the CA chain is not shown in the > figure. The "index" link relation isn't shown at all, though that > couldn't be shown easily. You might want to note that in some way in > the paragraph before the figure. > > [RLB] Disagree. > > > | Submit an order | POST new-order | 201 -> order | > > When I first read this, I was unclear what an "order" is. It turns > out that it is a request for a certificate. E.g., > > o Order resources, representing an account's requests to issue > certificates (Section 7.1.3) > > You might want to either move toward the nomenclature "request a > certificate" or more heavily emphasize "order" in the text. If you > enlarge section 2 to cover all the specialized terminology, putting an > entry in it for "order" would be helpful. > > [RLB] Disagree. > > > There are quite a number of example request responses that do not > contain the "index" link header. > > [RLB] This seems unlikely to lead to interop failure. > > > The figure does not show the key-change resource. > > [RLB] Done. > > > 7.1.1. Directory > > whose fields names are drawn from the following table > > s/fields names/field names/ > > [RLB] Done. > > > +-------------+--------------------+ > | Field | URL in value | > +-------------+--------------------+ > | new-nonce | New nonce | > | | | > | new-account | New account | > | | | > | new-order | New order | > | | | > | new-authz | New authorization | > | | | > | revoke-cert | Revoke certificate | > | | | > | key-change | Key change | > +-------------+--------------------+ > > In this table, one of the "URL in value" items is a predicate > (verb-object), which makes sense; one is a noun phrase naming an > action; and four are noun phrases (which are objects of an implied > "get" or "obtain"). I suggest rephrasing the items into predicates > directly telling what the URL does, e.g., "request new nonce", "change > key". > > [RLB] Disagree. > > > There is no constraint on the actual URL of the directory except > that > > "actual" is probably superfluous here. > > [RLB] Done. > > > The following metadata items are defined, all of which are OPTIONAL: > > It would probably be wise to allow servers to include non-standard > metadata items. > > [RLB] There is nothing forbidding it. > > > HTTP/1.1 200 OK > Content-Type: application/json > > This should be preceded by something like "An example response to a > directory GET is:". I suggest providing some sort of direct > description of each example, and it would help to show requests and > responses together. (But perhaps the RFC Editor thinks that unlabeled > examples are OK if the context makes their purpose clear enough.) > > [RLB] I think the purpose is clear enough from context. > > > 7.1.2. Account Objects > > contact (optional, array of string): An array of URLs that the > server can use to contact the client for issues related to this > account. For example, the server may wish to notify the client > about server-initiated revocation or certificate expiration. > > Strictly, you want "URIs" here, as tel:, sip:, and mailto: URIs are > not URLs [RFC 6068]. > > [RLB] There is long-standing consensus in the WG to use "URL" instead of > "URI" in this document, because it is more commonly used, and because the > exact line between URIs and URLs in not clear. For example, the WHATWG URL > spec does consider the examples you cite to be URLs. > > > 7.1.2.1. Orders List > > How long does an order URL remain valid? The particular URLs in the > example suggests that the order URLs are valid only as long as the set > of orders doesn't change. > > [RLB] The semantics here are the same as for an Amazon or Google search > results page. If the underlying data set changes, then the list provided > when dereferencing the URL will also change. No stability guarantees. > > > A larger question is whether order objects are ever purged from the > orders list? > > [RLB] Up to the server, subject to the guidance in this section. > > > Indeed, these questions can be generalized -- Can the server ever > purge resources, invalidating the URLs that pointed to them? What > sort of assurances can the client rely on? > > [RLB] What sort of assurances do you imagine the client needs? > > > 7.1.3. Order Objects > > For final > orders, the authorizations that were completed. > > What is a "final" order? The term "final" is used in a number of > places, with possibly slightly different meanings, and needs to be > properly defined. > > [RLB] Clarified, "(in the "valid" or "invalid" state)" > > > 7.1.4. Authorization Objects > > status (required, string): The status of this authorization. > Possible values are: "pending", "processing", "valid", "invalid" > and "revoked". > > It might be worth spelling out here what these states mean, as this is > the definition of this field of the authorization object. > > [RLB] These are described elsewhere with better context. > > > If this field is absent, then > the CA MUST consider this authorization valid for all orders > until > the authorization expires. > > There doesn't seem to be an "expired" status, so how can an > authorization expire? > > [RLB] This field has since been deleted. > > > For final authorizations it contains the > challenges that were successfully completed. > > What is a "final" authorization? > > [RLB] Clarified, "(in the "valid" or "invalid" state)" > > > Section 8 describes a set of challenges for domain name validation. > > Section 8 is about challenges generally; really the challenges for > domain name validation are sections 8.4 to 8.6. Perhaps they should > be grouped into a subsection and this sentence should point to that? > > [RLB] Disagree. The "and some other stuff" is implicit. > > > 7.3. Account Creation > > If the server wishes to present the client with terms under which > the > ACME service is to be used, it MUST indicate the URL where such > terms > can be accessed in the "terms-of-service" subfield of the "meta" > field in the directory object, and the server MUST reject > new-account > requests that do not have the "terms-of-service-agreed" set to > "true". Clients SHOULD NOT automatically agree to terms by default. > Rather, they SHOULD require some user interaction for agreement to > terms. > > I note that there seems to be no recording of when the account was > created, i.e., *when* the terms of service was agreed to. Since the > content behind the terms of service URL can change unpredictably, > noting that the terms of service were agreed to is meaningless unless > there is some fixation of the time of agreement. > > [RLB] Servers are welcome to log this information if they see fit. > > > an error of type "invalidContact". > > The wording of the text is inconsistent (or just unclear) whether > error types are give as full URNs or just the last component. > > [RLB] Errors are always provided as full URNs, as required by RFC 7807. > Add a clarification to the "Errors" section. > > > 7.3.4. Changes of Terms of Service > > The problem document returned with the error MUST also include an > "instance" field, indicating a URL that the client should direct a > human user to visit in order for instructions on how to agree to the > terms. > > This seems inconsistent with section 7.3, as the client can agree to > the terms of service when creating an account within Acme, but changes > in terms seem to require going out-of-band to agree to the new terms > of service. > > [RLB] The decision of the WG was that this was the correct trade-off given > that re-agreement is almost never needed. > > > Given that this could become a legal matter, it seems like a lot of > care and thought should be put in on this. Ideally, a good lawyer > should be consulted on this. > > [RLB] It's not the IETF's job to make legal decisions, just to make > mechanisms that work for participants. Several CAs weighed in to say this > mechanism was OK with them. > > > HTTP/1.1 403 Forbidden > Replay-Nonce: IXVHDyxIRGcTE0VSblhPzw > Link: <https://example.com/acme/terms/2017-6-02>;rel="terms- > of-service" > Content-Type: application/problem+json > Content-Language: en > > The various examples don't seem to be indented consistently. Although > I expect the RFC Editor will clean that up. > > [RLB] As do I. > > > 7.3.5. External Account Binding > > This can be used to an ACME account with an > existing account in a non-ACME system, such as a CA customer > database. > > There's a word missing after "This can be used to". > > [RLB] This is fixed in https://github.com/ietf-wg-acme/acme/pull/357 > > > The server MAY require a value to be present for the "external- > account-binding" field. > > It would help the reader recover the context by starting this with, > "In an account creation request,". > > [RLB] Done. > > > To enable ACME account binding, a CA needs to provision the ACME > client with a MAC key and a key identifier. > > You might want to annotate this, "by some means outside the scope of > this document", or "presumably as part of establishing the external > account". And I would use "provide" rather than "provision" -- > "provision" suggests to me that there is a specific provisioning > process that will be defined. > > [RLB] Done. > > > What is a "MAC key"? I think you mean that any account binding must > be represented by a key pair for the external account, and the private > key of that pair is the "MAC key". > > OTOH, this may be inconveniently heavy-weight for real-world use -- I > would expect the CA to simply provide a secret associated with the > external account. (Or is that what a "MAC key" is?) > > [RLB] A MAC key is a key used to compute Message Authentication Codes, > i.e., a symmetric secret. > > > The ACME client then computes a binding JWS to indicate the external > account's approval of the ACME account key. > > This isn't quite correct. Perhaps > > The ACME client then computes a binding JWS to indicate that that > the client, the owner of the external account, approves of the ACME > account key. > > Or is that "the client, on behalf of the owner of the external > account"? > > [RLB] Changed to "external account holder's approval" > > -- > > MUST reflect value of the "external-account-binding" field > > s/reflect value/reflect the value/ > > [RLB] Done. > > > 7.3.6. Account Key Roll-over > > The client then encapsulates the key-change object in a JWS, signed > with the requested new account key (i.e., the key matching the > "newKey" value). > > The outer JWS MUST meet the normal requirements for an ACME JWS (see > Section 6.2). The inner JWS MUST meet the normal requirements, with > the following exceptions: > > Some detail is being left out. I think that the JWS described in the > first of these paragraphs becomes the "inner JWS" of the next > paragraph. But exactly how that nesting is to be performed doesn't > seem to be described. > > [RLB] Added some clarification. > > > 3. Check that the JWS protected header of the inner JWS has a "jwk" > field. > > Is the generation of the "jwk" field specified in the text anywhere? > > [RLB] It's just a public key generated by the client. Added a > clarification that "jwk" is REQUIRED in the inner JWS. > > > 7.4. Applying for Certificate Issuance > > then the > server MUST proactively issue the requested certificate and provide > a > URL for it in the "certificate" field of the order. > > I'm not sure that "proactively" has a specific meaning. I think you > can just s/proactively issue/issue/ and capture the desired meaning -- > the server doesn't have to issue a certificate instantly, but it > cannot delay. > > [RLB] This has been replaced in https://github.com/ietf-wg- > acme/acme/pull/342 > > > The status of the order will indicate what action the > client should take: > > This list is part of the definition of the order object, and should be > put in section 7.1.3. > > [RLB] Disagree. > > > 7.4.1. Pre-Authorization > > In some cases, a CA running an ACME server might have a completely > external, non-ACME process for authorizing a client to issue for an > identifier. > > I'm not sure that "client" is a proper subject for "issue". Perhaps > you mean "for authorizing a client to be issued certificate(s) for an > identifier". > > [RLB] Changed "issue" to "request issuance for" > > > 7.4.2. Downloading the Certificate > > A certificate resource represents a single, immutable certificate. > If the client wishes to obtain a renewed certificate, the client > initiates a new order process to request one. > > Though I think you want to add what you really mean, namely that the > new certificate will be fetched from a different URL. > > [RLB] Disagree. > > > 7.5. Identifier Authorization > > The server may declare > that an authorization is only valid for a specific order by setting > the "scope" field of the authorization to the URL for that order. > > "scope" isn't shown in the figure in section 7.1. > > [RLB] "scope" has been deleted https://github.com/ietf-wg- > acme/acme/pull/349 > > > 7.5.1. Responding to Challenges > > The server is said to "finalize" the authorization when it has > > Despite the existence of a section titled "Terminology", very little > of the terminology created for this document is listed there. > > [RLB] Disagree. > > > 8. Identifier Validation Challenges > > Each challenge must describe: > > This isn't right; a challenge doesn't describe anything. But the > descriptions of the challenge types include various information, etc. > > [RLB] Changed to "The definition of a new type of challenge" > > > status (required, string): The status of this authorization. > Possible values are: "pending", "valid", and "invalid". > > I think you mean "the status of this challenge". But you might mean > "the status of the authorization containing this challenge". > > [RLB] Typo. Done. > > > validated (optional, string): The time at which this challenge was > completed by the server > > I'm not sure in what sense you mean "completed by", since it's the > client that does the completing. I think you mean "the time at which > the server recognized that the challenge was completed". > > [RLB] Changed to "The time at which the server considered this challenge > complete" > > > The server can limit the size > of this object by limiting the number of times it will retry a > challenge. > > Rather, "the number of times it will permit the client to retry a > challenge". Actually, the semantics of this field probably depends on > the pattern of the actions by which the challenge is satisfied, and so > may be dependent on the challenge type. > > [RLB] Changed to "try to validate a challenge" > > > If the > server sets a challenge's "status" to "invalid", it SHOULD also > include the "error" field to help the client diagnose why the > challenge failed. > > Presumably, 'the "errors" field'. > > [RLB] Done. > > > Also, section 8.2, "The server MUST add an entry to the "errors" field > in the challenge after each failed validation query.", suggests that > the server MUST include the "errors" field, not just SHOULD include. > > [RLB] Suggests, but does not imply. A server could invalidate a challenge > just because it feels like it. > > > > 8.1. Key Authorizations > > A key authorization is a string that expresses > a domain holder's authorization for a specified key to satisfy a > specified challenge, by concatenating the token for the challenge > with a key fingerprint, separated by a "." character: > > key-authz = token || '.' || base64url(JWK_Thumbprint(accountKey)) > > In what way does a key authorization indicate something about a > "domain holder"? The k.a. includes the token (presumably from the > challenge object) and a computation based on an account's (private) > key, so it includes information from the account holder. > > Or do you mean that "in the challenge, a token will be sent by the > server that only the domain holder will be able to receive, and as > part of the account holder's response to the challenge, it composes a > key authorization string"? > > Really, I doubt that this is understandable without first explaining > the general model of challenge/response that the challenge types > defined here use, and that model doesn't seem to be described > anywhere. I think it would be very helpful if that model was > presented first, before the specific challenge types that use that > model. > > Alternatively, you could just describe this as an abstract operation > on strings, > > key-authz(token, accountKey) = > token || '.' || base64url(JWK_Thumbprint(accountKey)) > > and leave defining its semantics to where key-authz() is used. > > [RLB] Disagree. > > > The "JWK_Thumbprint" step indicates the computation specified in > [RFC7638], using the SHA-256 digest [FIPS180-4]. As noted in JWA > [RFC7518] any prepended zero octets in the JWK object MUST be > stripped before doing the computation. > > The second sentence seems to be unclear. Is the "JWK object" the > output of "JWK_Thumbprint(accountKey)"? If so, why isn't it called > "the JWK_Thumbprint object"? And the significance of "prepended zero > octets" is unclear; RFC 7518 does not include the word "prepend", so > presumably does not specify any prepending. I suspect you mean that > some stage of the processing of RFC 7518 is modified by stripping > initial zero octets from some string, but such octets wouldn't be > described as "prepended". > > [RLB] This is a minor issue with RSA keys, where sometimes integers have > zeros prepended to make clear that they're positive. Changed to "any > prepended zero octets in the fields of a JWK object". > > > 8.2. Retrying Challenges > > Clients can explicitly request a retry by re-sending their response > to a challenge in a new POST request (with a new nonce, etc.). > > Again, this makes sense only under the assumption that satisfying a > challenge has certain data-flow patterns, in that (apparently) the > client must send a "response" and then -- well, it's not entirely > clear what "a retry" is. You really need to lay out this pattern -- > and the names you use for the actions within it -- before you specify > the details of how clients and servers can perform it. > > [RLB] Disagree. > > > In order to avoid > denial-of-service attacks via client-initiated retries, servers > SHOULD rate-limit such requests. > > There are two uses of "request" in the preceding sentence -- which of > them is being rate-limited? > > [RLB] The noun "request" appears twice, but referencing the same action. > > > 8.3. HTTP Challenge > > With HTTP validation, the client in an ACME transaction proves its > control over a domain name by proving that for that domain name it > can provision resources to be returned by an HTTP server. > > Better, "by proving that it can provision resources that are returned > by > an HTTP server accessible using a URL whose host is that domain name". > > [RLB] Done. > > > type (required, string): The string "http-01" > > You don't actually say that these two fields are part of HTTP > challenge objects. > > [RLB] Disagree. > > > It MUST NOT contain any characters outside the base64url > alphabet, > including padding characters ("="). > > This could be read two ways; are the padding characters part of "the > base64url alphabet", or are they part of "characters outside the > base64url alphabet"? Perhaps: > > It MUST NOT contain any characters that are outside the > base64url alphabet, or padding characters ("="). > > or > > It MUST NOT contain any characters that are outside the > base64url alphabet (including padding characters ("=")). > > Maybe better would be "It must contain only characters in the > base64url alphabet including/excluding padding characters("=")." > > Actually, this is just ugly to specify using English, because it's > really hard to say it without using two negatives in one sentence, and > making clear what the scope of each negative is. I think the best > approach is to rely on the fact that RFC 7515 section 2 clearly > defines that "=" is *not* in the base64url alphabet: > > It MUST NOT contain any characters that are not in the base64url > alphabet. > > If someone complains this is unclear, add separate sentence saying > that following RFC 7515 section 2, "=" is not in the base64url > alphabet. > > [RLB] Done. > > > The value of the resource MUST be the ASCII representation of the > key authorization. > > Given that the key authorization is an ASCII string, it's not clear > what its "ASCII representation" is. > > [RLB] Given that some systems do not use UTF-8 as their string encoding > (e.g., JavaScript uses UTF-16), it doesn't hurt to re-emphasize this. > > The client's response to this challenge indicates its agreement to > this challenge by sending the server the key authorization covering > the challenge's token and the client's account key. > > I think you mean, "The client responds to this challenge by POSTing an > update to the challenge object, adding a "keyAuthorization" field > containing the key authorization derived from the challenge's token > and the client's account key." > > [RLB] Changed "this challenge" to "the validation request" > > > 1. Construct a URL by populating the URL template [RFC6570] > "http://{domain}/.well-known/acme-challenge/{token}", where: * > the domain field is set to the domain name being verified; and * > the token field is set to the token in the challenge. > > What do the "*" mean? > > [RLB] Those are supposed to be bullets. Reformatted. > > > 8.5. DNS Challenge > > The record provisioned to the DNS is the base64url encoding of this > digest. > > This doesn't make sense, as a DNS record is not a string per se. > However, the next two sentences make clear what the DNS record should > be. > > [RLB] Changed "is" to "contains" > > > _acme-challenge.example.org. 300 IN TXT "gfj9Xq...Rg85nM" > > It's not clear where "gfj9Xq...Rg85nM" came from, as it's supposed to > be a SHA-256 digest. Though the previous paragraph doesn't specify > how the digest is to be represented; in parallel to earlier > discussion, lower-case hexadecimal seems to be assumed. > > [RLB] No, as it says just above this, it is the base64url encoding of the > digest. > > > 8.6. Out-of-Band Challenge > > the client indicates this by sending a simple > acknowledgment response to the server. > > The text doesn't describe what a "simple acknowledgements response" > is. > > However, the other challenge types involve what seem to be parallel > acknowledgment responses that are required to contain copies of token > values, though in none of these cases does the POST carry any actual > information other than the fact that the POST was made to the > particular URL. What is the reason for this inconsistency? For that > matter, why does the payload of the response for this challenge > contain a "type" field? > > [RLB] This has been simplified in https://github.com/ietf-wg- > acme/acme/pull/357 > > > Perhaps there is something I don't understand about these POSTs which > seem to convey no information other than triggering the server to take > some action with regard to the target resource. > > [RLB] Sometimes you don't need any more information! :) It's still > important for these to be POSTs, though, so that they're authenticated. > > > 9.1. MIME Type: application/pem-certificate-chain > > The "Media Types" registry should be updated with the following > additional value: > > IMO it's better to phrase this, "The following entry should be added > to the "Media Types" registry:". I like to use "update" only for > operations that modify existing entries. > > [RLB] Disagree. > > > File should contain one or more certificates encoded as PEM > according > to RFC 7468 [RFC7468]. > > "should contain"? I think you want to say "File contains". Actually, > "File must consist of ...". > > [RLB] Changed to "contains" > > > "encoded as PEM" seems to be undefined by RFC 7468. Perhaps "encoded > using PEM textual encoding according to RFC 7468" is meant. > > [RLB] Done. > > > 9.6. URN Sub-namespace for ACME (urn:ietf:params:acme) > > I don't see how this specifies that this registry is connected with > the the registry (ACME Error Types, section 9.7.3) which provides the > final component of "urn:ietf:params:acme:*" URNs. I suspect you want > the "Repository" datum in this section to state that it points to the > registry created per section 9.7.3. > > [RLB] There is already a request for the RFC editor to "replace URL-TBD > with the URL assigned by IANA for registries of ACME parameters" > > 9.7. New Registries > > Is there a registry for fields in authorization objects? > > [RLB] Added one. > > 9.7.4. Resource Types > > Are there entries for "new-nonce" and "new-authz"? > > [RLB] Done. > > [END] > > > >
- [Acme] Resend: [Gen-art] Genart telechat review o… Dale R. Worley
- Re: [Acme] Resend: [Gen-art] Genart telechat revi… Salz, Rich
- Re: [Acme] Resend: [Gen-art] Genart telechat revi… Richard Barnes