Subject: Re: [TLS] Comments on

From: Adam Langley <[email-masked]>
Date: Thu, 13 Feb 2014 10:52:42 -0500

On Thu, Feb 13, 2014 at 5:11 AM, Niels Möller <[email-masked]> wrote:
> 1. It would be nice with a couple of additional test cases for
>    AEAD_CHACHA20_POLY1305. In particular for the corner cases of empty
>    associated data and/or empty plaintext.

Ack. Yoav pulled out the AEAD bit into
https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-01 so
that it's not TLS specific and that's probably the place for this now.

> 2. The input to the poly1305mac is defined as
>
>      ad | length(ad) | cryptotext | length(cryptotext)
>
>    As far as I understand, this is a bit redundant, since the second
>    length field is sufficient to make the encoding injective. Does using
>    two length fields increase security in some subtle way?

I don't believe so, it was just habit to put a length on each piece.
(The lengths were originally prefixes of the data. wtc suggested
moving them to the end so that the AEAD could be computed without
knowing the length of the data apriori. Although this does lead to the
possibility of "streaming" APIs which I would discourage as they
release unauthenticated plaintext and force others to also.)

>    At least in my implementantation, the length(ad) field causes some
>    additional complexity, so

Could you elaborate on why knowing the length of the AD is problematic?

> 3. Do you think reduced round variants of chacha make sense? If not,
>    the name "chacha-poly1305" is nicer than "chacha20-poly1305".

I suspect that some folks will want reduced round variants since it's
faster and the reduced round versions are holding up to analysis.

Cheers

AGL

---

From: Wan-Teh Chang <[email-masked]>
Date: Thu, 13 Feb 2014 10:25:48 -0800

Hi Niels,

Adams already answered all of your questions. I'll just provide some
additional info.

draft-agl-tls-chacha20poly1305 has been merged into
http://tools.ietf.org/html/draft-mavrogiannopoulos-chacha-tls-01. But
the specification of the ChaCha20-Poly1305 AEAD cipher suites did not
change.

On Thu, Feb 13, 2014 at 2:11 AM, Niels Möller <[email-masked]> wrote:
>    length field is sufficient to make the encoding injective.

You are right. I suspect this may have been modeled after GCM. (GCM
may have used two lengths to just to fill up a block for GHASH.)

draft-mcgrew-aead-aes-cbc-hmac-sha2-02 does it in the way you suggested:

  T = MAC(MAC_KEY, A || S || AL),

except that they use the length of the associated data (AL) instead.
(A is the associated data. S is the ciphertext.)

>      ad | cryptotext | length(cryptotext)
>
>    would be preferable.

I'm also curious to know why. What about

    ad | cryptotext | length(ad)

?

Wan-Teh

---

From: [email-masked] (Niels Möller)
Date: Thu, 13 Feb 2014 11:11:58 +0100

Hi,

I have a couple of comments on
https://datatracker.ietf.org/doc/draft-agl-tls-chacha20poly1305/?include_text=1
I hope cc:ing the tls ietf list is appropriate (I'm not involved in this
wg).

   would be preferable. I'm not sure if this draft should be read as
   proposing a new aead construction, or if it documents an algorithm
   which is already deployed; in the latter case changes like this can't
   be made easily, of course.

Regards,
/Niels

-- 
Niels Möller. PGP-encrypted email is preferred. Keyid C0B98E26.
Internet email is subject to wholesale government surveillance.

---

From: [email-masked] (Niels Möller)
Date: Fri, 14 Feb 2014 09:42:23 +0100

> that it's not TLS specific and that's probably the place for this now.

Thanks for the pointer. This specifies a 96-bit nonce, both for chacha
and chacha20-poly1305. I'm a bit confused by the different definition
of chacha, with a 32-bit counter and 96-bit nonce, rather than 64 bits
each like in the chacha spec.

This discrepancy gives me the feeling that I definitely should consider
my implementation as experimental, and not promise any compatibility
until the dust settles.

> release unauthenticated plaintext and force others to also.)

I agree that most applications shouldn't use streaming operation, at
least for decryption. But I also think there are valid usecases for
streaming operation, e.g., processing a large file where you really want
a single indication of autenticity for the complete file. In GNU Nettle,
which is a general purpose but pretty low level crypto library, I'd like
to support aead streaming operation whenever possible.

> Could you elaborate on why knowing the length of the AD is problematic?

Knowing it is not a problem, but inserting it at that place in the
poly1305 input is an annoyingly large proportion of the implementation,
even if the total code size and complexity is pretty small.

I have a low-level streaming interface (I'm considering adding a less
general but more easy to use interface on top), with basically these
functions for encryption (decryption is similar), to be called in order:

set_key
  set_nonce         (one or more times per key)
    update          (process ad, zero or more times per nonce)
    encrypt         (process plaintext, zero or more times per nonce
  digest            (produce the authentication tag, once per nonce)

Note that to keep this interface simple, there's no explicit function to
mark the end of the ad; calling either of encrypt or digest implies the
end of the associated data.

Doing a final length field is very straighforward, it is added
unconditionally by the digest function. However, inserting the ad
length, between the ad and the crypto text, gets a bit more scattered.
If encrypt is ever called, inserting the ad length has to be done for
the first call to encrypt (or more precisely, I do it on the first call
to encrypt providing a non-empty segment of plaintext, since for the
bookkeeping I need to ensure that the ad length has been inserted if and
only if the amount of processed plaintext is non-zero). But in case
plaintext is empty, the ad length instead has to be inserted by the
digest function.

For some numbers, my current implementation is 101 non-comment lines of
C (on top of chacha and poly1305 building blocks). Of those, 20% of the
lines and 80% of the if statements are for the insertion of the ad
length.

See
https://git.lysator.liu.se/nettle/nettle/blobs/master/chacha-poly1305.c

(And I'm currently *not* confident that this code is correct, since I
lack tests for the corner cases).

> faster and the reduced round versions are holding up to analysis.

I see. Vaguely related question: Do you see any need for 128-bit chacha
keys? They're not really in the very short chacha paper, but they are in
the reference implementation.

> the specification of the ChaCha20-Poly1305 AEAD cipher suites did not

Thanks for the pointer. And here, chacha and chacha-poly1305 are both
specified with a 64-bit nonce.

>     ad | cryptotext | length(ad)

Adequately explained above, I hope. And the variant you propose should
be as nice and simple to implement as ad | cryptotext | length(cryptotext). Or
for that matter, 

  ad | cryptotext | length(ad) | length(cryptotext)

with both lenghts at the end, if for some reason including both length
fields really is desirable.

Regards, 
/Niels

---

From: Dr Stephen Henson <[email-masked]>
Date: Fri, 14 Feb 2014 15:05:52 +0000

> to support aead streaming operation whenever possible.

Though not relevant to TLS there are also use cases where the whole length of
the data is not known is advance. A couple of examples would be reading from a
pipe or where the stream is obtained from an ASN1 BER decoder (CMS for example).

Steve.
-- 
Dr Stephen N. Henson.
Core developer of the   OpenSSL project: http://www.openssl.org/
Freelance consultant see: http://www.drh-consultancy.co.uk/
Email: [email-masked], PGP key: via homepage.

---

From: Adam Langley <[email-masked]>
Date: Fri, 14 Feb 2014 12:45:21 -0500

> each like in the chacha spec.

It appears that IPSec wants the extra 32 bits of nonce. Although this
is an important change in definition it doesn't actually change the
wire-format for TLS because the record-length limit means that those
bits are always zero anyway in both cases.

> to support aead streaming operation whenever possible.

Keep in mind that it affects more than just your users. By making
streaming designs easy you allow people to make bad designs (like CMS)
that force streaming designs on others in order to handle large files.
The point of AEADs is that it's an easier primitive to use. It would
be doubly unfortunate if they ended up with a sharp edge by returning
unauthenticated plaintext.

> lines and 80% of the if statements are for the insertion of the ad

Thanks. I understand why omitting the length would be easier for you
and it doesn't deeply bother me either way. The WG can figure it out.

However, my preference would be to leave it as is because I've already
got code that does it that way and I don't believe that streaming is
something that should be made easy.

> the reference implementation.

Since they are no faster I don't believe that anyone will want to
support them. However, I may be wrong about that.

Cheers

AGL

---

From: [email-masked] (Niels Möller)
Date: Fri, 14 Feb 2014 19:57:28 +0100

> bits are always zero anyway in both cases.

Right, with some care both views these input words could perhaps
coexist. And a 32-bit counter (256 GB message size, if I manage to get
the powers right) ought to be sufficient for almost all applications.
But I'm afraid it might to slow adoption of chacha if there are multiple
slightly incompatible specifications.

And my current focus is more on what the chacha programming interface
should look like, not wire format of any particular protocol.

> The point of AEADs is that it's an easier primitive to use.

By streaming, I don't advocate you do the decryption in a pipe line;
that's clearly a dangerous habit. Usecase is more like on one machine
running

  src-machine$ tar -cf - foo-dir | aead-encrypt | send

to send the encrypted data over some untrusted link. And on the
receiving side 

  target-machine$ recv | aead-decrypt -o foo.tar

The point of the "streaming" here is that there's no need to store any
copy of plaintext or cryptotext at the source, and at the receiver, at
least there's no need to store a copy of the ciphertext. (And with some
more care, and a paranoid enough tar program, it's even possibly to
safely extract the received tar file in a pipe, avoiding storing a copy
of the tar file, *if* one arranges to handle the aead-decrypt exit code
properly).

