In the upcoming release of Phosphorus Five, one of the things I have given great attention to, is its MIME and PGP parts. One of its really nifty use cases is the ability to invoke cryptographically signed and encrypted web services passing in MIME envelopes as the body of your request. This has a lot of interesting use cases, such as making it possible to demand that the invoker of your web service has cryptographically signed his invocation using a “whitelisted” PGP key – Resulting in a web service that can only be invoked by an authorised client. Or to transmit multiple Hyperlambda snippets, that are evaluated in order of appearance. Or to transmit file attachments together with your web service invocation, having access to these file attachments from your own (client) Hyperlambda, etc, etc, etc. If you have no idea what a “lambda web service is”, you can read one of my DZone articles about it here.
In the upcoming 8.4 release I will have a Hypereval “page” snippet, that actually acts as a web service endpoint, encapsulating a lot of interesting features down this alley. Notice, the code examples here requires that you have at least version 8.4 of Phosphorus Five, which is not yet released as of this writing. Anyway, let us look at what we can do, as 8.4 is released.
A simple HTTP POST web service invocation
So let us first create a simple (non PGP) web service invocation. Notice, if you’ve downloaded version 8.4, you’ll need to use e.g. “Peeples” to grant module access to the “/hypereval/lambda-ws” page to the guest account to be able to use this code.
/* * Creating a normal lambda web service invocation. */ p5.http.post:"http://127.0.0.1:8080/hypereval/lambda-ws" Content-Type:application/x-hyperlambda content +:int:7 *:int:20 _:10 return:x:/@+?value
The above Hyperlambda snippet will create an (unencrypted) HTTP POST request going towards your Hypereval “lambda-ws” page, and pass in a Hyperlambda snippet, that simply multiples 20 with 10, for then to add 7 to the result, and echos the results (207) back to the client. A slightly more complex version can be imagined using the following code.
p5.http.post:"http://127.0.0.1:8080/hypereval/lambda-ws" Content-Type:application/x-hyperlambda content split:Thomas Hansen is pretty cool =:" " add:x:/+ src:x:/@split/*?name return
The above will result in something resembling the following.
p5.http.post result:"http://127.0.0.1:8080/hypereval/lambda-ws" status:OK Status-Description:OK Content-Type:application/x-hyperlambda Last-Modified:date:"2018-06-19T13:17:04.998" Server:Mono.WebServer.XSP/188.8.131.52 MacOSX Date:"Tue, 19 Jun 2018 10:17:04 GMT" Cache-Control:private Set-Cookie:ASP.NET_SessionId=34F7802887AEA977F431B3DA; path=/; HttpOnly Connection:close content Thomas Hansen is pretty cool
Basically passing in Hyperlambda code, that splits a sentence (on the server may I add), as a web service invocation, and returns each word back to caller, as the body of the HTTP response. The reasons why this is pretty safe and secure, is because as I evaluate the Hyperlambda supplied by the client, I am using [eval-whitelist], which allows me to only allow for a (secure) subset of my server’s Active Event vocabulary. Hence, no malicious code constructs are possible to create that somehow changes the state of my server. What vocabulary you want to whitelist is easily configurable.
Encrypting and signing your web service invocation using PGP
This is where it gets interesting. First let’s have a look at some code that does something similar to our above code, with two crucial differences. First of all it encrypts our code. Secondly it cryptographically signs your code using a private PGP key.
/* * Creating a cryptographically secured lambda web service invocation. */ p5.http.post:"http://127.0.0.1:8080/hypereval/lambda-ws" .onrequest .p5.mime.serialize-to-stream multipart:mixed encrypt fingerprint:83bfcbe0235f90e0a67bb865863a22266f9ef39a sign application:x-hyperlambda content split:Thomas Hansen is pretty cool =:" " add:x:/+ src:x:/@split/*?name return .onresponse .p5.mime.load-from-stream
The above code will create a MIME envelope of our “string split” Hyperlambda. Then it will encrypt the code for then to cryptographically sign the message. The code will be cryptographically signed by your server’s PGP key, and it will be encrypted for the PGP key having the fingerprint of “83bfcbe0235f90e0a67bb865863a22266f9ef39a”. The latter of course must match the PGP key of the server you are transmitting your request to. Which you can read about how to acquire here.
This creates a couple of really interesting side effects. First of all, all of a sudden we have a guarantee of that the request originated by the client that had access to the private PGP key that was used to sign the envelope. Since the web service endpoint allows us to create a “white list” of accepted PGP keys, this allows us to only accept invocations from clients we know for a fact we can trust – Assuming your private PGP key hasn’t been compromised somehow of course.
In addition, it becomes literally impossible for an adversary to spy on your web service invocations. For code, this might not be that crucial. However, the MIME features of Phosphorus Five also allows you to transfer data and files, making this “tiny little detail” important. In addition, it also completely eliminates the problem with a “Man In The Middle” acting as a malicious proxy, tricking you into believing you have a secure SSL context, by giving you a fake certificate. In fact, even in the middle of a “Man In the Middle” attack, you can still have a cryptographic guarantee of that you have a securely encrypted communication channel – Assuming your PGP keys are correct though.
It also prevents “tampering” with the message, since if such a thing occurred, the PGP signature would no longer verify, and the invocation would never be evaluated. And since this all happens “automatically” for you, and the code is returned “semantically”, there is zero overhead for you as an application developer to implement this. In fact, here is what is returned from the web service after invocation.
p5.http.post result:"http://127.0.0.1:8080/hypereval/lambda-ws" status:OK Status-Description:OK Content-Type:text/html Last-Modified:date:"2018-06-19T13:24:19.390" Server:Mono.WebServer.XSP/184.108.40.206 MacOSX Date:"Tue, 19 Jun 2018 10:24:19 GMT" Cache-Control:private Set-Cookie:ASP.NET_SessionId=33FDE6A445F8D46F03602E74; path=/; HttpOnly Connection:close content multipart:signed signature firstname.lastname@example.org:bool:true fingerprint:83bfcbe0235f90e0a67bb865863a22266f9ef39a multipart:mixed application:x-hyperlambda content Thomas Hansen is pretty cool application:pgp-signature Content-Disposition:attachment; filename=signature.pgp Content-Transfer-Encoding:7bit content:blob: ... a long piece of PGP signature blob ...
At which point you can retrieve your Hyperlambda results with a simple x-pression. If the web service endpoint receives something that is cryptographically signed, it will encrypt the return value for that same PGP key, and cryptographically sign it with its server key. Resulting in that you have a 100% water tight cryptographically secured guarantee of that nobody have been tampering with your request somehow, and nobody has seen neither what was sent, nor what was returned.
Yet again, I want to emphasise that the code to accomplish this is not yet released, but will be released soon in the upcoming 8.4 version. If you’d like to see if 8.4 is released, you can check out this link. For the code examples, I used “Hypereval” myself, doing a simple loopback invocation to my own localhost server. You can of course use anything else as your client though, including CURL or C# code – As long as you’re able to somehow create the correct HTTP requests. And you can of course use anything as a client, and any Phosphorus Five server as a server.
As an additional bonus I have also created a GUI wrapper, allowing you to play around with Hyperlambda constructs, to test your web service code. Below is a screenshot.
When executed, a modal window will be displayed, with the same result and structure a web service invocation would yield.