Enigform: The OpenPGP Firefox Extension

We all know about the benefits of digitally signing email messages using
OpenPGP-based software like GnuPG (or its older commercial counterpart,
PGP). Imagine the same benefits applied to the world of the World Wide
Web.

The most well-known userland usage of OpenPGP is email signing and
encryption (check out Enigmail for Mozilla
Thunderbird). By digitally signing your email messages, recipients
with OpenPGP-enabled mail user agents are able to authenticate the
email's sender and message. If the message body was modified in any way
during transport, the signature will not verify. This capacity for data
authentication is why many files available for download on the Internet
also provide an OpenPGP digital signature in a .sig file. OpenPGP is
much safer than MD5.

Email messages can also be encrypted to specific recipients, even the
sender herself, adding privacy to the equation. For the moment, though,
let's just focus on the "data authentication" part.

One night, approximately one year ago, I suddenly woke at 3:00 AM with
two crazy sets of words in my head: "BEGIN PGP" (part of OpenPGP content
and signature delimiters of signed/encrypted messages) and "GET /".
Signing HTTP requests with OpenPGP! I realized that could provide Web
servers and applications the ability to determine sender and data
authenticity. In other words, to know not only who sent a
request, but also if it was tampered with during transport (for example,
by a malicious transparent proxy sitting between the browser and Web
server).

Of course, I couldn't sleep, and my wife was not in the mood to
understand my ramblings, so I got up, wrote the idea down, and went back
to sleep.

About ten months later, I decided to create a Firefox extension to
implement my idea. The first publicly-released version only worked with
the HTTP POST method and was ugly, but functional. Basically, I
replaced the POST body with a signed version. This turned out to be a
bad idea because Web servers and Web applications that didn't understand
it would be broken.

I teamed up with Rodhri Pugh, author
of the Smutty PHP
MVC project, and we started a nice brainstorming of ideas. Smutty
was the first PHP framework to support Enigform... but it
was still ugly.

I decided I needed feedback. I contacted the IETF OpenPGP Working Group,
and via the mailing list, they said: "OpenPGP signing is implemented for
newsgroup posts as a set of extra headers. Why don't you use that?" So,
I did; I rewrote Enigform. There was no more HTTP POST body tampering,
just a set of HTTP headers added to each request: The signature itself,
a GnuPG version string, and a Digest Algorithm string.

That did it: I was able to attach a digital signature to every kind of
HTTP request (GET, POST, PUT, whatever) and even to AJAX-originated
requests. The latter was very nice for AJAX, since one of its main
mis-implementations lies in the authentication of those asynchronous
requests. All this came without breaking HTTP at all.

Now, let's see how a standard HTTP request looks, for example, for a
FORM submission:

The request is still standard. A Web server or application that does not
know what the extra headers mean (and, more importantly, how to use
them) will do nothing but ignore them.

Let's do some further analysis on those headers:

X-OpenPGP-Type: S

This means the request is Signed. In the future, "E" for Encrypted and
"SE" for both Signed and Encrypted will be supported.

X-OpenPGP-Sig-Fields: body

This states which elements are signed, and in what order they were
submitted to the OpenPGP application. As you can see, only the "body"
of the request was signed. In the example, the body is the POST
payload, or "variable=value". In a GET request, the "body" would be
the QUERY STRING.

This is the OpenPGP signature itself, converted from its standard
three-line form to a simple string.

X-OpenPGP-Digest-Algo: SHA1

This is the hash algorithm used, in this case SHA1. This depends on
what choices the OpenPGP application provides and what the user
chooses to use.

X-OpenPGP-Version: GnuPG v1.4.6 (GNU/Linux)

This is the OpenPGP application's name, version, and platform. This is
extracted from the "Version:" field of standard, signed, ASCII armored
OpenPGP output.

X-OpenPGP-Agent: Enigform 0.7.6 for Mozilla Firefox

This is the software that created the X-OpenPGP set of headers and
signed the fields. With luck, once I finish the Internet Draft and if
it gets to be a Standards Track RFC, some browsers will support
OpenPGP natively, and Enigform will no longer be needed.

Enigform Usage

To use Enigform, you just need Firefox 1.5+ and GnuPG. For the moment,
I'm testing with GNU/Linux, MS Windows, and MacOS X platforms, so if you
have another OS (like Solaris), please send me an email, and we will get
Enigform working for you and the rest of the community.

Enigform tries to detect where the gpg (or gpg.exe) binary resides.
Although I plan to enhance this area, for the moment it works like this:

Under GNU/Linux, it searches for /usr/bin/gpg. Under MS Windows, it
tries to get the installation directory for GnuPG from the registry.
Under OS X, it searches for /usr/local/bin/gpg (where macgpg gets
installed). If GPG is not found, it warns you and asks you to set the
full path to it in the Enigform Preferences window. If your OS is
not (yet) supported, it just tells you so. Please contact me if you get
that message, so more users can try and benefit from Enigform.

