DEFINITION MODULE DKIM;

        (********************************************************)
        (*                                                      *)
        (*                    DKIM Signatures                   *)
        (*                                                      *)
        (*                                                      *)
        (*  Programmer:         see below                       *)
        (*  Started:            2 August 2023                   *)
        (*  Last edited:        25 February 2024                *)
        (*  Status:             Being modified.                 *)
        (*                                                      *)
        (*  The standard governing this code is RFC 6376        *)
        (*                                                      *)
        (* This is an adaptation of the DKIM module originally  *)
        (* written for Weasel.  I want to make it a bit more    *)
        (* generic, so that it can be used for Weasel as well   *)
        (* as for Major Major.                                  *)
        (*                                                      *)
        (********************************************************)


FROM TransLog IMPORT TransactionLogID;
FROM SYSTEM   IMPORT CARD8;
FROM Arith64  IMPORT CARD64;
FROM INIData  IMPORT HINI;


CONST
    DKIM_RC_OK                  = 0;
    DKIM_RC_KEYNOTPROVIDED      = 10; (* Caller did not provide a public/private key *)
    DKIM_RC_NOSIGNATURE         = 11; (* Invalid or missing "DKIM-Signature" *)
    DKIM_RC_INVALIDBODYHASH     = 12; (* Hash of the body does not match tag 'bh' value in "DKIM-Signature" *)
    DKIM_RC_VERIFICATIONFAILED  = 13; (* The signature was not verified *)
    DKIM_RC_UNSUPPORTEDVERSION  = 14; (* Tag 'v' of DKIM-Signature is not '1' *)

    (* Maximum file size.  This is only half what you would expect, because *)
    (* the OS/2 file system treats file size as a SIGNED integer.           *)

    DKIM_ENTIREBODY          = CARD64{MAX(CARDINAL) DIV 2, MAX(CARDINAL)};

TYPE
    (* Result of a DKIM signature check. This is as specified in    *)
    (* section 3.9 of the standard.  This is rather crude, though,  *)
    (* because it doesn't allow for conditions like "the message    *)
    (* has no DKIM signature".  I might have to violate the         *)
    (* standard for the sake of getting a useful result.            *)

    DKIMresult = (SUCCESS, PERMFAIL, TEMPFAIL);


PROCEDURE LoadParameters (hini: HINI);

    (* Sets several parameters controlling DKIM operation.  This is *)
    (* to create signatures on outgoing mail.  For incoming mail,   *)
    (* the parameters are instead taken from the existing DKIM      *)
    (* signature.                                                   *)

PROCEDURE InsertDKIMSignature (logID: TransactionLogID;
                                        infile, outfile: ARRAY OF CHAR);

    (* Inserts a DKIM signature as a header in the message file     *)
    (* infile, with the result put in outfile.  (If outfile is the  *)
    (* empty string, the result overwrites infile.)  No result is   *)
    (* returned to the caller.  Instead, error messages are sent to *)
    (* the log file.                                                *)

PROCEDURE CheckDKIMSignature (logID: TransactionLogID;
                                VAR (*IN*) filename: ARRAY OF CHAR;
                                VAR (*OUT*) reason: ARRAY OF CHAR;
                                VAR (*IN*) dummy: ARRAY OF CARD8)
                                                         : DKIMresult;

    (* Checks the DKIM-Signature header field, if any, in the file. *)
    (* If there is no such header, we return TEMPFAIL.  The reason  *)
    (* output is a message suitable for logging.                    *)

END DKIM.

