program TestCrSysPKI;
{ 
  Some tests for the Delphi/FreePascal interface to CryptoSys PKI
  $Id: TestCrSysPKI.pas $
  Copyright (C) 2010-23 David Ireland, DI Management Services Pty Limited.
  All rights reserved. <www.di-mgt.com.au> <www.cryptosys.net>
  Provided as is with no warranties. Use at your own risk.
  Last updated:
    $Date: 2023-10-12 07:23 $
    $Revision: 22.0.0 $
}

{$APPTYPE CONSOLE}
{$mode Delphi}

uses
  SysUtils, diCrPKI;

const
  CRLF = #13 + #10;

// UTILITIES WE USE IN THE TESTS...
Procedure pr_hexbytes(msg : String; arrbytes : Array of Byte);
// Displays an array of bytes as a hex string
var
  i : Integer;
  nbytes : Integer;
begin
  Write(msg);
  nbytes := Length(arrbytes);
  For i := 0 to (nbytes - 1) do
    Write(IntToHex(arrbytes[i], 2));
  WriteLn;
end;

Procedure pr_text_file(fname: AnsiString);
var
  myFile : TextFile;
  s : AnsiString;
begin
  AssignFile(myFile, fname);
  Reset(myFile);
  while not (eof(myFile)) do
  begin
    Readln(myFile, s);
	writeln(s);
  end;
  CloseFile(myFile);
end;



// DO THE TESTS TO CALL CRYPTOSYS PKI FUNCTIONS
Procedure do_tests;
var
  ret, nchars, nbytes : Integer;
  buf : AnsiString;
  ch : Char;
  n, i : Integer;
  arrbytes : Array of Byte;
  fname, keyfile, pubkeyfile, certfile, dumpfile : AnsiString;
  password : AnsiString;
  nbits : Integer;

begin
  WriteLn('Running ' + ExtractFileName(ParamStr(0)) + ' at ' + DateTimeToStr(Now));

  WriteLn(CRLF + 'GENERAL:');
  WriteLn('Interrogate the core diCrPKI DLL:');
  WriteLn('PKI_Version='+(IntToStr(PKI_Version(NIL, NIL))));
  nchars := PKI_CompileTime(NIL, 0);
  WriteLn('PKI_CompileTime returns nchars=' + IntToStr(nchars));
  buf := AnsiString(StringOfChar(#0,nchars));
  nchars := PKI_CompileTime(Pointer(buf), nchars);
  WriteLn('PKI_CompileTime=' + buf);
  Assert (nchars > 0);
  ch := Chr(PKI_LicenceType(0));
  WriteLn('PKI_LicenceType='+ ch);
  nchars := PKI_ModuleName(NIL, 0, 0);
  WriteLn('PKI_ModuleName returns nchars=' + IntToStr(nchars));
  buf := AnsiString(StringOfChar(#0, nchars));
  PKI_ModuleName(Pointer(buf), nchars, 0);
  WriteLn('PKI_ModuleName=' + Trim(string(buf)));

  WriteLn(CRLF + 'GENERATE SOME RANDOM INTEGERS IN RANGE [0,MaxInt]:');
  for i := 1 to 5 do
  begin
    n := RNG_Number(0, MaxInt);
    WriteLn('RNG_Number returns ' + IntToStr(n));
  end;
  WriteLn(CRLF + 'GENERATE SOME RANDOM BYTE ARRAYS:');
  nbytes := 16;
  SetLength(arrbytes, nbytes);
  for i := 1 to 5 do
  begin
    ret := RNG_Bytes(Pointer(arrbytes), nbytes, NIL, 0);
    //WriteLn('RNG_Bytes returns ' + IntToStr(ret) + ' (expected 0)');
    Assert(0 = ret);
    pr_hexbytes('RNG=', arrbytes);
  end;

  // Define USE_PROMPT to make this work
  {$IfDef USE_PROMPT}
  WriteLn(CRLF + 'GENERATE RANDOM BYTES WITH PROMPT:');
  nbytes := 24;
  SetLength(arrbytes, nbytes);
  // Use default prompt
  ret := RNG_BytesWithPrompt(Pointer(arrbytes), nbytes, '', 0);
  Assert(0 = ret);
  pr_hexbytes('RNG=', arrbytes);
  {$EndIf}

  WriteLn(CRLF + 'GENERATE A PAIR OF RSA KEYS:');
  nbits := 1024; // NB Not very secure length
  keyfile := 'myprivate.key';
  pubkeyfile := 'mypubkey.dat';
  password := 'password'; // High security here!!
  WriteLn('About to generate key of ' + IntToStr(nbits) + ' bits...');
  ret := RSA_MakeKeysXtd(pubkeyfile, keyfile, password, nbits,
    PKI_RSAEXP_EQ_65537, '', PKI_PBE_PBKDF2_AES128);
  WriteLn('RSA_MakeKeys returns ' + IntToStr(ret) + ' (expected 0)');

  WriteLn(CRLF + 'Check we can read these new key files...');
  // Private key file
  fname := keyfile;
  nchars := RSA_ReadAnyPrivateKey(NIL, 0, fname, password, 0);
  WriteLn('RSA_ReadAnyPrivateKey returns ' + IntToStr(nchars) + ' (expected +ve)');
  Assert(nchars > 0);
  buf := AnsiString(StringOfChar(#0, nchars));
  nchars := RSA_ReadAnyPrivateKey(Pointer(buf), nchars, fname, password, 0);
  Assert(nchars > 0);
  n := RSA_KeyBits(buf);
  WriteLn('Private key length=' + IntToStr(n));
  n := RSA_KeyHashCode(buf);
  WriteLn('KeyHashCode = 0x' + IntToHex(n, 8));
  // Public key file
  fname := pubkeyfile;
  nchars := RSA_ReadAnyPublicKey(NIL, 0, fname, 0);
  WriteLn('RSA_ReadAnyPublicKey returns ' + IntToStr(nchars) + ' (expected +ve)');
  Assert(nchars > 0);
  buf := AnsiString(StringOfChar(#0, nchars));
  nchars := RSA_ReadAnyPublicKey(Pointer(buf), nchars, fname, 0);
  Assert(nchars > 0);
  n := RSA_KeyBits(buf);
  WriteLn('Public key length=' + IntToStr(n));
  n := RSA_KeyHashCode(buf);
  WriteLn('KeyHashCode = 0x' + IntToHex(n, 8));

  WriteLn(CRLF + 'MAKE A SELF-SIGNED X.509 CERTIFICATE...');
  certfile := 'mycertca.cer';
  ret := X509_MakeCertSelf(certfile, keyfile, $101, $5, 'c=AU;CN=me;O=me@here.com', 
    'rfc822Name=me@here.com;subjectKeyIdentifier=fedcba9876543210', 
	PKI_X509_KEYUSAGE_KEYCERTSIGN or PKI_X509_KEYUSAGE_CRLSIGN or PKI_X509_KEYUSAGE_DIGITALSIGNATURE,
	'password', PKI_SIG_SHA256RSA);
  WriteLn('X509_MakeCertSelf returns ' + IntToStr(ret) + ' (expected 0)');

  WriteLn(CRLF + 'DUMP DETAILS OF X.509 CERTIFICATE...');
  dumpfile := 'x509dump.txt';
  ret := X509_TextDump(dumpfile, certfile, 0);
  WriteLn('X509_TextDump returns ' + IntToStr(ret) + ' (expected 0)');
  // Write out the text file we just created
  pr_text_file(dumpfile);

  WriteLn(CRLF+'ALL DONE.');

end;

// MAIN PROCEDURE
begin
  try
    do_tests;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.