从本地存储在 Android 中的客户端 cert.pem 文件获取 SSL 证书到期日期
Get SSL Certificate expiration date from client-cert.pem file stored locally in Android
如果我想检查 SSL 证书的到期日期,我可以使用 IdHTTP
连接到 IdSSLIOHandlerSocketOpenSSL
IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL1;
然后点击 OnVerifyPeer
function TForm1.IdSSLIOHandlerSocketOpenSSL1VerifyPeer(Certificate: TIdX509;
AOk: Boolean; ADepth, AError: Integer): Boolean;
begin
Showmessage(Certificate.notAfter));
end;
最后对我要检索其服务器证书的服务器执行 IdHTTP.Get
,这有效。
但是
我的 Android 设备上本地存储了一个客户端证书,该证书随应用程序一起部署,我将如何访问该证书?
意思是我如何将证书加载到 TidX509
对象中?
TidX509
的构造函数需要一个 PX509
,然后将其分配给记录 X509
的指针,所以我在那里迷路了
正如雷米指出的那样,我只需要看看 OpenSSL 如何从内存中加载证书以获取证书
但首先,您从读取证书中获得的值 notAfter
是字符串中的 UTC 时间值,因此您需要这样的东西
function StringUTCtoDATETIME(UTCString : String) : TDateTime;
begin
if UTCString.Length = 13 then
begin
Delete(UTCString,UTCString.Length,1);
Delete(UTCString,0,2);
Insert(Copy(FormatDateTime('yyyy',Now),0,2),UTCString,0);
end
else
begin
Delete(UTCString,UTCString.Length,1);
end;
Result := EncodeDateTime(StrToInt(Copy(UTCString,1,4)),StrToInt(Copy(UTCString,5,2)),StrToInt(Copy(UTCString,7,2)),
StrToInt(Copy(UTCString,9,2)),StrToInt(Copy(UTCString,11,2)),StrToInt(Copy(UTCString,13,2)),000);
end;
该值符合 ISO8601 标准,可以是 YYMMDDHHNNSS
或 YYYYMMDDHHNNSS
所以我只是规定返回值将始终是 YYYYMMDDHHNNSS
为了获取值,我们将其加载到内存中并像 Indy 一样使用它。
function ReturnCertificateExpiryDate(const AFileName: String): TDateTime;
var
LM : TMemoryStream;
LX: PX509;
LB: PBIO;
begin
LM := nil;
try
LM := TMemoryStream.Create;
LM.LoadFromFile(AFileName);
except
SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE, ERR_R_SYS_LIB);
LM.Free;
Exit;
end;
if LM = nil then
begin
Exit;
end;
try
LB := BIO_new_mem_buf(LM.Memory, LM.Size);
if Assigned(LB) then begin
LX := PEM_read_bio_X509(LB, nil, nil, nil);
if LX<> nil then
begin
RESULT := StringUTCtoDATETIME(String(LX.cert_info.validity.notAfter.data));
end;
end;
finally
FreeAndNil(LM);
end;
end;
而且你还需要创建一个上下文变量
var
Context : TIdSSLContext;
begin
Context := TIdSSLContext.Create;
ShowMessage(FormatDateTime('yyyy-mm-dd hh:nn:ss',(ReturnCertificateExpiryDate(TPath.Combine(TPath.GetDocumentsPath, 'client-cert.pem')))));
end;
如果我想检查 SSL 证书的到期日期,我可以使用 IdHTTP
连接到 IdSSLIOHandlerSocketOpenSSL
IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL1;
然后点击 OnVerifyPeer
function TForm1.IdSSLIOHandlerSocketOpenSSL1VerifyPeer(Certificate: TIdX509;
AOk: Boolean; ADepth, AError: Integer): Boolean;
begin
Showmessage(Certificate.notAfter));
end;
最后对我要检索其服务器证书的服务器执行 IdHTTP.Get
,这有效。
但是
我的 Android 设备上本地存储了一个客户端证书,该证书随应用程序一起部署,我将如何访问该证书?
意思是我如何将证书加载到 TidX509
对象中?
TidX509
的构造函数需要一个 PX509
,然后将其分配给记录 X509
的指针,所以我在那里迷路了
正如雷米指出的那样,我只需要看看 OpenSSL 如何从内存中加载证书以获取证书
但首先,您从读取证书中获得的值 notAfter
是字符串中的 UTC 时间值,因此您需要这样的东西
function StringUTCtoDATETIME(UTCString : String) : TDateTime;
begin
if UTCString.Length = 13 then
begin
Delete(UTCString,UTCString.Length,1);
Delete(UTCString,0,2);
Insert(Copy(FormatDateTime('yyyy',Now),0,2),UTCString,0);
end
else
begin
Delete(UTCString,UTCString.Length,1);
end;
Result := EncodeDateTime(StrToInt(Copy(UTCString,1,4)),StrToInt(Copy(UTCString,5,2)),StrToInt(Copy(UTCString,7,2)),
StrToInt(Copy(UTCString,9,2)),StrToInt(Copy(UTCString,11,2)),StrToInt(Copy(UTCString,13,2)),000);
end;
该值符合 ISO8601 标准,可以是 YYMMDDHHNNSS
或 YYYYMMDDHHNNSS
所以我只是规定返回值将始终是 YYYYMMDDHHNNSS
为了获取值,我们将其加载到内存中并像 Indy 一样使用它。
function ReturnCertificateExpiryDate(const AFileName: String): TDateTime;
var
LM : TMemoryStream;
LX: PX509;
LB: PBIO;
begin
LM := nil;
try
LM := TMemoryStream.Create;
LM.LoadFromFile(AFileName);
except
SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE, ERR_R_SYS_LIB);
LM.Free;
Exit;
end;
if LM = nil then
begin
Exit;
end;
try
LB := BIO_new_mem_buf(LM.Memory, LM.Size);
if Assigned(LB) then begin
LX := PEM_read_bio_X509(LB, nil, nil, nil);
if LX<> nil then
begin
RESULT := StringUTCtoDATETIME(String(LX.cert_info.validity.notAfter.data));
end;
end;
finally
FreeAndNil(LM);
end;
end;
而且你还需要创建一个上下文变量
var
Context : TIdSSLContext;
begin
Context := TIdSSLContext.Create;
ShowMessage(FormatDateTime('yyyy-mm-dd hh:nn:ss',(ReturnCertificateExpiryDate(TPath.Combine(TPath.GetDocumentsPath, 'client-cert.pem')))));
end;