procedure TOpenSSL.CreateSignedCert (const FileName: String; OutFiles: TStringList;
const Password: String;
ValidDays: Integer; KeySize: Integer; const ExtendedKeyUsage: String;
const CommonName, Email, Organization, OrganizationalUnit, Country: String;
const CAFileSpec, CAPFXFileSpec, CAPrivateKeyPassword: String;
ARandomFileSpec: String = '';
ProgressProc: TProgressProc = nil; LogMsgProc: TLogMsgProc = nil);
var
TmpPrivateKeyFileSpec, TmpPublicKeyFileSpec: String;
TmpCerFileSpec, TmpPfxFileSpec, TmpCsrFileSpec, TmpCASerialFileSpec, TmpExtFileSpec, TmpPemFileSpec: String;
TmpCAPrivateKeyFileSpec: String;
Subj: String;
TempDir: String;
Aborted: Boolean;
WasError: Boolean;
OutPublicKeyFileSpec: String;
begin
WasError: = True;
TempDir: = GetTempDir;
try
CheckIsFileExists (CAFileSpec);
// Retrieve the private key from the root certificate
TmpCAPrivateKeyFileSpec: = TempDir + ChangeFileExt (ExtractFileName (CAPFXFileSpec), '') + '.privateKey.pem';
ExportPrivateKeyFromPfx (CAPFXFileSpec, TmpCAPrivateKeyFileSpec, CAPrivateKeyPassword);
// All files are created in a temporary directory, and only after successful creation of all - // we transfer to the place of permanent storage
TmpPrivateKeyFileSpec: = TempDir + FileName + '.privateKey.pem';
TmpPublicKeyFileSpec: = TempDir + FileName + '.publicKey.pem';
TmpCerFileSpec: = TempDir + FileName + '.cer';
TmpPemFileSpec: = TempDir + FileName + '.pem';
TmpPfxFileSpec: = TempDir + FileName + '.pfx';
TmpCsrFileSpec: = TempDir + FileName + '.csr';
TmpCASerialFileSpec: = TempDir + FileName + '.srl';
Subj: = GetSubj (CommonName, Email, Organization, OrganizationalUnit, Country);
Aborted: = False;
if Assigned (ProgressProc) then
ProgressProc (13, 4, Aborted, Format ('% s (% d% s) ...' {'Generate Keys (% d bits) ...'}, [StKeysGenerate, KeySize, StBit]));
if aborted then
Exit;
CreatePrivateKey (TmpPrivateKeyFileSpec, TmpPublicKeyFileSpec, KeySize, ARandomFileSpec);
if Assigned (ProgressProc) then
ProgressProc (13, 5, Aborted, Format ('% s ...', [StGenerateCertificate]) {'Generate certificate ...'});
if aborted then
Exit;
if Assigned (ProgressProc) then
ProgressProc (13, 6, Aborted, Format ('% s ...', [StCreateCertificateRequest]) {'Create the certificate request ...'});
// Create a query - .csr
RunOpenSSLConsole (Format (
'req -new -key "% s" -out "% s" -days% d -subj% s',
[TmpPrivateKeyFileSpec, TmpCsrFileSpec, ValidDays, Subj]
), True, nil, nil);
if Assigned (ProgressProc) then
ProgressProc (13, 7, Aborted, Format ('% s ...', [StCreateExtensionsFile]) {'Create the extensions file ...'});
//
www.openssl.org/docs/apps/x509v3_config.htmlTmpExtFileSpec: = StrToFile (
// 'keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyCertSign' +
'keyUsage = digitalSignature, keyEncipherment' +
iif (ExtendedKeyUsage <> '', # 13 # 10'extendedKeyUsage = '+ ExtendedKeyUsage,' '),
TempDir + FileName + '.extensions.cfg'
);
if Assigned (ProgressProc) then
ProgressProc (13, 8, Aborted, Format ('% s ...', [StCreateSignedCertificate]) {'Create the signed certificate ...'});
// Based on the request, create a certificate signed by the root certificate
RunOpenSSLConsole (Format (
'x509 -req -days% d -passin pass:% s -in "% s" -CAform DER -CA "% s" -CAkey "% s" -Cserial "% s" -CAcreateserial -out "% s" - outform DER -extfile "% s" ',
[ValidDays, Password, TmpCsrFileSpec, CAFileSpec, TmpCAPrivateKeyFileSpec, TmpCASerialFileSpec, TmpCerFileSpec, TmpExtFileSpec]
), False, nil, nil);
if Assigned (ProgressProc) then
ProgressProc (13, 9, Aborted, Format ('% s ...', [StConvertCertificate]) {'Convert the certificate from the CER to the PEM format ...'});
// Convert cer => pem for the next export to pfx
RunOpenSSLConsole (Format (
'x509 -in "% s" -inform DER -out "% s" -outform PEM',
[TmpCerFileSpec, TmpPemFileSpec]
), False, nil, nil);
if Assigned (ProgressProc) then
ProgressProc (13, 10, Aborted, Format ('% s ...', [StCreatePFX]) {'Create the PFX certificate file ...'});
// Make pfx from pem and keys
RunOpenSSLConsole (Format (
'pkcs12 -password pass:% s -export -in "% s" -inkey "% s" -name "% s" -out "% s"',
[Password, TmpPemFileSpec, TmpPrivateKeyFileSpec, FileName, TmpPfxFileSpec]
), False, nil, nil);
OutPublicKeyFileSpec: = TmpPublicKeyFileSpec + '.signed';
if Assigned (ProgressProc) then
ProgressProc (13, 11, Aborted, Format ('% s ...', [StExportPublicKey]) {'Export public keys from the PFX certificate file ...'});
ExportPublicKeyFromPfx (TmpPfxFileSpec, OutPublicKeyFileSpec, Password);
// And the result is added to the file list
OutFiles.Add (TmpCerFileSpec);
OutFiles.Add (TmpPfxFileSpec);
OutFiles.Add (TmpPrivateKeyFileSpec);
OutFiles.Add (TmpPublicKeyFileSpec);
OutFiles.Add (OutPublicKeyFileSpec);
WasError: = False;
finally
// Delete temporary files
if WasError then
begin
CheckDeleteFile (TmpCerFileSpec);
CheckDeleteFile (TmpPfxFileSpec);
CheckDeleteFile (TmpPrivateKeyFileSpec);
CheckDeleteFile (TmpPublicKeyFileSpec);
CheckDeleteFile (OutPublicKeyFileSpec);
end;
CheckDeleteFile (TmpCsrFileSpec);
CheckDeleteFile (TmpCASerialFileSpec);
CheckDeleteFile (TmpExtFileSpec);
CheckDeleteFile (TmpPemFileSpec);
CheckDeleteFile (TmpCAPrivateKeyFileSpec);
end;
end;