Sample code for 30+ languages & platforms
Delphi DLL

Azure Key Vault Sign with a Certificate's Private Key

See more Azure Key Vault Examples

Signs a hash using the private key of a certificate previously imported to an Azure Key Vault.

Chilkat Delphi DLL Downloads

Delphi DLL
uses
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, HttpResponse, StringBuilder, JsonObject, Rsa, Cert, Http;

...

procedure TForm1.Button1Click(Sender: TObject);
var
success: Boolean;
json: HCkJsonObject;
sb: HCkStringBuilder;
signedString: PWideChar;
hash_base64url: PWideChar;
jsonBody: HCkJsonObject;
http: HCkHttp;
url: PWideChar;
resp: HCkHttpResponse;
statusCode: Integer;
jsonResp: HCkJsonObject;
cert: HCkCert;
rsa: HCkRsa;
valid: Boolean;

begin
success := False;

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

// See Azure Key Vault Get Certificates for a more detailed explanation
// for how Chilkat is automatically getting the OAuth2 access token for your application.

// Provide information needed for Chilkat to automatically get an OAuth2 access token as needed.
json := CkJsonObject_Create();
CkJsonObject_UpdateString(json,'client_id','APP_ID');
CkJsonObject_UpdateString(json,'client_secret','APP_PASSWORD');
CkJsonObject_UpdateString(json,'resource','https://vault.azure.net');
CkJsonObject_UpdateString(json,'token_endpoint','https://login.microsoftonline.com/TENANT_ID/oauth2/token');

// In this example, we'll sign the SHA256 hash of the string "This is a test"
sb := CkStringBuilder_Create();
signedString := 'This is a test';
CkStringBuilder_Append(sb,signedString);
hash_base64url := CkStringBuilder__getHash(sb,'sha256','base64url','utf-8');

// We're going to send a POST to the following URL:
// POST {vaultBaseUrl}/keys/{key-or-cert-name}/{key-or-cert-version}/sign?api-version=7.4

// For example:

// POST https://VAULT_NAME.vault.azure.net/keys/CERT_NAME/CERT_VERSION/sign?api-version=7.4
// 
// {
//   "alg": "RS512",
//   "value": "RUE3Nzg4NTQ4QjQ5RjFFN0U2NzAyQzhDNEMwMkJDOTA1MTYyOTUzNjI5NDhBNzZDQTlFOTM1NDA2M0ZGMjk2Mg"
// }

// The alg can be one of the following
// ES256  ECDSA using P-256 and SHA-256
// ES256K ECDSA using P-256K and SHA-256
// ES384  ECDSA using P-384 and SHA-384
// ES512  ECDSA using P-521 and SHA-512
// PS256  RSASSA-PSS using SHA-256 and MGF1 with SHA-256
// PS384  RSASSA-PSS using SHA-384 and MGF1 with SHA-384
// PS512  RSASSA-PSS using SHA-512 and MGF1 with SHA-512
// RS256  RSASSA-PKCS1-v1_5 using SHA-256
// RS384  RSASSA-PKCS1-v1_5 using SHA-384
// RS512  RSASSA-PKCS1-v1_5 using SHA-512

// The sample POST above uses SHA512.  We'll instead sign a SHA256 hash..

jsonBody := CkJsonObject_Create();
CkJsonObject_UpdateString(jsonBody,'alg','RS256');
CkJsonObject_UpdateString(jsonBody,'value',hash_base64url);

http := CkHttp_Create();

// Instead of providing an actual access token, we give Chilkat the information that allows it to 
// automatically fetch the access token using the OAuth2 client credentials flow.
CkHttp_putAuthToken(http,CkJsonObject__emit(json));

CkHttp_SetUrlVar(http,'certName','importCert01');
CkHttp_SetUrlVar(http,'certVersion','7140c8755ed14839b5d86a9f7e7f0497');
// Note: Replace "VAULT_NAME" with the name of your Azure key vault.
url := 'https://VAULT_NAME.vault.azure.net/keys/{$certName}/{$certVersion}/sign?api-version=7.4';
resp := CkHttpResponse_Create();
success := CkHttp_HttpJson(http,'POST',url,jsonBody,'application/json',resp);
if (success = False) then
  begin
    Memo1.Lines.Add(CkHttp__lastErrorText(http));
    Exit;
  end;

statusCode := CkHttpResponse_getStatusCode(resp);

jsonResp := CkJsonObject_Create();
CkHttpResponse_GetBodyJson(resp,jsonResp);

CkJsonObject_putEmitCompact(jsonResp,False);
Memo1.Lines.Add(CkJsonObject__emit(jsonResp));

if (statusCode <> 200) then
  begin
    Memo1.Lines.Add('Failed.');
    Exit;
  end;

// A successful response body contains JSON like this:
// Note: Azure's documentation is not very clear, but base64url is the encoding, not "base64".
// {
//   "kid": "https://kvchilkat.vault.azure.net/keys/importCert01/7140c8755ed14839b5d86a9f7e7f0497",
//   "value": "JzWd2YF21gjtW ... Em37hKOQ"
// }

// Let's validate the signature using the cert's public key.
// This example will load the corresponding certificate from a local file and will verify the signature against the original data.
// 
cert := CkCert_Create();
success := CkCert_LoadFromFile(cert,'qa_data/certs/chilkat_code_signing_2024.cer');
if (success = False) then
  begin
    Memo1.Lines.Add(CkCert__lastErrorText(cert));
    Exit;
  end;

rsa := CkRsa_Create();
// Tell the RSA object to use the cert's public key.
success := CkRsa_SetX509Cert(rsa,cert,False);
if (success = False) then
  begin
    Memo1.Lines.Add(CkRsa__lastErrorText(rsa));
    Exit;
  end;

// Verify the signature using the cert's public key against the original string.
CkRsa_putEncodingMode(rsa,'base64url');
valid := CkRsa_VerifyStringENC(rsa,signedString,'sha-256',CkJsonObject__stringOf(jsonResp,'value'));
Memo1.Lines.Add('signature valid = ' + IntToStr(Ord(valid)));

CkJsonObject_Dispose(json);
CkStringBuilder_Dispose(sb);
CkJsonObject_Dispose(jsonBody);
CkHttp_Dispose(http);
CkHttpResponse_Dispose(resp);
CkJsonObject_Dispose(jsonResp);
CkCert_Dispose(cert);
CkRsa_Dispose(rsa);

end;