Is it possible to use a GPG or SSH key for web based authentication in a secure fashion?
For a Web application, the main problem is that the Web site code (Javascript in a browser) is not able to read and write files at will. Well, in general, this is more a boon that a problem, but here it means that the Javascript code will not be able to access SSH or PGP private keys.
There are things which can be done, depending on how much technology-savvy your users are, and how many manual operations they will tolerate:
You could use a locally installed browser extension which accesses the SSH or PGP private keys on behalf of the Web site. Preferably, some user control is advisable: we really don't want a browser which will sign things just because a Web site said to do it.
The server may act as a SSH server, and requires clients to connect with SSH and key-based client authentication. The user would run SSH in "SOCKS proxy" mode. The Web server itself would listen only to
localhost
, i.e. be unreachable except through such a local proxy. In this mode, the Web server could even be HTTP, not HTTPS; this would really be replacing SSL with SSH. On the server side, keeping track of users should use mod_ident or something similar (the SSH server knows who the client is, but the information must be forwarded to the HTTP server; fortunately, this is on the same machine, so the Unix-level identity can be used).The Web site could display a "challenge" as a downloadable file with random contents. The user obtains the file, signs it with GnuPG, and pastes the (ASCII-armored) output into a text field on the Web site. The server verifies the signature, and accepts it as authenticating the user (provided that the server already knows the user's public key). Clunky, but works.
A mail-based variant of the above can be advisable, because PGP implementations are often embedded in email software, and also because it opens a possibility of not having to trust an external root CA. It would look like this:
User connects to the Web server with HTTPS. The server uses a self-signed certificate. The browser warns about it (the "red scary warning") but allows the user to proceed.
In the site, the user enters his name. Then the server sends a signed and encrypted email (with PGP) to the user; the signed email contains a random nonce, and also a copy of the server's SSL certificate thumbprint. The random nonce is also printed out on the Web site itself.
The user verifies the PGP signature on the server's email, then checks that the thumbprint matches the one he can see from his browser; this convinces the user that he is seeing the genuine server certificate, so there is no ongoing Man-in-the-Middle attack. (This is where we replace the X.509 CA system with PGP-based validation.)
The user also verifies that the nonce displayed on the Web site matches the one he sees in the email (this is important).
The user responds to the email by sending its contents back, this time signed with his own PGP private key, and encrypted with the server's public key. The server verifies that email and thus knows that the nonce value was indeed received by the intended user.
The server sends the nonce value as a cookie to the user's browser. This allows browsing without pestering the user with further authentication rounds. It is up to the server to decide how long it will accept the cookie as a valid authentication token.
In the above scheme, it is important to notice that by sending back his email response, the user is really authorizing the server to assume that whoever comes back with the nonce (as included in the email) is really the user himself. This is why manually checking that the nonce matches what is shown on the Web page is important.
Is it possible to use OpenPGP/SSH key pairs to authenticate with a web application in a secure fashion to replace traditional password-based authentication?
Yes. It is quite possible.
If it is possible, what will the authentication steps look like? Is there perhaps a known good implementation of such an idea for popular languages and platforms like Ruby, .NET, Java or Python?
See my answer for the next question.
If it isn't possible, what are the reasons? Is there perhaps a constraint on web browsers accessing the GPG keychain or SSH key file?
Processing SSH and OpenPGP keys in a web app is possible with third party libraries (especially C or Java libraries given their rich ecology), but you would be missing out on leveraging the most common existing solution - SSL/TLS.
The best bet would be for users to generate X509 client certificate signed by your server to authenticate themselves - because then your web app can simply rely on the web container (Catalina Tomcat, ApacheD, IIS, etc) to perform seamless encryption and authentication for your application.
Under the hood OpenPGP keys have the same RSA exponents as a X509 certificate, so tools such as openssl
can convert GPG/PGP keys to self-signed* X509 certificates; same for SSH keys.
* OpenPGP web-of-trust qualifies as 'self-signed' from the X509 standpoint because X509v3 can't have a multiply-rooted trust chain as far I've been able to determine.
The existing answers offer good advice - use the SSL stack in the browser instead.
However, it is actually possible to do exactly what you want - using JavaScript cryptography.
There is an OpenPGP implementation in JavaScript http://openpgpjs.org/ I can't vouch for it's quality.
Also, it is possible for HTML5 JavaScript to access local files, e.g. http://www.html5rocks.com/en/tutorials/file/dndfiles/
I think this would be more a curiosity than a practical system though.