我使用以下程序:
procedure TForm2.Label1DblClick(Sender: TObject);
procedure GenerateSelfSignedCertificate(const AFileName: string);
procedure GenerateRandomSerialNumber(SerialNumber: PASN1_INTEGER);
var
RandomValue: Int64;
I: Integer;
begin
// We generate a 64-bit random number
RandomValue := 0;
for I := 1 to 8 do
begin
RandomValue := (RandomValue shl 8) or Random(256);
end;
// We make sure the number is positive
RandomValue := RandomValue and $7FFFFFFFFFFFFFFF;
// We set the serial number
if ASN1_INTEGER_set(SerialNumber, RandomValue) = 0 then
raise Exception.Create('Error setting serial number');
end;
function DateToASN1_TIME(const ADate: TDateTime): PASN1_TIME;
var
AStruct: TSystemTime;
ASN1_Time: PASN1_TIME;
begin
DateTimeToSystemTime(ADate, AStruct);
ASN1_Time := ASN1_TIME_set(nil, SystemTimeToDateTime(AStruct));
Result := ASN1_Time;
end;
var
Cert: PX509;
PrivateKey: PEVP_PKEY;
SerialNumber: PASN1_INTEGER;
Name: PX509_NAME;
Bio: PBIO;
NotBefore, NotAfter: TDateTime;
begin
// Inițializați OpenSSL
IdSSLOpenSSL.LoadOpenSSLLibrary;
// A new certificate is created
Cert := X509_new; // ERROR!!!! Access Vioaltion at address 00000...
try // A new RSA private key is created
PrivateKey := EVP_PKEY_new;
try
if EVP_PKEY_assign(PrivateKey, EVP_PKEY_RSA,
PByte(RSA_generate_key(2048, RSA_F4, nil, nil))) = 0 then
raise Exception.Create('Error generating private key');
// Certificate version is set (X509 v3)
X509_set_version(Cert, 2);
// A random serial number is generated
SerialNumber := ASN1_INTEGER_new;
if SerialNumber = nil then
raise Exception.Create('Error creating ASN1_INTEGER');
try
GenerateRandomSerialNumber(SerialNumber);
if X509_set_serialNumber(Cert, SerialNumber) = 0 then
raise Exception.Create
('Error setting serial number for certificate');
finally
ASN1_INTEGER_free(SerialNumber);
end;
// The start and end date of the certificate is set
NotBefore := Now - 1;
// The certificate is valid from yesterday
NotAfter := NotBefore + 365;
// The certificate is valid for approximately one year
X509_set_notBefore(Cert, DateToASN1_TIME(NotBefore));
X509_set_notAfter(Cert, DateToASN1_TIME(NotAfter));
// The public key is set
X509_set_pubkey(Cert, PrivateKey);
// Issuer and subject name is set (localhost is used)
Name := X509_get_subject_name(Cert);
X509_NAME_add_entry_by_txt(Name, 'CN', MBSTRING_ASC,
PAnsiChar('localhost'), -1, -1, 0);
X509_set_issuer_name(Cert, Name);
// The certificate is signed
if X509_sign(Cert, PrivateKey, EVP_sha256) = 0 then
raise Exception.Create('Error signing the certificate');
// The certificate and private key are saved in a PEM file
Bio := BIO_new_file(PAnsiChar(AnsiString(AFileName)), 'w+');
try
PEM_write_bio_X509(Bio, Cert);
PEM_write_bio_PrivateKey(Bio, PrivateKey, nil, nil, 0, nil, nil);
finally
BIO_free(Bio);
end;
finally
EVP_PKEY_free(PrivateKey);
end;
finally
X509_free(Cert);
end;
end;
begin
GenerateSelfSignedCertificate('.\CertificatTest.pem');
ShowMessage('Certificate successfully generated!');
end;
在
Cert := X509_new;
线上我收到一条错误消息
地址访问冲突...
X509_new函数在使用OpenSSL的Indy框架的IdSSLOpenSSLHeaders单元中定义如下:
{$EXTERNALSYM X509_new}
X509_new : function: PX509 cdecl = nil;
我正在尝试生成自签名的 X509 证书。代码是在与 ChatGPT 多次讨论后生成的。但是我无法克服这个错误。
Indy 在运行时动态加载 OpenSSL 函数。在尝试使用它加载的任何函数之前,您不会检查
LoadOpenSSLLibrary()
是否成功。检查LoadOpenSSLLibrary()
的返回值,例如:
if not IdSSLOpenSSL.LoadOpenSSLLibrary then
begin
// error handling...
end;
此外,在 OpenSSL 加载失败后,请使用
IdSSLOpenSSLHeaders.WhichFailedToLoad()
检查,以了解实际加载失败的内容。 正如您在评论中提到的:
OpenSSl 库有版本 3
Indy 尚不支持 OpenSSL 3.x(正在进行中)。支持的最后一个版本是 1.0.2u,您可以从 https://github.com/IndySockets/OpenSSL-Binaries 获取该版本。如果您尝试加载较新的版本,
LoadOpenSSLLibrary()
将失败并且 WhichFailedToLoad()
将报告 Unsupported SSL Library version
。
话虽如此,
X509_new
不被视为关键函数,因为 Indy 不直接使用它,因此如果 X509_new
未从 libcrypto
库导出,则加载 OpenSSL 不会失败(如果成功的话)。 IdSSLOpenSSLHeaders.X509_new
指针将只是 nil
,因此如果您打算直接使用 X509_new()
,您还应该检查该条件。