Playing around with MIME/PGP lambda web services

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/4.4.0.0 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/4.4.0.0 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
          foo@bar.com: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.

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.