+++ /dev/null
-redo-ifchange cer-verify
-/cer-verify
/compile_flags.txt
+/pub-verify
--- /dev/null
+redo-ifchange pub-verify
#!/bin/sh -e
cd "$(dirname "$(realpath -- "$0")")"
-exec rm -f cer-verify compile_flags.txt conf/gcl3.rc conf/monocypher.rc *.o
+exec rm -f pub-verify compile_flags.txt conf/gcl3.rc conf/monocypher.rc *.o
#include <string.h>
#include <time.h>
+#include <keks/cm/pub.h>
#include <keks/err.h>
-#include <keks/items.h>
-#include <keks/pki/cer.h>
+#include "../lib/hex.h"
#include "../lib/mmap.h"
#include "../lib/uuid.h"
main(int argc, char **argv)
{
if (argc < 3) {
- fprintf(stderr, "Usage: %s EE.cer [CA.cer ...]\n", argv[0]);
+ fprintf(stderr, "Usage: %s EE.pub [CA.pub ...]\n", argv[0]);
return EXIT_FAILURE;
}
const size_t cersLen = (size_t)argc - 1;
- struct KEKSCer *cers = calloc(cersLen, sizeof(struct KEKSCer));
+ struct KEKSCMPub *cers = calloc(cersLen, sizeof(struct KEKSCMPub));
assert(cers != NULL);
char *failReason = NULL;
for (int i = 1; i < argc; i++) {
fputs(argv[i], stdout);
fputs(":\t", stdout);
size_t off = 0;
- enum KEKSErr err = KEKSCerParse(&(cers[i - 1]), &off, &failReason, buf, len);
+ enum KEKSErr err = KEKSCMPubParse(&(cers[i - 1]), &off, &failReason, buf, len);
if (err != KEKSErrNo) {
fprintf(stderr, "%s: %s\n", argv[i], failReason);
return EXIT_FAILURE;
}
fputs("cid:", stdout);
UUIDPrint(cers[i - 1].cid);
- fputs(" pkid:", stdout);
- UUIDPrint(cers[i - 1].pkid);
- fputs(" sid:", stdout);
- UUIDPrint(cers[i - 1].sid);
+ {
+ fputs(" pubId:", stdout);
+ char *hex = HexEnc(cers[i - 1].pubId, 32);
+ fputs(hex, stdout);
+ free(hex);
+ }
+ {
+ fputs(" sid:", stdout);
+ char *hex = HexEnc(cers[i - 1].sid, 32);
+ fputs(hex, stdout);
+ free(hex);
+ }
fputs("\n", stdout);
}
return EXIT_FAILURE;
}
- struct KEKSCerSigVerifier sigVerifiers[] = {
+ struct KEKSCMPubSigVerifier sigVerifiers[] = {
{.algo = "ed25519-blake2b", .func = ed25519blake2bSignatureVerifier},
{.algo = "gost3410-256A", .func = gost3410SignatureVerifier},
{.algo = "gost3410-512C", .func = gost3410SignatureVerifier},
{.algo = NULL},
};
- struct KEKSCerVerifyOpts opts = {.t = now, .sigVerifiers = sigVerifiers};
+ struct KEKSCMPubVerifyOpts opts = {.t = now, .sigVerifiers = sigVerifiers};
- struct KEKSCer *toVerify = &(cers[0]);
- struct KEKSCer *verifier = NULL;
+ struct KEKSCMPub *toVerify = &(cers[0]);
+ struct KEKSCMPub *verifier = NULL;
for (;;) {
fputs("verifying ", stdout);
UUIDPrint(toVerify->cid);
fputs(": ", stdout);
- if (!KEKSCerVerify(&failReason, &verifier, toVerify, cers, cersLen, opts)) {
+ if (!KEKSCMPubVerify(&failReason, &verifier, toVerify, cers, cersLen, opts)) {
fputs(failReason, stdout);
fputs("\n", stdout);
return EXIT_FAILURE;
}
- if (memcmp(toVerify->sid, toVerify->pkid, 16) == 0) {
+ if (memcmp(toVerify->sid, toVerify->pubId, 32) == 0) {
fputs("ok\n", stdout);
break;
}
-deps="../lib/mmap.o ../lib/uuid.o verifier-ed25519-blake2b.o verifier-gost3410.o"
+deps="
+../lib/hex.o
+../lib/mmap.o
+../lib/uuid.o
+verifier-ed25519-blake2b.o
+verifier-gost3410.o
+"
redo-ifchange $1.c $deps conf/gcl3.rc conf/monocypher.rc \
../../conf/cc ../../conf/cflags ../../conf/ldflags ../../conf/prefix
read CC <../../conf/cc
$CFLAGS -I$PREFIX/include \
-o $3 $2.c $deps \
$LDFLAGS $GCL3_LDFLAGS $MONOCYPHER_LDFLAGS -L$PREFIX/lib \
- -lkeks -lkekspki $GCL3_LDLIBS $MONOCYPHER_LDLIBS -static
+ -lkeks -lkekscm $GCL3_LDLIBS $MONOCYPHER_LDLIBS -static
(*failReason) = "invalid signature len";
return false;
}
- return crypto_eddsa_check(sig, pub, data, dataLen) == 0;
+ if (crypto_eddsa_check(sig, pub, data, dataLen) != 0) {
+ (*failReason) = "bad signature";
+ return false;
+ }
+ return true;
}
#!/bin/sh -e
cd "$(dirname "$(realpath -- "$0")")"
-pki/clean
+cm/clean
exec rm -f *.o *.a compile_flags.txt
--- /dev/null
+/libkekscm.a
+/pub.schema.keks
+/pub.schema.keks.c.in
--- /dev/null
+redo-ifchange $2.schema.keks
+echo "const unsigned char KEKSCMPubSchemaRaw[] = {"
+xxd -i -s +16 <$2.schema.keks
+echo "};"
+s=$(perl -e "print -s \"$2.schema.keks\"")
+s=$(( $s - 16 )) # skip MAGIC
+echo "const size_t KEKSCMPubSchemaRawLen = $s;"
--- /dev/null
+n=${2##*/}.tcl
+redo-ifchange ../../../tcl/schema2bin ../../../tcl/schemas/$n
+../../../tcl/schema2bin ../../../tcl/schemas/$n | xxd -r -p
--- /dev/null
+redo-ifchange *.h libkekscm.a ../../conf/prefix
+read PREFIX <../../conf/prefix
+mkdir -p $PREFIX/include/keks/cm $PREFIX/lib
+cp -f *.h $PREFIX/include/keks/cm
+cp -f libkekscm.a $PREFIX/lib
+chmod 644 $PREFIX/include/keks/cm/*.h $PREFIX/lib/libkekscm.a
--- /dev/null
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "../atom.h"
+#include "../dectai.h"
+#include "../err.h"
+#include "../items.h"
+#include "../schema.h"
+#include "pub.h"
+
+#include "pub.schema.keks.c.in"
+
+enum KEKSErr
+KEKSCMPubParse(
+ struct KEKSCMPub *cer,
+ size_t *off,
+ char **failReason,
+ const unsigned char *buf,
+ const size_t len)
+{
+ (*failReason) = "unspecified";
+ struct KEKSItems schema;
+ enum KEKSErr err = KEKSItemsInit(&schema, 512);
+ if (err != KEKSErrNo) {
+ (*failReason) = "init schema";
+ return err;
+ }
+ err = KEKSItemsParse(&schema, off, KEKSCMPubSchemaRaw, KEKSCMPubSchemaRawLen);
+ if (err != KEKSErrNo) {
+ (*failReason) = "parse schema";
+ return err;
+ }
+ size_t idxSchema = KEKSItemsGetByKey(&schema, 0, "pub");
+ if (idxSchema == 0) {
+ KEKSItemsFree(&schema);
+ (*failReason) = "schema: no pub";
+ return KEKSErrUnsatisfiedSchema;
+ }
+ struct KEKSItems *items = &(cer->items);
+ err = KEKSItemsInit(items, 512);
+ if (err != KEKSErrNo) {
+ KEKSItemsFree(&schema);
+ (*failReason) = "init items";
+ return err;
+ }
+ (*off) = 0;
+ err = KEKSItemsParse(items, off, buf, len);
+ if (err != KEKSErrNo) {
+ KEKSItemsFree(&schema);
+ (*failReason) = "parse items";
+ return err;
+ }
+ struct KEKSSchemaErr errSchema = KEKSSchemaValidate(&schema, items, idxSchema, 0);
+ KEKSItemsFree(&schema);
+ if (errSchema.code != KEKSSchemaErrNo) {
+ (*failReason) = "schema failed";
+ return KEKSErrUnsatisfiedSchema;
+ }
+ size_t idx = KEKSItemsGetByKey(items, KEKSItemsGetByKey(items, 0, "load"), "v");
+ cer->pub = KEKSItemsGetByKey(items, idx, "pub");
+ cer->pub = items->list[cer->pub].atom.v.list.head;
+ cer->sub = KEKSItemsGetByKey(items, idx, "sub");
+ cer->pubId = items->list[KEKSItemsGetByKey(items, idx, "id")].atom.v.str.ptr;
+ cer->sig = 0;
+ cer->cid = NULL;
+ cer->sid = NULL;
+ idx = KEKSItemsGetByKey(items, 0, "sigs");
+ if (idx == 0) {
+ return KEKSErrNo;
+ }
+ if (items->list[idx].atom.v.list.len != 1) {
+ (*failReason) = "len(/load/sigs) != 1";
+ return KEKSErrUnsatisfiedSchema;
+ }
+ cer->sig = items->list[idx].atom.v.list.head;
+ idx = KEKSItemsGetByKey(items, cer->sig, "tbs");
+ cer->cid = items->list[KEKSItemsGetByKey(items, idx, "cid")].atom.v.hexlet;
+ cer->sid = items->list[KEKSItemsGetByKey(items, idx, "sid")].atom.v.str.ptr;
+ idx = KEKSItemsGetByKey(items, idx, "exp");
+ err = KEKSTAI64ToTimespec(
+ &(cer->since),
+ items->list[idx + 1].atom.v.str.ptr,
+ items->list[idx + 1].atom.v.str.len);
+ if ((err != KEKSErrNo) || (cer->since.tv_nsec != 0)) {
+ (*failReason) = "bad /sigs/./tbs/exp/since value";
+ return KEKSErrUnsatisfiedSchema;
+ }
+ err = KEKSTimespecToUTC(&(cer->since));
+ if (err != KEKSErrNo) {
+ (*failReason) = "bad /sigs/./tbs/exp/since UTC value";
+ return KEKSErrUnsatisfiedSchema;
+ }
+ err = KEKSTAI64ToTimespec(
+ &(cer->till),
+ items->list[idx + 2].atom.v.str.ptr,
+ items->list[idx + 2].atom.v.str.len);
+ if ((err != KEKSErrNo) || (cer->till.tv_nsec != 0)) {
+ (*failReason) = "bad /sigs/./tbs/exp/till value";
+ return KEKSErrUnsatisfiedSchema;
+ }
+ err = KEKSTimespecToUTC(&(cer->till));
+ if (err != KEKSErrNo) {
+ (*failReason) = "bad /sigs/./tbs/exp/till UTC value";
+ return KEKSErrUnsatisfiedSchema;
+ }
+ return KEKSErrNo;
+}
+
+bool
+KEKSCMPubVerify(
+ char **failReason,
+ struct KEKSCMPub **verifier,
+ struct KEKSCMPub *cer,
+ struct KEKSCMPub *pool,
+ const size_t poolLen,
+ const struct KEKSCMPubVerifyOpts opts)
+{
+ (*failReason) = "unspecified";
+ if (opts.t.tv_sec <= cer->since.tv_sec) {
+ (*failReason) = "unsatisfied since";
+ return false;
+ }
+ if (opts.t.tv_sec >= cer->till.tv_sec) {
+ (*failReason) = "unsatisfied till";
+ return false;
+ }
+ (*verifier) = NULL;
+ for (size_t i = 0; i < poolLen; i++) {
+ if (memcmp(cer->sid, pool[i].pubId, 32) == 0) {
+ (*verifier) = &(pool[i]);
+ break;
+ }
+ }
+ if ((*verifier) == NULL) {
+ (*failReason) = "no verifier found";
+ return false;
+ }
+ struct KEKSItem *pubA = &((*verifier)->items.list[KEKSItemsGetByKey(
+ &((*verifier)->items), (*verifier)->pub, "a")]);
+ struct KEKSItem *pubV = &((*verifier)->items.list[KEKSItemsGetByKey(
+ &((*verifier)->items), (*verifier)->pub, "v")]);
+ size_t signIdx = KEKSItemsGetByKey(&(cer->items), cer->sig, "sign");
+ struct KEKSItem *sigV =
+ &(cer->items.list[KEKSItemsGetByKey(&(cer->items), signIdx, "v")]);
+ {
+ struct KEKSItem *sigA =
+ &(cer->items.list[KEKSItemsGetByKey(&(cer->items), signIdx, "a")]);
+ if ((sigA->atom.v.str.len != pubA->atom.v.str.len) ||
+ (memcmp(sigA->atom.v.str.ptr, pubA->atom.v.str.ptr, sigA->atom.v.str.len) !=
+ 0)) {
+ (*failReason) = "sign.a != pub.a";
+ return false;
+ }
+ }
+ const size_t cap = (size_t)1 << (uint8_t)10;
+ unsigned char buf[(uint16_t)1 << (uint8_t)10] = {0};
+ size_t off = 0;
+ if (!KEKSItemsEncode(
+ &(cer->items),
+ KEKSItemsGetByKey(&(cer->items), 0, "load"),
+ &off,
+ buf,
+ cap)) {
+ (*failReason) = "can not prepare tbs: load";
+ return false;
+ }
+ size_t off2 = 0;
+ if (!KEKSItemsEncode(
+ &(cer->items),
+ KEKSItemsGetByKey(&(cer->items), cer->sig, "tbs"),
+ &off2,
+ buf + off,
+ cap - off)) {
+ (*failReason) = "can not prepare tbs: tbs";
+ return false;
+ }
+ off += off2;
+
+ for (size_t i = 0; opts.sigVerifiers[i].algo != NULL; i++) {
+ if (!KEKSStrEqual(&(pubA->atom), opts.sigVerifiers[i].algo)) {
+ continue;
+ }
+ return opts.sigVerifiers[i].func(
+ failReason,
+ pubA->atom.v.str.ptr,
+ pubA->atom.v.str.len,
+ sigV->atom.v.str.ptr,
+ sigV->atom.v.str.len,
+ pubV->atom.v.str.ptr,
+ pubV->atom.v.str.len,
+ buf,
+ off);
+ }
+ (*failReason) = "no signature verifier found";
+ return false;
+}
-#ifndef KEKS_CER_H
-#define KEKS_CER_H
+#ifndef KEKS_CM_PUB_H
+#define KEKS_CM_PUB_H
#include <stdbool.h>
#include <stddef.h>
#include "../err.h"
#include "../items.h"
-// TEXINFO: KEKSCer
-// @deftp {Data type} {struct KEKSCer}
+// TEXINFO: KEKSCMPub
+// @deftp {Data type} {struct KEKSCMPub}
// Parsed certificate structure.
// @table @code
// @item .items
// Holds parsed @ref{KEKSItems} items.
-// @item .load
-// Items index of the @code{/load/v}, certificate body.
// @item .pub
// Items index of the first @code{/load/v/pub}, certificate's public key.
// @item .sub
// @item .sig
// Items index of the first @code{/sigs}, certificate's signature.
// @item .cid
-// Pointer to the start of if @code{cid} UUID, certificate's id.
-// @item .pkid
-// Pointer to the start of if @code{pkid} UUID, certificate's
-// first public key id.
+// 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} UUID, certificate's signature id.
+// 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 KEKSCer {
+struct KEKSCMPub {
struct KEKSItems items;
- size_t load;
size_t pub;
size_t sub;
size_t sig;
const unsigned char *cid;
- const unsigned char *pkid;
+ const unsigned char *pubId;
const unsigned char *sid;
struct timespec since;
struct timespec till;
};
-// TEXINFO: KEKSCerParse
-// @deftypefun {enum KEKSErr} KEKSCerParse ( @
-// struct KEKSCer *cer, @
+// TEXINFO: KEKSCMPubParse
+// @deftypefun {enum KEKSErr} KEKSCMPubParse ( @
+// struct KEKSCMPub *cer, @
// size_t *off, @
// char **failReason, @
// const unsigned char *buf, @
// the @var{failReason} to the string describing the error.
// @end deftypefun
enum KEKSErr
-KEKSCerParse(
- struct KEKSCer *,
+KEKSCMPubParse(
+ struct KEKSCMPub *,
size_t *off,
char **failReason,
const unsigned char *buf,
const unsigned char *data,
const size_t dataLen);
-// TEXINFO: KEKSCerSigVerifier
-// @deftp {Data type} {struct KEKSCerSigVerifier}
+// 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 KEKSCerSigVerifier {
+struct KEKSCMPubSigVerifier {
char *algo;
keksSigVerifier func;
};
-// TEXINFO: KEKSCerVerifyOpts
-// @deftp {Data type} {struct KEKSCerVerifyOpts}
-// Certificate verification options:
+// TEXINFO: KEKSCMPubVerifyOpts
+// @deftp {Data type} {struct KEKSCMPubVerifyOpts}
+// Pubtificate verification options:
// @table @code
// @item .t
// Validity time to check against.
// @item .sigVerifiers
-// List of @ref{KEKSCerSigVerifier}.
+// List of @ref{KEKSCMPubSigVerifier}.
// Its last dummy element must have NULL @code{.algo}.
// @end table
// @end deftp
-struct KEKSCerVerifyOpts {
+struct KEKSCMPubVerifyOpts {
struct timespec t;
- struct KEKSCerSigVerifier *sigVerifiers;
+ struct KEKSCMPubSigVerifier *sigVerifiers;
};
-// TEXINFO: KEKSCerVerify
-// @deftypefun bool KEKSCerVerify ( @
+// TEXINFO: KEKSCMPubVerify
+// @deftypefun bool KEKSCMPubVerify ( @
// char **failReason, @
-// struct KEKSCer **verifier, @
-// struct KEKSCer *cer, @
-// struct KEKSCer *pool, @
+// struct KEKSCMPub **verifier, @
+// struct KEKSCMPub *cer, @
+// struct KEKSCMPub *pool, @
// const size_t poolLen, @
-// const struct KEKSCerVerifyOpts opts)
+// 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{pkid} equals to @code{sid}),
+// 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
-KEKSCerVerify(
+KEKSCMPubVerify(
char **failReason,
- struct KEKSCer **verifier,
- struct KEKSCer *cer,
- struct KEKSCer *pool,
+ struct KEKSCMPub **verifier,
+ struct KEKSCMPub *cer,
+ struct KEKSCMPub *pool,
const size_t poolLen,
- const struct KEKSCerVerifyOpts opts);
+ const struct KEKSCMPubVerifyOpts opts);
-#endif // KEKS_CER_H
+extern const unsigned char KEKSCMPubSchemaRaw[];
+extern const size_t KEKSCMPubSchemaRawLen;
+
+#endif // KEKS_CM_PUB_H
+++ /dev/null
-/libkekspki.a
+++ /dev/null
-#include <stddef.h>
-#include <stdint.h>
-#include <string.h>
-
-#include "../atom.h"
-#include "../dectai.h"
-#include "../enc.h"
-#include "../err.h"
-#include "../items.h"
-#include "cer.h"
-
-enum KEKSErr
-KEKSCerParse(
- struct KEKSCer *cer,
- size_t *off,
- char **failReason,
- const unsigned char *buf,
- const size_t len)
-{
- struct KEKSItems *items = &(cer->items);
- enum KEKSErr err = KEKSItemsInit(items, 64);
- if (err != KEKSErrNo) {
- return err;
- }
- err = KEKSItemsParse(items, off, buf, len);
- if (err != KEKSErrNo) {
- return err;
- }
- size_t idx = 0;
- struct KEKSItem *item = NULL;
- if (KEKSItemsGetByKey(items, 0, "hash") != 0) {
- (*failReason) = "unexpected /hash";
- return KEKSErrUnsatisfiedSchema;
- }
- size_t loadIdx = KEKSItemsGetByKey(items, 0, "load");
- {
- if (loadIdx == 0) {
- (*failReason) = "no /load";
- return KEKSErrUnsatisfiedSchema;
- }
- idx = KEKSItemsGetByKeyAndType(items, loadIdx, "t", KEKSItemStr);
- if (loadIdx == 0) {
- (*failReason) = "no /load/t";
- return KEKSErrUnsatisfiedSchema;
- }
- if (!KEKSStrEqual(&(items->list[idx].atom), "cer")) {
- (*failReason) = "/load/t != cer";
- return KEKSErrUnsatisfiedSchema;
- }
- }
- cer->load = KEKSItemsGetByKey(items, loadIdx, "v");
- {
- if (cer->load == 0) {
- (*failReason) = "no /load/v";
- return KEKSErrUnsatisfiedSchema;
- }
- idx = KEKSItemsGetByKey(items, cer->load, "ku");
- if (idx != 0) {
- item = &(items->list[idx]);
- if (item->atom.v.list.len == 0) {
- (*failReason) = "empty /load/v/ku";
- return KEKSErrUnsatisfiedSchema;
- }
- if (!KEKSMapHasOnlyType(items, idx, KEKSItemNIL)) {
- (*failReason) = "bad /load/v/ku value";
- return KEKSErrUnsatisfiedSchema;
- }
- }
- }
- idx = KEKSItemsGetByKey(items, cer->load, "pub");
- {
- if (idx == 0) {
- (*failReason) = "no /load/v/pub";
- return KEKSErrUnsatisfiedSchema;
- }
- item = &(items->list[idx]);
- if (item->atom.v.list.len != 1) {
- (*failReason) = "len(/load/v/pub) != 1";
- return KEKSErrUnsatisfiedSchema;
- }
- idx = items->list[idx].atom.v.list.head;
- cer->pub = idx;
- while (idx != 0) {
- if (KEKSItemsGetByKeyAndType(items, idx, "a", KEKSItemStr) == 0) {
- (*failReason) = "no /load/v/pub/a";
- return KEKSErrUnsatisfiedSchema;
- }
- if (KEKSItemsGetByKeyAndType(items, idx, "v", KEKSItemBin) == 0) {
- (*failReason) = "no /load/v/pub/v";
- return KEKSErrUnsatisfiedSchema;
- }
- {
- size_t pkidIdx =
- KEKSItemsGetByKeyAndType(items, idx, "id", KEKSItemUUID);
- if (pkidIdx == 0) {
- (*failReason) = "no /load/v/pub/id";
- return KEKSErrUnsatisfiedSchema;
- }
- cer->pkid = items->list[pkidIdx].atom.v.uuid;
- }
- idx = items->list[idx].next;
- }
- }
- cer->sub = KEKSItemsGetByKey(items, cer->load, "sub");
- {
- if (cer->sub == 0) {
- (*failReason) = "no /load/v/sub";
- return KEKSErrUnsatisfiedSchema;
- }
- item = &(items->list[cer->sub]);
- if (item->atom.v.list.len == 0) {
- (*failReason) = "empty /load/v/sub";
- return KEKSErrUnsatisfiedSchema;
- }
- if (!KEKSMapHasOnlyType(items, cer->sub, KEKSItemStr)) {
- (*failReason) = "bad /load/v/sub value";
- return KEKSErrUnsatisfiedSchema;
- }
- }
- if (KEKSItemsGetByKey(items, cer->load, "crit") != 0) {
- (*failReason) = "/load/v/crit is unsupported";
- return KEKSErrUnsatisfiedSchema;
- }
- size_t sigsIdx = KEKSItemsGetByKey(items, 0, "sigs");
- {
- if (sigsIdx == 0) {
- (*failReason) = "no /sigs";
- return KEKSErrUnsatisfiedSchema;
- }
- item = &(items->list[sigsIdx]);
- if (item->atom.v.list.len != 1) {
- (*failReason) = "len(/load/sigs) != 1";
- return KEKSErrUnsatisfiedSchema;
- }
- size_t sigIdx = items->list[sigsIdx].atom.v.list.head;
- cer->sig = sigIdx;
- while (sigIdx != 0) {
- if (KEKSItemsGetByKey(items, sigIdx, "hash") != 0) {
- (*failReason) = "unexpected /sigs/./hash met";
- return KEKSErrUnsatisfiedSchema;
- }
- {
- idx = KEKSItemsGetByKey(items, sigIdx, "sign");
- if (idx == 0) {
- (*failReason) = "no /sigs/./sign";
- return KEKSErrUnsatisfiedSchema;
- }
- if (KEKSItemsGetByKeyAndType(items, idx, "a", KEKSItemStr) == 0) {
- (*failReason) = "no /sigs/./sign/a";
- return KEKSErrUnsatisfiedSchema;
- }
- if (KEKSItemsGetByKeyAndType(items, idx, "v", KEKSItemBin) == 0) {
- (*failReason) = "no /sigs/./sign/v";
- return KEKSErrUnsatisfiedSchema;
- }
- }
- {
- idx = KEKSItemsGetByKey(items, sigIdx, "tbs");
- if (idx == 0) {
- (*failReason) = "no /sigs/./tbs";
- return KEKSErrUnsatisfiedSchema;
- }
- {
- size_t cidIdx =
- KEKSItemsGetByKeyAndType(items, idx, "cid", KEKSItemUUID);
- if (cidIdx == 0) {
- (*failReason) = "no /sigs/./tbs/cid";
- return KEKSErrUnsatisfiedSchema;
- }
- cer->cid = items->list[cidIdx].atom.v.uuid;
- }
- {
- size_t sidIdx =
- KEKSItemsGetByKeyAndType(items, idx, "sid", KEKSItemUUID);
- if (sidIdx == 0) {
- (*failReason) = "no /sigs/./tbs/sid";
- return KEKSErrUnsatisfiedSchema;
- }
- cer->sid = items->list[sidIdx].atom.v.uuid;
- }
- idx = KEKSItemsGetByKeyAndType(items, idx, "exp", KEKSItemList);
- if (idx == 0) {
- (*failReason) = "no /sigs/./tbs/exp";
- return KEKSErrUnsatisfiedSchema;
- }
- if (!KEKSListHasOnlyType(items, idx, KEKSItemTAI64)) {
- (*failReason) = "bad /sigs/./tbs/exp value";
- return KEKSErrUnsatisfiedSchema;
- }
- item = &(items->list[idx]);
- if (item->atom.v.list.len != 2) {
- (*failReason) = "len(/sigs/./tbs/exp) != 2";
- return KEKSErrUnsatisfiedSchema;
- }
- err = KEKSTAI64ToTimespec(
- &(cer->since),
- items->list[idx + 1].atom.v.str.ptr,
- items->list[idx + 1].atom.v.str.len);
- if ((err != KEKSErrNo) || (cer->since.tv_nsec != 0)) {
- (*failReason) = "bad /sigs/./tbs/exp/since value";
- return KEKSErrUnsatisfiedSchema;
- }
- err = KEKSTimespecToUTC(&(cer->since));
- if (err != KEKSErrNo) {
- (*failReason) = "bad /sigs/./tbs/exp/since UTC value";
- return KEKSErrUnsatisfiedSchema;
- }
- err = KEKSTAI64ToTimespec(
- &(cer->till),
- items->list[idx + 2].atom.v.str.ptr,
- items->list[idx + 2].atom.v.str.len);
- if ((err != KEKSErrNo) || (cer->till.tv_nsec != 0)) {
- (*failReason) = "bad /sigs/./tbs/exp/till value";
- return KEKSErrUnsatisfiedSchema;
- }
- err = KEKSTimespecToUTC(&(cer->till));
- if (err != KEKSErrNo) {
- (*failReason) = "bad /sigs/./tbs/exp/till UTC value";
- return KEKSErrUnsatisfiedSchema;
- }
- }
- sigIdx = items->list[sigIdx].next;
- }
- }
- return KEKSErrNo;
-}
-
-bool
-KEKSCerVerify(
- char **failReason,
- struct KEKSCer **verifier,
- struct KEKSCer *cer,
- struct KEKSCer *pool,
- const size_t poolLen,
- const struct KEKSCerVerifyOpts opts)
-{
- if (opts.t.tv_sec <= cer->since.tv_sec) {
- (*failReason) = "unsatisfied since";
- return false;
- }
- if (opts.t.tv_sec >= cer->till.tv_sec) {
- (*failReason) = "unsatisfied till";
- return false;
- }
- (*verifier) = NULL;
- for (size_t i = 0; i < poolLen; i++) {
- if (memcmp(cer->sid, pool[i].pkid, 16) == 0) {
- (*verifier) = &(pool[i]);
- break;
- }
- }
- if ((*verifier) == NULL) {
- (*failReason) = "no verifier found";
- return false;
- }
- struct KEKSItem *pubA = &((*verifier)->items.list[KEKSItemsGetByKey(
- &((*verifier)->items), (*verifier)->pub, "a")]);
- struct KEKSItem *pubV = &((*verifier)->items.list[KEKSItemsGetByKey(
- &((*verifier)->items), (*verifier)->pub, "v")]);
- size_t signIdx = KEKSItemsGetByKey(&(cer->items), cer->sig, "sign");
- struct KEKSItem *sigV =
- &(cer->items.list[KEKSItemsGetByKey(&(cer->items), signIdx, "v")]);
- {
- struct KEKSItem *sigA =
- &(cer->items.list[KEKSItemsGetByKey(&(cer->items), signIdx, "a")]);
- if ((sigA->atom.v.str.len != pubA->atom.v.str.len) ||
- (memcmp(sigA->atom.v.str.ptr, pubA->atom.v.str.ptr, sigA->atom.v.str.len) !=
- 0)) {
- (*failReason) = "sign.a != pub.a";
- return false;
- }
- }
- const size_t cap = (size_t)1 << (uint8_t)10;
- unsigned char buf[(uint16_t)1 << (uint8_t)10] = {0};
- size_t off = 0;
- {
- const size_t items = 5;
- struct KEKSItem tbsItems[5];
- memset(&tbsItems, 0, sizeof tbsItems);
- struct KEKSItems tbs = {
- .list = tbsItems, .offsets = NULL, .len = items, .cap = -1};
- tbsItems[0].atom.typ = KEKSItemMap;
- tbsItems[0].atom.v.list.head = 1;
-
- tbsItems[1].atom.typ = KEKSItemStr;
- tbsItems[1].atom.v.str.len = 1;
- tbsItems[1].atom.v.str.ptr = (const unsigned char *)"t";
- tbsItems[1].next = 2;
-
- tbsItems[2].atom.typ = KEKSItemStr;
- tbsItems[2].atom.v.str.len = 3;
- tbsItems[2].atom.v.str.ptr = (const unsigned char *)"cer";
- tbsItems[2].next = 3;
-
- tbsItems[3].atom.typ = KEKSItemStr;
- tbsItems[3].atom.v.str.len = 1;
- tbsItems[3].atom.v.str.ptr = (const unsigned char *)"v";
- tbsItems[3].next = 4;
-
- tbsItems[4].atom.typ = KEKSItemNIL;
- tbsItems[4].next = 0;
-
- if (!KEKSItemsEncode(&tbs, 0, &off, buf, cap)) {
- (*failReason) = "can not prepare tbs: start";
- return false;
- }
- }
- off -= 2; // strip off NIL and EOC, continue map generation
- if (!KEKSItemsEncode(&(cer->items), cer->load, &off, buf, cap)) {
- (*failReason) = "can not prepare tbs: load";
- return false;
- }
- {
- size_t got = 0;
- if (!KEKSAtomStrEncode(
- &got, buf + off, cap - off, (const unsigned char *)"tbs", 3)) {
- (*failReason) = "can not prepare tbs: tbs key";
- return false;
- }
- off += got;
- }
- if (!KEKSItemsEncode(
- &(cer->items),
- KEKSItemsGetByKey(&(cer->items), cer->sig, "tbs"),
- &off,
- buf,
- cap)) {
- (*failReason) = "can not prepare tbs: tbs";
- return false;
- }
- {
- size_t got = 0;
- if (!KEKSAtomEOCEncode(&got, buf + off, cap - off)) {
- (*failReason) = "can not prepare tbs: eoc";
- return false;
- }
- off += got;
- }
- for (size_t i = 0; opts.sigVerifiers[i].algo != NULL; i++) {
- if (!KEKSStrEqual(&(pubA->atom), opts.sigVerifiers[i].algo)) {
- continue;
- }
- return opts.sigVerifiers[i].func(
- failReason,
- pubA->atom.v.str.ptr,
- pubA->atom.v.str.len,
- sigV->atom.v.str.ptr,
- sigV->atom.v.str.len,
- pubV->atom.v.str.ptr,
- pubV->atom.v.str.len,
- buf,
- off);
- }
- (*failReason) = "no signature verifier found";
- return false;
-}
+++ /dev/null
-redo-ifchange *.h libkekspki.a ../../conf/prefix
-read PREFIX <../../conf/prefix
-mkdir -p $PREFIX/include/keks/pki $PREFIX/lib
-cp -f *.h $PREFIX/include/keks/pki
-cp -f libkekspki.a $PREFIX/lib
-chmod 644 $PREFIX/include/keks/pki/*.h $PREFIX/lib/libkekspki.a
(*taken) = SIZE_MAX;
} else {
(*taken) = data->list[*taken].atom.v.list.head;
+ if (*eachInMap) {
+ (*taken) = data->list[*taken].next;
+ }
}
err.code = KEKSSchemaErrNo;
return err;