From: Sergey Matveev Date: Sun, 6 Apr 2025 16:06:50 +0000 (+0300) Subject: Restore c/cmd/pub-verify workability X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=572d9c01dfe3569820cdc6cfe7637085337991fb7adc2d1b56ed6b299809c160;p=keks.git Restore c/cmd/pub-verify workability --- diff --git a/c/cmd/cer-verify/all.do b/c/cmd/cer-verify/all.do deleted file mode 100644 index e6c21ce..0000000 --- a/c/cmd/cer-verify/all.do +++ /dev/null @@ -1 +0,0 @@ -redo-ifchange cer-verify diff --git a/c/cmd/cer-verify/.gitignore b/c/cmd/pub-verify/.gitignore similarity index 61% rename from c/cmd/cer-verify/.gitignore rename to c/cmd/pub-verify/.gitignore index 81179ab..c000ead 100644 --- a/c/cmd/cer-verify/.gitignore +++ b/c/cmd/pub-verify/.gitignore @@ -1,2 +1,2 @@ -/cer-verify /compile_flags.txt +/pub-verify diff --git a/c/cmd/pub-verify/all.do b/c/cmd/pub-verify/all.do new file mode 100644 index 0000000..84a3ca4 --- /dev/null +++ b/c/cmd/pub-verify/all.do @@ -0,0 +1 @@ +redo-ifchange pub-verify diff --git a/c/cmd/cer-verify/clean b/c/cmd/pub-verify/clean similarity index 50% rename from c/cmd/cer-verify/clean rename to c/cmd/pub-verify/clean index f5e1b4a..48f4a9b 100755 --- a/c/cmd/cer-verify/clean +++ b/c/cmd/pub-verify/clean @@ -1,4 +1,4 @@ #!/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 diff --git a/c/cmd/cer-verify/compile_flags.txt.do b/c/cmd/pub-verify/compile_flags.txt.do similarity index 100% rename from c/cmd/cer-verify/compile_flags.txt.do rename to c/cmd/pub-verify/compile_flags.txt.do diff --git a/c/cmd/cer-verify/conf/.gitignore b/c/cmd/pub-verify/conf/.gitignore similarity index 100% rename from c/cmd/cer-verify/conf/.gitignore rename to c/cmd/pub-verify/conf/.gitignore diff --git a/c/cmd/cer-verify/conf/gcl3.rc.do b/c/cmd/pub-verify/conf/gcl3.rc.do similarity index 100% rename from c/cmd/cer-verify/conf/gcl3.rc.do rename to c/cmd/pub-verify/conf/gcl3.rc.do diff --git a/c/cmd/cer-verify/conf/monocypher.rc.do b/c/cmd/pub-verify/conf/monocypher.rc.do similarity index 100% rename from c/cmd/cer-verify/conf/monocypher.rc.do rename to c/cmd/pub-verify/conf/monocypher.rc.do diff --git a/c/cmd/cer-verify/curves.c.in b/c/cmd/pub-verify/curves.c.in similarity index 100% rename from c/cmd/cer-verify/curves.c.in rename to c/cmd/pub-verify/curves.c.in diff --git a/c/cmd/cer-verify/cer-verify.c b/c/cmd/pub-verify/pub-verify.c similarity index 72% rename from c/cmd/cer-verify/cer-verify.c rename to c/cmd/pub-verify/pub-verify.c index f303c0d..ba459b7 100644 --- a/c/cmd/cer-verify/cer-verify.c +++ b/c/cmd/pub-verify/pub-verify.c @@ -20,10 +20,10 @@ #include #include +#include #include -#include -#include +#include "../lib/hex.h" #include "../lib/mmap.h" #include "../lib/uuid.h" @@ -34,11 +34,11 @@ int 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++) { @@ -51,17 +51,25 @@ main(int argc, char **argv) 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); } @@ -72,26 +80,26 @@ main(int argc, char **argv) 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; } diff --git a/c/cmd/cer-verify/cer-verify.do b/c/cmd/pub-verify/pub-verify.do similarity index 72% rename from c/cmd/cer-verify/cer-verify.do rename to c/cmd/pub-verify/pub-verify.do index e42594d..7f29ae5 100644 --- a/c/cmd/cer-verify/cer-verify.do +++ b/c/cmd/pub-verify/pub-verify.do @@ -1,4 +1,10 @@ -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 @@ -11,4 +17,4 @@ $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 diff --git a/c/cmd/cer-verify/verifier-ed25519-blake2b.c b/c/cmd/pub-verify/verifier-ed25519-blake2b.c similarity index 81% rename from c/cmd/cer-verify/verifier-ed25519-blake2b.c rename to c/cmd/pub-verify/verifier-ed25519-blake2b.c index 0ecadd9..fe5550c 100644 --- a/c/cmd/cer-verify/verifier-ed25519-blake2b.c +++ b/c/cmd/pub-verify/verifier-ed25519-blake2b.c @@ -27,5 +27,9 @@ ed25519blake2bSignatureVerifier( (*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; } diff --git a/c/cmd/cer-verify/verifier-ed25519-blake2b.h b/c/cmd/pub-verify/verifier-ed25519-blake2b.h similarity index 100% rename from c/cmd/cer-verify/verifier-ed25519-blake2b.h rename to c/cmd/pub-verify/verifier-ed25519-blake2b.h diff --git a/c/cmd/cer-verify/verifier-ed25519-blake2b.o.do b/c/cmd/pub-verify/verifier-ed25519-blake2b.o.do similarity index 100% rename from c/cmd/cer-verify/verifier-ed25519-blake2b.o.do rename to c/cmd/pub-verify/verifier-ed25519-blake2b.o.do diff --git a/c/cmd/cer-verify/verifier-gost3410.c b/c/cmd/pub-verify/verifier-gost3410.c similarity index 100% rename from c/cmd/cer-verify/verifier-gost3410.c rename to c/cmd/pub-verify/verifier-gost3410.c diff --git a/c/cmd/cer-verify/verifier-gost3410.h b/c/cmd/pub-verify/verifier-gost3410.h similarity index 100% rename from c/cmd/cer-verify/verifier-gost3410.h rename to c/cmd/pub-verify/verifier-gost3410.h diff --git a/c/cmd/cer-verify/verifier-gost3410.o.do b/c/cmd/pub-verify/verifier-gost3410.o.do similarity index 100% rename from c/cmd/cer-verify/verifier-gost3410.o.do rename to c/cmd/pub-verify/verifier-gost3410.o.do diff --git a/c/lib/clean b/c/lib/clean index f6a08ca..e633c5a 100755 --- a/c/lib/clean +++ b/c/lib/clean @@ -1,5 +1,5 @@ #!/bin/sh -e cd "$(dirname "$(realpath -- "$0")")" -pki/clean +cm/clean exec rm -f *.o *.a compile_flags.txt diff --git a/c/lib/cm/.gitignore b/c/lib/cm/.gitignore new file mode 100644 index 0000000..30015a3 --- /dev/null +++ b/c/lib/cm/.gitignore @@ -0,0 +1,3 @@ +/libkekscm.a +/pub.schema.keks +/pub.schema.keks.c.in diff --git a/c/lib/pki/clean b/c/lib/cm/clean similarity index 100% rename from c/lib/pki/clean rename to c/lib/cm/clean diff --git a/c/lib/cm/default.schema.keks.c.in.do b/c/lib/cm/default.schema.keks.c.in.do new file mode 100644 index 0000000..6fa1180 --- /dev/null +++ b/c/lib/cm/default.schema.keks.c.in.do @@ -0,0 +1,7 @@ +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;" diff --git a/c/lib/cm/default.schema.keks.do b/c/lib/cm/default.schema.keks.do new file mode 100644 index 0000000..4d4033b --- /dev/null +++ b/c/lib/cm/default.schema.keks.do @@ -0,0 +1,3 @@ +n=${2##*/}.tcl +redo-ifchange ../../../tcl/schema2bin ../../../tcl/schemas/$n +../../../tcl/schema2bin ../../../tcl/schemas/$n | xxd -r -p diff --git a/c/lib/cm/install.do b/c/lib/cm/install.do new file mode 100644 index 0000000..bc6bcf1 --- /dev/null +++ b/c/lib/cm/install.do @@ -0,0 +1,6 @@ +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 diff --git a/c/lib/pki/libkekspki.a.do b/c/lib/cm/libkekscm.a.do similarity index 100% rename from c/lib/pki/libkekspki.a.do rename to c/lib/cm/libkekscm.a.do diff --git a/c/lib/cm/o.list b/c/lib/cm/o.list new file mode 100644 index 0000000..8f31940 --- /dev/null +++ b/c/lib/cm/o.list @@ -0,0 +1 @@ +pub.o diff --git a/c/lib/cm/pub.c b/c/lib/cm/pub.c new file mode 100644 index 0000000..f059f9f --- /dev/null +++ b/c/lib/cm/pub.c @@ -0,0 +1,197 @@ +#include +#include +#include + +#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; +} diff --git a/c/lib/pki/cer.h b/c/lib/cm/pub.h similarity index 64% rename from c/lib/pki/cer.h rename to c/lib/cm/pub.h index 08eb4e8..ac831d0 100644 --- a/c/lib/pki/cer.h +++ b/c/lib/cm/pub.h @@ -1,5 +1,5 @@ -#ifndef KEKS_CER_H -#define KEKS_CER_H +#ifndef KEKS_CM_PUB_H +#define KEKS_CM_PUB_H #include #include @@ -8,14 +8,12 @@ #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 @@ -23,34 +21,32 @@ // @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, @ @@ -63,8 +59,8 @@ struct KEKSCer { // 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, @@ -81,56 +77,59 @@ typedef bool (*keksSigVerifier)( 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 diff --git a/c/lib/pki/.gitignore b/c/lib/pki/.gitignore deleted file mode 100644 index 3016f89..0000000 --- a/c/lib/pki/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/libkekspki.a diff --git a/c/lib/pki/cer.c b/c/lib/pki/cer.c deleted file mode 100644 index 81ce256..0000000 --- a/c/lib/pki/cer.c +++ /dev/null @@ -1,356 +0,0 @@ -#include -#include -#include - -#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; -} diff --git a/c/lib/pki/install.do b/c/lib/pki/install.do deleted file mode 100644 index 686011b..0000000 --- a/c/lib/pki/install.do +++ /dev/null @@ -1,6 +0,0 @@ -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 diff --git a/c/lib/pki/o.list b/c/lib/pki/o.list deleted file mode 100644 index c7f1e63..0000000 --- a/c/lib/pki/o.list +++ /dev/null @@ -1 +0,0 @@ -cer.o diff --git a/c/lib/schema.c b/c/lib/schema.c index 988d359..1338d9f 100644 --- a/c/lib/schema.c +++ b/c/lib/schema.c @@ -310,6 +310,9 @@ Eached: (*taken) = SIZE_MAX; } else { (*taken) = data->list[*taken].atom.v.list.head; + if (*eachInMap) { + (*taken) = data->list[*taken].next; + } } err.code = KEKSSchemaErrNo; return err;