Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   SDK Componente Verifactu para Delphi 7+ - Subforo Avisos/consultas (https://www.clubdelphi.com/foros/forumdisplay.php?f=81)
-   -   Obtener fecha de caducidad del certificado (https://www.clubdelphi.com/foros/showthread.php?t=97876)

Isaac_uni 21-11-2025 10:14:41

Obtener fecha de caducidad del certificado
 
Buenos días.
Estamos haciendo uso de la dll y nos hemos encontrado la duda de si hay forma de obtener la fecha de caducidad del certificado digital para poder informar al cliente de lo tiene que renovar.
De momento hemos optado por la opción de cargar el .pfx junto con el password del certificado sin instalarlo.
Gracias de antemano.

chenech 21-11-2025 18:57:11

Yo lo verifico desde el programa y si tiene menos de 30 días para caducar aviso al iniciar el programa cada vez.
Te adjunto el código pero está en C++, en Delphi no soy capaz de hacerlo, si alguien puede convertirlo.
Lo tengo en una función a la que llamo pasándole el archivo en ASCert, la contraseña en ASPass y me devuelve la fecha, luego ya calculo yo el tiempo que le queda para caducar,.
En caso de error o que no exista devuelve una cadena vacía.
Código:

                HANDLE hFile = CreateFileW(ASCert.c_str(), GENERIC_READ, FILE_SHARE_READ,
                                                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
                if(hFile == INVALID_HANDLE_VALUE)
                        return "";
                DWORD size = GetFileSize(hFile, NULL);
                BYTE* buffer = new BYTE[size];
                DWORD bytesRead;
                ReadFile(hFile, buffer, size, &bytesRead, NULL);
                CloseHandle(hFile);
                CRYPT_DATA_BLOB blob;
                blob.cbData = size;
                blob.pbData = buffer;
                HCERTSTORE hStore = PFXImportCertStore(&blob, ASPass.c_str(), PKCS12_NO_PERSIST_KEY);
                delete[] buffer;
                if(!hStore)
                        return "";
                PCCERT_CONTEXT pCert = CertEnumCertificatesInStore(hStore, NULL);
                if(!pCert)
                {
                        CertCloseStore(hStore, 0);
                        return "";
                }
                SYSTEMTIME st;
                FileTimeToSystemTime(&pCert->pCertInfo->NotAfter, &st);
                CertFreeCertificateContext(pCert);
                CertCloseStore(hStore, 0);
                wchar_t fecha[11];
                swprintf(fecha, 11, L"%02d/%02d/%04d", st.wDay, st.wMonth, st.wYear);
                return String(fecha);


ramherfer 25-11-2025 16:35:38

Yo utilizo esta función que me devuelve los días que faltan hasta la caducidad y si son 60 o menos envía mensaje al usuario cada vez que entra en la app.

Código Delphi [-]
function VerificarCaducidadCertificadoDesdePFX(const ArchivoPFX, Pwd: string; out DiasHastaCaducidad: Integer; out ErrorCode: Integer): Boolean;
var
  CertStore: HCERTSTORE;
  CertContext: PCERT_CONTEXT;
  PFXFile: TMemoryStream;
  PFXBlob: CRYPT_DATA_BLOB;
  ExpFT: FILETIME;
  SysTime: TSystemTime;
  ExpirationDate: TDateTime;
begin
  Result := False;
  DiasHastaCaducidad := 0;
  ErrorCode := 0;

  CertStore := nil; CertContext := nil;
  PFXFile := TMemoryStream.Create;
  try
    try
      PFXFile.LoadFromFile(ArchivoPFX);
      if PFXFile.Size = 0 then begin ErrorCode := 1001; Exit; end; // PFX vacío

      PFXBlob.cbData := PFXFile.Size;
      GetMem(PFXBlob.pbData, PFXBlob.cbData);
      try
        PFXFile.Position := 0;
        PFXFile.ReadBuffer(PFXBlob.pbData^, PFXBlob.cbData);

        CertStore := PFXImportCertStore(PFXBlob, PWideChar(WideString(Pwd)), 0);
        if CertStore = nil then begin
          ErrorCode := GetLastError;  // 86 = contraseña inválida
          Exit;
        end;

        CertContext := CertFindCertificateInStore(
          CertStore, X509_ASN_ENCODING or PKCS_7_ASN_ENCODING,
          0, CERT_FIND_ANY, nil, nil);
        if CertContext = nil then begin ErrorCode := 1002; Exit; end; // sin cert

        ExpFT := CertContext^.pCertInfo^.NotAfter;
        if not FileTimeToSystemTime(ExpFT, SysTime) then begin ErrorCode := 1003; Exit; end;

        ExpirationDate := SystemTimeToDateTime(SysTime);
        DiasHastaCaducidad := Trunc(ExpirationDate - Now); // puede ser negativo
        NotAfter := ExpirationDate;
        Result := True;
      finally
        if Assigned(PFXBlob.pbData) then FreeMem(PFXBlob.pbData);
      end;
    except
      on E: Exception do begin
        ErrorCode := 1999; // error no esperado
        Result := False;
      end;
    end;
  finally
    if CertContext <> nil then CertFreeCertificateContext(CertContext);
    if CertStore   <> nil then CertCloseStore(CertStore, 0);
    PFXFile.Free;
  end;
end;

Tenemos la ruta del fichero de certificado p12/pfx y la contraseña del mismo.

Si el usuario utiliza un certificado instalado en el sistema tenemos la siguiente función que tambien devuelve los días hasta la caducidad:

Código Delphi [-]
function VerificarCaducidadCertificado: Boolean;


    function ExtraerCN(const SubjectName: string): string;

    var
      PosCN, PosFin: Integer;
    begin
      Result := '';
      PosCN := Pos('CN=', SubjectName);
      if PosCN > 0 then
      begin
        PosCN := PosCN + 3; // Saltar "CN="
        PosFin := Pos(',', Copy(SubjectName, PosCN, Length(SubjectName))); // Buscar la siguiente coma
        if PosFin > 0 then
          Result := Copy(SubjectName, PosCN, PosFin - 1)
        else
          Result := Copy(SubjectName, PosCN, Length(SubjectName)); // Si no hay coma, tomar todo hasta el final
      end;
    end;


const
  CAPICOM_CURRENT_USER_STORE = 2;
  CAPICOM_MY_STORE = 'My';
var
  Store, Certs, Cert: OleVariant;
  i: Integer;
  CertName, CNExtraido: string;
begin
  Result := False;

  // Crear el objeto de almacén de certificados
  Store := CreateOleObject('CAPICOM.Store');
  Store.Open(CAPICOM_CURRENT_USER_STORE, CAPICOM_MY_STORE, 0); // Abre "Personal"

  // Obtener la colección de certificados en el almacén
  Certs := Store.Certificates;

  if Certs.Count > 0 then
  begin
    // Recorrer los certificados para buscar el que coincida con el nombre almacenado en sVFVerifactu
    for i := 1 to Certs.Count do
    begin
      Cert := Certs.Item[i];
      CertName := Cert.SubjectName;
      CNExtraido := ExtraerCN(CertName); // Extraemos solo el CN

      // Comparar con sVFCertificado
      if CNExtraido = sVFCertificado then
      begin
        // Intentamos obtener la fecha de expiración
        try
          NotAfter := VarToDateTime(Cert.ValidToDate); // Se usa ValidToDate en lugar de ExpirationDate
          DiasHastaCaducidad := DaysBetween(Now, NotAfter);

          // Si quedan menos de 60 días, devolver True
          Result := DiasHastaCaducidad <= 60;
          Exit;
        except
          ShowMessage('Error obteniendo la fecha de caducidad del certificado.');
          Result := False;
          Exit;
        end;
      end;

    end; // Final del for

  end;

  ShowMessage('NO SE ENCUENTRA EL CERTIFICADO EN EL ALMACÉN DE CERTIFICADOS');
end;

Compañero, espero te sirva alguna.
Un saludo,
Ramiro


La franja horaria es GMT +2. Ahora son las 06:30:35.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi