Einzelnen Beitrag anzeigen

querter

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

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

  Alt 11. Feb 2024, 19:07
Hallo,

OK, danke für eure Rückmeldung.

Boha - ich komme mit der englischen Forum-Software auf die schnelle gar nicht zurecht.

Wir haben uns in dieses Problem nun noch etwas weiter eingelesen.

Alles hier ist gefährliches Halbwissen. Es kann gut möglich sein, dass ich komplett falsch liege.

Eine mögliche grundlegende Ursache des Problems kann sein, dass bis 2049 UTC-Time und ab 2050 Generalized-Time verwendet wird.

Darauf müsste wohl INDY10 angepasst werden.

Zitat von RFC 5280:May 2008 - Internet X.509:

4.1.2.5. Validity

The certificate validity period is the time interval during which the
CA warrants that it will maintain information about the status of the
certificate. The field is represented as a SEQUENCE of two dates:
the date on which the certificate validity period begins (notBefore)
and the date on which the certificate validity period ends
(notAfter). Both notBefore and notAfter may be encoded as UTCTime or
GeneralizedTime.

CAs conforming to this profile MUST always encode certificate
validity dates through the year 2049 as UTCTime; certificate validity
dates in 2050 or later MUST be encoded as GeneralizedTime.
Conforming applications MUST be able to process validity dates that
are encoded in either UTCTime or GeneralizedTime.
Des weiteren sind in der Original-Funktion UTC_Time_Decode() (Repository #520) m.M.n. im letzten TZ-Bereich zwei grundlegende Syntax-Fehler enthalten, so dass dieser Decode-Bereich wohl noch nie so ganz richtig funktioniert haben sollte/könnte

Laut dem Author soll der TZ-Syntax angeblich "[+|-]HH( )MM" sein; Woher diese Spezifikation stammt - keine Ahnung. Im RFC zur UTC-Time zumindest habe ich nur ein optionales "[+|-]HHMM" rauslesen können.

Es kann aber gut möglich sein, dass aus den Functionen von OpenSSL diese UTC-Time-Muster zurück gegeben werden. Keine Ahnung. Ich vermute aber eher, dass TZ nie gesendet wird und daher dieses Problem hier nie ein Thema gewesen ist.

Fehler 1:
-------------
Delphi-Quellcode:
Lib\Protocols\IdSSLOpenSSLHeaders.pas

// Converts the following string representation into corresponding parts
// YYMMDDHHMMSS(+|-)HH( )MM
function UTC_Time_Decode(...)
   ...
   // Check TZ
   ...
    for i := 14 to 18 do begin // Check if numbers are numbers
      if i = 16 then begin
        Continue;
      end;
      if not IsNumeric(time_str[i]) then begin
      Exit;
      end;
   end;
   ...
end;
Das "optionale" Space in der TZ Uhrzeit wird in der Funktion hartkodiert als "bedingtes" Space überprüft. Bei einem fehlenden Space läuft bei der TZ-decodieren die For-Schleife über die Stringlänge hinaus, da der finalValue der For-Schleife nicht mit length(time_str) -1 angegeben wird, sondern der String immer fest bis 18 Zeichen überprüft wird.

Ohne einem Space ist die Variable "time_str" daher nur 18 Zeichen lang time_str[0..17] , und erhalten einen Abbruch der For-Schleifen bzgl. "Bereichsprüfung".

Mit einem Space ist die Variable "time_str" zwar 19 Zeichen lang time_str[0..18] , hier würde die For-Schleife durchlaufen, dann führt im Anschluss eine fehlerhafte copy-Implementierung (siehe Fehler 2) zu einem Abbruch der TZ-Schleife - also es wird m.M.n immer TZ als 00:00 zurück gegeben (werden müssen)

Fehler 2:
-------------
Delphi-Quellcode:
function UTC_Time_Decode(...)
   ...
   // Check TZ
   ...
   tz_hour := IndyStrToInt(Copy(time_str, 14, 15)) * tz_dir;
   tz_min := IndyStrToInt(Copy(time_str, 17, 18)) * tz_dir;
   ...
end;
Beim Copy() muss ein Start-Offset sowie ein Counter mit Anzahl an Zeichen angegeben werden (z.B. ab Zeichen 14 weitere 2 Zeichen = Zeichen 14 + 15); Im Source werden aber hartkodiert Start-Offset sowie ein End-Offset (von Zeichen 14 bis Zeichen 15) angegeben und somit werden laut copy() ab Zeichen 14 weiter 15 Zeichen kopiert und damit über das Stringende hinweg bzw. alles bis String-Ende kopiert wie z.B. "03 00"; Das Space in der Uhrzeit kann dann nicht zum Integer konvertiert werden und es wird ein Exception ausgelöst;

Code:

Delphi7: function UTC_Time_Decode() INDY10 (#520)

utc_1901
011224181920Z       = 24.12.2001 18:19:20  = UTC year bad, but OK (RFC-konform)
011224181920+0300    = error               = FAIL: Fehler bei Bereichsprüfung
011224181920+03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
011224181920-0300    = error               = FAIL: Fehler bei Bereichsprüfung
011224181920-03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
011224181920+1122    = error               = FAIL: Fehler bei Bereichsprüfung
011224181920+11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
011224181920-1122    = error               = FAIL: Fehler bei Bereichsprüfung
011224181920-11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
-
utc_1950
501224181920Z       = 24.12.1950 18:19:20  = OK
501224181920+0300    = error               = FAIL: Fehler bei Bereichsprüfung
501224181920+03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
501224181920-0300    = error               = FAIL: Fehler bei Bereichsprüfung
501224181920-03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
501224181920+1122    = error               = FAIL: Fehler bei Bereichsprüfung
501224181920+11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
501224181920-1122    = error               = FAIL: Fehler bei Bereichsprüfung
501224181920-11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
-
utc_1999
991224181920Z       = 24.12.1999 18:19:20  = OK
991224181920+0300    = error               = FAIL: Fehler bei Bereichsprüfung
991224181920+03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
991224181920-0300    = error               = FAIL: Fehler bei Bereichsprüfung
991224181920-03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
991224181920+1122    = error               = FAIL: Fehler bei Bereichsprüfung
991224181920+11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
991224181920-1122    = error               = FAIL: Fehler bei Bereichsprüfung
991224181920-11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
-
utc_2000
001224181920Z       = 24.12.2000 18:19:20  = OK
001224181920+0300    = error               = FAIL: Fehler bei Bereichsprüfung
001224181920+03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
001224181920-0300    = error               = FAIL: Fehler bei Bereichsprüfung
001224181920-03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
001224181920+1122    = error               = FAIL: Fehler bei Bereichsprüfung
001224181920+11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
001224181920-1122    = error               = FAIL: Fehler bei Bereichsprüfung
001224181920-11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
-
utc_2025
251224181920Z       = 24.12.2025 18:19:20  = OK
251224181920+0300    = error               = FAIL: Fehler bei Bereichsprüfung
251224181920+03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
251224181920-0300    = error               = FAIL: Fehler bei Bereichsprüfung
251224181920-03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
251224181920+1122    = error               = FAIL: Fehler bei Bereichsprüfung
251224181920+11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
251224181920-1122    = error               = FAIL: Fehler bei Bereichsprüfung
251224181920-11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
-
utc_2049
491224181920Z       = 24.12.2049 18:19:20  = OK
491224181920+0300    = error               = FAIL: Fehler bei Bereichsprüfung
491224181920+03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
491224181920-0300    = error               = FAIL: Fehler bei Bereichsprüfung
491224181920-03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
491224181920+1122    = error               = FAIL: Fehler bei Bereichsprüfung
491224181920+11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
491224181920-1122    = error               = FAIL: Fehler bei Bereichsprüfung
491224181920-11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
-
utc_2050
501224181920Z       = 24.12.1950 18:19:20  = UTC year bad, but OK (RFC-konform)
501224181920+0300    = error               = FAIL: Fehler bei Bereichsprüfung
501224181920+03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
501224181920-0300    = error               = FAIL: Fehler bei Bereichsprüfung
501224181920-03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
501224181920+1122    = error               = FAIL: Fehler bei Bereichsprüfung
501224181920+11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
501224181920-1122    = error               = FAIL: Fehler bei Bereichsprüfung
501224181920-11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
-
utc_2099
991224181920Z       = 24.12.1999 18:19:20  = UTC year bad, but OK (RFC-konform)
991224181920+0300    = error               = FAIL: Fehler bei Bereichsprüfung
991224181920+03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
991224181920-0300    = error               = FAIL: Fehler bei Bereichsprüfung
991224181920-03 00   = error               = FAIL: '03 00' ist kein gültiger Integerwert
991224181920+1122    = error               = FAIL: Fehler bei Bereichsprüfung
991224181920+11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
991224181920-1122    = error               = FAIL: Fehler bei Bereichsprüfung
991224181920-11 22   = error               = FAIL: '11 22' ist kein gültiger Integerwert
-
general_1901
19011224181920Z     = error               = FAIL: Ungültiges Argument zum Codieren der Uhrzeit
19011224181920+0300  = error               = FAIL: Ungültiges Argument zum Codieren der Uhrzeit
19011224181920+03 00 = error               = FAIL: Ungültiges Argument zum Codieren der Uhrzeit
19011224181920-0300  = error               = FAIL: Ungültiges Argument zum Codieren der Uhrzeit
19011224181920-03 00 = error               = FAIL: Ungültiges Argument zum Codieren der Uhrzeit
19011224181920+1122  = error               = FAIL: Ungültiges Argument zum Codieren der Uhrzeit
19011224181920+11 22 = error               = FAIL: Ungültiges Argument zum Codieren der Uhrzeit
19011224181920-1122  = error               = FAIL: Ungültiges Argument zum Codieren der Uhrzeit
19011224181920-11 22 = error               = FAIL: Ungültiges Argument zum Codieren der Uhrzeit
-
general_1950
19501224181920Z     = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19501224181920+0300  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19501224181920+03 00 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19501224181920-0300  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19501224181920-03 00 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19501224181920+1122  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19501224181920+11 22 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19501224181920-1122  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19501224181920-11 22 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
-
general_1999
19991224181920Z     = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19991224181920+0300  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19991224181920+03 00 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19991224181920-0300  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19991224181920-03 00 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19991224181920+1122  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19991224181920+11 22 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19991224181920-1122  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
19991224181920-11 22 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
-
general_2000
20001224181920Z     = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20001224181920+0300  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20001224181920+03 00 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20001224181920-0300  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20001224181920-03 00 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20001224181920+1122  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20001224181920+11 22 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20001224181920-1122  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20001224181920-11 22 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
-
general_2025
20251224181920Z     = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20251224181920+0300  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20251224181920+03 00 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20251224181920-0300  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20251224181920-03 00 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20251224181920+1122  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20251224181920+11 22 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20251224181920-1122  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20251224181920-11 22 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
-
general_2049
20491224181920Z     = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20491224181920+0300  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20491224181920+03 00 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20491224181920-0300  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20491224181920-03 00 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20491224181920+1122  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20491224181920+11 22 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20491224181920-1122  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20491224181920-11 22 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
-
general_2050
20501224181920Z     = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20501224181920+0300  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20501224181920+03 00 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20501224181920-0300  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20501224181920-03 00 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20501224181920+1122  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20501224181920+11 22 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20501224181920-1122  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20501224181920-11 22 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
-
general_2099
20991224181920Z     = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20991224181920+0300  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20991224181920+03 00 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20991224181920-0300  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20991224181920-03 00 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20991224181920+1122  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20991224181920+11 22 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20991224181920-1122  = error               = FAIL: Ungültiges Argument zum Codieren des Datums
20991224181920-11 22 = error               = FAIL: Ungültiges Argument zum Codieren des Datums
-
<kopfkratz>

Ich habe "für mich" die Funktion erst einmal wie folgt angepasst/modifiziert, damit "unsere" Software erst einmal mit den neuen Zertifikaten beim Hoster weiter arbeitet;

Ich habe nur D7 getestet, keine Ahnung was bei Lazarus, BCB oder anderen Delphi-Versionen (32/64bit, Unicode/Widestring etc.pp) passiert!

Ich habe keine Rücksicht auf {Do not Localize} genommen, dass muss ggf. noch jemand mit INDY10- Fachwissen übernehmen

Sollten Fehler zu erkennen sein oder Cleancode-Hinweise in den Finger gribbeln - bitte sehr gerne aufschreiben. Danke.

Delphi-Quellcode:
{
  This file is part of the Indy (Internet Direct) project, and is offered
  under the dual-licensing agreement described on the Indy website.
  (http://www.indyproject.org/)

  Copyright:
  (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
}

...
// Author : Gregor Ibich (gregor.ibic@intelicom.si)
// Pascal translation: Doychin Bondzhev (doichin@5group.com)
// 02/10/2024 modified: Harald E. Sommermeyer (hes) - UTC-Time and Generalized-Time with tow and four digit years in dates (Y2K50)

// Converts the following string representation into corresponding parts
// UTC-Time: YYMMDDHHMMSS(+|-)HH( )MM // Indy10 old version;
// and
// (hes) RFC 5280, May 2008 (Internet X.509) 4.1.2.5.1. UTCTime
// UTC-Time: YYMMDDHHMMSS(Z|(+|-)HHMM)
// and
// (hes) RFC 5280, May 2008 (Internet X.509) Section 4.1.2.5.2. GeneralizedTime
// Generalized-Time: YYYYMMDDHHMMSS(Z|(+|-)HHMM)

// Note:
// hes: According to RFC 5280, May 2008 (Internet X.509) Section 4.1.2.5.1. UTCTime
// The universal time type, UTCTime, is a standard ASN.1 type intended
// for representation of dates and time. UTCTime specifies the year
// through the two low-order digits and time is specified to the
// precision of one minute or one second. UTCTime includes either Z
// (for Zulu, or Greenwich Mean Time) or a time differential.

// For the purposes of this profile, UTCTime values MUST be expressed in
// Greenwich Mean Time (Zulu) and MUST include seconds (i.e., times are
// YYMMDDHHMMSSZ), even where the number of seconds is zero. Conforming
// systems MUST interpret the year field (YY) as follows:

// Where YY is greater than or equal to 50, the year SHALL be
// interpreted as 19YY; and
// Where YY is less than 50, the year SHALL be interpreted as 20YY.

// hes: According to RFC 5280, May 2008 (Internet X.509) Section 4.1.2.5:
// Validity: The certificate validity period is the time interval during which the
// CA warrants that it will maintain information about the status of the
// certificate. The field is represented as a SEQUENCE of two dates:
// the date on which the certificate validity period begins (notBefore)
// and the date on which the certificate validity period ends
// (notAfter). Both notBefore and notAfter may be encoded as UTCTime or
// GeneralizedTime.

// CAs conforming to this profile MUST always encode certificate
// validity dates through the year 2049 as UTCTime; certificate validity
// dates in 2050 or later MUST be encoded as GeneralizedTime.
// Conforming applications MUST be able to process validity dates that
// are encoded in either UTCTime or GeneralizedTime."

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;
  time_str: string;
  {$IFNDEF USE_MARSHALLED_PTRS}
   {$IFNDEF STRING_IS_ANSI}
  LTemp: AnsiString;
   {$ENDIF}
  {$ENDIF}
  LOffset: Integer;
  Ltz_space: Integer;
const
  LDigit = 1;
  LDigit2 = 2;
  LDigit4 = 4;
  LShortDate = 12; // length('YYMMDDHHMMSS')
  LFullDate = 14; // length('YYYYMMDDHHMMSS')
  LShortYear = LDigit2; // YY
  LFullYear = LDigit4; // YYYY
  LMonth = LDigit2; // MM
  LDay = LDigit2; // DD
  LHour = LDigit2; // HH
  LMinute = LDigit2; // MM
  LSecond = LDigit2; // SS
  LMonthDays : array[1..12] of byte = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
  LMonthDaysLeapYear : array[1..12] of byte = (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); // LeapYear
begin
   Result := 1;
   year := 0;
   month := 0;
   day := 0;
   hour := 0;
   min := 0;
   sec := 0;
   tz_hour := 0;
   tz_min := 0;
   try
      if UCTtime^.length < LShortDate then begin
         Abort;
      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(Z|(+|-)HH( )MM)
      if not IsNumeric(time_str, LShortDate) then begin
         Abort;
      end;

      // Convert time from string to number
      LOffset := 1;

      // CHOICE {GeneralizedTime, UTCTime}
      // If the year has four Digits, check if first 14 characters are number.
      if IsNumeric(time_str, LFullDate) then
      begin
         // GeneralizedTime: YYYYMMDDHHMMSS(Z|(+|-)HHMM)
         year := IndyStrToInt(Copy(time_str, LOffset, LFullYear));
         inc(LOffset, LFullYear);
      end else begin
         // UTCTime: YYMMDDHHMMSS(Z|(+|-)HH( )MM)
         year := IndyStrToInt(Copy(time_str, LOffset, LShortYear)) + 1900;
         inc(LOffset, LShortYear);
         // Fix year. This function is Y2k but isn't compatible with Y2k5 :-( {Do not Localize}
         // Note: 20240209 (hes) - dates >=2050 MUST as GeneralizedTime with four digit year
         if year < 1950 then begin // RFC 2822, Section 3.3 and 4.3
            Inc(year, 100);
         end;
      end;
      if not ((year >= 1) and (year <= 9999)) then Abort;

      month := IndyStrToInt(Copy(time_str, LOffset, LMonth));
      if not (month in [1..12]) then Abort;
      inc(LOffset, LMonth);

      day := IndyStrToInt(Copy(time_str, LOffset, LDay));
      // Is function IsLeapYear() in SysUtils cross-platform?
      if IsLeapYear(Year) then begin
      // if (Year mod 4 = 0) and ((Year mod 100 <> 0) or (Year mod 400 = 0)) then begin
         if not (day in [0..LMonthDaysLeapYear[month]]) then Abort; // LeapYear
      end else begin
         if not (day in [0..LMonthDays[month]]) then Abort; // no LeapYear
      end;
      inc(LOffset, LDay);

      hour := IndyStrToInt(Copy(time_str, LOffset, LHour));
      if not (hour in [0..23]) then Abort;
      inc(LOffset, LHour);

      min := IndyStrToInt(Copy(time_str, LOffset, LMinute));
      if not (min in [0..59]) then Abort;
      inc(LOffset, LMinute);

      sec := IndyStrToInt(Copy(time_str, LOffset, LSecond));
      if not (sec in [0..59]) then Abort;
      inc(LOffset, LSecond);

      // Check TZ
      if CharIsInSet(time_str, LOffset, '-+') then begin {Do not Localize}
         tz_dir := iif(CharEquals(time_str, LOffset, '-'), -1, 1); {Do not Localize}
         inc(LOffset, LDigit);
         if IsNumeric(time_str[LOffset + LDigit2]) then begin // optional space
            Ltz_space := 0;
         end else begin
            Ltz_space := 1;
         end;
         for i := LOffset to (LOffset + LDigit4 + Ltz_space) -1 do begin // Check if numbers are numbers
            if (i = LOffset + LDigit2) and (Ltz_space = 1) then begin // optional space
               Continue;
            end;
            if not IsNumeric(time_str[i]) then begin
               exit;
            end;
         end;
         tz_hour := IndyStrToInt(Copy(time_str, LOffset, LHour)) * tz_dir;
         if not ((tz_hour >= -12) and (tz_hour <= 14)) then tz_hour := 0; // check UTC offsets
         inc(LOffset, LHour + Ltz_space); // and add optional blank
         tz_min := IndyStrToInt(Copy(time_str, LOffset, LMinute)) * tz_dir;
         if not ((tz_min >= -59) and (tz_min <= 59)) then tz_min := 0;
      end;
   except
      Result := 0;
   end;
end;
und noch der passende Test dazu. Ich finde, das sieht doch schon einmal ganz gut aus.

Code:

Delphi7: function UTC_Time_Decode() INDY10 (#520) hes - modifiziert

utc_1901
011224181920Z       = 24.12.2001 18:19:20  = UTC year bad, but OK (RFC-konform)
011224181920+0300    = 24.12.2001 21:19:20  = UTC year bad, but OK (RFC-konform)
011224181920+03 00   = 24.12.2001 21:19:20  = UTC year bad, but OK (RFC-konform)
011224181920-0300    = 24.12.2001 15:19:20  = UTC year bad, but OK (RFC-konform)
011224181920-03 00   = 24.12.2001 15:19:20  = UTC year bad, but OK (RFC-konform)
011224181920+1122    = 25.12.2001 05:41:20  = UTC year bad, but OK (RFC-konform)
011224181920+11 22   = 25.12.2001 05:41:20  = UTC year bad, but OK (RFC-konform)
011224181920-1122    = 24.12.2001 06:57:20  = UTC year bad, but OK (RFC-konform)
011224181920-11 22   = 24.12.2001 06:57:20  = UTC year bad, but OK (RFC-konform)
-
utc_1950
501224181920Z       = 24.12.1950 18:19:20  = OK
501224181920+0300    = 24.12.1950 21:19:20  = OK
501224181920+03 00   = 24.12.1950 21:19:20  = OK
501224181920-0300    = 24.12.1950 15:19:20  = OK
501224181920-03 00   = 24.12.1950 15:19:20  = OK
501224181920+1122    = 25.12.1950 05:41:20  = OK
501224181920+11 22   = 25.12.1950 05:41:20  = OK
501224181920-1122    = 24.12.1950 06:57:20  = OK
501224181920-11 22   = 24.12.1950 06:57:20  = OK
-
utc_1999
991224181920Z       = 24.12.1999 18:19:20  = OK
991224181920+0300    = 24.12.1999 21:19:20  = OK
991224181920+03 00   = 24.12.1999 21:19:20  = OK
991224181920-0300    = 24.12.1999 15:19:20  = OK
991224181920-03 00   = 24.12.1999 15:19:20  = OK
991224181920+1122    = 25.12.1999 05:41:20  = OK
991224181920+11 22   = 25.12.1999 05:41:20  = OK
991224181920-1122    = 24.12.1999 06:57:20  = OK
991224181920-11 22   = 24.12.1999 06:57:20  = OK
-
utc_2000
001224181920Z       = 24.12.2000 18:19:20  = OK
001224181920+0300    = 24.12.2000 21:19:20  = OK
001224181920+03 00   = 24.12.2000 21:19:20  = OK
001224181920-0300    = 24.12.2000 15:19:20  = OK
001224181920-03 00   = 24.12.2000 15:19:20  = OK
001224181920+1122    = 25.12.2000 05:41:20  = OK
001224181920+11 22   = 25.12.2000 05:41:20  = OK
001224181920-1122    = 24.12.2000 06:57:20  = OK
001224181920-11 22   = 24.12.2000 06:57:20  = OK
-
utc_2025
251224181920Z       = 24.12.2025 18:19:20  = OK
251224181920+0300    = 24.12.2025 21:19:20  = OK
251224181920+03 00   = 24.12.2025 21:19:20  = OK
251224181920-0300    = 24.12.2025 15:19:20  = OK
251224181920-03 00   = 24.12.2025 15:19:20  = OK
251224181920+1122    = 25.12.2025 05:41:20  = OK
251224181920+11 22   = 25.12.2025 05:41:20  = OK
251224181920-1122    = 24.12.2025 06:57:20  = OK
251224181920-11 22   = 24.12.2025 06:57:20  = OK
-
utc_2049
491224181920Z       = 24.12.2049 18:19:20  = OK
491224181920+0300    = 24.12.2049 21:19:20  = OK
491224181920+03 00   = 24.12.2049 21:19:20  = OK
491224181920-0300    = 24.12.2049 15:19:20  = OK
491224181920-03 00   = 24.12.2049 15:19:20  = OK
491224181920+1122    = 25.12.2049 05:41:20  = OK
491224181920+11 22   = 25.12.2049 05:41:20  = OK
491224181920-1122    = 24.12.2049 06:57:20  = OK
491224181920-11 22   = 24.12.2049 06:57:20  = OK
-
utc_2050
501224181920Z       = 24.12.1950 18:19:20  = UTC year bad, but OK (RFC-konform)
501224181920+0300    = 24.12.1950 21:19:20  = UTC year bad, but OK (RFC-konform)
501224181920+03 00   = 24.12.1950 21:19:20  = UTC year bad, but OK (RFC-konform)
501224181920-0300    = 24.12.1950 15:19:20  = UTC year bad, but OK (RFC-konform)
501224181920-03 00   = 24.12.1950 15:19:20  = UTC year bad, but OK (RFC-konform)
501224181920+1122    = 25.12.1950 05:41:20  = UTC year bad, but OK (RFC-konform)
501224181920+11 22   = 25.12.1950 05:41:20  = UTC year bad, but OK (RFC-konform)
501224181920-1122    = 24.12.1950 06:57:20  = UTC year bad, but OK (RFC-konform)
501224181920-11 22   = 24.12.1950 06:57:20  = UTC year bad, but OK (RFC-konform)
-
utc_2099
991224181920Z       = 24.12.1999 18:19:20  = UTC year bad, but OK (RFC-konform)
991224181920+0300    = 24.12.1999 21:19:20  = UTC year bad, but OK (RFC-konform)
991224181920+03 00   = 24.12.1999 21:19:20  = UTC year bad, but OK (RFC-konform)
991224181920-0300    = 24.12.1999 15:19:20  = UTC year bad, but OK (RFC-konform)
991224181920-03 00   = 24.12.1999 15:19:20  = UTC year bad, but OK (RFC-konform)
991224181920+1122    = 25.12.1999 05:41:20  = UTC year bad, but OK (RFC-konform)
991224181920+11 22   = 25.12.1999 05:41:20  = UTC year bad, but OK (RFC-konform)
991224181920-1122    = 24.12.1999 06:57:20  = UTC year bad, but OK (RFC-konform)
991224181920-11 22   = 24.12.1999 06:57:20  = UTC year bad, but OK (RFC-konform)
-
general_1901
19011224181920Z     = 24.12.1901 18:19:20  = OK
19011224181920+0300  = 24.12.1901 21:19:20  = OK
19011224181920+03 00 = 24.12.1901 21:19:20  = OK
19011224181920-0300  = 24.12.1901 15:19:20  = OK
19011224181920-03 00 = 24.12.1901 15:19:20  = OK
19011224181920+1122  = 25.12.1901 05:41:20  = OK
19011224181920+11 22 = 25.12.1901 05:41:20  = OK
19011224181920-1122  = 24.12.1901 06:57:20  = OK
19011224181920-11 22 = 24.12.1901 06:57:20  = OK
-
general_1950
19501224181920Z     = 24.12.1950 18:19:20  = OK
19501224181920+0300  = 24.12.1950 21:19:20  = OK
19501224181920+03 00 = 24.12.1950 21:19:20  = OK
19501224181920-0300  = 24.12.1950 15:19:20  = OK
19501224181920-03 00 = 24.12.1950 15:19:20  = OK
19501224181920+1122  = 25.12.1950 05:41:20  = OK
19501224181920+11 22 = 25.12.1950 05:41:20  = OK
19501224181920-1122  = 24.12.1950 06:57:20  = OK
19501224181920-11 22 = 24.12.1950 06:57:20  = OK
-
general_1999
19991224181920Z     = 24.12.1999 18:19:20  = OK
19991224181920+0300  = 24.12.1999 21:19:20  = OK
19991224181920+03 00 = 24.12.1999 21:19:20  = OK
19991224181920-0300  = 24.12.1999 15:19:20  = OK
19991224181920-03 00 = 24.12.1999 15:19:20  = OK
19991224181920+1122  = 25.12.1999 05:41:20  = OK
19991224181920+11 22 = 25.12.1999 05:41:20  = OK
19991224181920-1122  = 24.12.1999 06:57:20  = OK
19991224181920-11 22 = 24.12.1999 06:57:20  = OK
-
general_2000
20001224181920Z     = 24.12.2000 18:19:20  = OK
20001224181920+0300  = 24.12.2000 21:19:20  = OK
20001224181920+03 00 = 24.12.2000 21:19:20  = OK
20001224181920-0300  = 24.12.2000 15:19:20  = OK
20001224181920-03 00 = 24.12.2000 15:19:20  = OK
20001224181920+1122  = 25.12.2000 05:41:20  = OK
20001224181920+11 22 = 25.12.2000 05:41:20  = OK
20001224181920-1122  = 24.12.2000 06:57:20  = OK
20001224181920-11 22 = 24.12.2000 06:57:20  = OK
-
general_2025
20251224181920Z     = 24.12.2025 18:19:20  = OK
20251224181920+0300  = 24.12.2025 21:19:20  = OK
20251224181920+03 00 = 24.12.2025 21:19:20  = OK
20251224181920-0300  = 24.12.2025 15:19:20  = OK
20251224181920-03 00 = 24.12.2025 15:19:20  = OK
20251224181920+1122  = 25.12.2025 05:41:20  = OK
20251224181920+11 22 = 25.12.2025 05:41:20  = OK
20251224181920-1122  = 24.12.2025 06:57:20  = OK
20251224181920-11 22 = 24.12.2025 06:57:20  = OK
-
general_2049
20491224181920Z     = 24.12.2049 18:19:20  = OK
20491224181920+0300  = 24.12.2049 21:19:20  = OK
20491224181920+03 00 = 24.12.2049 21:19:20  = OK
20491224181920-0300  = 24.12.2049 15:19:20  = OK
20491224181920-03 00 = 24.12.2049 15:19:20  = OK
20491224181920+1122  = 25.12.2049 05:41:20  = OK
20491224181920+11 22 = 25.12.2049 05:41:20  = OK
20491224181920-1122  = 24.12.2049 06:57:20  = OK
20491224181920-11 22 = 24.12.2049 06:57:20  = OK
-
general_2050
20501224181920Z     = 24.12.2050 18:19:20  = OK
20501224181920+0300  = 24.12.2050 21:19:20  = OK
20501224181920+03 00 = 24.12.2050 21:19:20  = OK
20501224181920-0300  = 24.12.2050 15:19:20  = OK
20501224181920-03 00 = 24.12.2050 15:19:20  = OK
20501224181920+1122  = 25.12.2050 05:41:20  = OK
20501224181920+11 22 = 25.12.2050 05:41:20  = OK
20501224181920-1122  = 24.12.2050 06:57:20  = OK
20501224181920-11 22 = 24.12.2050 06:57:20  = OK
-
general_2099
20991224181920Z     = 24.12.2099 18:19:20  = OK
20991224181920+0300  = 24.12.2099 21:19:20  = OK
20991224181920+03 00 = 24.12.2099 21:19:20  = OK
20991224181920-0300  = 24.12.2099 15:19:20  = OK
20991224181920-03 00 = 24.12.2099 15:19:20  = OK
20991224181920+1122  = 25.12.2099 05:41:20  = OK
20991224181920+11 22 = 25.12.2099 05:41:20  = OK
20991224181920-1122  = 24.12.2099 06:57:20  = OK
20991224181920-11 22 = 24.12.2099 06:57:20  = OK
-
Meine Test-Schleife dazu.

Delphi-Quellcode:
uses
  ...
  IdSSLOpenSSL,
  IdSSLOpenSSLHeaders
  ...


// 20240207: hes - only Datum Test Indy UTC_Time_Decode() BugFix;
procedure UTC_Time_Decode;
var
  year: Word;
  month: Word;
  day: Word;
  hour: Word;
  min: Word;
  sec: Word;
  tz_h: Integer;
  tz_m: Integer;
  UCTTime: PASN1_UTCTIME;
  dt : TDateTime;
  s, s1 : String;
  sl, sl2: TStringList;
  i, j: Integer;
  value: String;
begin
   sl := TStringList.Create;
   sl2 := TStringList.Create;
   try
      sl.Append('utc_1901=011224181920');
      sl.Append('utc_1950=501224181920');
      sl.Append('utc_1999=991224181920');
      sl.Append('utc_2000=001224181920');
      sl.Append('utc_2025=251224181920');
      sl.Append('utc_2049=491224181920');
      sl.Append('utc_2050=501224181920');
      sl.Append('utc_2099=991224181920');

// Generalied
      sl.Append('general_1901=19011224181920');
      sl.Append('general_1950=19501224181920');
      sl.Append('general_1999=19991224181920');
      sl.Append('general_2000=20001224181920');
      sl.Append('general_2025=20251224181920');
      sl.Append('general_2049=20491224181920');
      sl.Append('general_2050=20501224181920');
      sl.Append('general_2099=20991224181920');

      sl2.Append('Z');
      sl2.Append('+0300');
      sl2.Append('+03 00');
      sl2.Append('-0300');
      sl2.Append('-03 00');
      sl2.Append('+1122');
      sl2.Append('+11 22');
      sl2.Append('-1122');
      sl2.Append('-11 22');

      new(UCTTime);
      try
         for i := 0 to sl.Count -1 do begin
            self.MemoLog.Lines.Append(format('%s', [sl.Names[i]]));
            for j := 0 to sl2.Count -1 do begin
               UCTTime^.data := PAnsiChar(sl.ValueFromIndex[i]+sl2.Strings[j]);
               UCTTime^.length := length(sl.ValueFromIndex[i]+sl2.Strings[j]);
               try
                  s1 := '';
                  dt := UTC_Time_Decode(UCTTime, year, month, day, hour, min, sec, tz_h, tz_m);
                  UCTTime^.length := 0;
                  UCTTime^.data := nil;
                  dt := EncodeDate(year, month, day) + EncodeTime(hour, min, sec, 0);
                  dt := dt + tz_m / (60 * 24);
                  dt := dt + tz_h / 24.0;
                  s1 := DateTimeToStr(dt);
                  value := 'OK';
               except
                  on E: Exception do value := 'FAIL: ' + E.Message;
               end;
               if s1 <> 'then begin
                  self.MemoLog.Lines.Append(format('%-20s = %-20s = %s', [sl.ValueFromIndex[i]+sl2.Strings[j], s1, value]));
               end else begin
                  self.MemoLog.Lines.Append(format('%-20s = %-20s = %s', [sl.ValueFromIndex[i]+sl2.Strings[j], 'error', value]));
               end;
            end;
            self.MemoLog.Lines.Append('-');
         end;
      finally
         dispose(UCTTime);
      end;
   finally
      sl.Free;
      sl2.Free;
   end;
end;
Weiter ist nun der Funktionname nicht mehr ganz stimmig ... keine Ahnung wie damit im INDY-Projekt umgegangen wird ... die Function müsste nun eher ggf. UTC_Generalized_Time_Decode() oder so heissen ... die Funktion in UTC-Time und Generalized-Time splitten ist irgendwie auch blöd, da 90% des Source ggf. gleich bleibt.

weiter geht's ggf. dann im englischen Forum;
SSL Cert gültig bis 2051: Indy10 (D7) TIdX509.notAfter = EConvertError

Herzliche Grüße
qwerter

Geändert von querter (11. Feb 2024 um 19:12 Uhr) Grund: URL ins EN Forum eingefügt
  Mit Zitat antworten Zitat