SkillAgentSearch skills...

DelphiOpenSsl

Using OpenSsl with Delphi on all OS platforms for X.509 certificates and JWT

Install / Use

/learn @grijjy/DelphiOpenSsl
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

In this article we are going to discuss how to use the latest version of OpenSsl 1.1.1 with Delphi directly to create X.509 certificates, decode, verify, encode and sign JSON Web Tokens and generate random data. Additionally we will do this in a way that works on Delphi supported platforms including Windows, macOS, iOS, Android and Linux as well as all current compiler targets for 32 and 64-bit devices.

Introduction

The OpenSsl library contains a wealth of useful tools that cover many aspects beyond just encryption and related protocol tasks. OpenSsl is widely used to implement encryption and security over the network and the latest versions of OpenSsl support the newest standard TLS 1.3.

Developers often are reluctant to use OpenSsl in their projects because they must redistribute the library along with their project. Also, it's nearly impossible to find examples of using it on Delphi platforms other than Windows. The nice thing about using OpenSsl is that the interface for Delphi developers is consistent across all the platforms supported by Delphi. Once you implement it on Windows, you can use that same approach on iOS, Android, Linux and macOS and expect that behavior to be consistent. Additionally, OpenSsl has highly optimized internal crypto routines that typically outperform other crypto libraries on most platforms. This is a consideration when building apps that spend the majority of their time communicating securely over the network or the Internet.

Here at Grijjy we use OpenSsl to implement TLS secure communications over the network when we implement HTTP/S and secure WebSockets. We transmit and receive high-def video, audio and desktop sharing on all the OS platforms supported by Delphi in real-time using WebSockets and TLS with OpenSsl. OpenSsl works well on multi-threaded, scalable socket servers and with bi-directional protocols like WebSockets with TCP or DTLS (datagram TLS) when transmitting data using the UDP protocol. This allows us to have a common network stack to target all the platforms Delphi supports but to do this in a predictable manner.

This is a fundamental issue with using the platform-native (or integrated) approach to HTTP/S and sockets when you need TLS. While you get the advantage of not distributing OpenSsl, it can lead to unpredictable behavior from device to device and from machine to machine for simple tasks such as hashing, HTTP/S and other operations. How one platform-native HTTP/S client handles asynchronous and/or synchronous requests or parallel threads, can vary widely.

Besides the obvious HTTP/S usage, OpenSsl contains a wealth of useful routines that you can use in your Delphi projects. This article will cover just some of those use cases including using OpenSsl to create random bytes, creating your own X.509 certificates and using OpenSsl for handling JSON Web Tokens (JWT). I like simple, straight-forward examples so this is by no means an exhaustive look at these subjects and is only intended as a primer for using OpenSsl with Delphi.

JSON Web Tokens

JSON Web Tokens are very popular as a way to provide the secure exchange of information between applications in the cloud over just exchanging regular access tokens. They are widely used by many services and APIs available in the cloud like those offered by Google.

Traditionally, access tokens are used in OAuth models. While both access tokens and JWTs are used for similar purposes they each have their own characteristics that make them suitable to certain scenarios. With an access token, typically an implementation needs to track the token and lookup whether it has expired or what other detail is related to the token. At Grijjy, we typically cache tokens into memory and a database and then expire them (delete them) when their expiration interval is up. Access tokens require that all the details of the token are maintained until it is no longer needed.

JWTs work a bit differently. A typical JWT contains all the information related to the token within the token itself. This includes enough information validate that the token is authorized and not expired. JWTs can also contain custom payloads specific to your application. For this purposes they can avoid a round trip to a cache of tokens in memory or in the database for each request. However, processing JWTs with each request and validating them can be a time consuming thing. Quite a few APIs end up mixing both access tokens and JWTs for their APIs.

Personally I feel that JWTs can be very efficient, especially if you validate them one time and then cache them into memory until their expiration is up. That way, with each request you are not validating the entire signature of the JWT again but instead just looking up to see if you previously validated the JWT. A full discussion of tokens is beyond the scope of this article, but we will demonstrate JWTs using at least one hash scheme with OpenSsl.

Note: This is not meant as an exhaustive look at JWTs. We are only demonstrating one algorithm. There are other nice libraries for handling JWTs in Delphi. Our intent is to show how OpenSsl can do this in a simple, straightforward and cross-platform way.

