From: Sergey Matveev Date: Tue, 15 Oct 2024 07:31:30 +0000 (+0300) Subject: cyac implemented certificate verifier X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c1746b25f739a78e2f97fab5dc6dd37365d66ddaea48a8712780ea7762364edb;p=keks.git cyac implemented certificate verifier --- diff --git a/cyac/.gitignore b/cyac/.gitignore index a0169a4..b83cc45 100644 --- a/cyac/.gitignore +++ b/cyac/.gitignore @@ -1,3 +1 @@ -/*.o /compile_flags.txt -/libyac.a diff --git a/cyac/cmd/.gitignore b/cyac/cmd/.gitignore deleted file mode 100644 index 9caf01a..0000000 --- a/cyac/cmd/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/print-items -/print-itered -/test-vector diff --git a/cyac/cmd/all.do b/cyac/cmd/all.do deleted file mode 100644 index 1cf8db8..0000000 --- a/cyac/cmd/all.do +++ /dev/null @@ -1 +0,0 @@ -redo-ifchange print-items print-itered test-vector diff --git a/cyac/cmd/cer-verify/.gitignore b/cyac/cmd/cer-verify/.gitignore new file mode 100644 index 0000000..81179ab --- /dev/null +++ b/cyac/cmd/cer-verify/.gitignore @@ -0,0 +1,2 @@ +/cer-verify +/compile_flags.txt diff --git a/cyac/cmd/cer-verify/all.do b/cyac/cmd/cer-verify/all.do new file mode 100644 index 0000000..e6c21ce --- /dev/null +++ b/cyac/cmd/cer-verify/all.do @@ -0,0 +1 @@ +redo-ifchange cer-verify diff --git a/cyac/cmd/cer-verify/cer-verify.c b/cyac/cmd/cer-verify/cer-verify.c new file mode 100644 index 0000000..9643a29 --- /dev/null +++ b/cyac/cmd/cer-verify/cer-verify.c @@ -0,0 +1,99 @@ +// cyac -- C YAC encoder implementation +// Copyright (C) 2024 Sergey Matveev +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, version 3 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program. If not, see . + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../lib/mmap.h" +#include "../lib/uuid.h" + +#include "verifier-gost3410.h" + +int +main(int argc, char **argv) +{ + if (argc < 3) { + fprintf(stderr, "Usage: %s EE.cer [CA.cer ...]\n", argv[0]); + return EXIT_FAILURE; + } + const ptrdiff_t cersLen = (ptrdiff_t)argc - 1; + struct YACCer *cers = calloc((size_t)cersLen, sizeof(struct YACCer)); + assert(cers != NULL); + char *failReason = NULL; + for (int i = 1; i < argc; i++) { + unsigned char *buf = NULL; + size_t len = 0; + if (!Mmap(&buf, &len, argv[i])) { + fprintf(stderr, "%s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + fputs(argv[i], stdout); + fputs(":\t", stdout); + ptrdiff_t off = 0; + enum YACErr err = YACCerParse(&(cers[i - 1]), &off, &failReason, buf, len); + if (err != YACErrNo) { + fprintf(stderr, "%s\n", 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("\n", stdout); + } + + struct timeval now; + if (gettimeofday(&now, NULL) != 0) { + fprintf(stderr, "%s\n", strerror(errno)); + return EXIT_FAILURE; + } + + struct YACCerSigVerifier sigVerifiers[] = { + {.algo = "gost3410-256A", .func = gost3410SignatureVerifier}, + {.algo = "gost3410-512C", .func = gost3410SignatureVerifier}, + }; + struct YACCerVerifyOpts opts = { + .t = now, .sigVerifiers = sigVerifiers, .sigVerifiersLen = 2}; + + struct YACCer *toVerify = &(cers[0]); + struct YACCer *verifier = NULL; + for (;;) { + fputs("verifying ", stdout); + UUIDPrint(toVerify->cid); + fputs(": ", stdout); + if (!YACCerVerify( + &failReason, &verifier, toVerify, cers, (size_t)cersLen, opts)) { + fputs(failReason, stdout); + fputs("\n", stdout); + return EXIT_FAILURE; + } + fputs("ok\n", stdout); + if (memcmp(toVerify->sid, toVerify->pkid, 16) == 0) { + break; + } + toVerify = verifier; + } + return EXIT_SUCCESS; +} diff --git a/cyac/cmd/cer-verify/cer-verify.do b/cyac/cmd/cer-verify/cer-verify.do new file mode 100644 index 0000000..ad75159 --- /dev/null +++ b/cyac/cmd/cer-verify/cer-verify.do @@ -0,0 +1,13 @@ +deps="../lib/mmap.o ../lib/uuid.o verifier-gost3410.o" +redo-ifchange $1.c $deps conf/gcl3.rc \ + ../../conf/cc ../../conf/cflags ../../conf/ldflags ../../conf/prefix +read CC <../../conf/cc +CFLAGS=$(cat ../../conf/cflags) +LDFLAGS=$(cat ../../conf/ldflags) +. conf/gcl3.rc +read PREFIX <../../conf/prefix +$CC \ + $CFLAGS -I$PREFIX/include \ + -o $3 $2.c $deps \ + $LDFLAGS $GCL3_LDFLAGS -L$PREFIX/lib \ + -lyac -lyacpki $GCL3_LDLIBS diff --git a/cyac/cmd/cer-verify/clean b/cyac/cmd/cer-verify/clean new file mode 100755 index 0000000..cdb7ffb --- /dev/null +++ b/cyac/cmd/cer-verify/clean @@ -0,0 +1,3 @@ +#!/bin/sh -e + +exec rm -f cer-verify compile_flags.txt conf/gcl3.rc diff --git a/cyac/cmd/cer-verify/compile_flags.txt.do b/cyac/cmd/cer-verify/compile_flags.txt.do new file mode 100644 index 0000000..e6bf334 --- /dev/null +++ b/cyac/cmd/cer-verify/compile_flags.txt.do @@ -0,0 +1,5 @@ +redo-ifchange ../../conf/prefix conf/gcl3.rc +. conf/gcl3.rc +read PREFIX <../../conf/prefix +printf %s "-I$PREFIX/include $GCL3_CFLAGS" | +tr " " "\n" | grep -v "^$" | sort | uniq diff --git a/cyac/cmd/cer-verify/conf/.gitignore b/cyac/cmd/cer-verify/conf/.gitignore new file mode 100644 index 0000000..0f57c2c --- /dev/null +++ b/cyac/cmd/cer-verify/conf/.gitignore @@ -0,0 +1 @@ +/gcl3.rc diff --git a/cyac/cmd/cer-verify/conf/gcl3.rc.do b/cyac/cmd/cer-verify/conf/gcl3.rc.do new file mode 100644 index 0000000..eeb9168 --- /dev/null +++ b/cyac/cmd/cer-verify/conf/gcl3.rc.do @@ -0,0 +1,12 @@ +PKGCONF=${PKGCONF:-`command -v pkgconf || command -v pkg-config`} +cat < + +// clang-format off +static uint8_t gost3410Curve256Ap[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0x97, +}; +static uint8_t gost3410Curve256Aq[32] = { + 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0F,0xD8,0xCD,0xDF,0xC8,0x7B,0x66,0x35, 0xC1,0x15,0xAF,0x55,0x6C,0x36,0x0C,0x67, +}; +static uint8_t gost3410Curve256Ae[32] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, +}; +static uint8_t gost3410Curve256Ad[32] = { + 0x06,0x05,0xF6,0xB7,0xC1,0x83,0xFA,0x81, 0x57,0x8B,0xC3,0x9C,0xFA,0xD5,0x18,0x13, + 0x2B,0x9D,0xF6,0x28,0x97,0x00,0x9A,0xF7, 0xE5,0x22,0xC3,0x2D,0x6D,0xC7,0xBF,0xFB, +}; +static uint8_t gost3410Curve256Au[32] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D, +}; +static uint8_t gost3410Curve256Av[32] = { + 0x60,0xCA,0x1E,0x32,0xAA,0x47,0x5B,0x34, 0x84,0x88,0xC3,0x8F,0xAB,0x07,0x64,0x9C, + 0xE7,0xEF,0x8D,0xBE,0x87,0xF2,0x2E,0x81, 0xF9,0x2B,0x25,0x92,0xDB,0xA3,0x00,0xE7, +}; + +static uint8_t gost3410Curve512Cp[64] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xC7, +}; +static uint8_t gost3410Curve512Cq[64] = { + 0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xC9,0x8C,0xDB,0xA4,0x65,0x06,0xAB,0x00, 0x4C,0x33,0xA9,0xFF,0x51,0x47,0x50,0x2C, + 0xC8,0xED,0xA9,0xE7,0xA7,0x69,0xA1,0x26, 0x94,0x62,0x3C,0xEF,0x47,0xF0,0x23,0xED, +}; +static uint8_t gost3410Curve512Ce[64] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, +}; +static uint8_t gost3410Curve512Cd[64] = { + 0x9E,0x4F,0x5D,0x8C,0x01,0x7D,0x8D,0x9F, 0x13,0xA5,0xCF,0x3C,0xDF,0x5B,0xFE,0x4D, + 0xAB,0x40,0x2D,0x54,0x19,0x8E,0x31,0xEB, 0xDE,0x28,0xA0,0x62,0x10,0x50,0x43,0x9C, + 0xA6,0xB3,0x9E,0x0A,0x51,0x5C,0x06,0xB3, 0x04,0xE2,0xCE,0x43,0xE7,0x9E,0x36,0x9E, + 0x91,0xA0,0xCF,0xC2,0xBC,0x2A,0x22,0xB4, 0xCA,0x30,0x2D,0xBB,0x33,0xEE,0x75,0x50, +}; +static uint8_t gost3410Curve512Cu[64] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12, +}; +static uint8_t gost3410Curve512Cv[64] = { + 0x46,0x9A,0xF7,0x9D,0x1F,0xB1,0xF5,0xE1, 0x6B,0x99,0x59,0x2B,0x77,0xA0,0x1E,0x2A, + 0x0F,0xDF,0xB0,0xD0,0x17,0x94,0x36,0x8D, 0x9A,0x56,0x11,0x7F,0x7B,0x38,0x66,0x95, + 0x22,0xDD,0x4B,0x65,0x0C,0xF7,0x89,0xEE, 0xBF,0x06,0x8C,0x5D,0x13,0x97,0x32,0xF0, + 0x90,0x56,0x22,0xC0,0x4B,0x2B,0xAA,0xE7, 0x60,0x03,0x03,0xEE,0x73,0x00,0x1A,0x3D, +}; +// clang-format on diff --git a/cyac/cmd/cer-verify/verifier-gost3410.c b/cyac/cmd/cer-verify/verifier-gost3410.c new file mode 100644 index 0000000..9fe1ea6 --- /dev/null +++ b/cyac/cmd/cer-verify/verifier-gost3410.c @@ -0,0 +1,142 @@ +#include +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#include +#pragma clang diagnostic pop + +#include "verifier-gost3410.h" + +#include "curves.c.in" + +static unsigned char * +align16(unsigned char *p) +{ + unsigned int n = (uint64_t)p % 16; + if (n == 0) { + return p; + } + return p + (ptrdiff_t)(16 - n); +} + +bool +gost3410SignatureVerifier( + 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) +{ + const char *ai256A = "gost3410-256A"; + const char *ai512C = "gost3410-512C"; + size_t pointLen = 0; + bool is256 = false; + if ((aiLen == strlen(ai256A)) && (memcmp(ai, ai256A, aiLen) == 0)) { + is256 = true; + pointLen = 32; + } else if ((aiLen == strlen(ai512C)) && (memcmp(ai, ai512C, aiLen) == 0)) { + is256 = false; + pointLen = 64; + } else { + (*failReason) = "unknown ai"; + return false; + } + if (pubLen != pointLen * 2) { + (*failReason) = "invalid pubkey len"; + return false; + } + if (sigLen != pointLen * 2) { + (*failReason) = "invalid signature len"; + return false; + } + unsigned char hsh[64] = {0}; + int gcl3rc = GCL_RC_FAILED; + { + unsigned char ctx[GCL_GOSTR34112012_CTX_SIZE] = {0}; + GclGostR34112012Ctx *h = NULL; + if (is256) { + h = gcl_gostr34112012_ctx256_init_mem( + (GclGostR34112012Ctx *)align16(ctx), &gcl3rc); + } else { + h = gcl_gostr34112012_ctx512_init_mem( + (GclGostR34112012Ctx *)align16(ctx), &gcl3rc); + } + if (gcl3rc != GCL_RC_OK) { + (*failReason) = "gcl_gostr34112012_ctxX_init_mem failed"; + return false; + } + gcl3rc = gcl_gostr34112012_hash_update(h, data, dataLen); + if (gcl3rc != GCL_RC_OK) { + (*failReason) = "gcl_gostr34112012_hash_update failed"; + return false; + } + if (is256) { + gcl3rc = gcl_gostr34112012_hash256_finalize(h, hsh); + } else { + gcl3rc = gcl_gostr34112012_hash512_finalize(h, hsh); + } + gcl_gostr34112012_ctx_clean(h); + if (gcl3rc != GCL_RC_OK) { + (*failReason) = "gcl_gostr34112012_hashX_finalize failed"; + return false; + } + } + { + unsigned char ctx[GCL_GOSTR3410_CTX_SIZE] = {0}; + if (is256) { + gcl_edwards_ctx_init_mem_varsize( + (GclGostR3410Ctx *)ctx, + gost3410Curve256Ap, + gost3410Curve256Aq, + gost3410Curve256Ae, + gost3410Curve256Ad, + gost3410Curve256Au, + gost3410Curve256Av, + 256, + &gcl3rc); + } else { + gcl_edwards_ctx_init_mem_varsize( + (GclGostR3410Ctx *)ctx, + gost3410Curve512Cp, + gost3410Curve512Cq, + gost3410Curve512Ce, + gost3410Curve512Cd, + gost3410Curve512Cu, + gost3410Curve512Cv, + 512, + &gcl3rc); + } + if (gcl3rc != GCL_RC_OK) { + (*failReason) = "gcl_edwards_ctx_init_mem_varsize failed"; + return false; + } + gcl3rc = gcl_gostr3410_ctx_set_public_key_varsize( + (GclGostR3410Ctx *)ctx, pub, pub + pointLen, pointLen * 8); + if (gcl3rc != GCL_RC_OK) { + gcl_gostr3410_ctx_clean((GclGostR3410Ctx *)ctx); + (*failReason) = "gcl_gostr3410_ctx_set_public_key_varsize failed"; + return false; + } + gcl3rc = gcl_gostr3410_verify_varsize( + (GclGostR3410Ctx *)ctx, hsh, pointLen, sig, pointLen * 2); + gcl_gostr3410_ctx_clean((GclGostR3410Ctx *)ctx); + switch (gcl3rc) { + case GCL_RC_OK: + return true; + case GCL_RC_ECINVALID: + (*failReason) = "invalid signature"; + break; + default: + (*failReason) = "gcl_gostr3410_ctx_set_public_key_varsize failed"; + } + } + return false; +} diff --git a/cyac/cmd/cer-verify/verifier-gost3410.h b/cyac/cmd/cer-verify/verifier-gost3410.h new file mode 100644 index 0000000..af6ddd6 --- /dev/null +++ b/cyac/cmd/cer-verify/verifier-gost3410.h @@ -0,0 +1,19 @@ +#ifndef YAC_VERIFIER_GOST3410_H +#define YAC_VERIFIER_GOST3410_H + +#include +#include + +bool +gost3410SignatureVerifier( + 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); + +#endif // YAC_VERIFIER_GOST3410_H diff --git a/cyac/cmd/cer-verify/verifier-gost3410.o.do b/cyac/cmd/cer-verify/verifier-gost3410.o.do new file mode 100644 index 0000000..57c637c --- /dev/null +++ b/cyac/cmd/cer-verify/verifier-gost3410.o.do @@ -0,0 +1,5 @@ +redo-ifchange ${1%.o}.c conf/gcl3.rc ../../conf/cc ../../conf/cflags +read CC <../../conf/cc +CFLAGS=$(cat ../../conf/cflags) +. conf/gcl3.rc +$CC $CFLAGS $GCL3_CFLAGS -c -o $3 ${1%.o}.c diff --git a/cyac/cmd/clean b/cyac/cmd/clean index defcb85..c0a8302 100755 --- a/cyac/cmd/clean +++ b/cyac/cmd/clean @@ -1,3 +1,7 @@ #!/bin/sh -e -exec rm -f print-items print-itered test-vector +( cd cer-verify ; ./clean ) +( cd lib ; ./clean ) +( cd print-items ; ./clean ) +( cd print-itered ; ./clean ) +( cd test-vector ; ./clean ) diff --git a/cyac/cmd/default.do b/cyac/cmd/default.do deleted file mode 100644 index 2b6e469..0000000 --- a/cyac/cmd/default.do +++ /dev/null @@ -1,6 +0,0 @@ -redo-ifchange $2.c ../conf/cc ../conf/cflags ../conf/ldflags ../conf/prefix -read CC <../conf/cc -CFLAGS=$(cat ../conf/cflags) -LDFLAGS=$(cat ../conf/ldflags) -read PREFIX <../conf/prefix -$CC $CFLAGS -I$PREFIX/include -o $3 $2.c $LDFLAGS -L$PREFIX/lib -lyac -lm diff --git a/cyac/cmd/lib/clean b/cyac/cmd/lib/clean new file mode 100755 index 0000000..f973ebd --- /dev/null +++ b/cyac/cmd/lib/clean @@ -0,0 +1,3 @@ +#!/bin/sh -e + +exec rm -f *.o diff --git a/cyac/cmd/lib/default.o.do b/cyac/cmd/lib/default.o.do new file mode 100644 index 0000000..ac567c2 --- /dev/null +++ b/cyac/cmd/lib/default.o.do @@ -0,0 +1,4 @@ +redo-ifchange $2.c ../../conf/cc ../../conf/cflags +read CC <../../conf/cc +CFLAGS=$(cat ../../conf/cflags) +$CC $CFLAGS -c -o $3 $2.c diff --git a/cyac/cmd/hex.c.in b/cyac/cmd/lib/hex.c similarity index 91% rename from cyac/cmd/hex.c.in rename to cyac/cmd/lib/hex.c index b941ccf..25c1a3c 100644 --- a/cyac/cmd/hex.c.in +++ b/cyac/cmd/lib/hex.c @@ -1,10 +1,10 @@ #include -static const size_t maxStrLen = 40; +#include "hex.h" static const char hexdigits[] = "0123456789ABCDEF"; -static char * +char * HexEnc(const unsigned char *src, const size_t srcLen) { // it was based on libressl/crypto/x509v3/v3_utl.c:hex_to_string diff --git a/cyac/cmd/lib/hex.h b/cyac/cmd/lib/hex.h new file mode 100644 index 0000000..a5f956a --- /dev/null +++ b/cyac/cmd/lib/hex.h @@ -0,0 +1,9 @@ +#ifndef YAC_HEX_H +#define YAC_HEX_H + +#include + +char * +HexEnc(const unsigned char *src, const size_t srcLen); + +#endif // YAC_HEX_H diff --git a/cyac/cmd/lib/mmap.c b/cyac/cmd/lib/mmap.c new file mode 100644 index 0000000..9a0c8ce --- /dev/null +++ b/cyac/cmd/lib/mmap.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "mmap.h" + +bool +Mmap(unsigned char **buf, size_t *len, const char *path) +{ + int fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd == -1) { + return false; + } + struct stat sb; + memset(&sb, 0, sizeof(struct stat)); + if (fstat(fd, &sb) != 0) { + return false; + } + (*len) = (size_t)sb.st_size; + (*buf) = mmap(NULL, *len, PROT_READ, MAP_SHARED, fd, 0); + return true; +} diff --git a/cyac/cmd/lib/mmap.h b/cyac/cmd/lib/mmap.h new file mode 100644 index 0000000..e5416b8 --- /dev/null +++ b/cyac/cmd/lib/mmap.h @@ -0,0 +1,10 @@ +#ifndef YAC_MMAP_H +#define YAC_MMAP_H + +#include +#include + +bool +Mmap(unsigned char **buf, size_t *len, const char *path); + +#endif // YAC_MMAP_H diff --git a/cyac/cmd/lib/uuid.c b/cyac/cmd/lib/uuid.c new file mode 100644 index 0000000..421c9dd --- /dev/null +++ b/cyac/cmd/lib/uuid.c @@ -0,0 +1,27 @@ +#include + +#include "uuid.h" + +void +UUIDPrint(const unsigned char *buf) +{ + fprintf( + stdout, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + buf[0], + buf[1], + buf[2], + buf[3], + buf[4], + buf[5], + buf[6], + buf[7], + buf[8], + buf[9], + buf[10], + buf[11], + buf[12], + buf[13], + buf[14], + buf[15]); +} diff --git a/cyac/cmd/lib/uuid.h b/cyac/cmd/lib/uuid.h new file mode 100644 index 0000000..fbe31c3 --- /dev/null +++ b/cyac/cmd/lib/uuid.h @@ -0,0 +1,7 @@ +#ifndef YAC_UUID_H +#define YAC_UUID_H + +void +UUIDPrint(const unsigned char *buf); + +#endif // YAC_UUID_H diff --git a/cyac/cmd/print-items/.gitignore b/cyac/cmd/print-items/.gitignore new file mode 100644 index 0000000..043dac5 --- /dev/null +++ b/cyac/cmd/print-items/.gitignore @@ -0,0 +1 @@ +/print-items diff --git a/cyac/cmd/print-items/all.do b/cyac/cmd/print-items/all.do new file mode 100644 index 0000000..a28095f --- /dev/null +++ b/cyac/cmd/print-items/all.do @@ -0,0 +1 @@ +redo-ifchange print-items diff --git a/cyac/cmd/print-items/clean b/cyac/cmd/print-items/clean new file mode 100755 index 0000000..c8ef676 --- /dev/null +++ b/cyac/cmd/print-items/clean @@ -0,0 +1,3 @@ +#!/bin/sh -e + +exec rm -f print-items diff --git a/cyac/cmd/print-items.c b/cyac/cmd/print-items/print-items.c similarity index 86% rename from cyac/cmd/print-items.c rename to cyac/cmd/print-items/print-items.c index 38b4150..c0cf449 100644 --- a/cyac/cmd/print-items.c +++ b/cyac/cmd/print-items/print-items.c @@ -15,15 +15,12 @@ #include #include -#include #include #include #include #include #include #include -#include -#include #include #include @@ -32,7 +29,11 @@ #include #include -#include "hex.c.in" +#include "../lib/hex.h" +#include "../lib/mmap.h" +#include "../lib/uuid.h" + +static const size_t maxStrLen = 40; static const char *ColourRed = "\x1b[31m"; static const char *ColourGreen = "\x1b[32m"; @@ -100,24 +101,8 @@ printer( fputs("TRUE\n", stdout); break; case YACItemUUID: - printf( - "UUID(%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x)\n", - item->atom.val.buf[0], - item->atom.val.buf[1], - item->atom.val.buf[2], - item->atom.val.buf[3], - item->atom.val.buf[4], - item->atom.val.buf[5], - item->atom.val.buf[6], - item->atom.val.buf[7], - item->atom.val.buf[8], - item->atom.val.buf[9], - item->atom.val.buf[10], - item->atom.val.buf[11], - item->atom.val.buf[12], - item->atom.val.buf[13], - item->atom.val.buf[14], - item->atom.val.buf[15]); + UUIDPrint(item->atom.val.buf); + fputs("\n", stdout); break; case YACItemUint: fprintf(stdout, "%zu\n", item->atom.val.uint); @@ -288,20 +273,9 @@ main(int argc, char **argv) { size_t len = 0; unsigned char *buf = NULL; - { - int fd = open(argv[1], O_RDONLY | O_CLOEXEC); - if (fd == -1) { - fprintf(stderr, "%s\n", strerror(errno)); - return EXIT_FAILURE; - } - struct stat sb; - memset(&sb, 0, sizeof(struct stat)); - if (fstat(fd, &sb) != 0) { - fprintf(stderr, "%s\n", strerror(errno)); - return EXIT_FAILURE; - } - len = (size_t)sb.st_size; - buf = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); + if (!Mmap(&buf, &len, argv[1])) { + fprintf(stderr, "%s\n", strerror(errno)); + exit(EXIT_FAILURE); } NoColour = getenv("NO_COLOR") != NULL; @@ -314,14 +288,13 @@ main(int argc, char **argv) ptrdiff_t off = 0; enum YACErr err = YACItemsParse(&items, &off, buf, len); if (err != YACErrNo) { - fprintf(stderr, "err: %d\n", err); + fprintf(stderr, "err: %s\n", YACErr2Str(err)); return EXIT_FAILURE; } err = printer(&items, 0, 0, -1, NULL); if (err != YACErrNo) { - fprintf(stderr, "err: %d\n", err); + fprintf(stderr, "err: %s\n", YACErr2Str(err)); return EXIT_FAILURE; } - return EXIT_SUCCESS; } diff --git a/cyac/cmd/print-items/print-items.do b/cyac/cmd/print-items/print-items.do new file mode 100644 index 0000000..c735e34 --- /dev/null +++ b/cyac/cmd/print-items/print-items.do @@ -0,0 +1,8 @@ +deps="../lib/hex.o ../lib/mmap.o ../lib/uuid.o" +redo-ifchange $1.c $deps \ + ../../conf/cc ../../conf/cflags ../../conf/ldflags ../../conf/prefix +read CC <../../conf/cc +CFLAGS=$(cat ../../conf/cflags) +LDFLAGS=$(cat ../../conf/ldflags) +read PREFIX <../../conf/prefix +$CC $CFLAGS -I$PREFIX/include -o $3 $2.c $deps $LDFLAGS -L$PREFIX/lib -lyac -lm diff --git a/cyac/cmd/print-itered/.gitignore b/cyac/cmd/print-itered/.gitignore new file mode 100644 index 0000000..e918769 --- /dev/null +++ b/cyac/cmd/print-itered/.gitignore @@ -0,0 +1 @@ +/print-itered diff --git a/cyac/cmd/print-itered/all.do b/cyac/cmd/print-itered/all.do new file mode 100644 index 0000000..ec62894 --- /dev/null +++ b/cyac/cmd/print-itered/all.do @@ -0,0 +1 @@ +redo-ifchange print-itered diff --git a/cyac/cmd/print-itered/clean b/cyac/cmd/print-itered/clean new file mode 100755 index 0000000..1556146 --- /dev/null +++ b/cyac/cmd/print-itered/clean @@ -0,0 +1,3 @@ +#!/bin/sh -e + +exec rm -f print-itered diff --git a/cyac/cmd/print-itered.c b/cyac/cmd/print-itered/print-itered.c similarity index 82% rename from cyac/cmd/print-itered.c rename to cyac/cmd/print-itered/print-itered.c index f8a52d7..1a933d8 100644 --- a/cyac/cmd/print-itered.c +++ b/cyac/cmd/print-itered/print-itered.c @@ -15,13 +15,10 @@ #include #include -#include #include #include #include #include -#include -#include #include #include @@ -30,7 +27,11 @@ #include #include -#include "hex.c.in" +#include "../lib/hex.h" +#include "../lib/mmap.h" +#include "../lib/uuid.h" + +static const size_t maxStrLen = 40; struct CbState { ptrdiff_t indent; @@ -78,24 +79,8 @@ myCb( fputs("TRUE\n", stdout); break; case YACItemUUID: - printf( - "UUID(%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x)\n", - atom->val.buf[0], - atom->val.buf[1], - atom->val.buf[2], - atom->val.buf[3], - atom->val.buf[4], - atom->val.buf[5], - atom->val.buf[6], - atom->val.buf[7], - atom->val.buf[8], - atom->val.buf[9], - atom->val.buf[10], - atom->val.buf[11], - atom->val.buf[12], - atom->val.buf[13], - atom->val.buf[14], - atom->val.buf[15]); + UUIDPrint(atom->val.buf); + fputs("\n", stdout); break; case YACItemUint: fprintf(stdout, "%zu\n", atom->val.uint); @@ -207,34 +192,23 @@ main(int argc, char **argv) { size_t len = 0; unsigned char *buf = NULL; - { - int fd = open(argv[1], O_RDONLY | O_CLOEXEC); - if (fd == -1) { - fprintf(stderr, "%s\n", strerror(errno)); - return EXIT_FAILURE; - } - struct stat sb; - memset(&sb, 0, sizeof(struct stat)); - if (fstat(fd, &sb) != 0) { - fprintf(stderr, "%s\n", strerror(errno)); - return EXIT_FAILURE; - } - len = (size_t)sb.st_size; - buf = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); + if (!Mmap(&buf, &len, argv[1])) { + fprintf(stderr, "%s\n", strerror(errno)); + exit(EXIT_FAILURE); } struct YACAtom atom; memset(&atom, 0, sizeof(struct YACAtom)); ptrdiff_t off = 0; enum YACErr err = YACAtomDecode(&atom, buf, len); if (err != YACErrNo) { - fprintf(stderr, "err: %d\n", err); + fprintf(stderr, "err: %s\n", YACErr2Str(err)); return EXIT_FAILURE; } off += atom.off; struct CbState cbState = {.indent = 0}; err = myCb(NULL, 0, -1, &cbState, &atom, &off, buf, len); if (err != YACErrNo) { - fprintf(stderr, "err: %d\n", err); + fprintf(stderr, "err: %s\n", YACErr2Str(err)); return EXIT_FAILURE; } assert(cbState.indent == 0); diff --git a/cyac/cmd/print-itered/print-itered.do b/cyac/cmd/print-itered/print-itered.do new file mode 100644 index 0000000..3fdc613 --- /dev/null +++ b/cyac/cmd/print-itered/print-itered.do @@ -0,0 +1,8 @@ +deps="../lib/hex.o ../lib/mmap.o ../lib/uuid.o" +redo-ifchange $1.c $deps \ + ../../conf/cc ../../conf/cflags ../../conf/ldflags ../../conf/prefix +read CC <../../conf/cc +CFLAGS=$(cat ../../conf/cflags) +LDFLAGS=$(cat ../../conf/ldflags) +read PREFIX <../../conf/prefix +$CC $CFLAGS -I$PREFIX/include -o $3 $2.c $deps $LDFLAGS -L$PREFIX/lib -lyac diff --git a/cyac/cmd/test-vector/.gitignore b/cyac/cmd/test-vector/.gitignore new file mode 100644 index 0000000..349f06b --- /dev/null +++ b/cyac/cmd/test-vector/.gitignore @@ -0,0 +1 @@ +/test-vector diff --git a/cyac/cmd/test-vector/all.do b/cyac/cmd/test-vector/all.do new file mode 100644 index 0000000..7d70447 --- /dev/null +++ b/cyac/cmd/test-vector/all.do @@ -0,0 +1 @@ +redo-ifchange test-vector diff --git a/cyac/cmd/test-vector/clean b/cyac/cmd/test-vector/clean new file mode 100755 index 0000000..a309a96 --- /dev/null +++ b/cyac/cmd/test-vector/clean @@ -0,0 +1,3 @@ +#!/bin/sh -e + +exec rm -f test-vector diff --git a/cyac/cmd/test-vector.c b/cyac/cmd/test-vector/test-vector.c similarity index 93% rename from cyac/cmd/test-vector.c rename to cyac/cmd/test-vector/test-vector.c index c341b84..c30329e 100644 --- a/cyac/cmd/test-vector.c +++ b/cyac/cmd/test-vector/test-vector.c @@ -168,6 +168,16 @@ main(int argc, char **argv) YACTimevalToTAI64(tai, &tv); adder(&off, YACAtomTAI64Encode(buf + off, len - off, tai, 12)); + adder( + &off, + YACAtomRawEncode( + buf + off, + len - off, + YACAtomTAI64N, + (const unsigned char + *)"\x40\x00\x00\x00\x49\x96\x02\xF4\x00\x06\xF8\x55", + 12)); + adder( &off, YACAtomRawEncode( @@ -175,7 +185,7 @@ main(int argc, char **argv) len - off, YACAtomTAI64NA, (const unsigned char - *)"\x40\x00\x00\x00\x00\x00\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99", + *)"\x40\x00\x00\x00\x49\x96\x02\xF4\x00\x06\xF8\x55\x07\x5B\xCD\x15", 16)); } adder(&off, YACAtomEOCEncode(buf + off, len - off)); // .dates @@ -206,6 +216,14 @@ main(int argc, char **argv) adder(&off, YACAtomBinEncode(buf + off, len - off, NULL, 0)); memset(bin, '\x00', 16); adder(&off, YACAtomUUIDEncode(buf + off, len - off, bin)); + adder( + &off, + YACAtomRawEncode( + buf + off, + len - off, + YACAtomTAI64, + (const unsigned char *)"\x00\x00\x00\x00\x00\x00\x00\x00", + 8)); adder(&off, YACAtomEOCEncode(buf + off, len - off)); // .empties adder(&off, YACAtomEOCEncode(buf + off, len - off)); // . diff --git a/cyac/cmd/test-vector/test-vector.do b/cyac/cmd/test-vector/test-vector.do new file mode 100644 index 0000000..28cdd53 --- /dev/null +++ b/cyac/cmd/test-vector/test-vector.do @@ -0,0 +1,6 @@ +redo-ifchange $1.c ../../conf/cc ../../conf/cflags ../../conf/ldflags ../../conf/prefix +read CC <../../conf/cc +CFLAGS=$(cat ../../conf/cflags) +LDFLAGS=$(cat ../../conf/ldflags) +read PREFIX <../../conf/prefix +$CC $CFLAGS -I$PREFIX/include -o $3 $2.c $LDFLAGS -L$PREFIX/lib -lyac diff --git a/cyac/default.o.do b/cyac/default.o.do deleted file mode 100644 index fe9918a..0000000 --- a/cyac/default.o.do +++ /dev/null @@ -1,4 +0,0 @@ -redo-ifchange $2.c $(./h-extract.pl $2.[ch]) conf/cc conf/cflags -read CC ) { - /^#include "([^\/]+)"$/ and ($1 !~ /\.in$/) and $inc{$1} = 1; + /^#include "(.+)"$/ and ($1 !~ /\.in$/) and $inc{$1} = 1; }; print join " ", sort keys %inc; diff --git a/cyac/install.do b/cyac/lib/install.do similarity index 68% rename from cyac/install.do rename to cyac/lib/install.do index b5dc6fa..c2d5470 100644 --- a/cyac/install.do +++ b/cyac/lib/install.do @@ -1,5 +1,5 @@ -redo-ifchange *.h libyac.a conf/prefix -read PREFIX #include "dec.h" +#include "enc.h" #include "err.h" #include "items.h" @@ -263,3 +264,202 @@ YACItemsParse( } return YACErrNo; } + +ptrdiff_t +YACItemsEncode( + struct YACItems *items, + ptrdiff_t idx, + ptrdiff_t *off, + unsigned char *buf, + const size_t cap) +{ + struct YACItem *item = &(items->list[idx]); + ptrdiff_t diff = 0; + switch (item->atom.typ) { + case YACItemEOC: + return -1; + case YACItemNIL: + diff = YACAtomNILEncode(buf + *off, cap - (size_t)(*off)); + break; + case YACItemFalse: + diff = YACAtomBoolEncode(buf + *off, cap - (size_t)(*off), false); + break; + case YACItemTrue: + diff = YACAtomBoolEncode(buf + *off, cap - (size_t)(*off), true); + break; + case YACItemUUID: + diff = YACAtomUUIDEncode(buf + *off, cap - (size_t)(*off), item->atom.val.buf); + break; + case YACItemUint: + diff = YACAtomUintEncode(buf + *off, cap - (size_t)(*off), item->atom.val.uint); + break; + case YACItemSint: + diff = YACAtomSintEncode(buf + *off, cap - (size_t)(*off), item->atom.val.sint); + break; + case YACItemList: + diff = YACAtomListEncode(buf + *off, cap - (size_t)(*off)); + if (diff < 0) { + return diff; + } + (*off) += diff; + idx = item->atom.val.first; + while (idx != -1) { + diff = YACItemsEncode(items, idx, off, buf, cap); + if (diff < 0) { + return diff; + } + idx = items->list[idx].next; + } + diff = YACAtomEOCEncode(buf + *off, cap - (size_t)(*off)); + break; + case YACItemMap: + diff = YACAtomMapEncode(buf + *off, cap - (size_t)(*off)); + if (diff < 0) { + return diff; + } + (*off) += diff; + idx = item->atom.val.first; + while (idx != -1) { + diff = YACItemsEncode(items, idx, off, buf, cap); + if (diff < 0) { + return diff; + } + idx = items->list[idx].next; + } + diff = YACAtomEOCEncode(buf + *off, cap - (size_t)(*off)); + break; + case YACItemBlob: { + size_t chunkLen = item->atom.val.uint; + diff = YACAtomBlobEncode(buf + *off, cap - (size_t)(*off), item->atom.val.uint); + if (diff < 0) { + return diff; + } + (*off) += diff; + for (;;) { + idx++; + item = &(items->list[idx]); + if (item->atom.len != chunkLen) { + break; + } + diff = YACAtomChunkEncode( + buf + *off, cap - (size_t)(*off), item->atom.val.buf, item->atom.len); + if (diff < 0) { + return diff; + } + (*off) += diff; + continue; + } + diff = YACAtomBinEncode( + buf + *off, cap - (size_t)(*off), item->atom.val.buf, item->atom.len); + break; + } + case YACItemFloat: + return -1; + case YACItemTAI64: + diff = YACAtomTAI64Encode( + buf + *off, cap - (size_t)(*off), item->atom.val.buf, item->atom.len); + break; + case YACItemBin: + diff = YACAtomBinEncode( + buf + *off, cap - (size_t)(*off), item->atom.val.buf, item->atom.len); + break; + case YACItemStr: + diff = YACAtomStrEncode( + buf + *off, cap - (size_t)(*off), item->atom.val.buf, item->atom.len); + break; + case YACItemRaw: + diff = YACAtomRawEncode( + buf + *off, + cap - (size_t)(*off), + item->atom.tag, + item->atom.val.buf, + item->atom.len); + break; + default: + return -1; + } + if (diff < 0) { + return diff; + } + (*off) += diff; + return 0; +} + +ptrdiff_t +YACItemsGetByKeyLen( + struct YACItems *items, + const ptrdiff_t itemIdx, + const char *key, + const size_t keyLen) +{ + struct YACItem *item = &(items->list[itemIdx]); + if (item->atom.typ != YACItemMap) { + return -1; + } + ptrdiff_t idx = item->atom.val.first; + while (idx != -1) { + if ((items->list[idx].atom.len == keyLen) && + (memcmp(items->list[idx].atom.val.buf, key, keyLen) == 0)) { + return idx + 1; + } + idx = items->list[idx].next; + idx = items->list[idx].next; + } + return -1; +} + +ptrdiff_t +YACItemsGetByKey(struct YACItems *items, const ptrdiff_t itemIdx, const char *key) +{ + return YACItemsGetByKeyLen(items, itemIdx, key, strlen(key)); +} + +ptrdiff_t +YACItemsGetByKeyAndType( + struct YACItems *items, + const ptrdiff_t itemIdx, + const char *key, + const enum YACItemType typ) +{ + ptrdiff_t idx = YACItemsGetByKey(items, itemIdx, key); + if (idx == -1) { + return -1; + } + if (items->list[idx].atom.typ != typ) { + return -1; + } + return idx; +} + +bool +YACStrEqual(struct YACAtom *atom, const char *s) +{ + return (atom->len == strlen(s)) && (memcmp(atom->val.buf, s, atom->len) == 0); +} + +bool +YACListHasOnlyType(struct YACItems *items, ptrdiff_t idx, const enum YACItemType typ) +{ + idx = items->list[idx].atom.val.first; + while (idx != -1) { + if (items->list[idx].atom.typ != typ) { + return false; + } + idx = items->list[idx].next; + } + return true; +} + +bool +YACMapHasOnlyType(struct YACItems *items, ptrdiff_t idx, const enum YACItemType typ) +{ + idx = items->list[idx].atom.val.first; + while (idx != -1) { + idx = items->list[idx].next; + if (items->list[idx].atom.typ != typ) { + return false; + } + idx = items->list[idx].next; + } + return true; +} diff --git a/cyac/items.h b/cyac/lib/items.h similarity index 62% rename from cyac/items.h rename to cyac/lib/items.h index 18c26d8..ae5de44 100644 --- a/cyac/items.h +++ b/cyac/lib/items.h @@ -1,6 +1,7 @@ #ifndef YAC_POOL_H #define YAC_POOL_H +#include #include #include "dec.h" @@ -17,7 +18,10 @@ // // Remember that @code{.next} of the list/map/blob is the (possible) // element after the whole list/map/blob. @code{.atom.val.first} is the -// (possible) first element inside those containers. +// (possible) first element inside map/list. +// +// Blob's first element always present and it is the next binary string +// item, until its length is less than chunk len. // @end deftypevar struct YACItem { ptrdiff_t next; @@ -51,4 +55,38 @@ YACItemsParse( const unsigned char *buf, const size_t len); +ptrdiff_t +YACItemsEncode( + struct YACItems *, + ptrdiff_t idx, + ptrdiff_t *off, + unsigned char *buf, + const size_t cap); + +ptrdiff_t +YACItemsGetByKeyLen( + struct YACItems *, + const ptrdiff_t itemIdx, + const char *key, + const size_t keyLen); + +ptrdiff_t +YACItemsGetByKey(struct YACItems *, const ptrdiff_t itemIdx, const char *key); + +ptrdiff_t +YACItemsGetByKeyAndType( + struct YACItems *, + const ptrdiff_t itemIdx, + const char *key, + const enum YACItemType typ); + +bool +YACStrEqual(struct YACAtom *, const char *s); + +bool +YACListHasOnlyType(struct YACItems *, ptrdiff_t idx, const enum YACItemType typ); + +bool +YACMapHasOnlyType(struct YACItems *, ptrdiff_t idx, const enum YACItemType typ); + #endif // YAC_POOL_H diff --git a/cyac/iter.c b/cyac/lib/iter.c similarity index 93% rename from cyac/iter.c rename to cyac/lib/iter.c index 17ce6a6..c7c2b5e 100644 --- a/cyac/iter.c +++ b/cyac/lib/iter.c @@ -33,7 +33,7 @@ YACIterList( enum YACErr err = YACErrInvalid; bool eoc = false; for (size_t n = 0;; n++) { - err = YACAtomDecode(atom, buf + *off, (size_t)((ptrdiff_t)len - *off)); + err = YACAtomDecode(atom, buf + *off, len - (size_t)(*off)); if (err != YACErrNo) { return err; } @@ -63,7 +63,7 @@ YACIterMap( size_t keyLen = 0; enum YACErr err = YACErrInvalid; for (;;) { - err = YACAtomDecode(atom, buf + *off, (size_t)((ptrdiff_t)len - *off)); + err = YACAtomDecode(atom, buf + *off, len - (size_t)(*off)); if (err != YACErrNo) { return err; } @@ -89,7 +89,7 @@ YACIterMap( } keyLen = atom->len; key = atom->val.buf; - err = YACAtomDecode(atom, buf + *off, (size_t)((ptrdiff_t)len - *off)); + err = YACAtomDecode(atom, buf + *off, len - (size_t)(*off)); if (err != YACErrNo) { return err; } @@ -118,7 +118,7 @@ YACIterBlob( enum YACErr err = YACErrInvalid; bool eoc = false; for (size_t n = 0; !eoc; n++) { - err = YACAtomDecode(atom, buf + *off, (size_t)((ptrdiff_t)len - *off)); + err = YACAtomDecode(atom, buf + *off, len - (size_t)(*off)); if (err != YACErrNo) { return err; } diff --git a/cyac/iter.h b/cyac/lib/iter.h similarity index 100% rename from cyac/iter.h rename to cyac/lib/iter.h diff --git a/cyac/leapsecs.c b/cyac/lib/leapsecs.c similarity index 100% rename from cyac/leapsecs.c rename to cyac/lib/leapsecs.c diff --git a/cyac/leapsecs.h b/cyac/lib/leapsecs.h similarity index 100% rename from cyac/leapsecs.h rename to cyac/lib/leapsecs.h diff --git a/cyac/libyac.a.do b/cyac/lib/libyac.a.do similarity index 58% rename from cyac/libyac.a.do rename to cyac/lib/libyac.a.do index 8068afa..0d627bd 100644 --- a/cyac/libyac.a.do +++ b/cyac/lib/libyac.a.do @@ -1,6 +1,6 @@ redo-ifchange o.list objs=$(cat o.list) -redo-ifchange $objs conf/ar -read AR +#include +#include + +#include "../dec.h" +#include "../dectai.h" +#include "../enc.h" +#include "../err.h" +#include "../items.h" +#include "cer.h" + +enum YACErr +YACCerParse( + struct YACCer *cer, + ptrdiff_t *off, + char **failReason, + const unsigned char *buf, + const size_t len) +{ + struct YACItems *items = &(cer->items); + YACItemsInit(items); + enum YACErr err = YACItemsParse(items, off, buf, len); + if (err != YACErrNo) { + return err; + } + ptrdiff_t idx = 0; + struct YACItem *item = NULL; + if (YACItemsGetByKey(items, 0, "hash") != -1) { + (*failReason) = "unexpected /hash"; + return YACErrUnsatisfiedSchema; + } + ptrdiff_t loadIdx = YACItemsGetByKey(items, 0, "load"); + { + if (loadIdx == -1) { + (*failReason) = "no /load"; + return YACErrUnsatisfiedSchema; + } + idx = YACItemsGetByKeyAndType(items, loadIdx, "t", YACItemStr); + if (loadIdx == -1) { + (*failReason) = "no /load/t"; + return YACErrUnsatisfiedSchema; + } + if (!YACStrEqual(&(items->list[idx].atom), "cer")) { + (*failReason) = "/load/t != cer"; + return YACErrUnsatisfiedSchema; + } + } + cer->load = YACItemsGetByKey(items, loadIdx, "v"); + { + if (cer->load == -1) { + (*failReason) = "no /load/v"; + return YACErrUnsatisfiedSchema; + } + idx = YACItemsGetByKey(items, cer->load, "ku"); + if (idx != -1) { + item = &(items->list[idx]); + if (item->atom.len == 0) { + (*failReason) = "empty /load/v/ku"; + return YACErrUnsatisfiedSchema; + } + if (!YACMapHasOnlyType(items, idx, YACItemNIL)) { + (*failReason) = "bad /load/v/ku value"; + return YACErrUnsatisfiedSchema; + } + } + } + idx = YACItemsGetByKey(items, cer->load, "pub"); + { + if (idx == -1) { + (*failReason) = "no /load/v/pub"; + return YACErrUnsatisfiedSchema; + } + item = &(items->list[idx]); + if (item->atom.len != 1) { + (*failReason) = "len(/load/v/pub) != 1"; + return YACErrUnsatisfiedSchema; + } + idx = items->list[idx].atom.val.first; + cer->pub = idx; + while (idx != -1) { + if (YACItemsGetByKeyAndType(items, idx, "a", YACItemStr) == -1) { + (*failReason) = "no /load/v/pub/a"; + return YACErrUnsatisfiedSchema; + } + if (YACItemsGetByKeyAndType(items, idx, "v", YACItemBin) == -1) { + (*failReason) = "no /load/v/pub/v"; + return YACErrUnsatisfiedSchema; + } + { + ptrdiff_t pkidIdx = + YACItemsGetByKeyAndType(items, idx, "id", YACItemUUID); + if (pkidIdx == -1) { + (*failReason) = "no /load/v/pub/id"; + return YACErrUnsatisfiedSchema; + } + cer->pkid = items->list[pkidIdx].atom.val.buf; + } + idx = items->list[idx].next; + } + } + cer->sub = YACItemsGetByKey(items, cer->load, "sub"); + { + if (cer->sub == -1) { + (*failReason) = "no /load/v/sub"; + return YACErrUnsatisfiedSchema; + } + item = &(items->list[cer->sub]); + if (item->atom.len == 0) { + (*failReason) = "empty /load/v/sub"; + return YACErrUnsatisfiedSchema; + } + if (!YACMapHasOnlyType(items, cer->sub, YACItemStr)) { + (*failReason) = "bad /load/v/sub value"; + return YACErrUnsatisfiedSchema; + } + } + if (YACItemsGetByKey(items, cer->load, "crit") != -1) { + (*failReason) = "/load/v/crit is unsupported"; + return YACErrUnsatisfiedSchema; + } + ptrdiff_t sigsIdx = YACItemsGetByKey(items, 0, "sigs"); + { + if (sigsIdx == -1) { + (*failReason) = "no /sigs"; + return YACErrUnsatisfiedSchema; + } + item = &(items->list[sigsIdx]); + if (item->atom.len != 1) { + (*failReason) = "len(/load/sigs) != 1"; + return YACErrUnsatisfiedSchema; + } + ptrdiff_t sigIdx = items->list[sigsIdx].atom.val.first; + cer->sig = sigIdx; + while (sigIdx != -1) { + if (YACItemsGetByKey(items, sigIdx, "hash") != -1) { + (*failReason) = "unexpected /sigs/./hash met"; + return YACErrUnsatisfiedSchema; + } + { + idx = YACItemsGetByKey(items, sigIdx, "sign"); + if (idx == -1) { + (*failReason) = "no /sigs/./sign"; + return YACErrUnsatisfiedSchema; + } + if (YACItemsGetByKeyAndType(items, idx, "a", YACItemStr) == -1) { + (*failReason) = "no /sigs/./sign/a"; + return YACErrUnsatisfiedSchema; + } + if (YACItemsGetByKeyAndType(items, idx, "v", YACItemBin) == -1) { + (*failReason) = "no /sigs/./sign/v"; + return YACErrUnsatisfiedSchema; + } + } + { + idx = YACItemsGetByKey(items, sigIdx, "tbs"); + if (idx == -1) { + (*failReason) = "no /sigs/./tbs"; + return YACErrUnsatisfiedSchema; + } + { + ptrdiff_t cidIdx = + YACItemsGetByKeyAndType(items, idx, "cid", YACItemUUID); + if (cidIdx == -1) { + (*failReason) = "no /sigs/./tbs/cid"; + return YACErrUnsatisfiedSchema; + } + cer->cid = items->list[cidIdx].atom.val.buf; + } + { + ptrdiff_t sidIdx = + YACItemsGetByKeyAndType(items, idx, "sid", YACItemUUID); + if (sidIdx == -1) { + (*failReason) = "no /sigs/./tbs/sid"; + return YACErrUnsatisfiedSchema; + } + cer->sid = items->list[sidIdx].atom.val.buf; + } + idx = YACItemsGetByKeyAndType(items, idx, "exp", YACItemList); + if (idx == -1) { + (*failReason) = "no /sigs/./tbs/exp"; + return YACErrUnsatisfiedSchema; + } + if (!YACListHasOnlyType(items, idx, YACItemTAI64)) { + (*failReason) = "bad /sigs/./tbs/exp value"; + return YACErrUnsatisfiedSchema; + } + item = &(items->list[idx]); + if (item->atom.len != 2) { + (*failReason) = "len(/sigs/./tbs/exp) != 2"; + return YACErrUnsatisfiedSchema; + } + err = YACTAI64ToTimeval( + &(cer->since), + items->list[idx + 1].atom.val.buf, + items->list[idx + 1].atom.len); + if ((err != YACErrNo) || (cer->since.tv_usec != 0)) { + (*failReason) = "bad /sigs/./tbs/exp/since value"; + return YACErrUnsatisfiedSchema; + } + err = YACTAI64ToTimeval( + &(cer->till), + items->list[idx + 2].atom.val.buf, + items->list[idx + 2].atom.len); + if ((err != YACErrNo) || (cer->till.tv_usec != 0)) { + (*failReason) = "bad /sigs/./tbs/exp/till value"; + return YACErrUnsatisfiedSchema; + } + } + sigIdx = items->list[sigIdx].next; + } + } + return YACErrNo; +} + +bool +YACCerVerify( + char **failReason, + struct YACCer **verifier, + struct YACCer *cer, + struct YACCer *pool, + const size_t poolLen, + struct YACCerVerifyOpts 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 YACItem *pubA = &((*verifier)->items.list[YACItemsGetByKey( + &((*verifier)->items), (*verifier)->pub, "a")]); + struct YACItem *pubV = &((*verifier)->items.list[YACItemsGetByKey( + &((*verifier)->items), (*verifier)->pub, "v")]); + ptrdiff_t signIdx = YACItemsGetByKey(&(cer->items), cer->sig, "sign"); + struct YACItem *sigV = + &(cer->items.list[YACItemsGetByKey(&(cer->items), signIdx, "v")]); + { + struct YACItem *sigA = + &(cer->items.list[YACItemsGetByKey(&(cer->items), signIdx, "a")]); + if ((sigA->atom.len != pubA->atom.len) || + (memcmp(sigA->atom.val.buf, pubA->atom.val.buf, sigA->atom.len) != 0)) { + (*failReason) = "sign.a != pub.a"; + return false; + } + } + const size_t cap = 1 << 10; + unsigned char buf[1 << 10] = {0}; + ptrdiff_t off = 0; + { + const size_t items = 5; + struct YACItem tbsItems[5]; + memset(&tbsItems, 0, sizeof tbsItems); + struct YACItems tbs = {.list = tbsItems, items, items}; + tbsItems[0].atom.typ = YACItemMap; + tbsItems[0].atom.val.first = 1; + + tbsItems[1].atom.typ = YACItemStr; + tbsItems[1].atom.len = 1; + tbsItems[1].atom.val.buf = (const unsigned char *)"t"; + tbsItems[1].next = 2; + + tbsItems[2].atom.typ = YACItemStr; + tbsItems[2].atom.len = 3; + tbsItems[2].atom.val.buf = (const unsigned char *)"cer"; + tbsItems[2].next = 3; + + tbsItems[3].atom.typ = YACItemStr; + tbsItems[3].atom.len = 1; + tbsItems[3].atom.val.buf = (const unsigned char *)"v"; + tbsItems[3].next = 4; + + tbsItems[4].atom.typ = YACItemNIL; + tbsItems[4].next = -1; + + if (YACItemsEncode(&tbs, 0, &off, buf, cap) != 0) { + (*failReason) = "can not prepare tbs"; + return false; + } + } + off -= 2; // strip off NIL and EOC, continue map generation + if (YACItemsEncode(&(cer->items), cer->load, &off, buf, cap) != 0) { + (*failReason) = "can not prepare tbs"; + return false; + } + { + ptrdiff_t diff = YACAtomStrEncode( + buf + off, cap - (size_t)off, (const unsigned char *)"tbs", 3); + if (diff < 1) { + (*failReason) = "can not prepare tbs"; + return false; + } + off += diff; + } + if (YACItemsEncode( + &(cer->items), + YACItemsGetByKey(&(cer->items), cer->sig, "tbs"), + &off, + buf, + cap) != 0) { + (*failReason) = "can not prepare tbs"; + return false; + } + { + ptrdiff_t diff = YACAtomEOCEncode(buf + off, cap - (size_t)off); + if (diff < 1) { + (*failReason) = "can not prepare tbs"; + return false; + } + off += diff; + } + for (size_t i = 0; i < opts.sigVerifiersLen; i++) { + if (!YACStrEqual(&(pubA->atom), opts.sigVerifiers[i].algo)) { + continue; + } + return opts.sigVerifiers[i].func( + failReason, + pubA->atom.val.buf, + pubA->atom.len, + sigV->atom.val.buf, + sigV->atom.len, + pubV->atom.val.buf, + pubV->atom.len, + buf, + (size_t)off); + } + (*failReason) = "no signature verifier found"; + return false; +} diff --git a/cyac/lib/pki/cer.h b/cyac/lib/pki/cer.h new file mode 100644 index 0000000..052a0ab --- /dev/null +++ b/cyac/lib/pki/cer.h @@ -0,0 +1,63 @@ +#ifndef YAC_CER_H +#define YAC_CER_H + +#include +#include +#include + +#include "../err.h" +#include "../items.h" + +struct YACCer { + struct YACItems items; + ptrdiff_t load; + ptrdiff_t pub; + ptrdiff_t sub; + ptrdiff_t sig; + const unsigned char *cid; + const unsigned char *pkid; + const unsigned char *sid; + struct timeval since; + struct timeval till; +}; + +enum YACErr +YACCerParse( + struct YACCer *, + ptrdiff_t *off, + char **failReason, + const unsigned char *buf, + const size_t len); + +typedef bool (*yacSigVerifier)( + 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); + +struct YACCerSigVerifier { + char *algo; + yacSigVerifier func; +}; + +struct YACCerVerifyOpts { + struct timeval t; + struct YACCerSigVerifier *sigVerifiers; + size_t sigVerifiersLen; +}; + +bool +YACCerVerify( + char **failReason, + struct YACCer **verifier, + struct YACCer *cer, + struct YACCer *pool, + const size_t poolLen, + struct YACCerVerifyOpts opts); + +#endif // YAC_CER_H diff --git a/cyac/lib/pki/clean b/cyac/lib/pki/clean new file mode 100755 index 0000000..318e647 --- /dev/null +++ b/cyac/lib/pki/clean @@ -0,0 +1,3 @@ +#!/bin/sh -e + +exec rm -f *.o *.a diff --git a/cyac/lib/pki/install.do b/cyac/lib/pki/install.do new file mode 100644 index 0000000..219b91b --- /dev/null +++ b/cyac/lib/pki/install.do @@ -0,0 +1,6 @@ +redo-ifchange *.h libyacpki.a ../../conf/prefix +read PREFIX <../../conf/prefix +mkdir -p $PREFIX/include/yac/pki $PREFIX/lib +cp -f *.h $PREFIX/include/yac/pki +cp -f libyacpki.a $PREFIX/lib +chmod 644 $PREFIX/include/yac/pki/*.h $PREFIX/lib/libyacpki.a diff --git a/cyac/lib/pki/libyacpki.a.do b/cyac/lib/pki/libyacpki.a.do new file mode 100644 index 0000000..437e92a --- /dev/null +++ b/cyac/lib/pki/libyacpki.a.do @@ -0,0 +1,6 @@ +redo-ifchange o.list +objs=$(cat o.list) +redo-ifchange $objs ../../conf/ar +read AR <../../conf/ar +$AR -rcs $3.a $objs +mv $3.a $3 diff --git a/cyac/lib/pki/o.list b/cyac/lib/pki/o.list new file mode 100644 index 0000000..c7f1e63 --- /dev/null +++ b/cyac/lib/pki/o.list @@ -0,0 +1 @@ +cer.o diff --git a/cyac/tobe.c b/cyac/lib/tobe.c similarity index 100% rename from cyac/tobe.c rename to cyac/lib/tobe.c diff --git a/cyac/tobe.h b/cyac/lib/tobe.h similarity index 100% rename from cyac/tobe.h rename to cyac/lib/tobe.h diff --git a/cyac/utf8.c b/cyac/lib/utf8.c similarity index 100% rename from cyac/utf8.c rename to cyac/lib/utf8.c diff --git a/cyac/utf8.h b/cyac/lib/utf8.h similarity index 100% rename from cyac/utf8.h rename to cyac/lib/utf8.h