If I want to encrypt a large file (say, with key derived from a
passphrase, or with an random and RSA-encrypted session key), I see no
clearly better or easier way to do that than as a single large AEAD
message processed using a streaming/incremental API. Sure, I could
divide the data into reasonably sized shorter blocks and process each
block as a separate message with AEAD, but then I would have to think
about how to do sequence numbers and a properly authenticated EOF
indication, to prevent reorder and truncation. And to me, that's also
very much against the spirit of AEAD as a safe and easy-to-use
mechanism.

> got code that does it that way

I'm afraid that's the answer that I expected...

> and I don't believe that streaming is something that should be made
> easy.

We'll probably just have to disagree on that.

>> keys?

Thanks. (I currently do support them in my development version, but I'm
considering removing that feature, for simplicity, before release).

Regards,
/Niels

---

From: Adam Langley <[email-masked]>
Date: Fri, 14 Feb 2014 14:49:38 -0500

> slightly incompatible specifications.

I intend for the 64/64 bit version to be dead at this point. I think
everyone can agree on the 96/32 split. I wouldn't want there to be two
versions if it can be avoided.

>   src-machine$ tar -cf - foo-dir | aead-encrypt | send

This use of streaming is fine by my criteria, assuming that
"aead-encrypt" is chunking the input into different blocks and
applying the AEAD to each block. This is perfectly fine with a
one-shot(*), AEAD API at the core.

> very much against the spirit of AEAD as a safe and easy-to-use

I disagree here and this seems to contradict your statement above that
decryption in a pipeline is a "dangerous habit". Wouldn't your
streaming/incremental API return unauthenticated plaintext to the
caller and thus encourage just this habit?

Certainly I have much sympathy with the problem of giving the user a
simple API for dealing with large files. However, I think such an API
should, under the covers, chunk the data and apply an AEAD to each
chunk. That design can avoid holding large amounts of plaintext or
ciphertext in memory and also avoid returning unauthenticated
plaintext.

There is still the need to handle unexpected truncation, but I think
that's fundamental when one cannot hold the whole file in memory at
once.

So I think that what you want is an "AEAD chunking format" which is a
higher level concept than an AEAD and that our disagreement arises
from merging what I see as two different layers.

(*) by one-shot I mean that it does the whole operation in one call. I.e.:

ssize_t EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx,
                         unsigned char *out, size_t max_out_len,
                         const unsigned char *nonce, size_t nonce_len,
                         const unsigned char *in, size_t in_len,
                         const unsigned char *ad, size_t ad_len);

Cheers

AGL

---

From: [email-masked] (Niels Möller)
Date: Fri, 14 Feb 2014 21:49:21 +0100

> caller and thus encourage just this habit?

The proper way is to process the file incrementally (with bounded RAM),
write the result to a temporary file on disk (preferably hidden, if
supported by the OS). At the end of data, check authentication, and
either rename the file and advertise it, or delete it and return a
failure exit code.

And I think this is the right way to do it no matter of you use plain
AEAD or some "AEAD chunking format" (more on truncation below).

> from merging what I see as two different layers.