Decoding and verifying the signature of a JWT

Decoding a JWT is a straightforward process of separating the entire token into 3 logical parts; the header, the payload and the signature. For simplicity sake we created a small helper record in Delphi to assist with decoding, verifying, encoding and signing the JWT using OpenSsl.

  { JSON Web Token }
  TgoJWT = record
  private
    FHeader: TBytes;
    FPayload: TBytes;
    FSignature: TBytes;
  public
    { Initializes the token with the provided header

      Parameters:
        AHeader: the header for the token }
    procedure Initialize(const AHeader: String); overload;

    { Initializes the token with the provided header and payload

      Parameters:
        AHeader: the header for the token
        APayload: the data payload for the token }
    procedure Initialize(const AHeader, APayload: String); overload;

    { Decodes a json web token into the header, payload and signature parts

      Parameters:
        AJSONWebToken: the encoded token

      Returns:
        True if the token was decoded, False otherwise }
    function Decode(const AJSONWebToken: String): Boolean;

    { Signs the json web token using the provided private key or secret

      Parameters:
        APrivateKey: the private key or secret
        AJSONWebToken: the encoded and signed token

      Returns:
        True if the token was successfully signed along with the resulting token, False otherwise }
    function Sign(const APrivateKey: TBytes; out AJSONWebToken: String): Boolean;

    { Verifies the token was signed with the provided private key

      Parameters:
        AData: the data that was signed
        ASignature: the signature for the data
        APrivateKey: the private key or secret

      Returns:
        True if the token signature was verified, False otherwise }
    function VerifyWithPrivateKey(const AData, ASignature: TBytes; const APrivateKey: TBytes): Boolean; overload;

    { Verifies the token was signed with the provided private key

      Parameters:
        AJSONWebToken: the encoded token
        APrivateKey: the private key or secret

      Returns:
        True if the token signature was verified, False otherwise }
    function VerifyWithPrivateKey(const AJSONWebToken: String; const APrivateKey: TBytes): Boolean; overload;

    { Verifies the token was signed with the provided private key

      Parameters:
        APrivateKey: the private key or secret

      Returns:
        True if the token signature was verified, False otherwise }
    function VerifyWithPrivateKey(const APrivateKey: TBytes): Boolean; overload;

    { Verifies the token was signed with a private key associated with the provided public key

      Parameters:
        AJSONWebToken: the encoded token
        APublicKey: the public key

      Returns:
        True if the token signature was verified, False otherwise

      Note: The public key can be in the form of a PEM formatted RSA PUBLIC KEY or CERTIFICATE }
    function VerifyWithPublicKey(const AJSONWebToken: String; const APublicKey: TBytes): Boolean;
  public
    { Web token header }
    property Header: TBytes read FHeader write FHeader;

    { Web token data payload }
    property Payload: TBytes read FPayload write FPayload;

    { Signature for the token }
    property Signature: TBytes read FSignature write FSignature;
  end;

To keep things simple, the record contains a method called Decode() that separates the token into a header, payload and signature. You can also call the method VerifyWithPublicKey() to directly verify that the JWT was signed using a private key that matches the provided public key.

We have included an example Firemonkey application and source code demonstrates the process of decoding and verifying the signature.

In the above example, the Encoded memo contains the entire JSON Web Token. By clicking decode, it decodes the header and payload and the signature. Clicking verify will check to make sure that the JWT is signed properly by checking the signature against the public key that is provided under the Certificate tab in the example application.

Internally the routine VerifyWithPublicKey() uses the OpenSsl method PEM_read_bio_RSAPublicKey to load the PEM public key certificate and the EVP_DigestVerify APIs to verify the signature is correct.

Encoding and signing a JWT

Encoding a JWT follows a similar approach. You supply the header and the payload and it this content is signed to form a complete encoded JSON Web Token.

Our example application also demonstrates the ability to encode and sign the JWT. Internally it OpenSsl methods ```

Related Skills

View on GitHub
GitHub Stars106
CategoryDevelopment
Updated4h ago
Forks26

Languages

Pascal

Security Score

80/100

Audited on Apr 8, 2026

No findings