(**************************************************************************)
(*                                                                        *)
(*  Transport Layer Security                                              *)
(*  Copyright (C) 2025   Peter Moylan                                     *)
(*                                                                        *)
(*  This program is free software: you can redistribute it and/or modify  *)
(*  it under the terms of the GNU General Public License as published by  *)
(*  the Free Software Foundation, either version 3 of the License, or     *)
(*  (at your option) any later version.                                   *)
(*                                                                        *)
(*  This program is distributed in the hope that it will be useful,       *)
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
(*  GNU General Public License for more details.                          *)
(*                                                                        *)
(*  You should have received a copy of the GNU General Public License     *)
(*  along with this program.  If not, see <http://www.gnu.org/licenses/>. *)
(*                                                                        *)
(*  To contact author:   http://www.pmoylan.org   peter@pmoylan.org       *)
(*                                                                        *)
(**************************************************************************)

IMPLEMENTATION MODULE TLSAlerts;

        (********************************************************)
        (*                                                      *)
        (*                Transport Layer Security              *)
        (*                     Alert messages                   *)
        (*                                                      *)
        (*  Programmer:         P. Moylan                       *)
        (*  Started:            3 December 2024                 *)
        (*  Last edited:        2 August 2025                   *)
        (*  Status:             OK                              *)
        (*                                                      *)
        (********************************************************)


IMPORT Strings;

FROM SYSTEM IMPORT CARD8;

FROM TransLog IMPORT
    (* type *)  TransactionLogID,
    (* proc *)  LogTransaction;

FROM TLSBase IMPORT
    (* type *)  TextType,
    (* proc *)  DiscardFragment;

FROM MiscFuncs IMPORT
    (* proc *)  AppendCard;

FROM Storage IMPORT
    (* proc *)  ALLOCATE;

(************************************************************************)

CONST
    SSLversionMajor = 3;
    SSLversionMinor = 3;

(************************************************************************)
(*                              ALERTS                                  *)
(************************************************************************)

PROCEDURE LogAlert (ID: TransactionLogID;  VAR (*INOUT*) buffer: TextType;
                    VAR (*OUT*) done, ConnectionLost: BOOLEAN): BOOLEAN;

    (* Returns TRUE iff not a fatal alert. *)

    VAR type, descr: CARD8;  success: BOOLEAN;
        message: ARRAY [0..127] OF CHAR;

    BEGIN
        done := FALSE;
        ConnectionLost := FALSE;
        Strings.Assign ("received ", message);
        IF buffer.fragment = NIL THEN
            Strings.Append ("buffer.fragment = NIL", message);
            success := TRUE;
        ELSE
            type := buffer.fragment^[0];
            descr := buffer.fragment^[1];
            success := type = 1;    (* warning rather than fatal *)
            IF success THEN Strings.Append ("Warning", message);
            ELSE
                Strings.Append ("Fatal", message);
                done := TRUE;
            END (*IF*);
            IF descr = 0 THEN
                Strings.Append (" error: peer closing connection", message);
                ConnectionLost := TRUE;
                done := TRUE;
            ELSIF descr = 10 THEN
                Strings.Append (" error: unexpected message", message);
            ELSE
                Strings.Append (" alert ", message);
                AppendCard (descr, message);
                CASE descr OF
                    | 20:   Strings.Append (" = bad MAC", message);
                    | 22:   Strings.Append (" = record overflow", message);
                    | 40:   Strings.Append (" = handshake failure", message);
                    | 42:   Strings.Append (" = bad certificate", message);
                    | 43:   Strings.Append (" = unsupported certificate", message);
                    | 45:   Strings.Append (" = certificate expired", message);
                    | 48:   Strings.Append (" = unknown CA", message);
                    | 50:   Strings.Append (" = decode error", message);
                ELSE
                    (* Don't need explanations of other cases so far. *)
                END (*CASE*);
            END (*IF*);
        END (*IF*);
        DiscardFragment (buffer);
        LogTransaction (ID, message);
        RETURN success;
    END LogAlert;

(************************************************************************)

PROCEDURE CreateAlert (alerttype: CARDINAL;  fatal: BOOLEAN;
                            VAR (*OUT*) buffer: TextType);

    (* Fills buffer with the details of an alert, ready to send to the peer. *)

    BEGIN
        buffer.contenttype := 21;
        buffer.majversion := SSLversionMajor;
        buffer.minversion := SSLversionMinor;
        buffer.length := 2;
        ALLOCATE (buffer.fragment, 2);
        IF fatal THEN
            buffer.fragment^[0] := 2;
        ELSE
            buffer.fragment^[0] := 1;
        END (*IF*);
        buffer.fragment^[1] := alerttype;
    END CreateAlert;

(************************************************************************)

END TLSAlerts.

