DEFINITION MODULE DKIM;

        (********************************************************)
        (*                                                      *)
        (*                    DKIM Signatures                   *)
        (*                                                      *)
        (*                                                      *)
        (*  Programmer:         see below                       *)
        (*  Started:            2 August 2023                   *)
        (*  Last edited:        26 April 2025                   *)
        (*  Status:             Mostly complete, some tuning    *)
        (*                          needed                      *)
        (*                                                      *)
        (*  The standard governing this code is RFC 6376        *)
        (*                                                      *)
        (* This is a new approach that bypasses the solution    *)
        (* by Andrey Vasilkin (digi@os2.snc.ru).  For some      *)
        (* reason my use of his DLL is giving incorrect         *)
        (* results, so I've gone back to square one.            *)
        (*                                                      *)
        (********************************************************)


FROM Domains  IMPORT Domain;
FROM TransLog IMPORT TransactionLogID;
FROM SYSTEM   IMPORT CARD8;
FROM Arith64  IMPORT CARD64LE;


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' *)
    DKIM_RC_ILLEGALHASHALG      = 15; (* Illegal hash algorithm *)

    (* 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          = CARD64LE{MAX(CARDINAL), MAX(CARDINAL) DIV 2};

TYPE
    ParamPtr;          (* is private *)

    (* 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 LoadDefaultParameters;

    (* Sets several parameters controlling DKIM operation.  This is  *)
    (* the version where we use the same parameters for all domains. *)

PROCEDURE DiscardAllDKIMParameters;

    (* To be called when the INI file has changed.  We unload all   *)
    (* the DKIM parameters that we have stored.  They will be       *)
    (* reloaded gradually as calls to insert a DKIM signature arise.*)

PROCEDURE GetDKIMEnable (D: Domain;  VAR (*OUT*) check, sign: BOOLEAN);

    (* Is DKIM checking and signing enabled for this domain? *)

PROCEDURE InsertDKIMSignature (logID: TransactionLogID;  D: Domain;
                                        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.

