【问题标题】:Get SSL Certificate expiration date from client-cert.pem file stored locally in Android从 Android 本地存储的 client-cert.pem 文件中获取 SSL 证书到期日期
【发布时间】:2016-06-26 22:34:10
【问题描述】:

如果我想检查 SSL 证书的到期日期,我可以使用连接到 IdSSLIOHandlerSocketOpenSSLIdHTTP

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 库具有从文件或内存加载 PEM 格式证书的功能。您无法将证书从 Android 的证书存储区直接加载到 OpenSSL,因此您必须先将证书导出到文件中(如果尚未导出)。
  • @RemyLebeau ,感谢您的信息,我看到 idSSLOpenSSL 使用函数 IndySSL_load_client_CA_file(const AFileName: String) : PSTACK_OF_X509_NAME; 但这会返回 PSTACK_OF_X509_NAME 但如果我没记错的话,我需要 PSTACK_OF_X509_INFO 吗?因为 X509_INFO 记录包含 X509 证书? idSSLOpenSSLHeaders 中没有 sk_X509_INFO_new 变量,请原谅我对此事缺乏了解这是我第一次使用和处理证书

标签: android delphi ssl-certificate firemonkey indy


【解决方案1】:

正如 Remy 指出的,我只需要查看 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 标准,可以是 YYMMDDHHNNSSYYYYMMDDHHNNSS 所以我只是规定返回的值将始终是 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;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-20
    • 2015-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-08
    • 1970-01-01
    • 2012-03-29
    相关资源
    最近更新 更多