Under the assumption that processing of a truncated version or "prefix"
of the authenticated file is somehow safe, an AEAD chunking format has
an advantage over plain AEAD, in that it can provide prefixes of the
authenticated file early.

But in the case that you really want proper authentication of the
*complete* file before you start processing it, I think an AEAD chunking
format is additional complexity with no benefit over plain AEAD, since
plain AEAD provides exactly the type of autentication needed.

I'd prefer not assume that prefixes are safe. I don't have any very
concrete example, but I think that in general handling a truncated file
should be considered dangerous. As one example, I think pdf files have
some kind of master index at the end, and also some possibility to edit
earlier contents by appending data and a new index at the end (intended
for adding notes on top of a signed pdf, iirc).

>                          const unsigned char *ad, size_t ad_len);

I intend to provide an interface like that in the Nettle library; the
streaming/incremental interface will not be the only one. And I expect
that the one-shot functions will be the right choice for most
applications.

But since the one-shot functions will be implemented on top of the
lower-level incremental interface I described earlier, any additional
complexity there is relevant also for applications exlusively using the
one-shot interface.

Regards,
/Niels

---

From: Adam Langley <[email-masked]>
Date: Fri, 14 Feb 2014 17:05:10 -0500

> either rename the file and advertise it, or delete it and return a

I think that's a fine API to expose if you can limit it to operations
like that. However, I fear requirements creep will will set in as data
needs to be further processed and one ends up evincing a "streaming"
API that has the unauthenticated plaintext problems that I worry
about.

For example, in my favourite, recreational language of the moment
(Go), the convention for layering transforms like decryption is to do
it in a streaming fashion via a minimal interface that provides a
read() like, virtual function. Using a temp file in a library would be
considered poor form, although it does solve the truncation problem.

I admit that I'm hypothesising with little evidence which implies that
the argument can be dismissed with little effort.

Although, if you were to implement just an API like that then you
could require that update be called exactly once, since it wouldn't be
public API anyway, and that would solve your AD length problems.

> plain AEAD provides exactly the type of autentication needed.

I think the benefit is that one doesn't have to worry about possibly
exposing an unsafe, streaming API. Everything can be composed from a
one-shot, AEAD function and we don't have to worry about littering
header files with more comments describing the superficially correct,
but unsafe, ways that the functions shouldn't be used.

But just because it's not my personal preferences doesn't mean that
it's unreasonable.

Cheers

AGL

---

From: Nikos Mavrogiannopoulos <[email-masked]>
Date: Mon, 17 Feb 2014 09:09:48 +0100

> one-shot(*), AEAD API at the core.

I'd pretty much agree with the chunked approach, but I now realize that
it is more hard to get it right than the streaming one. In the chunked
approach one would need to implement sequence numbers (could be implicit
as additional data) and a termination block. So both approaches have
quite some disadvantages. The streaming approach allows for misuse of
the API which may cancel the benefits of AEAD, and the chunked approach
requires the developer to create a safe protocol over AEAD.

If the idea is for AEAD to be used by an average developer, it seems we
need even a higher abstraction than that; even for such a simple
use-cases.

regards,
Nikos

---

From: Watson Ladd <[email-masked]>
Date: Mon, 17 Feb 2014 07:45:48 -0800

> need even a higher abstraction than that; even for such a simple

Let's back up a bit. The assumption is that we are sending a file over
the network, and we want to encrypt and authenticate it. If we have an
encrypted and authenticated channel all is good. Alternatively, we can
encrypt the entire file as one big chunk and decrypt on receipt.  I've
still not found a case where one of these doesn't work.

Sincerely,
Watson Ladd
>
> regards,
> Nikos
>
>
> _______________________________________________
> TLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/tls

-- 
"Those who would give up Essential Liberty to purchase a little
Temporary Safety deserve neither  Liberty nor Safety."
-- Benjamin Franklin

---

From: Adam Langley <[email-masked]>
Date: Mon, 17 Feb 2014 20:59:05 -0500

> need even a higher abstraction than that; even for such a simple

I certainly agree with this. In some sense we already have this in the
shape of the TLS record protocol itself, but it doesn't lend itself to
being reused in a non-transport setting very well.

Cheers

AGL

-- 
Adam Langley [email-masked] http://www.imperialviolet.org

---

From: Adam Langley <[email-masked]>
Date: Mon, 17 Feb 2014 21:05:44 -0500

On Mon, Feb 17, 2014 at 10:45 AM, Watson Ladd <[email-masked]> wrote:
> Alternatively, we can

I don't believe that there's any disagreement about the fact that
operating on the file as one, large chunk works, technically.

The problem is that I believe that it results in dangerous APIs. For
example, OpenPGP does this and I was very unhappy about it when
writing this[1] implementation which returns unverified plaintext. I
called the Reader "UnverifiedBody" and put a big comment in there but
I think we should be able to do better. The point of AEADs was to
provide a safer abstraction in the first place, no?

(Niels suggested buffering everything before returning anything and
that's certainly safe. But I feel that it's somewhat anti-social for a
library to do so.)

[1] https://code.google.com/p/go/source/browse/openpgp/read.go?repo=crypto#38

Cheers

AGL

---

From: Watson Ladd <[email-masked]>
Date: Mon, 17 Feb 2014 21:00:27 -0800

> that's certainly safe. But I feel that it's somewhat anti-social for a

I don't think there is any way around that. If I want to ensure all
read data has property P, and P depends on every byte of input, I need
to look at all the input bytes before revealing any data.

Sincerely,
Watson Ladd

---

From: Bill Frantz <[email-masked]>
Date: Mon, 17 Feb 2014 21:19:15 -0800

>to look at all the input bytes before revealing any data.

Well, you can work on sub-blocks of the whole chunk of data. 
Either a MAC or digital signature on each sub-block would do. 
Verify the sub-block and it can be released to the relying 
application. If we are using a 32 byte MAC, then 3200 byte 
blocks would only have 1% overhead for checking. There are very 
few systems where a buffer size the order of 3200 would cause a 
serious problem.

Cheers - Bill

-----------------------------------------------------------------------
Bill Frantz        |The nice thing about standards| Periwinkle
(408)356-8506      |is there are so many to choose| 16345 
Englewood Ave
www.pwpconsult.com |from.   - Andrew Tanenbaum    | Los Gatos, 
CA 95032

---

From: Watson Ladd <[email-masked]>
Date: Mon, 17 Feb 2014 21:38:57 -0800

On Mon, Feb 17, 2014 at 9:19 PM, Bill Frantz <[email-masked]> wrote:
> Well, you can work on sub-blocks of the whole chunk of data. Either a MAC or
> digital signature on each sub-block would do. Verify the sub-block and it
> can be released to the relying application. If we are using a 32 byte MAC,
> then 3200 byte blocks would only have 1% overhead for checking. There are
> very few systems where a buffer size the order of 3200 would cause a serious
> problem.
>

The application has to be ready to accept truncations on arbitrary
subblock boundaries for this to work out.
That's not the same as semantics indicating the entire file is fine if
you can read from it.
Sincerely,
Watson Ladd

> (408)356-8506      |is there are so many to choose| 16345 Englewood Ave
> www.pwpconsult.com |from.   - Andrew Tanenbaum    | Los Gatos, CA 95032
>

---

From: Bill Frantz <[email-masked]>
Date: Mon, 17 Feb 2014 22:17:00 -0800

>That's not the same as semantics indicating the entire file is fine if

However, it is a situation that any application that is reading 
files needs to be prepared to handle. Disk errors and all 
that...  Not much different from losing the network connection 
either. In fact, there is probably no way to assure the 
application that it absolutely, no fail -- ever --, will be able 
to read some data, even if the data is all in main memory.

Cheers - Bill

---------------------------------------------------------------------------
Bill Frantz        |"After all, if the conventional wisdom was 
working, the
408-356-8506       | rate of systems being compromised would be 
going down,
www.pwpconsult.com | wouldn't it?" -- Marcus Ranum

---

From: Alfredo Pironti <[email-masked]>
Date: Tue, 18 Feb 2014 11:15:24 +0100

On Tue, Feb 18, 2014 at 7:17 AM, Bill Frantz <[email-masked]> wrote:
> However, it is a situation that any application that is reading files needs
> to be prepared to handle. Disk errors and all that...  Not much different
> from losing the network connection either. In fact, there is probably no way
> to assure the application that it absolutely, no fail -- ever --, will be
> able to read some data, even if the data is all in main memory.

