If you follow the W3C or web development, you probably know that the WebCrypto API was designed to provide fairly low-level cryptographic algorithms so that you could build web applications that interoperate with existing systems.
The idea being it was largely the cryptographic primitives that needed to be implemented natively and that the other layers of interoperability could be handled in pure Javascript when combined with good application security practices and new features like SRI.
While there are legitimate concerns over the use of cryptography in browser-based applications there are also legitimate uses. Afterall who doesn’t like to watch a film on Netflix now and again without having to run Flash?
For another example of an application that makes heavy use of WebCrypto take a look at 1Password which is one of the most popular password managers in use today. They use WebCrypto and the same origin security model of browsers to allow them to help manage their passwords locally and store the associated ciphertext on their servers.
The utility of WebCrypto does not end with applications though, many libraries, some by my company, Peculiar Ventures, leverage this raw cryptographic capability to make it easier for others to build applications that interoperate with their counterparts on other platforms. For example consider PKIjs, XMLDSIG, XADESjs, 2key-ratchet and js-jose.
However powerful this new native cryptographic capability is, it intentionally left out providing access to local cryptographic certificates and key stores as well opted out of providing web applications access to smart cards and other security elements. I personally both agree with these decisions and understand why they were made but that is something for another post. With that said, that doesn’t mean those capabilities are not useful and that is where Fortify comes in.
So what is Fortify?
Fortify is a client application that you install that runs in the background as a tray application in Windows, OSX, and Linux that provides these missing capabilities to authorized applications.
It does this by binding to 127.0.0.1 and listening to a high-order well-known port for incoming requests. Browsers allow web applications to initiate sessions to this address, over that session a Fortify enabled application establishes a secure session and if approved by the user is allowed to access these missing capabilities.
How is this secure session established?
At the core of Fortify is a library called 2key-ratchet. This implements a `Double Ratchet` protocol similar to what is used by Signal. In this protocol each peer has an identity key pair, we use the public keys from each participant to compute a short numeric value since in the protocol the peers prove control of the respective private keys we know that once the keys are authenticated we are talking to the same “identity”.
Since 2key-ratchet uses WebCrypto we leverage the fact that keys generated in a web application are bound to the same origin, we also (when possible) utilize non-exportable keys to mitigate the risks of these approved keys from being stolen.
This gives us an origin bound identity for the web application that the Fortify client uses as the principal in an Access Control List. This means if you visit a new site (a new origin), even if operated by the same organization, you will need to approve their access to use Fortify.
For good measure (and browser compatibility) this exchange is also performed over a TLS session. At installation time a local CA is created, this CA is used to create an SSL certificate for 127.0.0.1. The private key of the CA is then deleted once the SSL certificate is created and the Root CA of the certificate chain is installed as a locally trusted CA. This prevents the CA from being abused to issue certificates for other origins.
What happens over this session?
The protocol used by Fortify use a /.wellknown/ (not yet registered) location for capability discovery. The core protocol itself is Protobuf based.
We call this protocol webcrypto-socket. You can think of the protocol as a Remote Procedure Call or (RPC) to the local cryptographic and certificate implementations in your operating system.
Architecturally what does the client look like?
The Fortify client is a Node.js application based on Electron and it accesses all cryptographic implementations via node-webcrypto-p11. This library was designed to provide a WebCrypto compatible API to Node.js applications but it also extends the WebCrypto API to provide basic access to certificate stores.
The Fortify client uses another Peculiar Ventures project called PVPKCS11 to access the OSX KeyStore, Mozilla NSS or Windows CryptoAPI via this PKCS#11 wrapper.
It also uses pcsclite to listen for a smart card or security token insertions and removals, when new insertions are detected it inspects the ATR of the card. If it is a known card the client attempts to load the PKCS#11 library associated with the card. If that succeeds events in the `webcrypto-socket` protocol are used to let the web application know about the availability of the new cryptographic and certificate provider.
Ironically, despite the complication of the PKCS#11 API, this approach enables the code to maintain a fairly easy to understand structure.
The application also includes a tray application that is used to help with debugging, access a test application and manage which domains can access the service.
So what can I do with it?
In the simplest case, you can think of Fortify as a replacement for the <keygen> tag.
Since the client SDK that implements the `webcrypto-socket` protocol is a superset of WebCrypto, with slight modifications, if you have an web application that uses WebCrypto you can also use locally enrolled certificates and/or smart cards.
Some of the scenarios we had in mind when building the Fortify client included:
— Enrolling for X.509 certificates over the web,
— Signing and encrypting/decrypting email or documents,
— Building certificate-based authentication schemes with a modern user experience.
Can I use this today?
Yes, it is feature complete and ready for you to take a look.
There are some examples on its usage here and you can find the documentation here.
It works on Windows 7+, OSX 10.12+, and Debian based Linux distributions, it also works on IE11, Edge, Safari, Chrome, and Firefox.
In general, you should consider this initial release of a Beta quality, for example I know we need to do additional testing with smart cards and make sure we have the metadata for each card so they work on each supported platform. Otherwise, we expect it to work largely as expected.
Is it Open Source?
Yes, all Peculiar Ventures related libraries to-date have been licensed as BSD or MIT and this is no different so you are free to do with them as you see fit.
What’s next?
Over the next year, we will gain enough confidence in the solution to declare it complete. We will also look at adding other useful like smart card password changes and unblocking at some point in the future.
Other than that, we are just looking for your feedback so we can refine the quality of the solution.
Thanks
I want to thank the members of the CASC for their support of this project and the many individuals from Twitter who provided feedback and testing.