Einzelnen Beitrag anzeigen

querter

Registriert seit: 19. Apr 2008
30 Beiträge
 
#1

SSL Cert gültig bis 2051: Indy10 (D7) TIdX509.notAfter = EConvertError

  Alt 6. Feb 2024, 21:43
Hallo INDY-Anwender;

Kann jemand von euch hier folgendes unten in der Weiterleitung auf die Indy-Seite per New issue erstellen? Wir haben bei GitHub keinen Account ...

Das wäre klasse. Gerne mit Rückmeldung. Danke!

Nach einem Server-Update seitens Hoster konnten wir mit INDY10 nicht mehr die Gültigkeit des Certs einer FTPES-Verbindung auslesen.

Dabei hat sich herausgestellt, dass der ftp-Server nun das NotAfter-Datum mit einer vierstelligen Jahreszahl sendet. Damit kann INDY10 nicht umgehen und schmeisst ein EConvertError. Da das Cert-Datum gültig bis 2051 ist - wird ggf. wahrscheinlich dieses mit dem Y2K38-Problem zusammen hängen.

Mit dem unten angehängten Workaround funktioniert INDY10 wieder wie gehabt. Datum mit zweistelliger und vierstelliger Jahreszahl werden korrekt konvertiert;

Zitat von Harald E. Sommermeyer:
Indy10 (D7)

TIdX509.notBefore with four digits for the year has failed.

GoDaddy / Domainfactory (DE) new self-signed certificate has date "Not after" > 2038 and the ftp server sends new date format with four digits for the year.

Code:
(TIdX509.DisplayInfo.Text)

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=DE, ST=Bayern, L=Muenchen, O=ispgateway, CN=webserver.ispgateway.de
        Validity
            Not Before: Dec 12 05:43:54 2023 GMT
            Not After : Apr 29 05:43:54 2051 GMT
...
The ftp server send the data-format:

Not Before: 231212054354Z
Not After : 20510429054354Z

TIdX509.notBefore can only decode two digits for the year YYMMDDHHMMSS.
TIdX509.notAfter can only decode two digits for the year YYMMDDHHMMSS.

TIdX509.notBefore: OK = 12.12.2023 05:43:54
TIdX509.notAfter: FAIL = EConvertError and excepted.

in IdSSLOpenSSL.pas:
-> TIdX509 property notAfter -> call function RnotAfter -> call function UTCTime2DateTime() -> call function UTC_Time_Decode() ! failed;

In IdSSLOpenSSLHeader.pas the function UTC_Time_Decode() give missmatch back.

The workaround can now decode both four-digit and two-digit years.

TIdX509.notBefore now can decode two and four digits for the year YYMMDDHHMMSS / YYYYMMDDHHMMSS.
TIdX509.notAfter now can decode two and four digits for the year YYMMDDHHMMSS / YYYYMMDDHHMMSS.

TIdX509.notBefore: OK = 12.12.2023 05:43:54
TIdX509.notAfter: OK = 29.04.2051 05:43:54

-----------
Delphi-Quellcode:
// Author : Gregor Ibich (gregor.ibic@intelicom.si)
// Pascal translation: Doychin Bondzhev (doichin@5group.com)
// 20240206 modified: Harald E. Sommermeyer (hes)

// Converts the following string representation into corresponding parts
// YYMMDDHHMMSS(+|-)HH( )MM
// and
// YYYYMMDDHHMMSS(+|-)HH( )MM (20240206: hes - Y2K38-Fix)
function UTC_Time_Decode(UCTtime : PASN1_UTCTIME; var year, month, day, hour, min, sec: Word;
  var tz_hour, tz_min: Integer): Integer;
var
  i, tz_dir: Integer;
  idx_add, idx_from: Integer;
  time_str: string;
  {$IFNDEF USE_MARSHALLED_PTRS}
   {$IFNDEF STRING_IS_ANSI}
  LTemp: AnsiString;
   {$ENDIF}
  {$ENDIF}
begin
  Result := 1;
  if UCTtime^.length < 12 then begin
   Exit;
  end;
  {$IFDEF USE_MARSHALLED_PTRS}
  time_str := TMarshal.ReadStringAsAnsi(TPtrWrapper.Create(UCTtime^.data), UCTtime^.length);
  {$ELSE}
   {$IFDEF STRING_IS_ANSI}
  SetString(time_str, UCTtime^.data, UCTtime^.length);
   {$ELSE}
  SetString(LTemp, UCTtime^.data, UCTtime^.length);
  time_str := String(LTemp); // explicit convert to Unicode
   {$ENDIF}
  {$ENDIF}
  // Check if first 12 chars are numbers
  // YYMMDDHHMMSS(+|-)HH( )MM
  idx_from := 0;
  idx_add := 0;
  if not IsNumeric(time_str, 12) then begin
   Exit;
  end;
  // Convert time from string to number
  // Y2K38 Fix: If the year has four digits, check if first 14 characters are number.
  idx_from := 1;
  if IsNumeric(time_str, 14) then
  begin
     // YYYYMMDDHHMMSS(+|-)HH( )MM
     idx_add := 4;
     year := IndyStrToInt(Copy(time_str, idx_from, idx_add));
  end else begin
     // YYMMDDHHMMSS(+|-)HH( )MM
     idx_add := 2;
     year := IndyStrToInt(Copy(time_str, idx_from, idx_add)) + 1900;
  end;
  inc(idx_from, idx_add);

  idx_add := 2;
  month := IndyStrToInt(Copy(time_str, idx_from, idx_add));
  inc(idx_from, idx_add);

  day := IndyStrToInt(Copy(time_str, idx_from, idx_add));
  inc(idx_from, idx_add);

  hour := IndyStrToInt(Copy(time_str, idx_from, idx_add));
  inc(idx_from, idx_add);

  min := IndyStrToInt(Copy(time_str, idx_from, idx_add));
  inc(idx_from, idx_add);

  sec := IndyStrToInt(Copy(time_str, idx_from, idx_add));
  inc(idx_from, idx_add);

  // Fix year. This function is Y2k but isn't compatible with Y2k5 :-( {Do not Localize}
  if year < 1950 then begin
   Inc(year, 100);
  end;
  // Check TZ
  tz_hour := 0;
  tz_min := 0;
  if CharIsInSet(time_str, idx_from, '-+') then begin {Do not Localize}
   tz_dir := iif(CharEquals(time_str, idx_from, '-'), -1, 1); {Do not Localize}
   inc(idx_from, 1);
   for i := idx_from to idx_from + 4 do begin // Check if numbers are numbers
     if i = idx_from + 2 then begin
      Continue;
     end;
     if not IsNumeric(time_str[i]) then begin
      Exit;
     end;
   end;
   tz_hour := IndyStrToInt(Copy(time_str, idx_from, idx_from + 1)) * tz_dir;
   inc(idx_from, 2);
   tz_min := IndyStrToInt(Copy(time_str, idx_from, idx_from + 1)) * tz_dir;
  end;
end;
-----------
  Mit Zitat antworten Zitat