When Enigform detects a request whose URI ends in
#Enigform_Sign# (named anchors are safe to use in this
case, although I plan to enhance this by reading a special HTTP header
in a response), or if the "Always Sign" option is enabled, it will try
to sign the body. If the passphrase is unknown, it asks you to input it.
(Enigform can remember it if told to do so, and you can also clear it
from memory using a context menu item).

Enigform calls GnuPG and feeds the passphrase and request body using
random temporary filenames that are stored in a random new temporary
directory under your OS's temp directory. It also reads the signed
version from a file. It deletes the files and the directory that held
them as soon as possible, starting with the passphrase file.

Once the signed version is read, the required elements are extracted and
converted to the form we saw in the signed request example. The headers
are added, and the normal flow of the request is restored.

And that's it! The receiving Web application/server can act, or not,
accordingly.

By means of an Apache module I'm developing, mod_auth_openpgp,
adding Enigform support to Apache is very simple.
Although the module is still in development, it can be used to test this
new security schema.

Additionally, at the Enigform Test Site, you
can find some PHP code snippets for playing with Enigform. The Smutty
source code for the Smutty_GPG
class is another invaluable resource.

A webmaster has a site on an OpenPGP-enabled Apache server, and wants to avoid having to implement a username/password based login system. So he just implements a signup mechanism that asks users for their pgp public key.

Then, he just adds a special "Login" link to his page, and all Enigform-enabled browsers will be able to click on it, start a session, and be automatically authenticated.

The protocol is a challenge/response mechanism which uses openpgp encryption/decryption to accomplish its goal.

From then on,e ach request that goes to the server will be signed, and have this sesison hash embedded, thus the apache server can determine if the sesison is valid, invalid, or timed-out :)

personally, I think the biggest risk on the Net today is simple surfing: user may be browsing what is normally a reliable site but clicks on a link that interests him and this link could very easily lead into the back alley where the RATS live.

The site the user came from is most likely well intentioned. but the character of the destination may have changes either by revisions made by the web authors or by some kind of DNS spoofing

which is why it is critical to establish and enforce the simple rule No Signature: No Execute as far as anything executable goes.

Hopefully we can prevent the RAT from getting his signature approved by the Certificate Authority but we should discuss auditing of software distributions separately. For starters we kill all un-authorized executables on the spot.

Re: EnigForm
To win we must beat the RAT and we must beat him by a complete shut-out.

Which means: No Signature: No Execute.

Once that has been done on the communication link finishing the issue will require some kind of auditing for software that we do allow to be distributed.

One other thing too: and that is about Certificate Authorities: we will have to insist that everyone appear in person with identification at the Certificate Authority or at an authorized agent thereof such as a Credit Union, Office Max etc. in order to obtain the public key for the Certificate Authority and to register personal public key.

>
> % I don't know if scam prevention was
> part
> % of your goals. I did read in your
> % comments you originally sent this
> idea
> % to Goggle so maybe it was. I believe
> % there is still much to think of with
> % such a scheme to make it secure.
>
>
> Yes, although it still needs much work
> (making it at least usable is the first
> step to get good community feedback, I'm
> a full-disclousure and
> security-through-clarity guy), anti
> phishing / scam prevention are one of my
> goals.
>
> As you saw, I decided to focus on
> Identity and Data authentication of
> client at server, but of course I'm also
> thinking about the same scheme in
> reverse.
>
> Additionally, Encryption WILL be
> implemented some day in the near future,
> although this is now something I have in
> my mind because of your comments
> regarding SSL and multiple virtualhosts
> on the same IP: it's a good thing to
> implement and lots of people might
> benefit from it.
>
> To prevent scams, all that is needed is
> the server identifying the client, and
> the client identifying the server. If
> they both can trust each other, as no
> other credentials (passwords, PINs, etc)
> are needed, then phishing becomes
> useless.
>
> For example, a fake paypal site that
> requests my username and password would
> simply not work, as there is no username
> (well, email address actually) and
> password. There is only signed http
> requests that get into paypal, that
> paypal can verify as belonging to that
> user, and they also can be sure the data
> has not been tampered with.
>
> Okey, the private key and the passphrase
> could still be stolen, but that's a
> whole other issue.
>
>
>
>

I like this plugin very much. Any idea when there will be a new version? There are some features I am missing, would be cool if anybody can update this and add some more features! Bye, Paul.

3) although you can be your own CA, if you want to avoid the hassle of telling your users to have your root cert into their browsers or whatever, then you need to spend lots of money on ssl certificates.

4) message-based, not socket-based.

5) you can mix openpgp signed requests (which are VERY flexible from web-developers and designers' perspective) over HTTPS.