TLS is indeed designed to distinguish between "fatal" closure and
"graceful" closure. A "fatal" closure (fatal alert or network
disruption) ensures that a *prefix* of the data sent by the peer are
received; by comparison, "graceful" closure via full-duplex
close_notify ensures that *all* data are received as sent by the peer.
Even the standard socket and I/O functions make this distinction
(although there's no integrity check there).

Cheers,
Alfredo

> Bill Frantz        |"After all, if the conventional wisdom was working, the
> 408-356-8506       | rate of systems being compromised would be going down,

---

From: [email-masked] (Niels Möller)
Date: Tue, 18 Feb 2014 13:56:41 +0100

Bill Frantz <[email-masked]> writes:

> However, it is a situation that any application that is reading files
> needs to be prepared to handle. Disk errors and all that...

I think there's a difference between on one hand, truncation due to
random failures of your own, reasonably trusted, hardware. And on the
other hand, truncation caused the enemy attacking the communication
channel for some evil purpose.

If we really want to make progress with this discussion, I guess we must
also distinguish between file types where appending data doesn't change
the meaning of earlier data (e.g, a typical log file), and file types
where appending data can change the meaning radically (e.g., consider a
document format where you can add data at the end of the file which adds
a mark "this document is fake" on top of every page when the file is
displayed or printed).

Regards,
/Niels

---

From: Daniel Kahn Gillmor <[email-masked]>
Date: Tue, 18 Feb 2014 11:05:56 -0500

> channel for some evil purpose.

I agree that there is a difference between those cases in the abstract
sense.  But from the recipient's point of view, these cases are often
indistinguishable from one another.  I'm not sure that any AEAD api
should try to distinguish between them.

> a mark "this document is fake" on top of every page when the file is

I think this distinction is also likely to be hard for generic tools
(tools which want to be context-independent) to make.  But, just going
with a non-exhaustive, first-pass comparison approach, there are some
unsettling results:

text/html is a content-type that meets the
"sensitive-append/risky-truncation" definition, since new html elements
(not to mention javascript) can effectively obscure or override previous
html elements, at least in common visual renderers; text/plain arguably
meets the "insensitive-append/safe-truncation" definition, since new
elements never directly collide with old elements (though a postscript
to a human-drafted document that says "PS ha ha just kidding" changes
the semantics of the earlier content significantly).

Looking at the behavior of modern browsers using https with GCM
(ECDHE-RSA-AES128-GCM-SHA256), they render both text/html and text/plain
data streams as they receive them, and they do not provide any
indication to the user that they believe the data to be truncated, even
when receiving an early TCP connection termination, or when a
Content-Length: header is not satisfied, or when (in the case of
text/html) the html document is not properly closed.

So content truncation attacks appear to be already possible in current
implementations, despite any guarantees provided by AEAD.  Note that I
haven't tried to attack the AEAD itself at the TLS record layer, but i'm
observing that common utilities like browsers don't propagate truncation
errors up to the user already. :(

Perhaps this angle on the issue is best moved over to the uta working
group, since it's about what to do in the application layer with certain
kinds of TLS failures.

	--dkg

---

From: Bill Frantz <[email-masked]>
Date: Tue, 18 Feb 2014 13:49:36 -0800

>channel for some evil purpose.

 From the point of view of an application, there isn't much 
difference. In both cases, it receives notification from the 
infrastructure that the read couldn't complete because an error occurred.

System managers certainly want to know if they are under attack, 
but even just knowing that there was a MAC verification failure 
is not solidly definitive. There could have been an undetected 
failure in the transmission which only showed up because of the 
MAC failure -- since the MAC is a stronger check than the checks 
in TCP/IP. IF I were that manager, one failure -- be on high 
alert for attackers. Two failures -- try to located the 
attackers and deal with them. :-)

>a mark "this document is fake" on top of every page when the file is

I see no need to make such a distinction at our level. We will 
give the application an error that says we couldn't give it all 
the data. How it handles the error is not our problem. Handling 
this error like any other "couldn't read the rest of the file" 
error seems right in all cases.

Cheers - Bill

---------------------------------------------------------------------------
Bill Frantz        | Re: Computer reliability, performance, and security:
408-356-8506       | The guy who *is* wearing a parachute is 
*not* the
www.pwpconsult.com | first to reach the ground.  - Terence Kelly