Sample code for 30+ languages & platforms
Pascal (Lazarus/Delphi)

SSH HSM Public Key Authentication

See more SSH Examples

Demonstrates SSH public-key authentication using a private key stored on an HSM — a USB token or smart card — accessed through PKCS#11. A session is opened with the vendor's driver, the key handles are located, and an SshKey object is bound to them with UsePkcs11.

Background: The point of an HSM is that the private key is generated on the device and cannot be exported: the signing operation happens on the hardware, so the key material never reaches your application's memory or disk. Even a fully compromised host cannot yield a copy of the key. PKCS#11 is the vendor-neutral interface to such devices, which is why the driver path and the object-finding template are the only vendor-specific parts of this example.

Chilkat Pascal (Lazarus/Delphi) Downloads

Pascal (Lazarus/Delphi)
program ChilkatDemo;

// Demonstrates using the Chilkat Pascal wrapper via the C bridge DLL.
// Builds as a console application under Lazarus (FPC) or Delphi.

{$IFDEF FPC}
  {$MODE DELPHI}
{$ENDIF}
{$APPTYPE CONSOLE}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  SysUtils,
  CkDllLoader,
  Chilkat.SshKey,
  Chilkat.Pkcs11,
  Chilkat.Ssh,
  Chilkat.JsonObject;

// ---------------------------------------------------------------------------

procedure RunDemo;
var
  success: Boolean;
  pkcs11: TPkcs11;
  pin: string;
  userType: Integer;
  json: TJsonObject;
  priv_handle: LongWord;
  pub_handle: LongWord;
  key: TSshKey;
  keyType: string;
  ssh: TSsh;
  port: Integer;

begin
  success := False;

  //  This example requires the Chilkat API to have been previously unlocked.
  //  See Global Unlock Sample for sample code.

  //  Demonstrates SSH public-key authentication using a private key stored on an HSM (a USB token
  //  or smart card) accessed through PKCS#11.
  //  
  //  Note: Chilkat's PKCS#11 implementation runs on Windows, Linux, macOS, and other supported
  //  operating systems.

  pkcs11 := TPkcs11.Create;

  //  The PKCS#11 driver supplied by your HSM vendor: a .dll on Windows, a .so on Linux, or a
  //  .dylib on macOS.
  pkcs11.SharedLibPath := 'C:/Program Files (x86)/Gemalto/IDGo 800 PKCS#11/IDPrimePKCS1164.dll';

  //  The PIN should come from a secure source rather than being hard-coded.
  pin := '0000';

  //  Normal user = 1
  userType := 1;

  success := pkcs11.QuickSession(userType,pin);
  if (success = False) then
    begin
      WriteLn(pkcs11.LastErrorText);
      Exit;
    end;

  //  Describe the private key object to be located on the HSM.
  json := TJsonObject.Create;
  json.UpdateString('class','private_key');
  json.UpdateString('label','MySshKey');

  priv_handle := pkcs11.FindObject(json);
  if (priv_handle = 0) then
    begin
      WriteLn(pkcs11.LastErrorText);
      Exit;
    end;

  //  Find the corresponding public key by changing the class in the same template.
  json.UpdateString('class','public_key');

  pub_handle := pkcs11.FindObject(json);
  if (pub_handle = 0) then
    begin
      WriteLn(pkcs11.LastErrorText);
      Exit;
    end;

  //  Create an SSH key object that uses the HSM handles.  The key type may be "rsa" or "ec".
  key := TSshKey.Create;
  keyType := 'rsa';
  success := key.UsePkcs11(pkcs11,priv_handle,pub_handle,keyType);
  if (success = False) then
    begin
      WriteLn(key.LastErrorText);
      Exit;
    end;

  ssh := TSsh.Create;

  port := 22;
  success := ssh.Connect('ssh.example.com',port);
  if (success = False) then
    begin
      WriteLn(ssh.LastErrorText);
      Exit;
    end;

  //  The corresponding public key must already be installed on the SSH server for the account.
  //  The signing operation happens on the HSM -- the private key never leaves the device.
  success := ssh.AuthenticatePk('mySshLogin',key);
  if (success = False) then
    begin
      WriteLn(ssh.LastErrorText);
      Exit;
    end;

  WriteLn('Public-key authentication successful.');

  ssh.Disconnect();

  pkcs11.Logout();
  pkcs11.CloseSession();


  pkcs11.Free;
  json.Free;
  key.Free;
  ssh.Free;

end;

// ---------------------------------------------------------------------------

begin

  try
    RunDemo;
  except
    on E: Exception do
      WriteLn('Unhandled exception: ', E.ClassName, ': ', E.Message);
  end;

  WriteLn;
  {$IFDEF MSWINDOWS}
  WriteLn('Press Enter to exit...');
  ReadLn;
  {$ENDIF}
end.