-/*.o
/compile_flags.txt
-/libyac.a
+++ /dev/null
-/print-items
-/print-itered
-/test-vector
+++ /dev/null
-redo-ifchange print-items print-itered test-vector
--- /dev/null
+/cer-verify
+/compile_flags.txt
--- /dev/null
+redo-ifchange cer-verify
--- /dev/null
+// cyac -- C YAC encoder implementation
+// Copyright (C) 2024 Sergey Matveev <stargrave@stargrave.org>
+//
+// 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 <http://www.gnu.org/licenses/>.
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <yac/err.h>
+#include <yac/pki/cer.h>
+
+#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;
+}
--- /dev/null
+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
--- /dev/null
+#!/bin/sh -e
+
+exec rm -f cer-verify compile_flags.txt conf/gcl3.rc
--- /dev/null
+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
--- /dev/null
+PKGCONF=${PKGCONF:-`command -v pkgconf || command -v pkg-config`}
+cat <<EOF
+{
+ read GCL3_CFLAGS
+ read GCL3_LDFLAGS
+ read GCL3_LDLIBS
+} <<EOF
+EOF
+$PKGCONF --cflags gcl3
+$PKGCONF --libs-only-L gcl3
+$PKGCONF --libs-only-l gcl3
+echo EOF
--- /dev/null
+#include <stdint.h>
+
+// 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
--- /dev/null
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
+#pragma clang diagnostic ignored "-Wreserved-id-macro"
+#include <gcl.h>
+#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;
+}
--- /dev/null
+#ifndef YAC_VERIFIER_GOST3410_H
+#define YAC_VERIFIER_GOST3410_H
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+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
--- /dev/null
+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
#!/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 )
+++ /dev/null
-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
--- /dev/null
+#!/bin/sh -e
+
+exec rm -f *.o
--- /dev/null
+redo-ifchange $2.c ../../conf/cc ../../conf/cflags
+read CC <../../conf/cc
+CFLAGS=$(cat ../../conf/cflags)
+$CC $CFLAGS -c -o $3 $2.c
#include <stdlib.h>
-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
--- /dev/null
+#ifndef YAC_HEX_H
+#define YAC_HEX_H
+
+#include <stdlib.h>
+
+char *
+HexEnc(const unsigned char *src, const size_t srcLen);
+
+#endif // YAC_HEX_H
--- /dev/null
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#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;
+}
--- /dev/null
+#ifndef YAC_MMAP_H
+#define YAC_MMAP_H
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+bool
+Mmap(unsigned char **buf, size_t *len, const char *path);
+
+#endif // YAC_MMAP_H
--- /dev/null
+#include <stdio.h>
+
+#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]);
+}
--- /dev/null
+#ifndef YAC_UUID_H
+#define YAC_UUID_H
+
+void
+UUIDPrint(const unsigned char *buf);
+
+#endif // YAC_UUID_H
--- /dev/null
+/print-items
--- /dev/null
+redo-ifchange print-items
--- /dev/null
+#!/bin/sh -e
+
+exec rm -f print-items
#include <assert.h>
#include <errno.h>
-#include <fcntl.h>
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <yac/err.h>
#include <yac/items.h>
-#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";
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);
{
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;
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;
}
--- /dev/null
+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
--- /dev/null
+/print-itered
--- /dev/null
+redo-ifchange print-itered
--- /dev/null
+#!/bin/sh -e
+
+exec rm -f print-itered
#include <assert.h>
#include <errno.h>
-#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <yac/err.h>
#include <yac/iter.h>
-#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;
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);
{
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);
--- /dev/null
+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
--- /dev/null
+/test-vector
--- /dev/null
+redo-ifchange test-vector
--- /dev/null
+#!/bin/sh -e
+
+exec rm -f test-vector
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(
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
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)); // .
--- /dev/null
+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
+++ /dev/null
-redo-ifchange $2.c $(./h-extract.pl $2.[ch]) conf/cc conf/cflags
-read CC <conf/cc
-CFLAGS=$(cat conf/cflags)
-$CC $CFLAGS -c -o $3 $2.c
--- /dev/null
+/*.o
+/compile_flags.txt
+/libyac.a
#!/bin/sh -e
-( cd cmd ; ./clean )
+( cd pki ; ./clean )
exec rm -f *.o *.a compile_flags.txt
--- /dev/null
+deps="../conf/cc ../conf/cflags"
+dir=$(dirname $1)
+for dep in $(./h-extract.pl $2.[ch]) ; do deps="$deps $dir/$dep"; done
+redo-ifchange $deps
+read CC <../conf/cc
+CFLAGS=$(cat ../conf/cflags)
+$CC $CFLAGS -c -o $3 $2.c
--- /dev/null
+#include "err.h"
+
+const char *
+YACErr2Str(const enum YACErr err)
+{
+ switch (err) {
+ case YACErrInvalid:
+ return "Invalid";
+ case YACErrNo:
+ return "No";
+ case YACErrNotEnough:
+ return "NotEnough";
+ case YACErrUnknownType:
+ return "UnknownType";
+ case YACErrLenNonMinimal:
+ return "LenNonMinimal";
+ case YACErrLenTooBig:
+ return "LenTooBig";
+ case YACErrBadUTF8:
+ return "BadUTF8";
+ case YACErrIntZeroByte:
+ return "IntZeroByte";
+ case YACErrIntNonMinimal:
+ return "IntNonMinimal";
+ case YACErrBlobBadLen:
+ return "BlobBadLen";
+ case YACErrBlobBadAtom:
+ return "BlobBadAtom";
+ case YACErrBlobBadTerm:
+ return "BlobBadTerm";
+ case YACErrTAI64TooBig:
+ return "TAI64TooBig";
+ case YACErrTAI64BadNsec:
+ return "TAI64BadNsec";
+ case YACErrTAI64BadAsec:
+ return "TAI64BadAsec";
+ case YACErrMapBadKey:
+ return "MapBadKey";
+ case YACErrMapNoVal:
+ return "MapNoVal";
+ case YACErrMapUnordered:
+ return "MapUnordered";
+ case YACErrNoMem:
+ return "NoMem";
+ case YACErrUnsatisfiedSchema:
+ return "UnsatisfiedSchema";
+ default:
+ return "unknown";
+ }
+}
// Unordered map keys.
// @item YACErrNoMem
// Not enough memory for allocation.
+// @item YACErrUnsatisfiedSchema
+// Unsatisfied structure's schema.
// @end table
// @end deftypevar
enum YACErr {
YACErrMapNoVal,
YACErrMapUnordered,
YACErrNoMem,
+ YACErrUnsatisfiedSchema,
};
+const char *
+YACErr2Str(const enum YACErr);
+
#endif // YAC_ERR_H
# hack, to badly exit if there is unexistent file
$SIG{__WARN__} = sub { die @_ };
-map { $inc{$_} = 1 } @ARGV;
+use File::Basename;
+
+map { $inc{basename($_)} = 1 } @ARGV;
while (<>) {
- /^#include "([^\/]+)"$/ and ($1 !~ /\.in$/) and $inc{$1} = 1;
+ /^#include "(.+)"$/ and ($1 !~ /\.in$/) and $inc{$1} = 1;
};
print join " ", sort keys %inc;
-redo-ifchange *.h libyac.a conf/prefix
-read PREFIX <conf/prefix
+redo-ifchange *.h libyac.a ../conf/prefix
+read PREFIX <../conf/prefix
mkdir -p $PREFIX/include/yac $PREFIX/lib
cp -f *.h $PREFIX/include/yac
cp -f libyac.a $PREFIX/lib
#include <string.h>
#include "dec.h"
+#include "enc.h"
#include "err.h"
#include "items.h"
}
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;
+}
#ifndef YAC_POOL_H
#define YAC_POOL_H
+#include <stdbool.h>
#include <stddef.h>
#include "dec.h"
//
// 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;
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
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;
}
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;
}
}
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;
}
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;
}
redo-ifchange o.list
objs=$(cat o.list)
-redo-ifchange $objs conf/ar
-read AR <conf/ar
+redo-ifchange $objs ../conf/ar
+read AR <../conf/ar
$AR -rcs $3.a $objs
mv $3.a $3
dectai.o
enc.o
enctai.o
+err.o
frombe.o
items.o
iter.o
--- /dev/null
+/libyacpki.a
--- /dev/null
+#include <stddef.h>
+#include <string.h>
+#include <sys/time.h>
+
+#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;
+}
--- /dev/null
+#ifndef YAC_CER_H
+#define YAC_CER_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <sys/time.h>
+
+#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
--- /dev/null
+#!/bin/sh -e
+
+exec rm -f *.o *.a
--- /dev/null
+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
--- /dev/null
+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