#ifndef KEKS_CM_PUB_H
#define KEKS_CM_PUB_H

#include <stdbool.h>
#include <stddef.h>
#include <time.h>

#include "../err.h"
#include "../items.h"

// TEXINFO: KEKSCMPub
// @deftp {Data type} {struct KEKSCMPub}
// Parsed certificate structure.
// @table @code
// @item .items
//     Holds parsed @ref{KEKSItems} items.
// @item .pub
//     Items index of the first @code{/data/pub}, certificate's public key.
// @item .sub
//     Items index of the @code{/data/sub}, certificate's subject.
// @item .sig
//     Items index of the first @code{/sigs}, certificate's signature.
// @item .cid
//     Pointer to the start of if @code{cid} hexlet, certificate's id.
// @item .pubId
//     Pointer to the start of if @code{id}, certificate's public key id.
// @item .sid
//     Pointer to the start of if @code{sid}, certificate's signature id.
// @item .since
//     Parsed "since" datetime.
// @item .till
//     Parsed un"till" datetime.
// @end table
// @end deftp
struct KEKSCMPub {
    struct KEKSItems items;
    size_t pub;
    size_t sub;
    size_t sig;
    const unsigned char *cid;
    const unsigned char *pubId;
    const unsigned char *sid;
    struct timespec since;
    struct timespec till;
};

// TEXINFO: KEKSCMPubParse
// @deftypefun {enum KEKSErr} KEKSCMPubParse ( @
//     struct KEKSCMPub *cer, @
//     size_t *off, @
//     char **failReason, @
//     const unsigned char *buf, @
//     const size_t len)
// Parse represented KEKS certificate from @var{buf} of @var{len} length,
// to the @var{cer}, starting with @var{off} offset in the buffer.
// Offset will be updated to show where parsing stopped. If parsing,
// made by @ref{KEKSItemsParse}, finished successfully, then
// @code{KEKSErrUnsatisfiedSchema} may be returned after that, setting
// the @var{failReason} to the string describing the error.
// @end deftypefun
enum KEKSErr
KEKSCMPubParse(
    struct KEKSCMPub *,
    size_t *off,
    char **failReason,
    const unsigned char *buf,
    const size_t len);

typedef bool (*keksSigVerifier)(
    char **failReason,
    const unsigned char *ai,
    const size_t aiLen,
    const unsigned char *sig,
    const size_t sigLen,
    const unsigned char *pub,
    const size_t pubLen,
    const unsigned char *data,
    const size_t dataLen);

// TEXINFO: KEKSCMPubSigVerifier
// @deftp {Data type} {struct KEKSCMPubSigVerifier}
// Cryptographic signature verifier. That structure's @code{.algo} holds
// the string identifier of the algorithm met in the KEKS structures.
// @code{.func} holds the pointer to the verifier function itself, that
// accepts the algorithm identifier, signature, raw public key, the data
// to be verified.
// @end deftp
struct KEKSCMPubSigVerifier {
    char *algo;
    keksSigVerifier func;
};

// TEXINFO: KEKSCMPubVerifyOpts
// @deftp {Data type} {struct KEKSCMPubVerifyOpts}
// Pubtificate verification options:
// @table @code
// @item .t
//     Validity time to check against.
// @item .sigVerifiers
//     List of @ref{KEKSCMPubSigVerifier}.
//     Its last dummy element must have NULL @code{.algo}.
// @end table
// @end deftp
struct KEKSCMPubVerifyOpts {
    struct timespec t;
    struct KEKSCMPubSigVerifier *sigVerifiers;
};

// TEXINFO: KEKSCMPubVerify
// @deftypefun bool KEKSCMPubVerify ( @
//     char **failReason, @
//     struct KEKSCMPub **verifier, @
//     struct KEKSCMPub *cer, @
//     struct KEKSCMPub *pool, @
//     const size_t poolLen, @
//     const struct KEKSCMPubVerifyOpts opts)
// Verify @var{cer} certificate. @var{pool} is a list of certificates of
// @var{poolLen} length, which is searched for verifier certificates. If
// verifier is found (certificate with @code{pubId} equals to @code{sid}),
// then @var{verifier} points to it. @var{opts} options affect
// verification process.
// @end deftypefun
bool
KEKSCMPubVerify(
    char **failReason,
    struct KEKSCMPub **verifier,
    struct KEKSCMPub *cer,
    struct KEKSCMPub *pool,
    const size_t poolLen,
    const struct KEKSCMPubVerifyOpts opts);

extern const unsigned char KEKSCMPubSchemaRaw[];
extern const size_t KEKSCMPubSchemaRawLen;

#endif // KEKS_CM_PUB_H
